void BatchNormalization_BackwardPass()

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];
    }
}