Weight Initialization › Xavier/Glorot Initialization

Michael BrenndoerferApril 25, 20256 min read
Language AI HandbookAll chapters
Part 10 of 67Neural Network Foundations
Chapter 70Weight Initialization › Xavier/Glorot Initialization
Reading section 6 of 19 · Xavier/Glorot Initialization · 6 minSection 6 of 19 · 6 min

Book contents

Section 6 of 19 · 6 min read

Weight Initialization › Xavier/Glorot InitializationOne section · Sections in this chapter6 / 19 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Our variance analysis derived the optimal weight variance for forward propagation. But training a neural network involves both forward and backward propagation, and gradients face the same variance amplification problem in reverse.

Xavier Glorot and Yoshua Bengio, in their 2010 paper "Understanding the Difficulty of Training Deep Feedforward Neural Networks," recognized that we must consider both signal directions simultaneously. If we optimize only for forward variance, gradients might explode or vanish during backpropagation. The key insight was that a good initialization must care about the health of the gradient signal just as much as the health of the forward activations, because training depends on both flowing cleanly through the entire network.

Forward and Backward Requirements

The forward pass constraint from our derivation above gives:

Var(w)=1nin\text{Var}(w) = \frac{1}{n_{\text{in}}}

where ninn_{\text{in}} is the fan-in (number of input connections to each neuron).

During backpropagation, gradients flow in the opposite direction. Each input neuron receives gradient contributions from all noutn_{\text{out}} output neurons. By the same reasoning applied to the gradient equations, maintaining gradient variance during the backward pass requires:

Var(w)=1nout\text{Var}(w) = \frac{1}{n_{\text{out}}}

where noutn_{\text{out}} is the fan-out (number of output connections from each input neuron).

To see why the backward pass requirement involves noutn_{\text{out}}, recall the chain rule during backpropagation. The gradient of the loss with respect to an input activation xix_i is:

∂L∂xi=∑j=1noutwij⋅∂L∂zj\frac{\partial L}{\partial x_i} = \sum_{j=1}^{n_{\text{out}}} w_{ij} \cdot \frac{\partial L}{\partial z_j}

This is a weighted sum of noutn_{\text{out}} gradient terms, structurally identical to the forward pass equation but with fan-out replacing fan-in. The same variance analysis applies, giving the backward requirement Var(w)=1/nout\text{Var}(w) = 1/n_{\text{out}}.

The Glorot Compromise

We face a dilemma. The forward pass requires Var(w)=1/nin\text{Var}(w) = 1/n_{\text{in}}, but the backward pass requires Var(w)=1/nout\text{Var}(w) = 1/n_{\text{out}}. These two constraints conflict whenever nin≠noutn_{\text{in}} \neq n_{\text{out}}, which is the common case for layers that change dimensionality.

Glorot and Bengio proposed taking the harmonic mean of the two fan values:

Var(w)=2nin+nout\text{Var}(w) = \frac{2}{n_{\text{in}} + n_{\text{out}}}

where:

  • ninn_{\text{in}}: fan-in (input dimension of the weight matrix)
  • noutn_{\text{out}}: fan-out (output dimension of the weight matrix)
  • 2nin+nout\frac{2}{n_{\text{in}} + n_{\text{out}}}: a compromise variance that partially satisfies both the forward and backward variance preservation constraints

Notice that when nin=noutn_{\text{in}} = n_{\text{out}}, this formula reduces to 1/nin1/n_{\text{in}}, recovering the LeCun result. For layers where the input and output dimensions differ substantially, the formula takes a middle path between the two competing requirements. This is an elegant engineering compromise: it is not optimal for either direction alone, but it avoids catastrophically failing in either direction.

This is Xavier initialization (also called Glorot initialization). To sample weights, we convert this target variance to the parameters of either a normal or uniform distribution.

For a normal distribution N(0,σ2)\mathcal{N}(0, \sigma^2), the variance is σ2\sigma^2. Setting σ2=2/(nin+nout)\sigma^2 = 2/(n_{\text{in}} + n_{\text{out}}) and taking the square root gives the standard deviation:

σ=2nin+nout\sigma = \sqrt{\frac{2}{n_{\text{in}} + n_{\text{out}}}}

Weights are drawn from:

w∼N ⁣(0,2nin+nout)w \sim \mathcal{N}\!\left(0, \sqrt{\frac{2}{n_{\text{in}} + n_{\text{out}}}}\right)

For a uniform distribution U[−a,a]U[-a, a], the variance is a2/3a^2/3. Setting a2/3=2/(nin+nout)a^2/3 = 2/(n_{\text{in}} + n_{\text{out}}) and solving for aa:

a=6nin+nouta = \sqrt{\frac{6}{n_{\text{in}} + n_{\text{out}}}}

Weights are drawn from:

w∼U ⁣[−6nin+nout,6nin+nout]w \sim U\!\left[-\sqrt{\frac{6}{n_{\text{in}} + n_{\text{out}}}}, \sqrt{\frac{6}{n_{\text{in}} + n_{\text{out}}}}\right]
Xavier/Glorot Initialization

A weight initialization scheme where weights are drawn from a distribution with variance 2/(nin+nout)2/(n_{\text{in}} + n_{\text{out}}). Designed for networks using symmetric activations like tanh or sigmoid, where the activation function is approximately linear near zero and does not systematically distort variance across layers.

In practice, the uniform variant is the more commonly referenced form, particularly in the original Glorot and Bengio paper. Both versions achieve similar results in practice because the variance formula is the same; only the shape of the distribution differs. The uniform variant is bounded, so it avoids the (very small) probability of drawing a very large outlier weight from the tails of a normal distribution.

Why This Works for Tanh and Sigmoid

The derivation assumes the activation function does not distort the variance of the signal. Tanh and sigmoid satisfy this assumption near zero, where they are both approximately linear. Specifically:

  • tanh⁡(z)≈z\tanh(z) \approx z for small ∣z∣|z|
  • σ(z)≈0.25z+0.5\sigma(z) \approx 0.25 z + 0.5 for small ∣z∣|z|, with derivative ≈0.25\approx 0.25

For tanh, the derivative near zero is approximately 1, meaning the function barely affects variance. For sigmoid, the derivative near zero is about 0.25, which does systematically reduce variance. This is why PyTorch's implementation includes an empirical correction factor of 5/35/3 for tanh (accounting for the actual saturation properties) and why some implementations of Xavier for sigmoid include additional adjustment. The original Glorot and Bengio paper noted that sigmoid is more problematic than tanh, because its non-zero mean output shifts the input distribution seen by subsequent layers.

Implementation

In[11]:
Code
def xavier_uniform(shape):
    """Xavier initialization with uniform distribution."""
    fan_in, fan_out = shape
    limit = np.sqrt(6 / (fan_in + fan_out))
    return np.random.uniform(-limit, limit, shape)


def xavier_normal(shape):
    """Xavier initialization with normal distribution."""
    fan_in, fan_out = shape
    std = np.sqrt(2 / (fan_in + fan_out))
    return np.random.randn(*shape) * std


def compare_initializations(n_layers, layer_size, init_func, activation="tanh"):
    """Track activation standard deviation through network with given initialization."""
    weights = [init_func((layer_size, layer_size)) for _ in range(n_layers)]
    x = np.random.randn(1000, layer_size)
    stds = [np.std(x)]
    for W in weights:
        x = x @ W
        if activation == "tanh":
            x = np.tanh(x)
        elif activation == "relu":
            x = np.maximum(0, x)
        stds.append(np.std(x))
    return stds
Out[12]:
Console
Activation standard deviations across layers (tanh network):
------------------------------------------------------------

Naive (std=1.0):
  Layer  0: std = 0.9999
  Layer  2: std = 0.9740
  Layer  4: std = 0.9738
  Layer  6: std = 0.9740
  Layer  8: std = 0.9740
  Layer 10: std = 0.9738

Small (std=0.01):
  Layer  0: std = 1.0004
  Layer  2: std = 0.0250
  Layer  4: std = 0.0006
  Layer  6: std = 0.0000
  Layer  8: std = 0.0000
  Layer 10: std = 0.0000

Xavier normal:
  Layer  0: std = 0.9991
  Layer  2: std = 0.4858
  Layer  4: std = 0.3593
  Layer  6: std = 0.2948
  Layer  8: std = 0.2531
  Layer 10: std = 0.2255

Xavier uniform:
  Layer  0: std = 1.0009
  Layer  2: std = 0.4855
  Layer  4: std = 0.3560
  Layer  6: std = 0.2921
  Layer  8: std = 0.2546
  Layer 10: std = 0.2241

Xavier initialization keeps activation standard deviation stable across layers, while naive (too large) and small (too small) initializations diverge in opposite directions.

Out[13]:
Visualization
Line plot comparing activation standard deviations across 10 layers for four initialization methods in a tanh network.
Activation standard deviation across 10 layers for four initialization strategies in a tanh network. Xavier initialization (both uniform and normal variants) maintains stable activation magnitudes throughout. Naive initialization (std=1.0) causes saturation in early layers where tanh is pushed to its extremes, while small initialization (std=0.01) causes activations to collapse toward zero in deeper layers.