| 167 | |
| 168 | template <typename Dtype> |
| 169 | void BatchNormLayer<Dtype>::Backward_cpu(const vector<Blob<Dtype>*>& top, |
| 170 | const vector<bool>& propagate_down, |
| 171 | const vector<Blob<Dtype>*>& bottom) { |
| 172 | const Dtype* top_diff; |
| 173 | if (bottom[0] != top[0]) { |
| 174 | top_diff = top[0]->cpu_diff(); |
| 175 | } else { |
| 176 | caffe_copy(x_norm_.count(), top[0]->cpu_diff(), x_norm_.mutable_cpu_diff()); |
| 177 | top_diff = x_norm_.cpu_diff(); |
| 178 | } |
| 179 | Dtype* bottom_diff = bottom[0]->mutable_cpu_diff(); |
| 180 | if (use_global_stats_) { |
| 181 | caffe_div(temp_.count(), top_diff, temp_.cpu_data(), bottom_diff); |
| 182 | return; |
| 183 | } |
| 184 | const Dtype* top_data = x_norm_.cpu_data(); |
| 185 | int num = bottom[0]->shape()[0]; |
| 186 | int spatial_dim = bottom[0]->count()/(bottom[0]->shape(0)*channels_); |
| 187 | // if Y = (X-mean(X))/(sqrt(var(X)+eps)), then |
| 188 | // |
| 189 | // dE(Y)/dX = |
| 190 | // (dE/dY - mean(dE/dY) - mean(dE/dY \cdot Y) \cdot Y) |
| 191 | // ./ sqrt(var(X) + eps) |
| 192 | // |
| 193 | // where \cdot and ./ are hadamard product and elementwise division, |
| 194 | // respectively, dE/dY is the top diff, and mean/var/sum are all computed |
| 195 | // along all dimensions except the channels dimension. In the above |
| 196 | // equation, the operations allow for expansion (i.e. broadcast) along all |
| 197 | // dimensions except the channels dimension where required. |
| 198 | |
| 199 | // sum(dE/dY \cdot Y) |
| 200 | caffe_mul(temp_.count(), top_data, top_diff, bottom_diff); |
| 201 | caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim, 1., |
| 202 | bottom_diff, spatial_sum_multiplier_.cpu_data(), 0., |
| 203 | num_by_chans_.mutable_cpu_data()); |
| 204 | caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1., |
| 205 | num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0., |
| 206 | mean_.mutable_cpu_data()); |
| 207 | |
| 208 | // reshape (broadcast) the above |
| 209 | caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, num, channels_, 1, 1, |
| 210 | batch_sum_multiplier_.cpu_data(), mean_.cpu_data(), 0., |
| 211 | num_by_chans_.mutable_cpu_data()); |
| 212 | caffe_cpu_gemm<Dtype>(CblasNoTrans, CblasNoTrans, channels_ * num, |
| 213 | spatial_dim, 1, 1., num_by_chans_.cpu_data(), |
| 214 | spatial_sum_multiplier_.cpu_data(), 0., bottom_diff); |
| 215 | |
| 216 | // sum(dE/dY \cdot Y) \cdot Y |
| 217 | caffe_mul(temp_.count(), top_data, bottom_diff, bottom_diff); |
| 218 | |
| 219 | // sum(dE/dY)-sum(dE/dY \cdot Y) \cdot Y |
| 220 | caffe_cpu_gemv<Dtype>(CblasNoTrans, channels_ * num, spatial_dim, 1., |
| 221 | top_diff, spatial_sum_multiplier_.cpu_data(), 0., |
| 222 | num_by_chans_.mutable_cpu_data()); |
| 223 | caffe_cpu_gemv<Dtype>(CblasTrans, num, channels_, 1., |
| 224 | num_by_chans_.cpu_data(), batch_sum_multiplier_.cpu_data(), 0., |
| 225 | mean_.mutable_cpu_data()); |
| 226 | // reshape (broadcast) the above to make |
nothing calls this directly
no test coverage detected