Caffe2 - C++ API
A deep learning, cross platform ML framework
normalize_op.h
1 #ifndef CAFFE2_OPERATORS_NORMALIZE_OP_H_
2 #define CAFFE2_OPERATORS_NORMALIZE_OP_H_
3 
4 #include "caffe2/core/context.h"
5 #include "caffe2/core/operator.h"
6 #include "caffe2/utils/eigen_utils.h"
7 #include "caffe2/utils/math.h"
8 
9 #define KEPS 1e-12f
10 
11 namespace caffe2 {
12 
13 template <typename T, class Context>
14 class NormalizeOp final : public Operator<Context> {
15  public:
16  USE_OPERATOR_CONTEXT_FUNCTIONS;
17  template <class... Args>
18  explicit NormalizeOp(Args&&... args)
19  : Operator<Context>(std::forward<Args>(args)...) {}
20 
21  bool RunOnDevice() override {
22  const auto& x = Input(0);
23 
24  const auto* xData = x.template data<T>();
25  auto* y = Output(0, x.sizes(), at::dtype<T>());
26  auto* yData = y->template mutable_data<T>();
27 
28  const auto canonical_axis = x.canonical_axis_index(
29  this->template GetSingleArgument<int>("axis", -1));
30  const int m = x.dim32(canonical_axis);
31  const int n = x.numel() / m;
32  const int sf = x.size_from_dim(canonical_axis + 1);
33  DoNormalize(xData, yData, m, n, sf);
34  return true;
35  }
36 
37  private:
38  const T kEps_ = KEPS;
39  void DoNormalize(
40  const T* xData,
41  T* yData,
42  const int m,
43  const int n,
44  const int sf) {
45  using InnerStride = Eigen::InnerStride<Eigen::Dynamic>;
46  using StridedVec =
47  Eigen::Map<Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
48  using ConstStridedVec =
49  Eigen::Map<const Eigen::Matrix<T, 1, Eigen::Dynamic>, 0, InnerStride>;
50 
51  for (int i = 0; i < n; ++i) {
52  auto base = (i / sf) * sf * m + (i % sf);
53  ConstStridedVec xVec(xData + base, 1, m, InnerStride(sf));
54  auto norm = xVec.template lpNorm<2>();
55  norm = std::max(norm, kEps_);
56  StridedVec yVec(yData + base, 1, m, InnerStride(sf));
57  yVec = xVec / norm;
58  }
59  }
60 };
61 
62 template <typename T, class Context>
63 class NormalizeGradientOp final : public Operator<Context> {
64  public:
65  USE_OPERATOR_CONTEXT_FUNCTIONS;
66  template <class... Args>
67  explicit NormalizeGradientOp(Args&&... args)
68  : Operator<Context>(std::forward<Args>(args)...) {}
69 
70  bool RunOnDevice() override {
71  const auto& x = Input(0);
72  const auto& gOut = Input(GRAD_OUT);
73 
74  auto* gIn = Output(GRAD_IN, gOut.sizes(), at::dtype<T>());
75 
76  const auto* xData = x.template data<T>();
77  const auto* gOutData = gOut.template data<T>();
78  auto* gInData = gIn->template mutable_data<T>();
79 
80  const auto canonical_axis = x.canonical_axis_index(
81  this->template GetSingleArgument<int>("axis", -1));
82  const int m = x.dim32(canonical_axis);
83  const int n = x.numel() / m;
84  const int sf = x.size_from_dim(canonical_axis + 1);
85  DoNormalize(xData, gOutData, gInData, m, n, sf);
86  return true;
87  }
88 
89  private:
90  const T kEps_ = KEPS;
91  void DoNormalize(
92  const T* xData,
93  const T* gOutData,
94  T* gInData,
95  const int m,
96  const int n,
97  const int sf);
98 
99  INPUT_TAGS(INPUT, GRAD_OUT);
100  OUTPUT_TAGS(GRAD_IN);
101 };
102 
103 } // namespace caffe2
104 
105 #endif // CAFFE2_OPERATORS_NORMALIZE_OP_H_
const Tensor & Input(int idx, DeviceType type=Context::GetDeviceType())
Retrieve a non-owning reference to the input at position &#39;idx&#39; for this operator. ...
Definition: operator.h:702
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13