Splits channels into groups and normalizes over within each sample, giving BatchNorm-like benefits without any batch dependence, the default for small-batch detection/segmentation.

Equation

For input with group index , let be the set of elements in group of sample :

where are per-channel affine parameters.

From scratch

import torch
from einops import rearrange
 
def group_norm(x, gamma, beta, groups, eps=1e-5):
    # x: (n, c, h, w); gamma, beta: (c,)
    xg = rearrange(x, "n (g k) h w -> n g (k h w)", g=groups)
    mu = xg.mean(-1, keepdim=True)
    var = xg.var(-1, keepdim=True, unbiased=False)
    xg = (xg - mu) * torch.rsqrt(var + eps)
    y = rearrange(xg, "n g (k h w) -> n (g k) h w", k=x.shape[1] // groups, h=x.shape[2])
    return y * gamma.view(1, -1, 1, 1) + beta.view(1, -1, 1, 1)

Notes

  • recovers LayerNorm over ; recovers InstanceNorm.
  • Identical behavior in train and eval: no running statistics.
  • Requires ; is the usual default.
  • See Normalization Comparison.