1 #include "caffe2/operators/pool_op.h" 5 #include "caffe2/utils/eigen_utils.h" 11 template <
typename T, StorageOrder kOrder>
12 void ComputeAveragePoolGradient1D(
17 const ConstEigenArrayMap<T>& dY_arr,
18 EigenArrayMap<T>* dX_arr);
21 void ComputeAveragePoolGradient1D<float, StorageOrder::NCHW>(
26 const ConstEigenArrayMap<float>& dY_arr,
27 EigenArrayMap<float>* dX_arr) {
28 dX_arr->col(0).segment(l, r - l) += dY_arr(y) * scale;
32 void ComputeAveragePoolGradient1D<float, StorageOrder::NHWC>(
37 const ConstEigenArrayMap<float>& dY_arr,
38 EigenArrayMap<float>* dX_arr) {
39 for (
int i = l; i < r; ++i) {
40 dX_arr->col(i) += dY_arr.col(y) * scale;
44 template <
typename T, StorageOrder kOrder>
45 void ComputeAveragePoolGradient2D(
53 const ConstEigenArrayMap<T>& dY_arr,
54 EigenArrayMap<T>* dX_arr);
57 void ComputeAveragePoolGradient2D<float, StorageOrder::NCHW>(
65 const ConstEigenArrayMap<float>& dY_arr,
66 EigenArrayMap<float>* dX_arr) {
67 dX_arr->block(l, t, r - l, b - t) += dY_arr(y) * scale;
71 void ComputeAveragePoolGradient2D<float, StorageOrder::NHWC>(
79 const ConstEigenArrayMap<float>& dY_arr,
80 EigenArrayMap<float>* dX_arr) {
81 for (
int i = t; i < b; ++i) {
82 for (
int j = l; j < r; ++j) {
83 dX_arr->col(i * W + j) += dY_arr.col(y) * scale;
88 template <
typename T, StorageOrder kOrder>
89 void ComputeAveragePoolGradient3D(
100 const ConstEigenArrayMap<T>& dY_arr,
101 EigenArrayMap<T>* dX_arr);
104 void ComputeAveragePoolGradient3D<float, StorageOrder::NCHW>(
115 const ConstEigenArrayMap<float>& dY_arr,
116 EigenArrayMap<float>* dX_arr) {
117 for (
int i = p; i < a; ++i) {
118 dX_arr->block(l, i * H + t, r - l, b - t) += dY_arr(y) * scale;
123 void ComputeAveragePoolGradient3D<float, StorageOrder::NHWC>(
134 const ConstEigenArrayMap<float>& dY_arr,
135 EigenArrayMap<float>* dX_arr) {
136 for (
int i = p; i < a; ++i) {
137 for (
int j = t; j < b; ++j) {
138 for (
int k = l; k < r; ++k) {
139 dX_arr->col(i * H * W + j * W + k) += dY_arr.col(y) * scale;
145 template <
typename T, StorageOrder kOrder>
146 void RunAveragePoolGradient1D(
154 const bool count_include_pad,
157 const int batch_size = kOrder == StorageOrder::NCHW ? N * C : N;
158 const int X_stride = kOrder == StorageOrder::NCHW ? X_size : X_size * C;
159 const int Y_stride = kOrder == StorageOrder::NCHW ? Y_size : Y_size * C;
160 std::memset(dX, 0,
sizeof(
T) * N * C * X_size);
161 const T* dY_ptr = dY;
163 for (
int i = 0; i < batch_size; ++i) {
164 ConstEigenArrayMap<T> dY_arr = kOrder == StorageOrder::NCHW
165 ? ConstEigenArrayMap<T>(dY_ptr, Y_size, 1)
166 : ConstEigenArrayMap<T>(dY_ptr, C, Y_size);
167 EigenArrayMap<T> dX_arr = kOrder == StorageOrder::NCHW
168 ? EigenArrayMap<T>(dX_ptr, X_size, 1)
169 : EigenArrayMap<T>(dX_ptr, C, X_size);
170 for (
int y = 0; y < Y_size; ++y) {
171 const int l = std::max(y * stride - pad, 0);
172 const int r = std::min(y * stride - pad + kernel, X_size);
173 const T scale =
T(1) /
static_cast<T>(count_include_pad ? kernel : r - l);
174 ComputeAveragePoolGradient1D<T, kOrder>(l, r, y, scale, dY_arr, &dX_arr);
181 template <
typename T, StorageOrder kOrder>
182 void RunAveragePoolGradient2D(
195 const bool count_include_pad,
198 const int batch_size = kOrder == StorageOrder::NCHW ? N * C : N;
199 const int X_HxW = X_H * X_W;
200 const int Y_HxW = Y_H * Y_W;
201 const int X_stride = kOrder == StorageOrder::NCHW ? X_HxW : X_HxW * C;
202 const int Y_stride = kOrder == StorageOrder::NCHW ? Y_HxW : Y_HxW * C;
203 std::memset(dX, 0,
sizeof(
T) * N * C * X_HxW);
204 const T* dY_ptr = dY;
206 for (
int i = 0; i < batch_size; ++i) {
207 ConstEigenArrayMap<T> dY_arr = kOrder == StorageOrder::NCHW
208 ? ConstEigenArrayMap<T>(dY_ptr, Y_W, Y_H)
209 : ConstEigenArrayMap<T>(dY_ptr, C, Y_HxW);
210 EigenArrayMap<T> dX_arr = kOrder == StorageOrder::NCHW
211 ? EigenArrayMap<T>(dX_ptr, X_W, X_H)
212 : EigenArrayMap<T>(dX_ptr, C, X_HxW);
213 for (
int h = 0; h < Y_H; ++h) {
214 const int t = std::max(h * stride_h - pad_t, 0);
215 const int b = std::min(h * stride_h - pad_t + kernel_h, X_H);
216 for (
int w = 0; w < Y_W; ++w) {
217 const int l = std::max(w * stride_w - pad_l, 0);
218 const int r = std::min(w * stride_w - pad_l + kernel_w, X_W);
219 const int y = h * Y_W + w;
220 const T scale =
T(1) /
221 static_cast<T>(count_include_pad ? kernel_h * kernel_w
222 : (b - t) * (r - l));
223 ComputeAveragePoolGradient2D<T, kOrder>(
224 X_W, t, b, l, r, y, scale, dY_arr, &dX_arr);
232 template <
typename T, StorageOrder kOrder>
233 void RunAveragePoolGradient3D(
251 const bool count_include_pad,
254 const int batch_size = kOrder == StorageOrder::NCHW ? N * C : N;
255 const int X_HxW = X_D * X_H * X_W;
256 const int Y_HxW = Y_D * Y_H * Y_W;
257 const int X_stride = kOrder == StorageOrder::NCHW ? X_HxW : X_HxW * C;
258 const int Y_stride = kOrder == StorageOrder::NCHW ? Y_HxW : Y_HxW * C;
259 std::memset(dX, 0,
sizeof(
T) * N * C * X_HxW);
260 const T* dY_ptr = dY;
262 for (
int i = 0; i < batch_size; ++i) {
263 ConstEigenArrayMap<T> dY_arr = kOrder == StorageOrder::NCHW
264 ? ConstEigenArrayMap<T>(dY_ptr, Y_W, Y_D * Y_H)
265 : ConstEigenArrayMap<T>(dY_ptr, C, Y_HxW);
266 EigenArrayMap<T> dX_arr = kOrder == StorageOrder::NCHW
267 ? EigenArrayMap<T>(dX_ptr, X_W, X_D * X_H)
268 : EigenArrayMap<T>(dX_ptr, C, X_HxW);
269 for (
int d = 0; d < Y_D; ++d) {
270 const int p = std::max(d * stride_d - pad_p, 0);
271 const int a = std::min(d * stride_d - pad_p + kernel_d, X_D);
272 for (
int h = 0; h < Y_H; ++h) {
273 const int t = std::max(h * stride_h - pad_t, 0);
274 const int b = std::min(h * stride_h - pad_t + kernel_h, X_H);
275 for (
int w = 0; w < Y_W; ++w) {
276 const int l = std::max(w * stride_w - pad_l, 0);
277 const int r = std::min(w * stride_w - pad_l + kernel_w, X_W);
278 const int y = d * Y_H * Y_W + h * Y_W + w;
279 const T scale =
T(1) /
280 static_cast<T>(count_include_pad ? kernel_d * kernel_h * kernel_w
281 : (a - p) * (b - t) * (r - l));
282 ComputeAveragePoolGradient3D<T, kOrder>(
283 X_H, X_W, p, a, t, b, l, r, y, scale, dY_arr, &dX_arr);
292 template <
typename T, StorageOrder kOrder>
293 void ComputeMaxPoolGradient1D(
297 const ConstEigenArrayMap<T>& dY_arr,
298 const ConstEigenArrayMap<T>& X_arr,
299 const ConstEigenArrayMap<T>& Y_arr,
300 EigenArrayMap<T>* dX_arr);
303 void ComputeMaxPoolGradient1D<float, StorageOrder::NCHW>(
307 const ConstEigenArrayMap<float>& dY_arr,
308 const ConstEigenArrayMap<float>& X_arr,
309 const ConstEigenArrayMap<float>& Y_arr,
310 EigenArrayMap<float>* dX_arr) {
311 dX_arr->col(0).segment(l, r - l) +=
312 (X_arr.col(0).segment(l, r - l) == Y_arr(y)).cast<float>() * dY_arr(y);
316 void ComputeMaxPoolGradient1D<float, StorageOrder::NHWC>(
320 const ConstEigenArrayMap<float>& dY_arr,
321 const ConstEigenArrayMap<float>& X_arr,
322 const ConstEigenArrayMap<float>& Y_arr,
323 EigenArrayMap<float>* dX_arr) {
324 for (
int i = l; i < r; ++i) {
326 (X_arr.col(i) == Y_arr.col(y)).cast<float>() * dY_arr.col(y);
330 template <
typename T, StorageOrder kOrder>
331 void ComputeMaxPoolGradient2D(
338 const ConstEigenArrayMap<T>& dY_arr,
339 const ConstEigenArrayMap<T>& X_arr,
340 const ConstEigenArrayMap<T>& Y_arr,
341 EigenArrayMap<T>* dX_arr);
344 void ComputeMaxPoolGradient2D<float, StorageOrder::NCHW>(
351 const ConstEigenArrayMap<float>& dY_arr,
352 const ConstEigenArrayMap<float>& X_arr,
353 const ConstEigenArrayMap<float>& Y_arr,
354 EigenArrayMap<float>* dX_arr) {
355 dX_arr->block(l, t, r - l, b - t) +=
356 (X_arr.block(l, t, r - l, b - t) == Y_arr(y)).cast<float>() * dY_arr(y);
360 void ComputeMaxPoolGradient2D<float, StorageOrder::NHWC>(
367 const ConstEigenArrayMap<float>& dY_arr,
368 const ConstEigenArrayMap<float>& X_arr,
369 const ConstEigenArrayMap<float>& Y_arr,
370 EigenArrayMap<float>* dX_arr) {
371 for (
int i = t; i < b; ++i) {
372 for (
int j = l; j < r; ++j) {
373 const int x = i * W + j;
375 (X_arr.col(x) == Y_arr.col(y)).cast<float>() * dY_arr.col(y);
380 template <
typename T, StorageOrder kOrder>
381 void ComputeMaxPoolGradient3D(
391 const ConstEigenArrayMap<T>& dY_arr,
392 const ConstEigenArrayMap<T>& X_arr,
393 const ConstEigenArrayMap<T>& Y_arr,
394 EigenArrayMap<T>* dX_arr);
397 void ComputeMaxPoolGradient3D<float, StorageOrder::NCHW>(
407 const ConstEigenArrayMap<float>& dY_arr,
408 const ConstEigenArrayMap<float>& X_arr,
409 const ConstEigenArrayMap<float>& Y_arr,
410 EigenArrayMap<float>* dX_arr) {
411 for (
int i = p; i < a; ++i) {
412 dX_arr->block(l, i * H + t, r - l, b - t) +=
413 (X_arr.block(l, i * H + t, r - l, b - t) == Y_arr(y)).cast<float>() *
419 void ComputeMaxPoolGradient3D<float, StorageOrder::NHWC>(
429 const ConstEigenArrayMap<float>& dY_arr,
430 const ConstEigenArrayMap<float>& X_arr,
431 const ConstEigenArrayMap<float>& Y_arr,
432 EigenArrayMap<float>* dX_arr) {
433 for (
int i = p; i < a; ++i) {
434 for (
int j = t; j < b; ++j) {
435 for (
int k = l; k < r; ++k) {
436 const int x = i * H * W + j * W + k;
438 (X_arr.col(x) == Y_arr.col(y)).cast<float>() * dY_arr.col(y);
444 template <
typename T, StorageOrder kOrder>
445 void RunMaxPoolGradient1D(
457 const int batch_size = kOrder == StorageOrder::NCHW ? N * C : N;
458 const int X_stride = kOrder == StorageOrder::NCHW ? X_size : X_size * C;
459 const int Y_stride = kOrder == StorageOrder::NCHW ? Y_size : Y_size * C;
460 std::memset(dX, 0,
sizeof(
T) * N * C * X_size);
461 const T* dY_ptr = dY;
465 for (
int i = 0; i < batch_size; ++i) {
466 ConstEigenArrayMap<T> dY_arr = kOrder == StorageOrder::NCHW
467 ? ConstEigenArrayMap<T>(dY_ptr, Y_size, 1)
468 : ConstEigenArrayMap<T>(dY_ptr, C, Y_size);
469 ConstEigenArrayMap<T> X_arr = kOrder == StorageOrder::NCHW
470 ? ConstEigenArrayMap<T>(X_ptr, X_size, 1)
471 : ConstEigenArrayMap<T>(X_ptr, C, X_size);
472 ConstEigenArrayMap<T> Y_arr = kOrder == StorageOrder::NCHW
473 ? ConstEigenArrayMap<T>(Y_ptr, Y_size, 1)
474 : ConstEigenArrayMap<T>(Y_ptr, C, Y_size);
475 EigenArrayMap<T> dX_arr = kOrder == StorageOrder::NCHW
476 ? EigenArrayMap<T>(dX_ptr, X_size, 1)
477 : EigenArrayMap<T>(dX_ptr, C, X_size);
478 for (
int y = 0; y < Y_size; ++y) {
479 const int l = std::max(y * stride - pad, 0);
480 const int r = std::min(y * stride - pad + kernel, X_size);
481 ComputeMaxPoolGradient1D<T, kOrder>(
482 l, r, y, dY_arr, X_arr, Y_arr, &dX_arr);
491 template <
typename T, StorageOrder kOrder>
492 void RunMaxPoolGradient2D(
509 const int batch_size = kOrder == StorageOrder::NCHW ? N * C : N;
510 const int X_HxW = X_H * X_W;
511 const int Y_HxW = Y_H * Y_W;
512 const int X_stride = kOrder == StorageOrder::NCHW ? X_HxW : X_HxW * C;
513 const int Y_stride = kOrder == StorageOrder::NCHW ? Y_HxW : Y_HxW * C;
514 std::memset(dX, 0,
sizeof(
T) * N * C * X_HxW);
515 const T* dY_ptr = dY;
519 for (
int i = 0; i < batch_size; ++i) {
520 ConstEigenArrayMap<T> dY_arr = kOrder == StorageOrder::NCHW
521 ? ConstEigenArrayMap<T>(dY_ptr, Y_W, Y_H)
522 : ConstEigenArrayMap<T>(dY_ptr, C, Y_HxW);
523 ConstEigenArrayMap<T> X_arr = kOrder == StorageOrder::NCHW
524 ? ConstEigenArrayMap<T>(X_ptr, X_W, X_H)
525 : ConstEigenArrayMap<T>(X_ptr, C, X_HxW);
526 ConstEigenArrayMap<T> Y_arr = kOrder == StorageOrder::NCHW
527 ? ConstEigenArrayMap<T>(Y_ptr, Y_W, Y_H)
528 : ConstEigenArrayMap<T>(Y_ptr, C, Y_HxW);
529 EigenArrayMap<T> dX_arr = kOrder == StorageOrder::NCHW
530 ? EigenArrayMap<T>(dX_ptr, X_W, X_H)
531 : EigenArrayMap<T>(dX_ptr, C, X_HxW);
532 for (
int h = 0; h < Y_H; ++h) {
533 const int t = std::max(h * stride_h - pad_t, 0);
534 const int b = std::min(h * stride_h - pad_t + kernel_h, X_H);
535 for (
int w = 0; w < Y_W; ++w) {
536 const int l = std::max(w * stride_w - pad_l, 0);
537 const int r = std::min(w * stride_w - pad_l + kernel_w, X_W);
538 const int y = h * Y_W + w;
539 ComputeMaxPoolGradient2D<T, kOrder>(
540 X_W, t, b, l, r, y, dY_arr, X_arr, Y_arr, &dX_arr);
550 template <
typename T, StorageOrder kOrder>
551 void RunMaxPoolGradient3D(
573 const int batch_size = kOrder == StorageOrder::NCHW ? N * C : N;
574 const int X_HxW = X_D * X_H * X_W;
575 const int Y_HxW = Y_D * Y_H * Y_W;
576 const int X_stride = kOrder == StorageOrder::NCHW ? X_HxW : X_HxW * C;
577 const int Y_stride = kOrder == StorageOrder::NCHW ? Y_HxW : Y_HxW * C;
578 std::memset(dX, 0,
sizeof(
T) * N * C * X_HxW);
579 const T* dY_ptr = dY;
583 for (
int i = 0; i < batch_size; ++i) {
584 ConstEigenArrayMap<T> dY_arr = kOrder == StorageOrder::NCHW
585 ? ConstEigenArrayMap<T>(dY_ptr, Y_W, Y_D * Y_H)
586 : ConstEigenArrayMap<T>(dY_ptr, C, Y_HxW);
587 ConstEigenArrayMap<T> X_arr = kOrder == StorageOrder::NCHW
588 ? ConstEigenArrayMap<T>(X_ptr, X_W, X_D * X_H)
589 : ConstEigenArrayMap<T>(X_ptr, C, X_HxW);
590 ConstEigenArrayMap<T> Y_arr = kOrder == StorageOrder::NCHW
591 ? ConstEigenArrayMap<T>(Y_ptr, Y_W, Y_D * Y_H)
592 : ConstEigenArrayMap<T>(Y_ptr, C, Y_HxW);
593 EigenArrayMap<T> dX_arr = kOrder == StorageOrder::NCHW
594 ? EigenArrayMap<T>(dX_ptr, X_W, X_D * X_H)
595 : EigenArrayMap<T>(dX_ptr, C, X_HxW);
596 for (
int d = 0; d < Y_D; ++d) {
597 const int p = std::max(d * stride_d - pad_p, 0);
598 const int a = std::min(d * stride_d - pad_p + kernel_d, X_D);
599 for (
int h = 0; h < Y_H; ++h) {
600 const int t = std::max(h * stride_h - pad_t, 0);
601 const int b = std::min(h * stride_h - pad_t + kernel_h, X_H);
602 for (
int w = 0; w < Y_W; ++w) {
603 const int l = std::max(w * stride_w - pad_l, 0);
604 const int r = std::min(w * stride_w - pad_l + kernel_w, X_W);
605 const int y = d * Y_H * Y_W + h * Y_W + w;
606 ComputeMaxPoolGradient3D<T, kOrder>(
607 X_H, X_W, p, a, t, b, l, r, y, dY_arr, X_arr, Y_arr, &dX_arr);
622 bool AveragePoolFunctor<CPUContext>::
623 GlobalPoolingBackward<float, StorageOrder::NCHW>(
631 CPUContext* )
const {
632 const int NxC = N * C;
633 EigenArrayMap<float> dX_arr(dX, HxW, NxC);
634 const float scale = 1.0f /
static_cast<float>(HxW);
635 for (
int i = 0; i < NxC; ++i) {
636 dX_arr.col(i).setConstant(dY[i] * scale);
643 bool AveragePoolFunctor<CPUContext>::
644 GlobalPoolingBackward<float, StorageOrder::NHWC>(
652 CPUContext* )
const {
653 ConstEigenArrayMap<float> dY_arr(dY, C, N);
654 const float scale = 1.0f /
static_cast<float>(HxW);
655 for (
int i = 0; i < N; ++i) {
656 EigenArrayMap<float>(dX + i * HxW * C, C, HxW).colwise() =
657 dY_arr.col(i) * scale;
663 template <
typename T, StorageOrder kOrder>
664 bool AveragePoolFunctor<CPUContext>::Backward(
667 const std::vector<int>& X_dims,
668 const std::vector<int>& Y_dims,
669 const std::vector<int>& kernel,
670 const std::vector<int>& ,
671 const std::vector<int>& stride,
672 const std::vector<int>& pads,
677 CPUContext* )
const {
678 const int ndim = X_dims.size();
681 RunAveragePoolGradient1D<T, kOrder>(
695 RunAveragePoolGradient2D<T, kOrder>(
714 RunAveragePoolGradient3D<T, kOrder>(
738 CAFFE_THROW(
"Unsupported pooling dim: ", ndim);
746 bool MaxPoolFunctor<CPUContext>::
747 GlobalPoolingBackward<float, StorageOrder::NCHW>(
755 CPUContext* )
const {
756 const int NxC = N * C;
757 ConstEigenArrayMap<float> X_arr(X, HxW, NxC);
758 EigenArrayMap<float> dX_arr(dX, HxW, NxC);
759 for (
int i = 0; i < NxC; ++i) {
760 dX_arr.col(i) = (X_arr.col(i) == Y[i]).
template cast<float>() * dY[i];
767 bool MaxPoolFunctor<CPUContext>::
768 GlobalPoolingBackward<float, StorageOrder::NHWC>(
776 CPUContext* )
const {
777 ConstEigenArrayMap<float> Y_arr(Y, C, N);
778 ConstEigenArrayMap<float> dY_arr(dY, C, N);
779 for (
int i = 0; i < N; ++i) {
780 ConstEigenArrayMap<float> X_arr(X + i * HxW * C, C, HxW);
781 EigenArrayMap<float> dX_arr(dX + i * HxW * C, C, HxW);
782 for (
int j = 0; j < HxW; ++j) {
784 (X_arr.col(j) == Y_arr.col(i)).
template cast<float>() * dY_arr.col(i);
791 template <
typename T, StorageOrder kOrder>
792 bool MaxPoolFunctor<CPUContext>::Backward(
795 const std::vector<int>& X_dims,
796 const std::vector<int>& Y_dims,
797 const std::vector<int>& kernel,
798 const std::vector<int>& ,
799 const std::vector<int>& stride,
800 const std::vector<int>& pads,
805 CPUContext* )
const {
806 const int ndim = X_dims.size();
809 RunMaxPoolGradient1D<T, kOrder>(
824 RunMaxPoolGradient2D<T, kOrder>(
844 RunMaxPoolGradient3D<T, kOrder>(
869 CAFFE_THROW(
"Unsupported pooling dim: ", ndim);
875 REGISTER_CPU_OPERATOR(
877 PoolGradientOp<
float, CPUContext, AveragePoolFunctor<CPUContext>>);
878 OPERATOR_SCHEMA(AveragePoolGradient).NumInputs(3).NumOutputs(1);
880 REGISTER_CPU_OPERATOR(
881 AveragePool1DGradient,
882 PoolGradientOp<
float, CPUContext, AveragePoolFunctor<CPUContext>>);
883 OPERATOR_SCHEMA(AveragePool1DGradient).NumInputs(3).NumOutputs(1);
885 REGISTER_CPU_OPERATOR(
886 AveragePool2DGradient,
887 PoolGradientOp<
float, CPUContext, AveragePoolFunctor<CPUContext>>);
888 OPERATOR_SCHEMA(AveragePool2DGradient).NumInputs(3).NumOutputs(1);
890 REGISTER_CPU_OPERATOR(
891 AveragePool3DGradient,
892 PoolGradientOp<
float, CPUContext, AveragePoolFunctor<CPUContext>>);
893 OPERATOR_SCHEMA(AveragePool3DGradient).NumInputs(3).NumOutputs(1);
895 REGISTER_CPU_OPERATOR(
897 PoolGradientOp<
float, CPUContext, MaxPoolFunctor<CPUContext>>);
898 OPERATOR_SCHEMA(MaxPoolGradient).NumInputs(3).NumOutputs(1);
900 REGISTER_CPU_OPERATOR(
902 PoolGradientOp<
float, CPUContext, MaxPoolFunctor<CPUContext>>);
903 OPERATOR_SCHEMA(MaxPool1DGradient).NumInputs(3).NumOutputs(1);
905 REGISTER_CPU_OPERATOR(
907 PoolGradientOp<
float, CPUContext, MaxPoolFunctor<CPUContext>>);
908 OPERATOR_SCHEMA(MaxPool2DGradient).NumInputs(3).NumOutputs(1);
910 REGISTER_CPU_OPERATOR(
912 PoolGradientOp<
float, CPUContext, MaxPoolFunctor<CPUContext>>);
913 OPERATOR_SCHEMA(MaxPool3DGradient).NumInputs(3).NumOutputs(1);
917 class GetPoolGradient :
public GradientMakerBase {
918 using GradientMakerBase::GradientMakerBase;
920 std::vector<OperatorDef> GetGradientDefs()
override {
922 def_.type() +
"Gradient",
924 std::vector<std::string>{I(0), O(0), GO(0)},
925 std::vector<std::string>{GI(0)});
932 REGISTER_GRADIENT(AveragePool1D, GetPoolGradient);
933 REGISTER_GRADIENT(AveragePool2D, GetPoolGradient);
934 REGISTER_GRADIENT(AveragePool3D, GetPoolGradient);
936 REGISTER_GRADIENT(
MaxPool, GetPoolGradient);
937 REGISTER_GRADIENT(MaxPool1D, GetPoolGradient);
938 REGISTER_GRADIENT(MaxPool2D, GetPoolGradient);
939 REGISTER_GRADIENT(MaxPool3D, GetPoolGradient);
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 ...