1 #include "caffe2/operators/spatial_batch_norm_op.h" 5 #include "caffe2/utils/eigen_utils.h" 11 void SpatialBNGradientOp<CPUContext>::
12 ComputeMultiBatchScaleBiasGradientsAndFusedParams(
26 ConstEigenVectorArrayMap<T> scale_arr(scale, C);
27 ConstEigenVectorArrayMap<T> mean_arr(mean, C);
28 ConstEigenVectorArrayMap<T> rstd_arr(rstd, C);
29 EigenVectorArrayMap<T> dscale_arr(dscale, C);
30 EigenVectorArrayMap<T> dbias_arr(dbias, C);
31 EigenVectorArrayMap<T> alpha_arr(alpha, C);
32 EigenVectorArrayMap<T> beta_arr(beta, C);
33 EigenVectorArrayMap<T> gamma_arr(gamma, C);
34 const T inv_num_batches =
T(1) /
static_cast<T>(num_batches_);
35 math::Scale<T, T, CPUContext>(
36 C, inv_num_batches, dscale_sum, dscale, &context_);
37 math::Scale<T, T, CPUContext>(
38 C, inv_num_batches, dbias_sum, dbias, &context_);
39 const T inv_nhw =
T(1) /
static_cast<T>(N * HxW);
40 alpha_arr = scale_arr * rstd_arr;
41 beta_arr = dscale_arr * rstd_arr;
42 gamma_arr = alpha_arr * (mean_arr * beta_arr - dbias_arr) * inv_nhw;
43 beta_arr *= -alpha_arr * inv_nhw;
48 void SpatialBNGradientOp<CPUContext>::ComputeScaleBiasGradientsAndFusedParams(
63 ConstEigenVectorArrayMap<T> scale_arr(scale, C);
64 ConstEigenVectorArrayMap<T> mean_arr(mean, C);
65 ConstEigenVectorArrayMap<T> rstd_arr(rstd, C);
66 EigenVectorArrayMap<T> dscale_arr(dscale, C);
67 EigenVectorArrayMap<T> dbias_arr(dbias, C);
68 EigenVectorArrayMap<T> alpha_arr(alpha, C);
69 EigenVectorArrayMap<T> beta_arr(beta, C);
70 EigenVectorArrayMap<T> gamma_arr(gamma, C);
71 math::Set<T, CPUContext>(C,
T(0), dscale, &context_);
72 math::Set<T, CPUContext>(C,
T(0), dbias, &context_);
73 if (order_ == StorageOrder::NCHW) {
74 ConstEigenArrayMap<T> dY_arr(dY, HxW, N * C);
75 ConstEigenArrayMap<T> X_arr(X, HxW, N * C);
76 for (
int i = 0; i < N; ++i) {
77 for (
int j = 0; j < C; ++j) {
78 const int c = i * C + j;
80 (dY_arr.col(c) * (X_arr.col(c) - mean_arr(j)) * rstd_arr(j)).sum();
81 dbias_arr(j) += dY_arr.col(c).sum();
85 const int outer_size = N * HxW;
86 ConstEigenArrayMap<T> dY_arr(dY, C, outer_size);
87 ConstEigenArrayMap<T> X_arr(X, C, outer_size);
88 for (
int i = 0; i < outer_size; ++i) {
89 dscale_arr += dY_arr.col(i) * (X_arr.col(i) - mean_arr) * rstd_arr;
90 dbias_arr += dY_arr.col(i);
93 const T inv_nhw =
T(1) /
static_cast<T>(N * HxW);
94 alpha_arr = scale_arr * rstd_arr;
95 beta_arr = dscale_arr * rstd_arr;
96 gamma_arr = alpha_arr * (mean_arr * beta_arr - dbias_arr) * inv_nhw;
97 beta_arr *= -alpha_arr * inv_nhw;
101 template <
typename T>
102 void SpatialBNGradientOp<CPUContext>::ComputeXGradient(
112 ConstEigenVectorArrayMap<T> alpha_arr(alpha, C);
113 ConstEigenVectorArrayMap<T> beta_arr(beta, C);
114 ConstEigenVectorArrayMap<T> gamma_arr(gamma, C);
115 if (order_ == NCHW) {
116 const int stride = C * HxW;
117 const T* dY_ptr = dY;
120 for (
int i = 0; i < N; ++i) {
121 EigenArrayMap<T>(dX_ptr, HxW, C) =
122 (ConstEigenArrayMap<T>(dY_ptr, HxW, C).rowwise() *
123 alpha_arr.transpose() +
124 ConstEigenArrayMap<T>(X_ptr, HxW, C).rowwise() *
125 beta_arr.transpose())
127 gamma_arr.transpose();
133 EigenArrayMap<T>(dX, C, N * HxW) =
134 (ConstEigenArrayMap<T>(dY, C, N * HxW).colwise() * alpha_arr +
135 ConstEigenArrayMap<T>(X, C, N * HxW).colwise() * beta_arr)
141 REGISTER_CPU_OPERATOR(SpatialBNGradient, SpatialBNGradientOp<CPUContext>);
145 OPERATOR_SCHEMA(SpatialBNGradient)
148 .AllowInplace({{5, 1}, {6, 2}});
154 class GetSpatialBNGradient :
public GradientMakerBase {
155 using GradientMakerBase::GradientMakerBase;
156 std::vector<OperatorDef> GetGradientDefs()
override {
159 ArgumentHelper::GetSingleArgument(def_, OpSchema::Arg_IsTest, 0);
160 const int num_batches =
161 ArgumentHelper::GetSingleArgument(def_,
"num_batches", 1);
162 const std::vector<string> grad_outputs = {GI(0), GI(1), GI(2)};
163 std::vector<string> grad_inputs;
169 CAFFE_ENFORCE_EQ(def_.input_size(), 5);
170 CAFFE_ENFORCE_EQ(def_.output_size(), 1);
171 grad_inputs = std::vector<std::string>{I(0), I(1), GO(0), I(3), I(4)};
172 }
else if (num_batches > 1) {
173 CAFFE_ENFORCE_EQ(def_.input_size(), 7);
174 CAFFE_ENFORCE_EQ(def_.output_size(), 5);
176 std::vector<std::string>{I(0), I(1), GO(0), O(3), O(4), GI(1), GI(2)};
178 CAFFE_ENFORCE_EQ(def_.input_size(), 5);
179 CAFFE_ENFORCE_EQ(def_.output_size(), 5);
180 grad_inputs = std::vector<std::string>{I(0), I(1), GO(0), O(3), O(4)};
182 return SingleGradientDef(
183 "SpatialBNGradient",
"", grad_inputs, grad_outputs);
189 REGISTER_GRADIENT(SpatialBN, GetSpatialBNGradient);
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...