Caffe2 - C++ API
A deep learning, cross platform ML framework
reduction_ops.cc
1 #include "caffe2/operators/reduction_ops.h"
2 
3 namespace caffe2 {
4 
5 REGISTER_CPU_OPERATOR(SumElements, SumElementsOp<float, CPUContext>);
6 REGISTER_CPU_OPERATOR(SumElementsInt, SumElementsIntOp<int, CPUContext>);
7 REGISTER_CPU_OPERATOR(SumSqrElements, SumSqrElementsOp<CPUContext>);
8 
9 REGISTER_CPU_OPERATOR(
10  SumElementsGradient,
11  SumElementsGradientOp<float, CPUContext>);
12 
13 REGISTER_CPU_OPERATOR(RowwiseMax, MaxReductionOp<float, CPUContext, true>);
14 REGISTER_CPU_OPERATOR(
15  RowwiseMaxGradient,
16  MaxReductionGradientOp<float, CPUContext, true>);
17 REGISTER_CPU_OPERATOR(
18  ColwiseMaxGradient,
19  MaxReductionGradientOp<float, CPUContext, false>);
20 REGISTER_CPU_OPERATOR(ColwiseMax, MaxReductionOp<float, CPUContext, false>);
21 
22 OPERATOR_SCHEMA(SumElements)
23  .NumInputs(1)
24  .NumOutputs(1)
25  .ScalarType(TensorProto::FLOAT)
26  .SetDoc("Sums the elements of the input tensor.")
27  .Arg("average", "whether to average or not")
28  .Input(0, "X", "Tensor to sum up")
29  .Output(0, "sum", "Scalar sum");
30 
31 OPERATOR_SCHEMA(SumElementsInt)
32  .NumInputs(1)
33  .NumOutputs(1)
34  .ScalarType(TensorProto::INT32)
35  .SetDoc("Sums the integer elements of the input tensor.")
36  .Input(0, "X", "Tensor to sum up")
37  .Output(0, "sum", "Scalar sum");
38 SHOULD_NOT_DO_GRADIENT(SumElementsInt);
39 
40 OPERATOR_SCHEMA(SumSqrElements)
41  .NumInputs(1)
42  .NumOutputs(1)
43  .ScalarType(TensorProto::FLOAT)
44  .SetDoc("Sums the squares elements of the input tensor.")
45  .Arg("average", "whether to average or not")
46  .Input(0, "X", "Tensor to sum up")
47  .Output(0, "sum", "Scalar sum of squares");
48 
49 OPERATOR_SCHEMA(SumElementsGradient).NumInputs(2).NumOutputs(1);
50 
52  using GradientMakerBase::GradientMakerBase;
53  vector<OperatorDef> GetGradientDefs() override {
54  return SingleGradientDef(
55  "SumElementsGradient",
56  "",
57  vector<string>{I(0), GO(0)},
58  vector<string>{GI(0)});
59  }
60 };
61 REGISTER_GRADIENT(SumElements, GetSumElementsGradient);
62 
63 OPERATOR_SCHEMA(RowwiseMax)
64  .NumInputs(1)
65  .NumOutputs(1)
66  .SetDoc("Compute row-wise max reduction of the input tensor.")
67  .Input(
68  0,
69  "X",
70  "A tenosr of dimensions batch_size x M x N to compute rowwise-max.")
71  .Output(0, "Y", "batch_size x M rowwise-max results matrix.");
72 
73 OPERATOR_SCHEMA(RowwiseMaxGradient).NumInputs(3).NumOutputs(1);
75  using GradientMakerBase::GradientMakerBase;
76  vector<OperatorDef> GetGradientDefs() override {
77  return SingleGradientDef(
78  "RowwiseMaxGradient",
79  "",
80  vector<string>{I(0), O(0), GO(0)},
81  vector<string>{GI(0)});
82  }
83 };
84 REGISTER_GRADIENT(RowwiseMax, GetRowwiseMaxGradient);
85 
86 OPERATOR_SCHEMA(ColwiseMaxGradient);
87 
88 OPERATOR_SCHEMA(ColwiseMax)
89  .NumInputs(1)
90  .NumOutputs(1)
91  .SetDoc("Compute column-wise max reduction of the input tensor.")
92  .Input(
93  0,
94  "X",
95  "A tenosr of dimensions batch_size x M x N to compute colwise-max.")
96  .Output(0, "Y", "batch_size x N column-max results matrix.");
97 
98 OPERATOR_SCHEMA(ColumnMaxGradient).NumInputs(3).NumOutputs(1);
100  using GradientMakerBase::GradientMakerBase;
101  vector<OperatorDef> GetGradientDefs() override {
102  return SingleGradientDef(
103  "ColwiseMaxGradient",
104  "",
105  vector<string>{I(0), O(0), GO(0)},
106  vector<string>{GI(0)});
107  }
108 };
109 REGISTER_GRADIENT(ColwiseMax, GetColwiseMaxGradient);
110 
111 template <typename T, class Context>
113 // TODO: T21635077 fix float-divide-by-zero undefined behavior
114 #if defined(__has_feature)
115 #if __has_feature(__address_sanitizer__)
116  __attribute__((__no_sanitize__("float-divide-by-zero")))
117 #endif
118 #endif
119 {
120  auto& X = Input(0);
121  TensorCPU sum_grad = TensorCPU(Input(1));
122  auto* dX = Output(0);
123  dX->ResizeLike(X);
124  DCHECK_EQ(sum_grad.size(), 1);
125  math::Set<T, Context>(
126  dX->size(),
127  static_cast<T>(sum_grad.data<T>()[0] * (average_ ? 1.0 / X.size() : 1)),
128  dX->template mutable_data<T>(),
129  &context_);
130  return true;
131 }
132 
133 template <typename T, class Context, bool ROWWISE>
135  auto& X = Input(0);
136  auto& Y = Input(1);
137  auto& dY = Input(2);
138 
139  auto* dX = Output(0);
140  dX->ResizeLike(X);
141 
142  CAFFE_ENFORCE_EQ(X.ndim(), 3);
143 
144  const int batch_size = X.dim32(0);
145  const int M = X.dim32(1);
146  const int N = X.dim32(2);
147 
148  const T* Xdata = X.template data<T>();
149  const T* Ydata = Y.template data<T>();
150  const T* dYdata = dY.template data<T>();
151  T* dXdata = dX->template mutable_data<T>();
152 
153  const int input_size = M * N;
154  for (int i = 0; i < batch_size; ++i) {
155  const T* Xdata_i = Xdata + i * input_size;
156  T* dXdata_i = dXdata + i * input_size;
157  if (ROWWISE) {
158  const T* Ydata_i = Ydata + i * M;
159  const T* dYdata_i = dYdata + i * M;
160  for (int m = 0; m < M; ++m) {
161  const T* Xdata_m = Xdata_i + m * N;
162  T* dXdata_m = dXdata_i + m * N;
163  for (int n = 0; n < N; ++n) {
164  if (Xdata_m[n] == Ydata_i[m]) {
165  dXdata_m[n] = dYdata_i[m];
166  } else {
167  dXdata_m[n] = static_cast<T>(0);
168  }
169  }
170  }
171  } else {
172  const T* Ydata_i = Ydata + i * N;
173  const T* dYdata_i = dYdata + i * N;
174  for (int n = 0; n < N; ++n) {
175  for (int m = 0; m < M; ++m) {
176  const T* Xdata_m = Xdata_i + m * N;
177  T* dXdata_m = dXdata_i + m * N;
178  if (Xdata_m[n] == Ydata_i[n]) {
179  dXdata_m[n] = dYdata_i[n];
180  } else {
181  dXdata_m[n] = static_cast<T>(0);
182  }
183  }
184  }
185  }
186  }
187 
188  return true;
189 }
190 
191 } // namespace caffe2
const T * data() const
Returns a typed pointer of the underlying storage.
Definition: tensor.h:484
TIndex size() const
Returns the size (i.e.
Definition: tensor.h:593
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 ...