Caffe2 - C++ API
A deep learning, cross platform ML framework
normalize_op.cc
1 
17 #include "caffe2/operators/normalize_op.h"
18 
19 #include "caffe2/core/tensor.h"
20 
21 namespace caffe2 {
22 
23 template <typename T, class Context>
24 void NormalizeOp<T, Context>::DoNormalize(
25  const T* xData,
26  T* yData,
27  const int m,
28  const int n,
29  const int sf) {
30  using InnerStride = Eigen::InnerStride<Eigen::Dynamic>;
31  using StridedVec =
32  Eigen::Map<Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
33  using ConstStridedVec =
34  Eigen::Map<const Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
35 
36  for (int i = 0; i < n; ++i) {
37  auto base = (i / sf) * sf * m + (i % sf);
38  ConstStridedVec xVec(xData + base, 1, m, InnerStride(sf));
39  auto norm = xVec.template lpNorm<2>();
40  if (norm != 0) {
41  StridedVec yVec(yData + base, 1, m, InnerStride(sf));
42  yVec = xVec / norm;
43  }
44  }
45 };
46 
47 template <typename T, class Context>
48 void NormalizeGradientOp<T, Context>::DoNormalize(
49  const T* xData,
50  const T* gOutData,
51  T* gInData,
52  const int m,
53  const int n,
54  const int sf) {
55  using InnerStride = Eigen::InnerStride<Eigen::Dynamic>;
56  using StridedVec =
57  Eigen::Map<Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
58  using ConstStridedVec =
59  Eigen::Map<const Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
60 
61  for (int i = 0; i < n; ++i) {
62  auto base = (i / sf) * sf * m + (i % sf);
63  ConstStridedVec xVec(xData + base, 1, m, InnerStride(sf));
64  ConstStridedVec gOutVec(gOutData + base, 1, m, InnerStride(sf));
65 
66  auto row_sum = xVec.dot(gOutVec);
67  auto row_norm = xVec.template lpNorm<2>();
68  auto row_norm_3 = pow(row_norm, 3);
69  if (row_norm != 0) {
70  StridedVec gInVec(gInData + base, 1, m, InnerStride(sf));
71  gInVec = (gOutVec / row_norm) - ((xVec / row_norm_3) * row_sum);
72  }
73  }
74 };
75 
76 REGISTER_CPU_OPERATOR(Normalize, NormalizeOp<float, CPUContext>);
77 OPERATOR_SCHEMA(Normalize)
78  .NumInputs(1)
79  .NumOutputs(1)
80  .Arg("axis", "axis to normalize")
81  .SetDoc(R"DOC(
82 Given a matrix, apply L2-normalization along the specified dimension.
83 )DOC")
84  .IdenticalTypeAndShape();
85 
86 REGISTER_CPU_OPERATOR(
87  NormalizeGradient,
88  NormalizeGradientOp<float, CPUContext>);
89 OPERATOR_SCHEMA(NormalizeGradient)
90  .NumInputs(2)
91  .NumOutputs(1)
92  .Arg("axis", "axis to normalize");
93 
94 class GetNormalizeGradient final : public GradientMakerBase {
95  using GradientMakerBase::GradientMakerBase;
96  vector<OperatorDef> GetGradientDefs() override {
97  CAFFE_ENFORCE_EQ(def_.input_size(), 1);
98  return SingleGradientDef(
99  "NormalizeGradient",
100  "",
101  vector<string>{I(0), GO(0)},
102  vector<string>{GI(0)});
103  }
104 };
105 REGISTER_GRADIENT(Normalize, GetNormalizeGradient);
106 
107 } // namespace caffe2
Copyright (c) 2016-present, Facebook, Inc.
static vector< OperatorDef > SingleGradientDef(const Args &...args)
a helper function to allow one to create one single operator def, which is usually the case for many ...