Skip to content

Backpropagation and optimizers

The chain rule at scale, and how weights get updated

Chapter 3 of 21 · I. Foundations · about 40 minutes. Builds on: 2. Neural networks and the multilayer perceptron.

Backpropagation is the chain rule, organized

Section titled “Backpropagation is the chain rule, organized”

A network is a composition of simple functions. To train it you need ∂L/∂θ\partial L / \partial \theta for every parameter, and the chain rule says how derivatives of a composition multiply. Backpropagation computes all of them in one backward sweep, reusing intermediate results.

Forward pass, with a ReLU or other activation φ\varphi and squared-error loss on one example:

z1=W1x+b1,a1=φ(z1)z2=W2a1+b2,L=12∥z2−y∥2\begin{aligned}z_1&=W_1x+b_1,&a_1&=\varphi(z_1)\\z_2&=W_2a_1+b_2,&L&=\tfrac12\lVert z_2-y\rVert^2\end{aligned}

Work backward. Define δk=∂L/∂zk\delta _{k} = \partial L / \partial z_{k}, the “error signal” at layer kk.

δ2=∂L∂z2=z2−y∂L∂W2=δ2 a1⊤,∂L∂b2=δ2∂L∂a1=W2⊤δ2(send the error back through the weights)δ1=(W2⊤δ2)⊙φ′(z1)∂L∂W1=δ1 x⊤,∂L∂b1=δ1\begin{aligned}\delta_2&=\frac{\partial L}{\partial z_2}=z_2-y\\[9pt]\frac{\partial L}{\partial W_2}&=\delta_2\,a_1^{\top},\qquad\frac{\partial L}{\partial b_2}=\delta_2\\[9pt]\frac{\partial L}{\partial a_1}&=W_2^{\top}\delta_2\qquad\text{(send the error back through the weights)}\\[9pt]\delta_1&=\bigl(W_2^{\top}\delta_2\bigr)\odot\varphi'(z_1)\\[9pt]\frac{\partial L}{\partial W_1}&=\delta_1\,x^{\top},\qquad\frac{\partial L}{\partial b_1}=\delta_1\end{aligned}

Each layer needs only the error from the layer above, its own stored input, and its local derivative. That is the pattern for any depth: reverse-mode automatic differentiation. Two practical consequences:

  • The backward pass costs about twice the forward pass (one matrix product for the gradient of the weights, one for the gradient of the input). Together with the forward pass this is the origin of the “6 FLOPs per parameter per token” rule in Chapter 9.
  • The forward activations must be stored (or recomputed) for the backward pass. Activation memory is often larger than the parameter memory, which is why frameworks offer activation checkpointing: store a few and recompute the rest.

The backward signal passes through a product of per-layer Jacobians. If those matrices tend to shrink vectors, the signal vanishes; if they tend to enlarge them, it explodes. Two standard remedies matter for transformers.

Instead of y=F(x)y = F(x), compute y = x + F(x) . Then ∂y/∂x=I+∂F/∂x\partial y / \partial x = I + \partial F / \partial x. The identity term gives gradients a direct path from the loss to early layers regardless of what FF does. A transformer is a stack of such residual updates to a single vector (the “residual stream”, Chapter 7).

Initial weights are random, and their scale is chosen so that activations and gradients keep roughly the same variance from layer to layer. For a layer with ninn_{in} inputs, a standard choice draws weights with variance proportional to 1/nin1 / n_{in} (with a constant of 2 for ReLU). Too large and activations blow up with depth; too small and they vanish. Large models also scale down the output weights of residual branches so the sum of many layers stays bounded.

Given the gradient g=∇L(θ)g = \nabla L(\theta) from a minibatch, an optimizer decides the step.

Plain SGD is θ←θ−η⋅g\theta \leftarrow \theta - \eta \cdot g. Momentum keeps a running velocity that smooths the noise and builds speed along consistent directions:

v←μ v+g,θ←θ−η v(μ≈0.9)v\leftarrow\mu\,v+g,\qquad\theta\leftarrow\theta-\eta\,v\qquad(\mu\approx0.9)

Adam keeps two running averages per parameter: the mean of the gradient (mm) and the mean of its square (vv), and divides one by the root of the other, so every parameter takes steps of roughly the same size no matter how big its gradients are:

m←β1m+(1−β1) gv←β2v+(1−β2) g2m^=m1−β1 t,v^=v1−β2 t(bias correction at step t)θ←θ−η m^v^+ε\begin{aligned}m&\leftarrow\beta_1m+(1-\beta_1)\,g\\v&\leftarrow\beta_2v+(1-\beta_2)\,g^2\\\hat m&=\frac{m}{1-\beta_1^{\,t}},\qquad\hat v=\frac{v}{1-\beta_2^{\,t}}\quad\text{(bias correction at step }t\text{)}\\\theta&\leftarrow\theta-\eta\,\frac{\hat m}{\sqrt{\hat v}+\varepsilon}\end{aligned}

The bias correction exists because mm and vv start at zero, so early on they underestimate the true averages. Typical values are β1=0.9\beta _{1} = 0.9, β2=0.95\beta _{2} = 0.95 to 0.999, ϵ=10−8\epsilon = 10^{-8}.

Weight decay shrinks weights toward zero to regularize. Adding an L2 penalty to the loss is not equivalent to decay when the optimizer rescales gradients, so AdamW applies decay directly to the weights, separately from the adaptive step:

θ←θ−η(m^v^+ε+λ θ)\theta\leftarrow\theta-\eta\Bigl(\frac{\hat m}{\sqrt{\hat v}+\varepsilon}+\lambda\,\theta\Bigr)

Adam treats each weight independently, but a weight matrix is a structured object. Muon accumulates momentum as usual, then replaces the momentum matrix by an approximately orthogonalized version (all singular values pushed toward 1, computed with a few Newton–Schulz matrix iterations) before applying it. report that, with modifications such as weight decay and per-matrix update scaling, it scales to large language model training and can be more compute-efficient than AdamW.

  • Warmup: ramp the learning rate from near zero over the first few thousand steps; early Adam statistics are unreliable.
  • Decay: reduce the rate (cosine or linear) toward the end of training.
  • Gradient clipping: rescale gg if ∥g∥\lVert g\rVert exceeds a threshold, which prevents rare huge gradients from wrecking the weights.

The loss below is f(x,y)=12(x2+30y2)f(x, y) = \tfrac12 (x^{2} + 30y^{2}): curvature is thirty times larger across the valley than along it. Chapter 1’s stability condition limits SGD to η<2/30\eta < 2 / 30, which makes progress along the valley slow. Compare the three optimizers and change the rates.

Everything above applies unchanged to a transformer: the loss is the average negative log-probability of each true next word, backpropagation produces a gradient for every weight matrix, and an optimizer moves the weights. The widget below does exactly that to a copy of the Model Explorer’s two-layer model, in your browser, using hand-written backpropagation that is checked against finite differences. Start from random weights, take a few steps on one sentence, and watch the probability of each true next word climb while the loss falls.

In the two-layer derivation, why does δ₁ contain φ′(z₁)?

Because a1=φ(z1)a_{1} = \varphi (z_{1}); by the chain rule, ∂L/∂z1=∂L/∂a1⋅∂a1/∂z1\partial L / \partial z_{1} = \partial L / \partial a_{1} \cdot \partial a_{1} / \partial z_{1}, and ∂a1/∂z1=φ′(z1)\partial a_{1} / \partial z_{1} = \varphi'(z_{1}) elementwise. For ReLU that factor is 1 where z1>0z_{1} > 0 and 0 elsewhere, so units that were “off” pass no gradient.

What does the residual connection do to the gradient?

It adds the identity to the Jacobian: ∂(x+F(x))/∂x=I+∂F/∂x\partial (x + F(x)) / \partial x = I + \partial F / \partial x. The identity path carries the gradient directly to earlier layers.

Why does Adam need bias correction?

mm and vv are initialized to 0 and are exponential averages, so at step tt they are biased toward 0 by a factor (1−βt)(1 - \beta ^{t}). Dividing by that factor removes the bias.

  • Introduces residual connections.
  • Adam.
  • AdamW; read for the argument about why L2 regularization and weight decay differ.
  • A recent matrix-aware optimizer shown to scale.
  • Chapters 8 (optimization) and 6.5 (backpropagation).