Skip to main content

πŸ“ Batch Normalization

Description​

< What is it? >​

[Batch normalization (batch norm)]
Batch norm normalizes a layer's inputs across the current mini-batch, then rescales the result with two learnable parameters. It is a layer, not a preprocessing step: it runs inside the forward pass, every step, on activations whose distribution keeps shifting as the weights below it change.

For each mini-batch during training, BatchNorm:

  1. Computes the mean and variance of activations across the batch
  2. Normalizes them to zero mean, unit variance
  3. Applies learnable scale (Ξ³) and shift (Ξ²) parameters

[Zero mean]
Zero mean means the average value is 00, not that every value is zero.

For example:

[2,4,6,8][2, 4, 6, 8]

has mean 55. Subtracting the mean gives:

[βˆ’3,βˆ’1,1,3][-3, -1, 1, 3]

and:

βˆ’3βˆ’1+1+34=0\frac{-3 - 1 + 1 + 3}{4} = 0

In BatchNorm, this is done separately for each feature or channel across the mini-batch. It centers that feature's activations around zero before the learned Ξ³\gamma and Ξ²\beta can rescale and shift them.

[Mini-batch]
A mini-batch is a small, randomly selected subset of the training dataset. Instead of passing the entire dataset through the model at once, we divide it into smaller batches. This allows for more efficient training and helps in stabilizing the learning process.

  • Why not the whole dataset (full batch) or one sample (stochastic)?
    • Full batch (entire dataset): Slow, memory-heavy, and often gets stuck in sharp local minima.
    • Single sample (stochastic, batch size = 1): Fast updates but very noisy, making training unstable.

[Normalization]
Normalization is a technique used to adjust the values of input data to a common scale, without distorting differences in the ranges of values. In the context of batch normalization, it involves scaling and shifting the inputs to have a mean of zero and a standard deviation of one.

< Simple examples >​

Normalization in general. Imagine a housing model with floor-area values [50, 100, 150] square metres and bedroom counts [1, 2, 3]. The numerical scales differ greatly even though both features may matter. Standardizing either sequence shifts its mean to 0 and scales its standard deviation to 1, producing approximately [-1.22, 0, 1.22]. The model can then learn from the features without large units such as square metres dominating the optimization merely because their numbers are bigger.

Batch norm inside a network. During one training step, suppose a BatchNorm1d feature produces these four activations for the current mini-batch:

x=[2,4,6,8],ΞΌB=5,ΟƒB2=5x = [2, 4, 6, 8], \qquad \mu_B = 5, \qquad \sigma_B^2 = 5

Ignoring the tiny Ο΅\epsilon for readability, batch norm first produces:

x^β‰ˆ[βˆ’1.34,βˆ’0.45,0.45,1.34]\hat{x} \approx [-1.34, -0.45, 0.45, 1.34]

If the layer learns Ξ³=2\gamma = 2 and Ξ²=1\beta = 1, its final output becomes:

y=2x^+1β‰ˆ[βˆ’1.68,0.11,1.89,3.68]y = 2\hat{x} + 1 \approx [-1.68, 0.11, 1.89, 3.68]

For images, BatchNorm2d performs the same idea separately for each channel, using values from all images and spatial positions in the mini-batch.

x ──▢ normalize with the batch's ΞΌ, σ² ──▢ scale by Ξ³, shift by Ξ² ──▢ y
(zero mean, unit variance) (learnable, per feature)

Without the second half, forcing every layer to zero mean and unit variance would throw away representational power β€” a sigmoid unit could never operate anywhere but its linear middle. The learnable Ξ³\gamma and Ξ²\beta give that power back: the layer can recover any mean and scale it needs, including the identity.

< The computation >​

For a mini-batch of mm examples, computed per feature (per channel, for images):

ΞΌB=1mβˆ‘i=1mxi,ΟƒB2=1mβˆ‘i=1m(xiβˆ’ΞΌB)2\mu_B = \frac{1}{m}\sum_{i=1}^{m} x_i, \qquad \sigma_B^2 = \frac{1}{m}\sum_{i=1}^{m}\left(x_i - \mu_B\right)^2 x^i=xiβˆ’ΞΌBΟƒB2+Ο΅,yi=γ x^i+Ξ²=BNΞ³,Ξ²(xi)\hat{x}_i = \frac{x_i - \mu_B}{\sqrt{\sigma_B^2 + \epsilon}}, \qquad y_i = \gamma\,\hat{x}_i + \beta = BN_{\gamma, \beta}(x_i)

Reading the symbols
β€” the subscript BB just means "over the batch".

SymbolNameWhat it is
ΞΌB\mu_BmiuThe mean of the feature across the mini-batch
ΟƒB2\sigma_B^2sigmaThe variance across the mini-batch. ΟƒB\sigma_B on its own is the standard deviation, which is what the formula's square root recovers
Ο΅\epsilonepsilonA small constant, typically 1e-5, that guards the division when a feature is constant across the batch
Ξ³\gammagammaThe learned scale, one per feature
Ξ²\betabetaThe learned shift, one per feature

Ξ³\gamma and Ξ²\beta are trained by backpropagation like any other parameter β€” one pair per feature, so a BatchNorm2d(64) layer adds 128 trainable values.

Key points​

< Why it works >​

  1. Reduces internal covariate shift (original explanation)
    As weights update during training, the distribution of inputs to each layer keeps shifting. BatchNorm re-centers and re-scales these distributions, so each layer sees more consistent input statistics. This lets layers learn without constantly chasing a moving target.

  2. Smoother optimization landscape(modern explanation)
    Later research (Santurkar et al., 2018) showed the main benefit isn't really covariate shift β€” it's that BatchNorm makes the loss landscape smoother. This:

    • Allows higher learning rates without divergence
    • Reduces sensitivity to initialization
    • Makes gradients more predictive, so optimizers take more reliable steps
  3. Regularization effect
    Because normalization uses batch statistics that vary from batch to batch, it adds noise to the training process. This acts like a mild regularizer, sometimes reducing the need for dropout.

  4. Gradient flow
    By keeping activations in a well-behaved range (especially with sigmoid/tanh), BatchNorm prevents gradients from vanishing or exploding as badly, helping deep networks train.

< Covariate shift, and the "internal" kind >​

Covariate shift is a change in the distribution of the input features between the data a model was trained on and the data it later sees. The defining condition is that the rule survives the change:

Ptrain(x)β‰ Pdeploy(x),P(y∣x)Β unchangedP_{\text{train}}(x) \neq P_{\text{deploy}}(x), \qquad P(y \mid x) \text{ unchanged}

Train a self-driving model on sunny daytime photographs and deploy it on foggy night streets: a stop sign is still a stop sign, so P(y∣x)P(y \mid x) is the same rule as before β€” but the pixel distribution is nothing like the training set, and the model has no reason to generalize into that unfamiliar input space. Only P(x)P(x) moved, and that was enough.

Real product example β€” booking. A booking model is trained mostly on desktop traffic from returning users. A new mobile-only campaign then brings many first-time visitors, so the distributions of the device and returning_user features change: P(x)P(x) has moved. If two users with the same price, location, trip details, and history still follow the same booking rule, P(y∣x)P(y \mid x) has not changed. The model can nevertheless perform worse because it saw too few first-time mobile visitors during training.

Internal covariate shift applies the same idea one layer down. Every layer's input is the previous layer's output, and the previous layer's weights change on every step β€” so each layer is chasing an input distribution that keeps moving underneath it. The argument is that this slows training, because later layers spend their capacity re-adapting instead of learning.

That was the original motivation for batch normalization: hold each layer's input distribution steady, and the layers above it can stop chasing. Later work (Santurkar et al., 2018) found the explanation does not hold up under measurement β€” batch norm helps even when noise is deliberately injected to restore the shift β€” and attributes the benefit instead to a smoother loss landscape with more predictable gradients. The technique works either way; the smoothing account is the better answer in an interview.

The two are worth keeping apart. Internal covariate shift happens during training and batch norm addresses it; ordinary covariate shift happens after deployment and normalization does nothing for it. That one is a data problem β€” retraining on representative data, or detecting the drift and flagging it. It also breaks calibration, whose guarantees hold only on the distribution the calibrator was fitted to.

< Covariate shift vs. data drift >​

Data drift is the broader term: production data differs from the data used for training. Covariate shift is one specific kind of data drift, in which the input population changes but the underlying prediction rule does not.

TermWhat changesExample
Covariate shiftPtrain(X)β‰ Pproduction(X)P_{\text{train}}(X) \neq P_{\text{production}}(X) while P(Y∣X)P(Y \mid X) stays the sameA new campaign brings more first-time mobile users, but users with the same features still follow the same booking rule
Data driftAny meaningful production-data change; teams sometimes use the term as a synonym for covariate shiftA feature distribution changes, a category becomes much more common, values become missing, or a feature pipeline changes

If the relationship between the features and outcome changes β€” for example, a new pricing policy changes how a given price affects booking β€” that is concept drift, not merely covariate shift. A broken feature pipeline can also look like drift, but it is an operational problem rather than a population change.

< Training vs. inference β€” the distinction that bites >​

ModeStatistics usedSet by
TrainingΞΌ\mu, Οƒ2\sigma^2 of the current batchmodel.train()
InferenceRunning averages accumulated during trainingmodel.eval()

During training the layer also updates a running mean and variance (an exponential moving average, controlled by momentum, default 0.1). At inference those fixed running values are used instead, so a prediction depends only on the input β€” not on whatever else happened to be batched alongside it.

Forgetting model.eval() is the classic bug: predictions change depending on batch composition, evaluation scores move between runs, and a batch of size 1 normalizes an example against itself, producing zeros. model.eval() also switches dropout off, which is why it is a single call for both.

< In PyTorch >​

LayerInput shapeNormalizes overTypical use
nn.BatchNorm1d(C)(N, C) or (N, C, L)N (and L)Fully connected layers, 1-D signals
nn.BatchNorm2d(C)(N, C, H, W)N, H, WImages β€” the common case in CNNs
nn.BatchNorm3d(C)(N, C, D, H, W)N, D, H, WVolumetric data, video
import torch.nn as nn

model = nn.Sequential(
# bias=False: BatchNorm's Ξ² makes the preceding bias redundant
nn.Conv2d(3, 64, kernel_size=3, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(),
)

model.train() # batch statistics; running averages updated
model.eval() # running averages; nothing updated

The argument is the feature/channel count, not the batch size. Two practical notes: the preceding layer's bias is redundant (Ξ² already provides the offset, so use bias=False), and the conventional order is Linear/Conv β†’ BatchNorm β†’ activation, following the original paper.

< Batch size sensitivity >​

Batch norm estimates ΞΌ\mu and Οƒ2\sigma^2 from the batch, so the estimates get noisier as the batch shrinks. Below roughly 8–16 examples the noise starts to hurt more than it regularizes; at a batch size of 1 the layer is undefined in training mode. This is the direct link between batch norm and your choice of mini-batch size, and it is why memory-constrained training (large images, detection, segmentation) often switches to a batch-size-independent alternative.

For those cases β€” and for transformers and RNNs, where sequence examples vary in length β€” layer norm or RMSNorm normalize within a single example instead. See Normalization inside the network for the comparison.

  • Data Normalization scales the inputs before training; batch norm scales activations during it. Doing one does not remove the need for the other.
  • Vanishing & Exploding Gradients covers what batch norm can and cannot fix.
  • Regularization puts its noise-based side effect in context.
  • Calibration is one of the first things ordinary covariate shift breaks after deployment.

Video Tutorial​

Reference​