in sparseconvnet/SCN/CPU/BatchNormalization.cpp [65:107]
void BatchNormalization_BackwardPass(T *input_features, T *d_input_features,
T *output_features, T *d_output_features,
Int nPlanes, Int input_stride,
Int output_stride, Int nActive,
T *saveMean, T *saveInvStd, T *runningMean,
T *runningVar, T *weight, T *bias,
T *d_weight, T *d_bias, T leakiness) {
std::vector<T> gradMean(nPlanes);
std::vector<T> dotp(nPlanes);
std::vector<T> k(nPlanes);
for (Int row = 0; row < nActive; row++) {
Int ci = row * input_stride;
Int co = row * output_stride;
for (Int plane = 0; plane < nPlanes; plane++, ci++, co++) {
T d = d_output_features[co];
const T r = (output_features[co] > 0) ? 1 : leakiness;
d *= r;
d_output_features[co] = d;
gradMean[plane] += d;
dotp[plane] += (input_features[ci] - saveMean[plane]) * d;
}
}
for (Int plane = 0; plane < nPlanes; plane++) {
if (d_bias)
d_bias[plane] = gradMean[plane]; // sum of grads, really, until ...
gradMean[plane] /= nActive; // ...now
k[plane] = dotp[plane] * saveInvStd[plane] * saveInvStd[plane] / nActive;
}
for (Int row = 0; row < nActive; row++) {
Int ci = row * input_stride;
Int co = row * output_stride;
for (Int plane = 0; plane < nPlanes; plane++, ci++, co++) {
d_input_features[ci] =
(d_output_features[co] - gradMean[plane] -
(input_features[ci] - saveMean[plane]) * k[plane]) *
saveInvStd[plane] * (weight ? weight[plane] : 1);
}
}
if (d_weight)
for (Int plane = 0; plane < nPlanes; plane++) {
d_weight[plane] = dotp[plane] * saveInvStd[plane];
}
}