Side-by-side of the standard normalizers for a conv-shaped tensor (transformers use with playing the role of ).

Equation

All share the same form, differing only in the reduction set :

NormReduced axesStats shapeBatch-dep.Train vs evalParams
BatchNormyesdiffers: running at eval
LayerNormnoidentical
InstanceNormnoidentical
GroupNormnoidentical
RMSNorm (no mean)noidentical

From scratch

import torch
 
def norm(x, dims, gamma, beta=None, center=True, eps=1e-5):
    # x: (n, c, h, w); dims: tuple of axes to reduce
    mu = x.mean(dims, keepdim=True) if center else 0.0
    var = ((x - mu) ** 2).mean(dims, keepdim=True)
    y = (x - mu) * torch.rsqrt(var + eps) * gamma.view(1, -1, 1, 1)
    return y + beta.view(1, -1, 1, 1) if beta is not None else y
 
# batch: dims=(0,2,3) | layer: (1,2,3) | instance: (2,3) | group: reshape to (n,g,-1) first

Notes

  • Only BatchNorm couples samples, so it breaks at batch size 1, under heavy augmentation skew, and in distributed setups without SyncBN.
  • LayerNorm, InstanceNorm: GroupNorm interpolates between them.
  • RMSNorm drops centering, so it is scale- but not shift-invariant; Adaptive LayerNorm makes functions of a condition.
  • All are and memory-bandwidth bound; fusing the norm with the following matmul is the usual win.