Batch Normalization › Running Statistics for Inference

Michael BrenndoerferApril 19, 20255 min read
Language AI HandbookAll chapters
Part 10 of 67Neural Network Foundations
Chapter 71Batch Normalization › Running Statistics for Inference
Reading section 4 of 17 · Running Statistics for Inference · 5 minSection 4 of 17 · 5 min

Book contents

Section 4 of 17 · 5 min read

Batch Normalization › Running Statistics for InferenceOne section · Sections in this chapter4 / 17 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

During training, batch normalization uses statistics computed from the current mini-batch: μB\mu_{\mathcal{B}} and σB2\sigma^2_{\mathcal{B}} change with every batch. This works because mini-batches are reasonably representative of the full dataset, and the stochastic nature of batch statistics even provides a mild regularization effect (discussed further below).

At inference time, however, there is typically only a single sample or a small batch that may not represent the training distribution. Computing statistics over a single sample would be meaningless: the "mean" of a single value is that value itself, and the "variance" is zero, so normalization would map every single input to zero regardless of its content. Instead, batch normalization switches to using fixed statistics estimated from the entire training set.

These fixed estimates, called running statistics or population statistics, are accumulated during training using exponential moving averages:

μrunning←(1−α)⋅μrunning+α⋅μBσrunning2←(1−α)⋅σrunning2+α⋅σB2\begin{aligned} \mu_{\text{running}} &\leftarrow (1 - \alpha) \cdot \mu_{\text{running}} + \alpha \cdot \mu_{\mathcal{B}} \\ \sigma^2_{\text{running}} &\leftarrow (1 - \alpha) \cdot \sigma^2_{\text{running}} + \alpha \cdot \sigma^2_{\mathcal{B}} \end{aligned}

where:

  • μrunning\mu_{\text{running}}: the exponential moving average of batch means, updated after each training batch
  • σrunning2\sigma^2_{\text{running}}: the exponential moving average of batch variances, updated after each training batch
  • α\alpha: the momentum parameter controlling how quickly the running estimates update (typically 0.1 in PyTorch, meaning new batches contribute 10%)

At inference time, normalization uses these stable estimates:

x^i=xi−μrunningσrunning2+ϵ\hat{x}_i = \frac{x_i - \mu_{\text{running}}}{\sqrt{\sigma^2_{\text{running}} + \epsilon}}

This means batch normalization layers have two distinct behaviors: a training mode that uses batch statistics and an inference mode that uses running statistics. In PyTorch, this is controlled with model.train() and model.eval().

Why Training and Inference Modes Differ

Forgetting to call model.eval() before inference is a common bug in PyTorch code. In training mode, the layer uses batch statistics that fluctuate with each batch, which introduces noise. In eval mode, it uses the stable running statistics. Running a model in training mode during evaluation produces noisier, slightly inconsistent predictions.

The momentum parameter α=0.1\alpha = 0.1 is a careful engineering choice. A larger α\alpha causes the running statistics to update more aggressively toward each new batch, which makes them track recent batches closely but can cause instability if the data distribution is noisy or the batch size is small. A smaller α\alpha makes the running estimates more stable but slower to converge to the true population statistics. The PyTorch default of 0.1 is a reasonable balance for most training setups with moderate batch sizes.

One subtlety worth understanding: the running statistics are not trained by gradient descent. They are updated via this exponential moving average rule and are never part of the computational graph during the forward pass in training mode. They are purely a bookkeeping mechanism for inference. This is why they are registered as "buffers" in PyTorch rather than "parameters": they are saved with the model state but not updated by the optimizer.

The figure below illustrates how running statistics converge toward the true dataset statistics over training batches, while individual batch estimates fluctuate around them.

Out[4]:
Visualization
Scatter plot of batch mean estimates with converging running mean line over 50 batches.
Running mean vs batch estimates over 50 training batches. The exponential moving average (red) converges to the true mean (green dashed), while individual batch estimates (blue dots) fluctuate around the true value.
Scatter plot of batch variance estimates with converging running variance line over 50 batches.
Running variance vs batch estimates over 50 training batches. The running variance stabilizes near the true population variance after roughly 30 batches, while batch estimates show greater fluctuation.