TAI BUI
Back to curriculum
BuildPython

Weight Initialization and Training Stability

Initialize wrong and training never starts. Initialize right and 50 layers train as smoothly as 3.

TIME: ~90 minutesPREREQUISITES: Lesson 03.04 (Activation Functions), Lesson 03.07 (Regularization)

Learning Objectives

  • Implement zero, random, Xavier/Glorot, and Kaiming/He initialization strategies and measure their effect on activation magnitudes through 50 layers
  • Derive why Xavier init uses Var(w) = 2/(fan_in + fan_out) and Kaiming uses Var(w) = 2/fan_in
  • Demonstrate the symmetry problem with zero initialization and explain why random scale alone is insufficient
  • Match the correct initialization strategy to the activation function: Xavier for sigmoid/tanh, Kaiming for ReLU/GELU

The Problem

Initialize all weights to zero. Nothing learns. Every neuron computes the same function, receives the same gradient, and updates identically. After 10,000 epochs, your 512-neuron hidden layer is still 512 copies of the same neuron. You paid for 512 parameters and got 1.

Initialize them too large. Activations explode through the network. By layer 10, values hit 1e15. By layer 20, they overflow to infinity. Gradients follow the same trajectory in reverse.

Initialize them randomly from a standard normal distribution. Works for 3 layers. At 50 layers, the signal collapses to zero or detonates to infinity depending on whether the random scale was slightly too small or slightly too large. The boundary between "works" and "broken" is razor-thin.

Weight initialization is the most underrated decision in deep learning. Architecture gets papers. Optimizers get blog posts. Initialization gets a footnote. But get it wrong and nothing else matters: your network is dead before training begins.

Warm-up0/3
1. A ReLU activation receives a negative number as input. What does it output?Warm-up
A single ReLU unit drawn as three boxes in a row: input −2.5, the ReLU box, and an output box showing a question mark.
Input value is illustrative.
2. A number is multiplied by 0.5 at each of 50 consecutive steps. What happens to its size?Warm-up
A chain of boxes: start 1.0, then steps 1, 2, 3, an ellipsis, and step 50, each multiplying by 0.5, ending at a label asking for the final size.
Starting value is illustrative.
3. Sigmoid and tanh squash large positive or negative inputs into a nearly flat region of the curve. Based on what you already know about how gradients flow backward through an activation function, what happens to the gradient in that flat region?Warm-up
Two plots side by side: sigmoid from −8 to 8 and tanh from −5 to 5, each with the far-left and far-right shaded as the nearly flat regions.
Curves computed from the definitions of sigmoid and tanh.
Check: The Problem0/4
1. What is weight initialization?Define
A training timeline with markers step 0, step 1, step 2, and a card showing the 4 by 2 weight matrix of a small layer at step 0, one row of two numbers per neuron, with a note that W changes with every update.
Values come from the lesson's kaiming_init(2, 4) with random.seed(42).
2. What is a dead network?Define
Three boxes in a row: 2 inputs, 8 sigmoid hidden units with N(0, 0.01) weights, and a sigmoid output, above a label asking for the training loss after 300 epochs on the circle dataset.
Configuration taken from the lesson's training_comparison.
3. What are exploding activations?Define
A chain of boxes: layer 1, layer 2, an ellipsis and layer 50, each with N(0,1) weights, width 64 and ReLU, above a label asking for the mean absolute activation at each layer.
Configuration of the lesson's forward_deep.
4. Your model's loss is NaN by step three, and you haven't touched the architecture recently. Per the lesson's Author's Note, what's the fastest first thing to check?Analyze
Terminal output of train.py ending in the line step 3 loss = nan, with a note that the architecture has not been touched recently.
Typed illustration of the stem, not captured from a real run.

The Concept

The Symmetry Problem

Symmetry is what happens when every neuron in a layer starts out identical and therefore stays identical. Each neuron runs the same computation: multiply inputs by weights, add a bias, apply an activation. If every weight starts at the same value (zero is the extreme case), every neuron produces the same output, receives the same gradient during backpropagation, and changes by the same amount at every update step. Hundreds of parameters, moving in lockstep, forever.

Random initialization is the brute-force fix: give each neuron a different starting point in weight space so each one settles on a different feature.

But "random" alone isn't enough. The scale of that randomness decides whether the network trains at all.

Variance Propagation Through Layers

Consider a single layer with fan_in inputs:

z = w1*x1 + w2*x2 + ... + w_n*x_n

If each weight wi is drawn from a distribution with variance Var(w) and each input xi has variance Var(x), the output variance is:

Var(z) = fan_in * Var(w) * Var(x)

If Var(w) = 1 and fan_in = 512, the output variance is 512x the input variance. After 10 layers: 512^10 = 1.2e27. Your signal has exploded.

If Var(w) = 0.001, the output variance shrinks by 0.001 * 512 = 0.512 per layer. After 10 layers: 0.512^10 = 0.00124. Your signal has vanished.

The goal: choose Var(w) so that Var(z) = Var(x). Signal magnitude stays constant across layers.

Xavier/Glorot Initialization

Glorot and Bengio (2010) derived the solution for sigmoid and tanh activations. To keep variance constant in both the forward and backward pass:

Var(w) = 2 / (fan_in + fan_out)

In practice, weights are drawn from:

w ~ Uniform(-limit, limit)  where limit = sqrt(6 / (fan_in + fan_out))

or:

w ~ Normal(0, sqrt(2 / (fan_in + fan_out)))

This works because sigmoid and tanh are roughly linear near zero, where properly initialized activations live. The variance stays stable through dozens of layers.

Kaiming/He Initialization

ReLU kills half the outputs (everything negative becomes zero). The effective fan_in is halved because on average half the inputs are zeroed. Xavier init doesn't account for this: it underestimates the variance needed.

He et al. (2015) adjusted the formula:

Var(w) = 2 / fan_in

Weights are drawn from:

w ~ Normal(0, sqrt(2 / fan_in))

The factor of 2 compensates for ReLU zeroing half the activations. Without it, the signal shrinks by ~0.5x per layer. With 50 layers: 0.5^50 = 8.8e-16. Kaiming init prevents this.

Transformer Initialization

GPT-2 introduced a different pattern. Residual connections add the output of each sub-layer to its input:

x = x + sublayer(x)

Each addition increases variance. With N residual layers, variance grows proportionally to N. GPT-2 scales the weights of residual layers by 1/sqrt(2N), where N is the number of layers. This keeps the accumulated signal magnitude stable.

Llama 3 (405B parameters, 126 layers) uses a similar scheme. Without this scaling, the residual stream would grow unbounded through 126 layers of attention and feedforward blocks.

Mermaid diagram

Activation Magnitude Through 50 Layers

Mermaid diagram

Choosing the Right Init

Mermaid diagram

Check: The Concept0/22
1. What does symmetry breaking mean in weight initialization?Define
A card listing the weights of a 4-neuron layer with 2 inputs and each neuron's sigmoid output for input [0.5, -0.3]: every row has the same weight pair 0.30, 0.30 and the same output 0.515.
0.30 is an illustrative constant.
2. What is a layer's fan-in?Define
A fully connected network with layers of 5, 4 and 2 neurons. One neuron, labelled h inside its circle, in the middle layer is highlighted, with its arrows coming in from the previous layer drawn blue and its arrows going out to the next layer drawn orange.
Layer sizes are illustrative.
3. What is a layer's fan-out?Define
A fully connected network with layers of 3, 6 and 4 neurons. One neuron, labelled h inside its circle, in the middle layer is highlighted, with its arrows coming in from the previous layer drawn blue and its arrows going out to the next layer drawn orange.
Layer sizes are illustrative.
4. Which description matches Xavier/Glorot initialization?Define
Histogram of 131,072 weights drawn by Xavier/Glorot init for a layer with fan_in 512 and fan_out 256, a bell shape centered on 0 between about −0.3 and 0.3.
numpy sample, std from the Xavier formula.
5. What does variance propagation analysis study?Define
Six boxes in a row, layers 1 to 6, each with N(0,1) weights, 64 inputs per neuron and ReLU, above a label asking for the mean of the squared activations after each layer.
Setup of the numpy run shown in the explanation; width 64 and six layers are illustrative.
6. What is residual scaling in transformer initialization?Define
A horizontal residual stream line with three plus circles where the outputs of sublayer 1, sublayer 2 and sublayer N are added back onto the stream, each sublayer also reading from the stream through a dashed skip line.
7. What is the formula for Kaiming/He initialization variance?Define
A layer with 256 inputs and 128 outputs drawn as boxes (W of shape 128 by 256 with ReLU), above a card showing the top-left 3 by 4 corner of the weight matrix from kaiming_init(256, 128).
Weight values are one random draw (seed 1) of the lesson's kaiming_init.
8. What happens if every weight in a neural network starts at zero?Explain
A fully connected network with 2 inputs, 4 hidden neurons and 1 output. Every connection has weight 0.0 and every neuron has bias 0.
9. Why does the scale (variance) of random weight initialization matter, not just whether the weights are random?Explain
Two histograms of 4,096 random weights for layers with fan_in 64: layer A with standard deviation 0.01 spread across −0.04 to 0.04, and layer B with standard deviation 1.0 spread across −4 to 4.
numpy samples, seed 3.
10. In Var(z) = fan_in * Var(w) * Var(x), what must fan_in * Var(w) equal for the signal to keep a constant variance from layer to layer?Explain
Three boxes in a row: the input with variance v, the signal after layer 1 with variance fan_in times Var(w) times v, and the signal after layer 2 with variance fan_in times Var(w) times Var(z1), followed by the goal that the variance be the same v after every layer and a question for fan_in times Var(w).
11. When should you use Xavier/Glorot initialization instead of Kaiming/He?Explain
Four small plots of activation functions, sigmoid, tanh, ReLU and GELU, for inputs from −4 to 4, above two cards giving the Xavier/Glorot formula 2/(fan_in + fan_out) and the Kaiming/He formula 2/fan_in.
Curves computed from the definitions.
12. Why does Xavier's formula use fan_in + fan_out in the denominator instead of fan_in alone?Explain
Table of weight variance for three layer shapes, 128 to 128, 784 to 128 and 128 to 10, under 1/fan_in and under 2/(fan_in + fan_out): the two rules agree for 128 to 128 and differ for the other two shapes.
Layer shapes are illustrative; values computed from the formulas.
13. Why does Kaiming init include the factor of 2 in Var(w) = 2/fan_in?Explain
Two cards for a layer with fan_in 256 and fan_out 256: Xavier/Glorot gives Var(w) = 2/(256 + 256) = 0.00391 and Kaiming/He gives Var(w) = 2/256 = 0.00781.
Computed from the two formulas; width 256 is illustrative.
14. You train a 50-layer ReLU network using Xavier initialization instead of Kaiming. What does the lesson's derivation predict?Explain
A chain of boxes: N(0,1) input, layer 1 with Xavier init and ReLU, an ellipsis, layer 50 with Xavier init and ReLU, then a box asking for the mean absolute activation at layer 50.
15. Why does GPT-2 scale residual layer weights by 1/sqrt(2N)?Explain
A residual stream line with three plus circles for block 1, block 2 and block N, each block output labelled W times 1/sqrt(2N) before it is added back to the stream.
16. A layer has fan_in = 100 and its weights have Var(w) = 0.01. By what factor does the variance of the signal change per layer?Apply
Three boxes in a row: input signal with variance v, a layer with fan_in = 100 and Var(w) = 0.01, and an output z with variance question mark times v.
17. With Var(w)=1 and fan_in=512, what happens to the variance of the signal after 10 layers, compared to Var(w)=0.001?Apply
Two rows of ten-layer chains with fan_in 512: the first with Var(w) = 1 and the second with Var(w) = 0.001, each starting from the same input variance v and ending in a label asking for the variance after layer 10.
18. A 512-neuron hidden layer starts with every weight set to the same constant. After 10,000 epochs all 512 neurons still output identical values. Which diagnosis fits?Analyze
A 64 by 8 grid of 512 identical cells, one per hidden neuron, all the same color, above a card giving the minimum and maximum neuron output 0.481136 and 0.481136 and the training loss going from 0.4513 to 0.2106.
Illustrative numpy run: 2-512-1 sigmoid net, lesson's circle data, every weight 0.005, bias 0, lr 0.5, full batch.
19. A colleague picks a fixed std of 0.125 for random init. It works in a width-64 network, so they reuse it unchanged in a width-1024 network and the activations explode. Why?Analyze
Two boxes: a width-64 network with fixed std 0.125 that works, and a width-1024 network with the same fixed std 0.125 whose activations explode.
20. You stack 30 custom transformer blocks with residual connections but skip GPT-2-style residual scaling entirely. What does the lesson's derivation predict?Analyze
A residual stream line with three plus circles for block 1, block 2 and block 30, with a note that no residual scaling is applied to any of the 30 blocks.
21. You are writing an init health check. For a layer with fan_in = 512 followed by GELU, which recommendation should it return?Design
A health-check pipeline: an input layer with fan_in 512 and GELU activation, a small plot of the GELU curve from −4 to 4, and an output box labelled recommendation with a question mark.
GELU curve computed from x·Φ(x).
22. You are writing a 48-layer transformer from scratch with residual connections, with no HuggingFace code. Which init plan fits?Design
A residual stream line with three plus circles for block 1, block 2 and block 48, with a note that each block adds to the stream and no HuggingFace code is used.

Build It

Step 1: Initialization Strategies

Four ways to initialize a weight matrix. Each returns a list of lists (a 2D matrix) with fan_in columns and fan_out rows.

python
import math
import random
 
 
def zero_init(fan_in, fan_out):
    return [[0.0 for _ in range(fan_in)] for _ in range(fan_out)]
 
 
def random_init(fan_in, fan_out, scale=1.0):
    return [[random.gauss(0, scale) for _ in range(fan_in)] for _ in range(fan_out)]
 
 
def xavier_init(fan_in, fan_out):
    std = math.sqrt(2.0 / (fan_in + fan_out))
    return [[random.gauss(0, std) for _ in range(fan_in)] for _ in range(fan_out)]
 
 
def kaiming_init(fan_in, fan_out):
    std = math.sqrt(2.0 / fan_in)
    return [[random.gauss(0, std) for _ in range(fan_in)] for _ in range(fan_out)]

Step 2: Activation Functions

We need sigmoid, tanh, and ReLU to test each init strategy with its intended activation.

python
def sigmoid(x):
    x = max(-500, min(500, x))
    return 1.0 / (1.0 + math.exp(-x))
 
 
def tanh_act(x):
    return math.tanh(x)
 
 
def relu(x):
    return max(0.0, x)

Step 3: Forward Pass Through 50 Layers

Pass random data through a deep network and measure mean activation magnitude at each layer.

python
def forward_deep(init_fn, activation_fn, n_layers=50, width=64, n_samples=100):
    random.seed(42)
    layer_magnitudes = []
 
    inputs = [[random.gauss(0, 1) for _ in range(width)] for _ in range(n_samples)]
 
    for layer_idx in range(n_layers):
        weights = init_fn(width, width)
        biases = [0.0] * width
 
        new_inputs = []
        for sample in inputs:
            output = []
            for neuron_idx in range(width):
                z = sum(weights[neuron_idx][j] * sample[j] for j in range(width)) + biases[neuron_idx]
                output.append(activation_fn(z))
            new_inputs.append(output)
        inputs = new_inputs
 
        magnitudes = []
        for sample in inputs:
            magnitudes.append(sum(abs(v) for v in sample) / width)
        mean_mag = sum(magnitudes) / len(magnitudes)
        layer_magnitudes.append(mean_mag)
 
    return layer_magnitudes

Step 4: The Experiment

Run all combinations: zero init, random N(0,1), random N(0,0.01), Xavier with sigmoid, Xavier with tanh, Kaiming with ReLU. Print the magnitude at key layers.

python
def run_experiment():
    configs = [
        ("Zero init + Sigmoid", lambda fi, fo: zero_init(fi, fo), sigmoid),
        ("Random N(0,1) + ReLU", lambda fi, fo: random_init(fi, fo, 1.0), relu),
        ("Random N(0,0.01) + ReLU", lambda fi, fo: random_init(fi, fo, 0.01), relu),
        ("Xavier + Sigmoid", xavier_init, sigmoid),
        ("Xavier + Tanh", xavier_init, tanh_act),
        ("Kaiming + ReLU", kaiming_init, relu),
    ]
 
    print(f"{'Strategy':<30} {'L1':>10} {'L5':>10} {'L10':>10} {'L25':>10} {'L50':>10}")
    print("-" * 80)
 
    for name, init_fn, act_fn in configs:
        mags = forward_deep(init_fn, act_fn)
        row = f"{name:<30}"
        for idx in [0, 4, 9, 24, 49]:
            val = mags[idx]
            if val > 1e6:
                row += f" {'EXPLODED':>10}"
            elif val < 1e-6:
                row += f" {'VANISHED':>10}"
            else:
                row += f" {val:>10.4f}"
        print(row)

Step 5: Symmetry Demonstration

Show that zero init produces identical neurons.

python
def symmetry_demo():
    random.seed(42)
    weights = zero_init(2, 4)
    biases = [0.0] * 4
 
    inputs = [0.5, -0.3]
    outputs = []
    for neuron_idx in range(4):
        z = sum(weights[neuron_idx][j] * inputs[j] for j in range(2)) + biases[neuron_idx]
        outputs.append(sigmoid(z))
 
    print("\nSymmetry Demo (4 neurons, zero init):")
    for i, out in enumerate(outputs):
        print(f"  Neuron {i}: output = {out:.6f}")
    all_same = all(abs(outputs[i] - outputs[0]) < 1e-10 for i in range(len(outputs)))
    print(f"  All identical: {all_same}")
    print(f"  Effective parameters: 1 (not {len(weights) * len(weights[0])})")

Step 6: Layer-by-Layer Magnitude Report

Print a visual bar chart of activation magnitudes through 50 layers.

python
def magnitude_report(name, magnitudes):
    print(f"\n{name}:")
    for i, mag in enumerate(magnitudes):
        if i % 5 == 0 or i == len(magnitudes) - 1:
            if mag > 1e6:
                bar = "X" * 50 + " EXPLODED"
            elif mag < 1e-6:
                bar = "." + " VANISHED"
            else:
                bar_len = min(50, max(1, int(mag * 10)))
                bar = "#" * bar_len
            print(f"  Layer {i+1:3d}: {bar} ({mag:.6f})")
Check: Build It0/7
1. In forward_deep with width=64, xavier_init(64, 64) draws weights from random.gauss(0, std). What is std?Apply
Code of the lesson's xavier_init function, which computes std from fan_in and fan_out and fills a matrix with random.gauss(0, std), above the line from forward_deep that calls init_fn(width, width) with width 64.
Code copied from the lesson, long lines wrapped.
2. The lesson's symmetry_demo() zero-initializes a layer with 2 inputs and 4 neurons (8 weights total), then runs one input through it. What does it print?Apply
The first part of the lesson's symmetry_demo function: it zero-initializes a layer with 2 inputs and 4 neurons and computes a sigmoid output for the input [0.5, -0.3] for each neuron, followed by a comment that the print statements are omitted.
Code copied from the lesson, long lines wrapped, print statements omitted.
3. In run_experiment(), what mean magnitude does the 'Zero init + Sigmoid' row show at layer 50?Apply
A table of the six run_experiment rows at layers 1, 5, 10, 25 and 50 with the Zero init + Sigmoid row shown as question marks and the other five rows filled in, above a card listing the EXPLODED, VANISHED and 4-decimal rules.
Other rows are real output of the lesson's code (seed 42).
4. In the lesson's run_experiment(), which configuration is more likely to hit the 'EXPLODED' label by layer 50: 'Random N(0,1) + ReLU' or 'Kaiming + ReLU'?Apply
Two configuration entries from the lesson's run_experiment, Random N(0,1) + ReLU using random_init with scale 1.0 and Kaiming + ReLU using kaiming_init, above a card with the 50 layers, width 64 run size and the EXPLODED and VANISHED rules.
Code copied from the lesson.
5. magnitude_report prints a layer with mean magnitude 250.0. The thresholds are 1e6 for EXPLODED and 1e-6 for VANISHED, and bar length is min(50, max(1, int(mag * 10))). What is printed for that layer?Apply
The code of the lesson's magnitude_report function with its 1e6 and 1e-6 thresholds and bar-length rule, and a note that the last layer has mean magnitude 250.0.
Code copied from the lesson.
6. A 50-layer width-64 ReLU network using random N(0, 0.01) weights reports VANISHED at layer 50. What is the underlying cause?Analyze
A card with the configuration random_init(64, 64, 0.01), ReLU, 50 layers, width 64, and the run_experiment row Random N(0,0.01) + ReLU reading 0.0313, VANISHED, VANISHED, VANISHED, VANISHED.
Real output of the lesson's code, seed 42.
7. A new 25-layer ReLU network with custom layers and N(0,1) weights returns NaN loss by step three. Which plan fits the lesson best?Design
Code for 25 stacked Linear(64, 64) plus ReLU layers with weights from normal std 1.0, and a training log ending in step 3 loss = nan.
Typed illustration of the stem; width 64 is illustrative.

Use It

PyTorch provides these as built-in functions:

python
import torch
import torch.nn as nn
 
layer = nn.Linear(512, 256)
 
nn.init.xavier_uniform_(layer.weight)
nn.init.xavier_normal_(layer.weight)
 
nn.init.kaiming_uniform_(layer.weight, nonlinearity='relu')
nn.init.kaiming_normal_(layer.weight, nonlinearity='relu')
 
nn.init.zeros_(layer.bias)

When you call nn.Linear(512, 256), PyTorch defaults to Kaiming uniform initialization. That's why most simple networks "just work": PyTorch already made the right choice. But when you build custom architectures or go deeper than 20 layers, you need to understand what's happening and potentially override the default.

For transformers, HuggingFace models typically handle initialization in their _init_weights method. GPT-2's implementation scales residual projections by 1/sqrt(N). If you're building a transformer from scratch, you need to add this yourself.

Check: Use It0/4
1. What initialization does PyTorch use by default when you create an nn.Linear layer?Explain
A Python session creating layer = nn.Linear(512, 256) and printing layer.weight.shape as torch.Size([256, 512]) and layer.bias.shape as torch.Size([256]), with a note that no training or init call has happened yet.
Real output from torch 2.14.
2. How do HuggingFace transformer models typically handle GPT-2's residual scaling, and what does that mean for a from-scratch build?Explain
Two boxes: a HuggingFace model from the transformers library and your own nn.Module written from scratch, each with a label asking where residual scaling comes from.
3. You call nn.init.xavier_uniform_ on nn.Linear(512, 256).weight. Using limit = sqrt(6 / (fan_in + fan_out)), what is the limit?Apply
A rectangle for layer.weight of shape [256, 512] from nn.Linear(512, 256) with in_features 512 along the columns and out_features 256 along the rows, above the Xavier uniform limit formula.
Shape is the real torch shape.
4. You stack 40 custom tanh layers using nn.Linear's default init, and training stalls. Which diagnosis best fits the lesson?Analyze
Code building a model of 40 stacked nn.Linear(64, 64) and Tanh layers with no init calls, with a note that during training the loss barely moves.
Width 64 is illustrative; the stem does not give a width.

Ship It

This lesson produces:

  • outputs/prompt-init-strategy.md, a prompt that diagnoses weight initialization problems and recommends the right strategy
Author's Note

The bug this lesson is really about rarely announces itself as an initialization bug. It shows up as a loss that's NaN by step three, or a network that sits at exactly chance-level accuracy for a thousand epochs and never budges. Most people burn a day tuning the learning rate before they think to check what their weights started at. Check init first. It's a five-second look compared to a day of blind hyperparameter search.

The other trap is trusting PyTorch's defaults past the point where they still apply. nn.Linear ships with Kaiming uniform, which is why toy networks train fine on the first try and give you a false sense that init is a solved problem. That confidence runs out the moment you write a custom layer, stack more than about 20 of them, or add residual connections without scaling them, because those are exactly the cases the default's assumptions don't cover. That's when the variance math in this lesson stops being trivia and starts being the thing that decides whether your network trains at all.

Exercises

  1. Add LeCun initialization (Var = 1/fan_in, designed for SELU activation). Run the 50-layer experiment with LeCun init + tanh and compare to Xavier + tanh.

  2. Implement the GPT-2 residual scaling: multiply the output of each layer by 1/sqrt(2*N) before adding to the residual stream. Run 50 layers with and without scaling, measure how fast the residual magnitude grows.

  3. Create an "init health check" function that takes a network's layer dimensions and activation type, then recommends the correct initialization and warns if the current init will cause problems.

  4. Run the experiment with fan_in = 16 vs fan_in = 1024. Xavier and Kaiming adapt to fan_in, but random init doesn't. Show how the gap between "works" and "breaks" widens with larger layers.

  5. Implement orthogonal initialization (generate a random matrix, compute its SVD, use the orthogonal matrix U). Compare to Kaiming for ReLU networks at 50 layers.

Key Terms

TermWhat people sayWhat it actually means
Weight initialization"Set starting weights randomly"The strategy for choosing initial weight values that determines whether a network can train at all
Symmetry breaking"Make neurons different"Using random initialization to ensure neurons learn distinct features instead of computing identical functions
Fan-in"Number of inputs to a neuron"The number of incoming connections, which determines how input variance accumulates in the weighted sum
Fan-out"Number of outputs from a neuron"The number of outgoing connections, relevant for maintaining gradient variance during backpropagation
Xavier/Glorot init"The sigmoid initialization"Var(w) = 2/(fan_in + fan_out), designed to preserve variance through sigmoid and tanh activations
Kaiming/He init"The ReLU initialization"Var(w) = 2/fan_in, accounts for ReLU zeroing half the activations
Variance propagation"How signals grow or shrink through layers"The mathematical analysis of how activation variance changes layer by layer based on weight scale
Residual scaling"GPT-2's init trick"Scaling residual connection weights by 1/sqrt(2N) to prevent variance growth through N transformer layers
Dead network"Nothing trains"A network where poor initialization causes all gradients to be zero or all activations to saturate
Exploding activations"Values go to infinity"When weight variance is too high, causing activation magnitudes to grow exponentially through layers

Further Reading

  • Glorot & Bengio, "Understanding the difficulty of training deep feedforward neural networks" (2010) — the original Xavier initialization paper with variance analysis
  • He et al., "Delving Deep into Rectifiers" (2015) — introduced Kaiming initialization for ReLU networks
  • Radford et al., "Language Models are Unsupervised Multitask Learners" (2019) — GPT-2 paper with residual scaling initialization
  • Mishkin & Matas, "All You Need is a Good Init" (2016) — layer-sequential unit-variance initialization, an empirical alternative to analytical formulas

Code

Ships With