Deep Learning
Batch Normalization
Normalize activations across a batch, apply a learned scale and shift, and understand why training and evaluation behave differently.
Jump to a section
Why this matters
Batch normalization rescales activations using statistics computed across a mini-batch, then applies a learned scale and shift. For an input shaped (N, C), it treats each feature column separately.
Its most important distinction is training versus inference. Training uses batch statistics; evaluation normally uses stored running estimates. Confusing those modes can change predictions even when the model weights stay fixed.
Build the mental model
For a batch of activations shaped (N, C) (N examples, C features) BN computes the mean and variance down each column (across the N examples) and standardizes that feature. Every feature ends up centered and scaled, regardless of what the previous layer's weights are doing. Then two learnable parameters, and , rescale and re-shift, so if the network is better off not normalizing a feature, it can learn , and recover the original.
Normalize one feature across a batch
Compare the same four activations before and after normalization. The batch mean is zero and its population variance is five.
The visual loads as you reach this section.
Inspect the plotted values
x,y,series 1,-3,Before 1,-1.3416394448610998,After 2,-1,Before 2,-0.4472131482870333,After 3,1,Before 3,0.4472131482870333,After 4,3,Before 4,1.3416394448610998,After
Contrast with Layer Norm, which normalizes across the features of a single example (along C, per row): independent of batch size, which is why Transformers use LN, not BN.
Work through the math
For a mini-batch (per feature), BN computes:
is a small constant for numerical stability. and are learned per feature.
Train vs. eval: the critical distinction. At training time, and are computed from the current batch. The layer also maintains running estimates via an exponential moving average:
At inference, BN uses these fixed running statistics, not the batch, so a single example (or any batch size) produces deterministic outputs. Forgetting to switch to eval mode (model.eval()) is a classic bug: predictions then depend on whatever else is in the batch.
Key takeaway: Batch Norm is two different behaviors wearing one layer: batch statistics while training, frozen running statistics at inference. The
model.eval()switch is not optional; it changes what the layer computes.
The normalization-family landscape, and when each applies:
| Method | Normalizes over | Depends on batch size? | Typical home |
|---|---|---|---|
| Batch Norm | Each feature, across the batch | Yes (statistics are noisy for small N) | CNNs, MLPs |
| Layer Norm | All features of one example | No | Transformers, RNNs |
| Instance Norm | Each channel, per example | No | Style transfer, image generation |
| Group Norm | Channel groups, per example | No | Detection/segmentation with small batches |
Read the implementation
1import torch
2from torch import Tensor, nn
3
4
5class BatchNorm1d(nn.Module):
6 def __init__(self, num_features: int, eps: float = 1e-5, momentum: float = 0.1) -> None:
7 super().__init__()
8 self.eps, self.momentum = eps, momentum
9 self.gamma = nn.Parameter(torch.ones(num_features)) # learnable scale
10 self.beta = nn.Parameter(torch.zeros(num_features)) # learnable shift
11 self.register_buffer("running_mean", torch.zeros(num_features))
12 self.register_buffer("running_var", torch.ones(num_features))
13
14 def forward(self, x: Tensor) -> Tensor: # x: (N, num_features)
15 if self.training:
16 mean = x.mean(dim=0)
17 var = x.var(dim=0, unbiased=False) # biased var, as in BN
18 with torch.no_grad(): # update running stats
19 self.running_mean.mul_(1 - self.momentum).add_(self.momentum * mean)
20 self.running_var.mul_(1 - self.momentum).add_(self.momentum * var)
21 else:
22 mean, var = self.running_mean, self.running_var # frozen at inference
23 x_hat = (x - mean) / torch.sqrt(var + self.eps)
24 return self.gamma * x_hat + self.beta
25
26
27bn = BatchNorm1d(16)
28out = bn(torch.randn(32, 16))
29assert out.shape == (32, 16)
30bn.eval() # switch to running stats
31assert bn(torch.randn(1, 16)).shape == (1, 16) # works for batch size 1Questions and trade-offs
- Conceptual: What does Batch Norm actually normalize, and along which axis? (Each feature, across the examples in the batch: per-column for
(N, C)input.) - Implementation: What changes between training and inference, and why? (Train uses batch stats + updates running averages; eval uses frozen running stats so output is independent of batch composition.)
- Applied: Why does BN struggle with very small batch sizes, and what would you use instead? (Batch stats become noisy/unreliable; use Group Norm or Layer Norm, which don't depend on batch size.)
- Systems-level: Why do Transformers use Layer Norm rather than Batch Norm? (LN normalizes per-example across features: independent of batch size and sequence length, and well-behaved for variable-length sequences and small/streaming batches.)
- Failure modes: Your model trains well but predictions are unstable in production. What's a likely BN-related cause? (Forgot
model.eval(), so BN uses batch stats at inference: outputs depend on what else is batched together.)
Check your understanding
Without looking: write the four BN equations (mean, variance, normalize, scale-shift), name what and are for, and explain in one sentence exactly what differs at inference time. Then compare against Stage 3.
Oliver Perrin
Machine Learning Engineer · Founder, LiminalML
LiminalML brings together concept explanations, mathematical examples, and working visuals. Find more writing by Oliver on the LiminalML Substack.
Keep exploring the idea.
Ask a follow-up in a guided session, work through the self-check, or open the visual in Studio to build on it.
Related concepts
Deep Learning
Backpropagation
Trace local derivatives backward through a computation and connect the chain rule to a manual implementation.
Optimization
Gradient Descent (SGD, Momentum, Adam)
Follow updates across a loss surface, then connect learning rate, momentum, and Adam to the update equations.
Deep Learning
Transformer Architecture
Follow attention, feed-forward layers, normalization, and residual connections through a Transformer block.