Skip to content
mlmentorship

Weight initialization (Kaiming, Xavier)

Set the initial variance of each layer's weights so that activations and gradients neither explode nor vanish through depth. The single most impactful one-line decision in deep nets.

Published · 4 min read ·Core ·Intermediate

Visual quick review

Visual first · depth when needed

Predict why a ReLU layer needs weight variance 2 divided by fan-in to preserve activation scale, and how a smaller or larger factor compounds through depth.

Preparing the visual…

Summary

Initialize each layer’s weights from a distribution whose variance is set so the variance of activations (forward pass) and gradients (backward pass) stays approximately constant from layer to layer. Two standard schemes: Xavier/Glorot for tanh/sigmoid layers, Kaiming/He for ReLU-family layers.

If weights are too small, activations shrink toward zero through depth and gradients vanish. If too large, activations explode and gradients blow up. With either failure, training stalls or diverges in the first few hundred steps.

A correct init lets a 24-layer transformer train to convergence with vanilla SGD or Adam; an incorrect init makes the same architecture untrainable without ad-hoc fixes (warmup hacks, smaller LR, etc.).

Learning objective

See why ReLU needs the factor of 2

Activation second moment through four ReLU layers at three initialization scales Under independent zero-mean symmetric preactivations, each ReLU layer multiplies activation second moment by fan-in times weight variance divided by 2. All three paths start at q zero equal to 1. Weight variance 1 over fan-in multiplies by one half per layer and ends at 1 over 16. Kaiming variance 2 over fan-in multiplies by 1 and remains at 1. Variance 3 over fan-in multiplies by three halves and ends at 81 over 16, about 5.06. Circle, square, and triangle markers plus dotted, dashed, and solid paths distinguish the cases without color. activation second moment q_l / q_0 · log scale 3 / fan-in: gain 1.5 / layer 2 / fan-in: gain 1 (Kaiming) 1 / fan-in: gain 0.5 / layer 5.0610.0625 01234 ReLU layers traversed
Read it this way: follow each path from the shared second moment q0 = 1. A linear map with fan-in · Var(W) = c multiplies the second moment by c; under the usual symmetric-preactivation assumptions, ReLU keeps half, so each layer multiplies by c/2. The dotted circle path shrinks to 1/16, the dashed square Kaiming path stays at 1, and the solid triangle path grows to 81/16. Position, labels, marker shapes, and line styles carry the result without color. Original schematic based on Glorot and Bengio (2010) and He et al. (2015).

The variance argument

For a linear layer with , zero-mean with variance , and drawn iid with mean 0 and variance :

To preserve variance (), pick .

The same argument on the backward pass gives . Compromise:

For ReLU activations, it is more precise to track the second moment : ReLU outputs are not zero-mean, so their variance is not their second moment. Under the usual independent, symmetric-preactivation assumptions, ReLU zeros half the values and retains half the second moment. Compensate with a factor of 2:

Practical defaults

Layer typeInit
Linear, ReLU/GELU activationKaiming-normal, fan-in
Linear, tanh/sigmoidXavier-uniform
Conv, ReLUKaiming-normal, fan-in
Embeddings for transformers; when followed by LayerNorm
LayerNorm 1
LayerNorm 0
Bias0

Most modern frameworks default to Kaiming-uniform for nn.Linear (PyTorch). For transformers, GPT-style models often add a per-residual scaling on the output projections to keep residual-stream variance bounded with depth.

Special cases

  • Residual connections: with N layers, the residual stream’s variance grows linearly with depth unless the contributions from each block are downscaled. GPT-2 / GPT-3 scale output projections by .
  • Identity init for recurrent (Le et al., 2015): initialize the recurrent weight matrix to the identity to make RNNs behave like feed-forward at .
  • Orthogonal init: weight matrices initialized to orthogonal matrices preserve norms exactly. Used in some RL policy networks.

Common pitfalls

  • Using PyTorch’s default nn.Linear for a transformer without checking it. The default is Kaiming-uniform with the wrong fan; many transformer codebases override it with .
  • Initializing bias to nonzero. Almost never helps; can break symmetry breaking arguments.
  • Forgetting to scale residual outputs. Without it, deep transformers produce huge residual-stream values at init.
  • Trusting “it trains” as proof of correct init. It might converge slower than a properly initialized run.