Caffe2 - C++ API
A deep learning, cross platform ML framework
normalize_op.cc
1 #include "caffe2/operators/normalize_op.h"
2 
3 #include "caffe2/core/tensor.h"
4 
5 namespace caffe2 {
6 
7 template <typename T, class Context>
8 void NormalizeOp<T, Context>::DoNormalize(
9  const T* xData,
10  T* yData,
11  const int m,
12  const int n,
13  const int sf) {
14  using InnerStride = Eigen::InnerStride<Eigen::Dynamic>;
15  using StridedVec =
16  Eigen::Map<Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
17  using ConstStridedVec =
18  Eigen::Map<const Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
19 
20  for (int i = 0; i < n; ++i) {
21  auto base = (i / sf) * sf * m + (i % sf);
22  ConstStridedVec xVec(xData + base, 1, m, InnerStride(sf));
23  auto norm = xVec.template lpNorm<2>();
24  if (norm != 0) {
25  StridedVec yVec(yData + base, 1, m, InnerStride(sf));
26  yVec = xVec / norm;
27  }
28  }
29 };
30 
31 template <typename T, class Context>
32 void NormalizeGradientOp<T, Context>::DoNormalize(
33  const T* xData,
34  const T* gOutData,
35  T* gInData,
36  const int m,
37  const int n,
38  const int sf) {
39  using InnerStride = Eigen::InnerStride<Eigen::Dynamic>;
40  using StridedVec =
41  Eigen::Map<Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
42  using ConstStridedVec =
43  Eigen::Map<const Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
44 
45  for (int i = 0; i < n; ++i) {
46  auto base = (i / sf) * sf * m + (i % sf);
47  ConstStridedVec xVec(xData + base, 1, m, InnerStride(sf));
48  ConstStridedVec gOutVec(gOutData + base, 1, m, InnerStride(sf));
49 
50  auto row_sum = xVec.dot(gOutVec);
51  auto row_norm = xVec.template lpNorm<2>();
52  auto row_norm_3 = pow(row_norm, 3);
53  if (row_norm != 0) {
54  StridedVec gInVec(gInData + base, 1, m, InnerStride(sf));
55  gInVec = (gOutVec / row_norm) - ((xVec / row_norm_3) * row_sum);
56  }
57  }
58 };
59 
60 REGISTER_CPU_OPERATOR(Normalize, NormalizeOp<float, CPUContext>);
61 OPERATOR_SCHEMA(Normalize)
62  .NumInputs(1)
63  .NumOutputs(1)
64  .Arg("axis", "axis to normalize")
65  .SetDoc(R"DOC(
66 Given a matrix, apply L2-normalization along the specified dimension.
67 )DOC")
68  .IdenticalTypeAndShape();
69 
70 REGISTER_CPU_OPERATOR(
71  NormalizeGradient,
72  NormalizeGradientOp<float, CPUContext>);
73 OPERATOR_SCHEMA(NormalizeGradient)
74  .NumInputs(2)
75  .NumOutputs(1)
76  .Arg("axis", "axis to normalize");
77 
78 class GetNormalizeGradient final : public GradientMakerBase {
79  using GradientMakerBase::GradientMakerBase;
80  vector<OperatorDef> GetGradientDefs() override {
81  CAFFE_ENFORCE_EQ(def_.input_size(), 1);
82  return SingleGradientDef(
83  "NormalizeGradient",
84  "",
85  vector<string>{I(0), GO(0)},
86  vector<string>{GI(0)});
87  }
88 };
89 REGISTER_GRADIENT(Normalize, GetNormalizeGradient);
90 
91 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
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 ...