Caffe2 - C++ API
A deep learning, cross platform ML framework
reduce_front_back_max_ops.cc
1 #include "caffe2/operators/reduce_front_back_max_ops.h"
2 #include "caffe2/core/operator_gradient.h"
3 
4 namespace caffe2 {
5 
6 #define REDUCTION_OP_SHAPE_INFERENCE(is_front_reducer) \
7  CAFFE_ENFORCE_LE(1, in.size()); \
8  CAFFE_ENFORCE_GE(2, in.size()); \
9  ArgumentHelper helper(def); \
10  int num_reduce_dims = helper.GetSingleArgument<int>("num_reduce_dim", 1); \
11  int start_index = is_front_reducer ? num_reduce_dims : 0; \
12  int end_index = is_front_reducer ? in[0].dims_size() \
13  : in[0].dims_size() - num_reduce_dims; \
14  vector<int> output_shape; \
15  for (int i = start_index; i < end_index; ++i) { \
16  output_shape.push_back(in[0].dims(i)); \
17  } \
18  return vector<TensorShape>{ \
19  CreateTensorShape(output_shape, in[0].data_type())};
20 
21 /***
22  Max Ops
23 ***/
24 
25 // ReduceFrontMax
26 template <>
27 void MaxReduceDimsOp<float, CPUContext, true>::Compute(
28  int rows,
29  int cols,
30  const float* data,
31  const int32_t* lengths_data,
32  float* out_data) {
33  for (int i = 0; i < cols; i++) {
34  float mx = data[i];
35  int length = lengths_data == nullptr ? rows : lengths_data[i];
36  for (int j = 1; j < length; j++) {
37  mx = std::max(mx, data[j * cols + i]);
38  }
39  out_data[i] = mx;
40  }
41 }
42 
43 // ReduceBackMax
44 template <>
45 void MaxReduceDimsOp<float, CPUContext, false>::Compute(
46  int rows,
47  int cols,
48  const float* data,
49  const int32_t* lengths_data,
50  float* out_data) {
51  for (int i = 0; i < rows; i++) {
52  float mx = data[i * cols];
53  int length = lengths_data == nullptr ? cols : lengths_data[i];
54  for (int j = 1; j < length; j++) {
55  mx = std::max(mx, data[i * cols + j]);
56  }
57  out_data[i] = mx;
58  }
59 }
60 
61 // ReduceFrontMaxGradient
62 template <>
63 void MaxReduceDimsGradientOp<float, CPUContext, true>::Compute(
64  int rows,
65  int cols,
66  const float* dYdata,
67  const float* Xdata,
68  const float* Ydata,
69  const int32_t* lengths_data,
70  float* dXdata) {
71  int len = cols * rows;
72  for (int i = 0; i < len; i++) {
73  int col = i % cols;
74  int row = i / cols;
75  if (lengths_data != nullptr && row >= lengths_data[col]) {
76  dXdata[i] = 0.0f;
77  } else {
78  dXdata[i] = Xdata[i] == Ydata[col] ? dYdata[col] : 0.0f;
79  }
80  }
81 }
82 
83 // ReduceBackMaxGradient
84 template <>
85 void MaxReduceDimsGradientOp<float, CPUContext, false>::Compute(
86  int rows,
87  int cols,
88  const float* dYdata,
89  const float* Xdata,
90  const float* Ydata,
91  const int32_t* lengths_data,
92  float* dXdata) {
93  int len = cols * rows;
94  for (int i = 0; i < len; i++) {
95  int row = i / cols;
96  int col = i % cols;
97  if (lengths_data == nullptr || col < lengths_data[row]) {
98  dXdata[i] = Xdata[i] == Ydata[row] ? dYdata[row] : 0.0f;
99  } else {
100  dXdata[i] = 0.0f;
101  }
102  }
103 }
104 
105 REGISTER_CPU_OPERATOR(ReduceFrontMax, MaxReduceDimsOp<float, CPUContext, true>);
106 REGISTER_CPU_OPERATOR(
107  ReduceFrontMaxGradient,
108  MaxReduceDimsGradientOp<float, CPUContext, true>);
109 
110 REGISTER_CPU_OPERATOR(ReduceBackMax, MaxReduceDimsOp<float, CPUContext, false>);
111 REGISTER_CPU_OPERATOR(
112  ReduceBackMaxGradient,
113  MaxReduceDimsGradientOp<float, CPUContext, false>);
114 
116  using GradientMakerBase::GradientMakerBase;
117  vector<OperatorDef> GetGradientDefs() override {
118  vector<string> grad_in = {GO(0), I(0), O(0)};
119  if (def_.input_size() == 2) {
120  grad_in.push_back(I(1));
121  }
122  return SingleGradientDef(
123  "ReduceFrontMaxGradient", "", grad_in, vector<string>{GI(0)});
124  }
125 };
126 
127 REGISTER_GRADIENT(ReduceFrontMax, GetReduceFrontMaxGradient);
128 
130  using GradientMakerBase::GradientMakerBase;
131  vector<OperatorDef> GetGradientDefs() override {
132  vector<string> grad_in = {GO(0), I(0), O(0)};
133  if (def_.input_size() == 2) {
134  grad_in.push_back(I(1));
135  }
136  return SingleGradientDef(
137  "ReduceBackMaxGradient", "", grad_in, vector<string>{GI(0)});
138  }
139 };
140 
141 REGISTER_GRADIENT(ReduceBackMax, GetReduceBackMaxGradient);
142 
143 OPERATOR_SCHEMA(ReduceFrontMax)
144  .NumInputs(1, 2)
145  .NumOutputs(1)
146  .Arg(
147  "num_reduce_dims",
148  "(*int*): number of dimensions to reduce (default=1)")
149  .SetDoc(R"DOC(
150 Reduces the input tensor along the last dimension of the by applying **max**.
151 
152 Can reduce more than one of the "first" dimensions by setting `num_reduce_dim`.
153 
154 A second (optional) input, `lengths`, can be passed, which enforces that only a subset of the elements are considered in the max operation.
155 - If input tensor `X` has shape $(d_0, d_1, d_2, ..., d_n)$, `lengths` must have shape $(d_1 * d_2 * ... * d_{n})$.
156 - The values of the `lengths` tensor determine how many of the values to consider for each vector in the $d_{0}$ dimension.
157 
158 For example if $X = [[1,5,2,9],[4,1,8,2],[2,7,0,3]]$ and $lengths = [2,3,1,2]$, then $Y = [max(1,4), max(5,1,7), max(2), max(9,2)] = [4, 7, 2, 9]$
159 
160 Github Links:
161 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/reduce_front_back_max_ops.cc
162 
163 <details>
164 
165 <summary> <b>Example</b> </summary>
166 
167 **Code**
168 
169 ```
170 
171 workspace.ResetWorkspace()
172 
173 op = core.CreateOperator(
174  "ReduceFrontMax",
175  ["X"],
176  ["Y"],
177  num_reduce_dim=2
178 )
179 
180 workspace.FeedBlob("X", np.random.randint(10, size=(2,3,3)).astype(np.float32))
181 print("X:", workspace.FetchBlob("X"))
182 workspace.RunOperatorOnce(op)
183 print("Y:", workspace.FetchBlob("Y"))
184 
185 ```
186 
187 **Result**
188 
189 ```
190 
191 X:
192 [[[2. 8. 1.]
193  [9. 6. 6.]
194  [7. 7. 0.]]
195 
196  [[4. 3. 9.]
197  [9. 2. 7.]
198  [6. 4. 7.]]]
199 Y: [9. 8. 9.]
200 
201 ```
202 
203 </details>
204 
205 )DOC")
206  .Input(0, "X", "(*Tensor`<float>`*): input tensor")
207  .Input(1, "lengths", "(*Tensor`<int>`*): number of elements in each sample")
208  .Output(0, "Y", "(*Tensor`<float>`*): reduced tensor")
209  .TensorInferenceFunction([](const OperatorDef& def,
210  const vector<TensorShape>& in) {
211  REDUCTION_OP_SHAPE_INFERENCE(true)
212  });
213 OPERATOR_SCHEMA(ReduceFrontMaxGradient).NumInputs(3, 4).NumOutputs(1);
214 
215 OPERATOR_SCHEMA(ReduceBackMax)
216  .NumInputs(1, 2)
217  .NumOutputs(1)
218  .Arg(
219  "num_reduce_dims",
220  "(*int*): number of dimensions to reduce (default=1)")
221  .SetDoc(R"DOC(
222 Reduces the input tensor along the last dimension of the by applying **max**.
223 
224 Can reduce more than one of the "last" dimensions by setting `num_reduce_dim`.
225 
226 A second (optional) input, `lengths`, can be passed, which enforces that only a subset of the elements are considered in the max operation.
227 - If input tensor `X` has shape $(d_0, d_1, d_2, ..., d_n)$, `lengths` must have shape $(d_0 * d_1 * d_2 * ... * d_{n-1})$.
228 - The values of the `lengths` tensor determine how many of the values to consider for each vector in the $d_{n-1}$ dimension.
229 
230 For example if $X = [[1,5,2,9],[4,1,8,2],[2,7,0,3]]$ and $lengths = [2,3,1]$, then $Y = [max(1,5), max(4,1,8), max(2)] = [5, 8, 2]$
231 
232 
233 Github Links:
234 - https://github.com/pytorch/pytorch/blob/master/caffe2/operators/reduce_front_back_max_ops.cc
235 
236 <details>
237 
238 <summary> <b>Example</b> </summary>
239 
240 **Code**
241 
242 ```
243 
244 workspace.ResetWorkspace()
245 
246 op = core.CreateOperator(
247  "ReduceBackMax",
248  ["X"],
249  ["Y"],
250  num_reduce_dim=2
251 )
252 
253 workspace.FeedBlob("X", np.random.randint(10, size=(1,2,3,3)).astype(np.float32))
254 print("X:", workspace.FetchBlob("X"))
255 workspace.RunOperatorOnce(op)
256 print("Y:", workspace.FetchBlob("Y"))
257 
258 ```
259 
260 **Result**
261 
262 ```
263 
264 X:
265 [[[[2. 5. 1.]
266  [6. 1. 9.]
267  [8. 5. 9.]]
268 
269  [[5. 7. 8.]
270  [9. 9. 6.]
271  [6. 5. 0.]]]]
272 Y: [[9. 9.]]
273 
274 ```
275 
276 </details>
277 
278 )DOC")
279  .Input(0, "X", "(*Tensor`<float>`*): input tensor")
280  .Input(1, "lengths", "(*Tensor`<int>`*): number of elements in each sample")
281  .Output(0, "Y", "(*Tensor`<float>`*): reduced tensor")
282  .TensorInferenceFunction([](const OperatorDef& def,
283  const vector<TensorShape>& in) {
284  REDUCTION_OP_SHAPE_INFERENCE(false)
285  });
286 OPERATOR_SCHEMA(ReduceBackMaxGradient).NumInputs(3, 4).NumOutputs(1);
287 
288 #undef REDUCTION_OP_SHAPE_INFERENCE
289 
290 } // namespace caffe2
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13
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 ...