Vibe Engines
YouTube

Vibe Engines is free, interactive AI engineering & system design — runs in your browser. Pick a learning path

~11 min readICML 2015

Batch Normalization,
explained.

Before this paper, training a deep network was a superstition-ridden ordeal of careful initialization and tiny learning rates. Then came one deceptively simple layer: at each step, re-center and re-scale a layer's outputs so the next layer always sees a stable distribution. Training sped up, learning rates went up, and depth got easier. Here's the whole transform — and the learnable knob that keeps it from throwing away information.

The delta

What changes against dropout: the target stops moving

Dropout (rung 1) accepts the optimisation problem as given and adds noise to stop the network memorising. Batch norm changes the optimisation problem itself. Every layer in a deep network is trying to learn a function of its input, and that input is the output of the layer below, which is still changing — so each layer is fitting a target that keeps moving as the layers beneath it update.

The change: normalise each feature to zero mean and unit variance across the examples in the mini-batch, as a layer, inside the network, on every forward pass. Because forcing that distribution would also destroy what the layer can express, it then applies a learned scale γ and shift β per feature — so the layer can recover any distribution it wants, including the unnormalised one, but it has to ask for it.

Stated in rung 1's units: dropout adds one hyperparameter and zero parameters; batch norm adds two parameters per feature (γ and β) and, more importantly, buys back a hyperparameter you were already spending — the learning rate. Normalised activations let you raise it by an order of magnitude without diverging, which is where most of the reported speed-up comes from. It also makes initialisation much less delicate, and it regularises hard enough that many recipes dropped rung 1 entirely when they adopted it.

01

The shifting-target problem

A deep network is a stack of layers, each learning to transform the outputs of the one below. But those outputs are a moving target: as the lower layer's weights update, the distribution of what it feeds upward keeps shifting — different mean, different spread, step after step. Every layer is chasing a target that won't hold still. The paper named this internal covariate shift, and argued it forces you to use tiny learning rates and careful initialization to keep the whole tower from diverging.

The fix is direct: don't let the distribution wander. After a layer computes its outputs, normalize them — re-center to zero mean and re-scale to unit variance — before passing them on. Now the layer above always receives inputs in a predictable range, no matter how the layer below drifts, and it can learn against a stable target.

The one-sentence version

Standardize each layer's outputs so the next layer always sees the same well-behaved distribution — then give the network a learnable knob to rescale if it needs to.

02

Normalize across the batch

The normalization is computed per feature, across the mini-batch. For a given feature, take its values over all examples in the current batch, compute their mean and variance, subtract the mean, divide by the standard deviation. A tiny ε in the denominator guards against a feature that happens to be constant (zero variance) in the batch.

The batch-norm transform, per feature
μBMean of this feature over the batch.
σ²BVariance of this feature over the batch.
x̂Standardize: (x − μB) / √(σ²B + ε) → zero mean, unit variance.
yScale & shift with learned γ, β → the layer's output.

Because the statistics come from the batch, batch norm couples the examples in a batch together — a subtle but important property. It also means very small batches give noisy statistics, which is one of batch norm's real limitations.

03

The learnable scale and shift

Forcing every layer to output exactly zero-mean, unit-variance activations would be too restrictive — sometimes a layer genuinely needs a different scale, or a nonzero mean to reach the useful part of its activation function. So batch norm adds two learnable parameters per feature, a scale γ and a shift β, applied after standardizing. The full transform:

Crucially, this does not cost expressiveness. If the optimal thing is to undo the normalization entirely, the network can learn γ = √(σ²B + ε) and β = μB, recovering the original activations exactly. Normalization sets a stable default the network can override — it removes the difficulty without removing the freedom. The runnable version below confirms both halves: standardizing yields mean≈0/var≈1, and γ, β restore any target mean and standard deviation.

04

Train vs test statistics

There is a catch at inference. During training, the mean and variance come from the current batch. But at test time you may be classifying a single image — there is no batch — and, more importantly, a prediction should never depend on which other examples happen to share its batch. So batch norm keeps a running average of the mean and variance seen during training (an exponential moving average), and uses those fixed statistics at test time:

running ← (1 − momentum)·running + momentum·batch_stat

This is the single most common batch-norm bug in practice: run the model in "training" mode at evaluation and it will normalize with batch statistics — leaking information across test examples and quietly wrecking your metrics. Every framework has an explicit train/eval switch precisely because of this layer.

How it works

How batch normalization is placed, computed and frozen

Ioffe and Szegedy add the transform as a layer between a linear map and its nonlinearity, and they pin down five things about how it runs.

A batch of activations, N × C × H × W example 1 example 2 example 3 example 4 channel 1 channel 2 channel 3 H × W H × W H × W H × W μ, σ² for channel 2 over N·H·W values γ, β for channel 2 shared by every position Dense layer: H = W = 1, so each unit uses only the m examples
In a convolutional layer, batch norm pools one channel across every example and every spatial position, so each channel gets a single mean, variance, γ and β.
  1. Normalize the pre-activation, not the layer input. For z = g(Wu + b), the layer becomes z = g(BN(Wu)). The input u is the output of another nonlinearity and its distribution keeps changing shape, while Wu is more likely to be symmetric, non-sparse and close to Gaussian, so fixing its first two moments gives a steadier distribution. The bias b is dropped, because mean subtraction would cancel it; β takes over its role.
  2. Compute statistics per activation over the mini-batch. For each dimension k, the mean μB and variance σ²B are taken over the m examples of the mini-batch, each value is standardized with a small ε added to the variance, and a learned pair γ^(k), β^(k) scales and shifts the result.
  3. In convolutional layers, pool over space too. To keep the convolutional property that every location of a feature map is treated alike, one channel's mean and variance are computed jointly over the batch and all spatial positions: m examples with p × q maps give an effective batch of m′ = m·p·q values per channel, and γ and β are learned per feature map rather than per activation.
  4. Backpropagate through the statistics. μB and σ²B depend on every example in the batch, so the gradient for one example depends on the others. The paper shows why this is required: if the normalization is treated as a constant outside the gradient step, an update to a bias is undone by the next mean subtraction, neither the output nor the loss changes, and the bias grows without bound.
  5. Freeze the layer for inference. After training, the batch statistics are replaced by population statistics: the average of μB over many training mini-batches, and the average of σ²B multiplied by m/(m − 1) to make the variance unbiased. The layer then becomes a fixed linear map per dimension, γ/√(Var[x] + ε) · x + (β − γE[x]/√(Var[x] + ε)), and the paper notes that moving averages can track these statistics while the model trains.

The network it was tested in

The ImageNet experiments use a variant of Inception with 13.6 million parameters: each 5 × 5 convolution is replaced by two stacked 3 × 3 convolutions, the 28 × 28 stage gets a third Inception module, and there are no fully connected layers apart from the final softmax. It was trained with SGD with momentum on mini-batches of 32 in a distributed setup, with BN before every nonlinearity. Inserting BN was only the start; the authors then rebuilt the training recipe around it:

  • raise the learning rate, with 5× and 30× variants;
  • remove dropout, which sped up training without increasing overfitting;
  • cut the L2 weight penalty by a factor of 5;
  • decay the learning rate 6 times faster;
  • remove local response normalization;
  • shuffle training examples within shards so the same examples stop sharing mini-batches, worth about 1% validation accuracy;
  • reduce photometric distortions, since a faster-training network sees each image fewer times.
The math

Backpropagating through the batch statistics

The paper derives the gradient of the loss ℓ through μB and σ²B with the chain rule, in six formulas. Writing gi = ∂ℓ/∂yi and collecting terms gives one line per example:

∂ℓ/∂xi = γ / (m · √(σ²B + ε)) · ( m·gi − Σj gj − x̂i · Σj gjx̂j ), ∂ℓ/∂γ = Σi gix̂i, ∂ℓ/∂β = Σi gi
  • m·gi — the direct path, the gradient as if the statistics were fixed numbers.
  • −Σ gj — the path through μB: it subtracts the batch total of the incoming gradient, because shifting every xi by the same amount cannot change x̂.
  • −x̂i Σ gjx̂j — the path through σ²B: it removes the part of the gradient that points along x̂, because stretching all deviations equally cannot change x̂ either.
  • γ/√(σ²B + ε) — the same rescaling the forward pass applied.

At the extremes: if every gj is equal, the bracket is zero and nothing reaches x. With m = 1, x − μB = 0, the layer outputs β whatever its input and the gradient to x vanishes, which is why a batch of one cannot train it. The paper adds a scale property, BN((aW)u) = BN(Wu) with ∂BN((aW)u)/∂(aW) = (1/a)·∂BN(Wu)/∂W: larger weights receive proportionally smaller gradients.

The evidence

What batch norm did to Inception's training

A first test on MNIST used three fully connected hidden layers of 100 sigmoid units, trained for 50,000 steps on mini-batches of 60: the BN network reached higher test accuracy, and the inputs to its sigmoids kept a stable distribution through training. The main test is single-crop ImageNet validation accuracy for the Inception variant, measured against the steps the original needed to reach its best:

ModelLearning rateSteps to 72.2%Best accuracy
Inception, no BN0.001531.0 million72.2%
BN-Baseline (BN added, nothing else)0.001513.3 million72.7%
BN-x5 (new recipe)0.00752.1 million73.0%
BN-x30 (new recipe)0.0452.7 million74.8%
BN-x5-Sigmoid0.0075not reached69.8%

Adding BN alone cut the steps by more than half; the fourteenfold saving needed the higher learning rate and the other recipe changes. BN-x30 starts slower than BN-x5 but keeps improving, reaching 74.8% after about 6 million steps. The sigmoid run is the sharpest ablation: with BN it trains to 69.8%, while the same sigmoid network without BN never exceeded one-in-a-thousand accuracy, which is chance for 1,000 classes.

A single BN network scored 7.82% top-5 validation error with one crop and 5.82% with many crops; an ensemble of six reached 4.9% on validation and 4.82% on the test server, which the authors note beats the reported accuracy of human raters. Even that ensemble kept a little dropout: some members used 5% or 10%, against 40% in the original Inception.

Since then

What the authors admit, and what happened next

The paper is explicit about the ugliest consequence, and it is the one that bites in production: the layer behaves differently at training and at inference. At training time the statistics come from the batch; at inference there is no batch, so the layer uses running averages accumulated during training. Forgetting to switch modes is a defect that produces a model which scores well in the training loop and badly when served, with no error message.

What the paper claims and does not establish is the mechanism. It attributes the gain to reducing "internal covariate shift" — the drift in each layer's input distribution. That explanation is contested: Santurkar and colleagues argued in 2018 that covariate shift is not what batch norm fixes, and demonstrated networks where the shift is deliberately reintroduced after normalisation and training is fast anyway; their account is that it smooths the loss surface. The layer works; the stated reason for why it works is not settled.

How it held up: it made very deep convolutional networks routine, and rung 4 is hard to imagine landing without it. But its dependence on the batch is a structural limit, not a detail — with a batch of one, or with sequences of different lengths where "the same feature across the batch" is not a well-defined set of numbers, the statistics are either unavailable or meaningless. That limit is precisely why rung 5 exists, and why the normaliser inside every transformer is not this one.

SOLVE IT YOURSELF

The transform, and what it preserves

The whole batch-norm transform in a handful of functions, with its two guarantees made checkable. Standardizing a batch gives mean ≈ 0 and variance ≈ 1; the normalization is invariant to any rescaling or shifting of the inputs (so the next layer is shielded from the previous layer's drift); the learnable γ and β restore an arbitrary mean and standard deviation (γ=5, β=3 → std 5, mean 3), proving no expressiveness is lost; the running-stat EMA is what test time uses; and ε keeps a constant feature finite. Change the batch, γ, β, or ε and watch it hold.

YOUR TASK

Write the body of normalize. Everything else in the file is already written; this is the function the paper is about. Press ▶ Run to check it against the 5 assertions below — they start red.

WHAT IT HAS TO SATISFY — 5 ASSERTIONS
  1. Standardizing gives ~zero mean and unit variance
  2. Normalization is invariant to scale and shift
  3. Gamma and beta restore an arbitrary mean and std
  4. The running-stat EMA moves toward the batch
  5. Epsilon keeps a zero-variance feature finite
CPython · WebAssembly
05

Why it helps so much

The measured effects were dramatic — the paper reached the same ImageNet accuracy in a fraction of the training steps — and they compound:

EffectWhy it happens
Faster trainingStable input distributions let gradients flow cleanly; fewer steps to converge.
Higher learning ratesNormalization bounds activation scale, so large steps don't blow up — a major speedup.
Less init-sensitivityThe layer re-centers regardless of how weights were initialized, forgiving bad starts.
Mild regularizationBatch statistics add noise per example, a small dropout-like effect (sometimes reducing the need for dropout).

Interestingly, the original "internal covariate shift" explanation is now debated — later work argued batch norm mainly helps by smoothing the loss landscape, making the optimization surface less jagged. The mechanism is still studied; that it works is not in doubt.

06

Batch norm's descendants

Batch norm's dependence on the batch is also its weakness: tiny batches give noisy statistics, and sequence models or distributed training make batch statistics awkward. That spawned a family of alternatives that normalize over different axes. Layer norm normalizes across a single example's features (no batch dependence) — which is why it, not batch norm, is standard in transformers and RNNs. Group norm and instance norm split the difference for vision, and RMSNorm strips layer norm down further for large language models.

But the core insight is universal and permanent: keeping activations at a controlled scale, with a learnable way to opt out, makes deep networks trainable. Nearly every modern architecture has a normalization layer of some kind in every block, and every one of them descends from this paper.

Worth knowing

At inference, batch norm's linear transform can be folded into the preceding convolution or linear layer's weights — so it costs literally nothing at test time, a common deployment optimization.

Questions

Questions people ask about Batch Normalization

How do you backpropagate through batch normalization?

Treat the batch mean and variance as functions of every input and apply the chain rule through them; the paper writes out the six resulting formulas. Collected, the gradient for example i is gamma divided by m times the batch standard deviation, multiplied by m times its own upstream gradient, minus the sum of all upstream gradients, minus its normalized value times the sum of each gradient multiplied by its normalized value. The second term removes any component that would only shift the batch, the third any component that would only rescale it. The gradients for gamma and beta are the sums of the upstream gradient times x-hat, and of the upstream gradient alone.

How does batch normalization work in convolutional layers?

It normalizes per channel instead of per activation. For a mini-batch of m images whose feature maps are p by q, each channel's mean and variance are computed over all m·p·q values in that channel, so every spatial position is normalized in the same way and the layer still behaves as a convolution. One gamma and one beta are learned per channel, so a 64-channel layer adds 128 parameters whatever the image size. The paper argues this keeps the convolutional property that different locations of a map are treated alike. At inference, each channel uses population statistics gathered during training instead of the current batch.

Why is the bias removed from a layer that feeds batch normalization?

Adding a bias b shifts every example's value of that unit by the same amount, and the batch-mean subtraction removes exactly that shift, so b cannot affect the output or the loss. Its gradient is in fact exactly zero, because the gradients flowing into a batch norm layer's inputs always sum to zero over the batch. The paper therefore normalizes Wu rather than Wu + b and lets the learned shift beta play the bias's role after normalization. Keeping the bias does no harm beyond wasted parameters, which is why convolutions followed by batch norm are usually created with the bias switched off.

Should batch norm go before or after the activation function?

The paper puts it before the nonlinearity, normalizing the pre-activation Wu and then applying the activation, z = g(BN(Wu)). Its argument is about distributions: a layer's input is the output of another nonlinearity and its shape keeps changing, while Wu tends to be symmetric and close to Gaussian, so standardizing its mean and variance is more likely to give a stable distribution. ResNet follows the same order of convolution, batch norm, then ReLU. Placing it after the activation also appears in practice, and the paper offers a distributional argument for its choice rather than a proof, so the alternative is an empirical question for a given model.

Why does batch normalization allow higher learning rates?

The paper gives a scale argument. Batch norm's output does not change if the weights feeding it are multiplied by a constant a, and the gradient with respect to those weights is divided by a. So if a large step inflates the weights, their next gradients shrink and the growth limits itself, while the layer's Jacobian is unaffected by the weight scale, which keeps small parameter changes from being amplified as they pass through many layers. In the Inception experiments, learning rates 5 and 30 times the original trained fine: BN-x5 reached the original's best accuracy in 2.1 million steps instead of 31 million, and BN-x30 went on to 74.8%.

Does batch normalization replace dropout?

In the paper's main network it largely did. Removing dropout from the batch-normalized Inception sped up training without increasing overfitting, and the authors attribute part of batch norm's regularizing effect to the noise of batch statistics, since each example's normalization depends on the other examples in its mini-batch. It was not removed everywhere, though: some members of the paper's six-network ensemble kept dropout at 5% or 10%, compared with 40% in the original Inception. Later convolutional networks such as ResNet were trained with batch norm and no dropout at all, while dropout stayed common elsewhere, for example in transformer blocks.

Check yourself

4 questions to test what you just read

Work each one out before you open it — a number, a prediction or a reason, not a definition. Producing the answer is what makes it stick. Your progress is kept on this device.

A convolutional layer outputs a batch of 32 images with 64 channels of 14 × 14. How many means does batch norm compute, over how many values each, and how many parameters does it add?

Show answer

64 means, one per channel, each over 32 × 14 × 14 = 6,272 values (the effective batch m′ = m·p·q). It adds one γ and one β per channel: 128 parameters, independent of the image size.

How much total gradient would a bias b added before batch norm receive over a batch, and why?

Show answer

Zero. Summing ∂ℓ/∂xi over the batch gives m·Σg − m·Σg − (Σx̂i)(Σgjx̂j), and Σx̂i = 0. Adding b shifts every xi equally and the mean subtraction removes the shift, so the loss cannot depend on b; β does its job.

A large update doubles every weight in W feeding a batch-normalized layer. What happens to the layer's output and to the next gradient with respect to W?

Show answer

The output is unchanged, since BN((2W)u) = BN(Wu). The gradient halves, because ∂BN((aW)u)/∂(aW) = (1/a)·∂BN(Wu)/∂W with a = 2. Oversized weights automatically take smaller steps, part of why BN tolerated a 30× learning rate.

From the step counts, how much of BN-x5's speed-up came from adding BN alone, and how much from the new recipe?

Show answer

BN alone took 31.0 million steps to 13.3 million, about 2.3×. The new recipe with a 5× learning rate took that to 2.1 million, a further 6.3×. Together that is about 14.8×, the paper's fourteenfold reduction.

Where this sits

Making deep nets train

Seven papers that turned "deeper is better in theory" into a network that actually converges. Every later architecture paper assumes all of them.

  1. 1Dropout2014
  2. 2Batch Normalization2015
  3. 3Adam2015
  4. 4ResNet2016
  5. 5LayerNorm & RMSNorm2016
  6. 6mixup2018
  7. 7The Lottery Ticket Hypothesis2019

All 110 papers, in 19 ladders →

Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift · Ioffe & Szegedy · ICML 2015 · read the original paper on arXiv → · Vibe Engines · 2026
Finished this one? 0 / 110 Paper Breakdowns done
NextAdam Next on the “Making deep nets train” ladder · rung 3 of 7

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.

More Paper Breakdowns