Training

Backpropagation and vanishing gradients

Press play and watch backpropagation run the error back through one neuron by the chain rule, then through twelve layers, where the sigmoid lets it fade to 18 million times weaker and ReLU, careful initialisation and residual connections keep it alive.

Network
Layers 12
Loading 3D view

Who is to blameThe network's answer is off, and training has to decide how much each of its 3,281 parameters is to blame, so backpropagation runs the error backwards through the same pipes the numbers came in by.

Narrated with James Phoenix's AI voice.

-0.25-0.5 × 0.25 × 2.0
Traced dL/dw1
Sigmoid12 layers
Network
1 / 18Mof the last layer
Layer 1 signal
3,28116 units a layer
Parameters

Sigmoid with standard initialisation: every layer multiplies the error by about a fifth, so almost nothing reaches the first layers.

A network makes a prediction, compares it with the answer, and gets a single number back: the loss. Training then has to share that one number out among every weight and bias in the network, deciding how much each one contributed and which way to nudge it. Backpropagation is how it decides. It runs the error backwards through the same computation that produced the prediction, and at every junction multiplies it by that junction's local slope. Those products are the gradients, and gradient descent moves each parameter a small step against its own.

The first half of the film traces one neuron you can check by hand. Inputs of 2.0 and 1.0, weights of 0.4 and minus 0.6 and a bias of minus 0.2 add up to exactly zero; the sigmoid turns zero into 0.5; against a target of 1, a squared-error loss with the usual half in front comes to 0.125. On the way back the loss contributes minus 0.5, the sigmoid multiplies that by its slope of 0.25 to give minus 0.125, and the weighted sum hands each weight that amount times its own input: minus 0.25 for the first weight, minus 0.125 for the second and for the bias. Nothing else is going on in backpropagation. A framework such as PyTorch builds this chain for every operation automatically, which is what automatic differentiation and a computational graph mean, but each link is exactly this multiplication.

The neuron was chosen to sit at the sigmoid's steepest point, and that is the uncomfortable part. The sigmoid's slope is its output times one minus its output, which peaks at 0.25 when the output is a half and is smaller everywhere else. Every sigmoid layer the error passes through therefore shrinks it by at least a factor of four from the slope alone. Six in a row leave 0.00024 at best.

The second half measures it. The run is a real network, twelve layers of sixteen units with 3,281 parameters, initialised from a fixed seed and fed a batch of 32 random examples, with a forward and a backward pass written out by hand. The gauges show the size of the error signal reaching each layer, divided by what reaches the last one. With sigmoid activations and standard initialisation it is 0.00013 six layers down and about 18 million times smaller at layer one, so the first layers' weights get almost no gradient and barely learn. That is the vanishing gradient problem, and it is why deep networks were close to untrainable before 2010. Tanh, whose slope reaches 1, fades by about a factor of five over the same twelve layers.

The fixes are what every modern network is built from. ReLU passes a slope of exactly 1 wherever it is switched on, and He initialisation scales the starting weights to the width of the layer to make up for the half of the units it switches off: the same run then delivers 1.7 times the last layer's signal to layer one. Initialisation matters as much as the activation. Double the starting weights and the signal grows at every junction instead, arriving at layer one 3,700 times stronger, and a single gradient step at a learning rate of 0.01 sends the loss from 5.8 million to about 10 to the 97, which is the exploding gradient problem. Residual connections are the third fix: adding each layer's input to its output gives the error a path that skips the layer, and even twelve sigmoid layers then deliver 1.6 times the signal to layer one. Every transformer block is built around two of them.

The simplifications, honestly. The network is sixteen units wide rather than thousands, and the numbers come from one seed and one batch, so the exact figures would move a little with another draw, although the orders of magnitude would not. The gauges show the error signal, the backpropagated delta, rather than the weight gradients themselves; the two tell the same story here (the weight gradient ratio for the sigmoid run is also below one in ten million), but in the exploding run the weight gradients are huge at every layer rather than growing towards layer one, because the forward activations blow up too. The residual run shows only that the signal gets through: without the normalisation real residual networks pair with it, its activations grow with depth and its loss starts high, so it is not something you would train as it stands.

The maths

The chain rule, one neuron
Lw1  =  Laazzw1  =  (ay)a(1a)x1  =  (0.5)(0.25)(2.0)=0.25\frac{\partial L}{\partial w_1} \;=\; \frac{\partial L}{\partial a}\cdot\frac{\partial a}{\partial z}\cdot\frac{\partial z}{\partial w_1} \;=\; (a - y)\cdot a(1-a)\cdot x_1 \;=\; (-0.5)(0.25)(2.0) = -0.25

The traced neuron, junction by junction. Each factor is a local slope printed at one junction of the pipes: the loss against the output, the sigmoid against its input, the weighted sum against the weight. Backpropagation is nothing more than multiplying them in order, from the loss back.

The sigmoid never passes back more than a quarter
σ(z)  =  σ(z)(1σ(z))    14,(14)60.00024\sigma'(z) \;=\; \sigma(z)\,\big(1-\sigma(z)\big) \;\le\; \tfrac14, \qquad \big(\tfrac14\big)^6 \approx 0.00024

The slope is largest at z = 0, where the output is 0.5 and the slope exactly 0.25, which is where the traced neuron happens to sit. Anywhere else it is smaller. Six sigmoid slopes in a row can therefore shrink the signal to 0.00024 at best, before the weights have had any say.

The signal one layer down
δ(l)  =  f ⁣(z(l))(W(l+1)) ⁣δ(l+1),LW(l)=δ(l)(h(l1)) ⁣\delta^{(l)} \;=\; f'\!\big(z^{(l)}\big) \,\odot\, \big(W^{(l+1)}\big)^{\!\top} \delta^{(l+1)}, \qquad \frac{\partial L}{\partial W^{(l)}} = \delta^{(l)}\, \big(h^{(l-1)}\big)^{\!\top}

The light in the run. Each layer multiplies the error arriving from above by its weights and by the activation slope at every unit. The gauges show the size of delta at each layer, relative to the last layer, for sixteen units per layer and a batch of 32 seeded examples; the junction labels are the measured multiplier from one layer to the next.

Initialisation and the residual pipe
WijN ⁣(0,1n) (LeCun),N ⁣(0,2n) (He),h(l)=h(l1)+f(W(l)h(l1))    h(l)h(l1)=I+W_{ij} \sim \mathcal{N}\!\Big(0, \tfrac{1}{n}\Big)\ \text{(LeCun)}, \quad \mathcal{N}\!\Big(0, \tfrac{2}{n}\Big)\ \text{(He)}, \qquad h^{(l)} = h^{(l-1)} + f\big(W^{(l)} h^{(l-1)}\big) \;\Rightarrow\; \frac{\partial h^{(l)}}{\partial h^{(l-1)}} = I + \cdots

He initialisation doubles the variance to make up for ReLU switching half its units off, so the signal neither shrinks nor grows on average. Doubling the standard deviation again multiplies it by roughly two per layer, which is the exploding run. A residual connection adds the identity to every layer's Jacobian: the straight pipe round each station.

Related terms

More visualisations

Building with language models?

These explainers come out of the work. If you want the same thinking applied to your own system, that is what I do.

See how I can help