Backpropagation

core 12 minfundamentalsgradientstraining

Builds on:Forward passActivation functionsDerivatives: change right now

The idea

Training needs ∂L/∂θ\partial L/\partial \theta for every parameter θ\theta, and a modern network has millions of them. Backprop is the observation that all those derivatives share structure. The chain rule for a composition L=f3(f2(f1(x)))L = f_3(f_2(f_1(x))) multiplies local derivatives along the path — and if you evaluate that product from the loss backwards, every parameter's gradient reuses the partial products already computed for the layers above it. One backward sweep—same asymptotic order as the forward pass and often roughly twice its FLOPs in dense networks—produces all parameter gradients.

The bookkeeping runs on the error signal δ(ℓ)=∂L/∂z(ℓ)\delta^{(\ell)} = \partial L/\partial z^{(\ell)} (loss gradient with respect to layer ℓ\ell's pre-activation). For a dense layer z(ℓ)=W(ℓ)a(ℓ−1)+b(ℓ)z^{(\ell)} = W^{(\ell)} a^{(\ell-1)} + b^{(\ell)}, three local rules do everything:

∂L∂W(ℓ)=δ(ℓ)(a(ℓ−1))⊤,∂L∂b(ℓ)=δ(ℓ),∂L∂a(ℓ−1)=W(ℓ)⊤δ(ℓ).\begin{aligned} \frac{\partial L}{\partial W^{(\ell)}} &= \delta^{(\ell)} \left(a^{(\ell-1)}\right)^\top, \\ \frac{\partial L}{\partial b^{(\ell)}} &= \delta^{(\ell)}, \\ \frac{\partial L}{\partial a^{(\ell-1)}} &= W^{(\ell)\top} \delta^{(\ell)}. \end{aligned}

The third rule is the recursion: it hands the error to the previous layer, which multiplies elementwise by its activation derivative, δ(ℓ−1)=W(ℓ)⊤δ(ℓ)⊙g′ ⁣(z(ℓ−1))\delta^{(\ell-1)} = W^{(\ell)\top}\delta^{(\ell)} \odot g^{\prime}\!\left(z^{(\ell-1)}\right), and repeats. Note the first rule needs a(ℓ−1)a^{(\ell-1)} — this is exactly why the forward pass caches every layer input.

Two consequences fall straight out of the product structure:

Worked example

The interview classic — one hidden ReLU unit, sigmoid output, and BCE loss — uses:

x=2,y=1,w1=0.5,b1=−0.5,w2=2,b2=−0.5.\begin{aligned} x &= 2, & y &= 1, \\ w_1 &= 0.5, & b_1 &= -0.5, \\ w_2 &= 2, & b_2 &= -0.5. \end{aligned}

Forward (cache everything):

z1=0.5⋅2−0.5=0.5,a1=0.5,z2=2⋅0.5−0.5=0.5,y^=σ(0.5)≈0.6225.\begin{aligned} z_1 &= 0.5 \cdot 2 - 0.5 = 0.5, \\ a_1 &= 0.5, \\ z_2 &= 2 \cdot 0.5 - 0.5 = 0.5, \\ \hat{y} &= \sigma(0.5) \approx 0.6225. \end{aligned}

The loss is:

L=−ln⁡y^≈0.474.L = -\ln \hat{y} \approx 0.474.

Backward, one row per chain-rule hop:

QuantityRuleValue
δ2=∂L/∂z2\delta_2 = \partial L/\partial z_2y^−y\hat{y} - y−0.3775-0.3775
∂L/∂w2\partial L/\partial w_2δ2⋅a1\delta_2 \cdot a_1−0.1888-0.1888
∂L/∂b2\partial L/\partial b_2δ2\delta_2−0.3775-0.3775
∂L/∂a1\partial L/\partial a_1δ2⋅w2\delta_2 \cdot w_2−0.7550-0.7550
δ1=∂L/∂z1\delta_1 = \partial L/\partial z_1∂L/∂a1⋅1[z1>0]\partial L/\partial a_1 \cdot \mathbf{1}[z_1 > 0]−0.7550-0.7550
∂L/∂w1\partial L/\partial w_1δ1⋅x\delta_1 \cdot x−1.5100-1.5100
∂L/∂b1\partial L/\partial b_1δ1\delta_1−0.7550-0.7550

Sanity checks worth saying out loud in an interview: every gradient is negative, so a gradient-descent step increases every parameter, which pushes z2z_2 up and y^\hat{y} toward the label y=1y = 1 — the signs make sense. And after one SGD step with η=0.1\eta = 0.1 (e.g. w1←0.651w_1 \leftarrow 0.651, w2←2.019w_2 \leftarrow 2.019), rerunning the forward pass gives y^≈0.787\hat{y} \approx 0.787 and L≈0.239L \approx 0.239: the loss halved.

Had z1z_1 been negative, 1[z1>0]=0\mathbf{1}[z_1 > 0] = 0 would have killed δ1\delta_1 and both first-layer gradients — the "dead ReLU" failure mode in miniature: no activation, no gradient, no learning on that path.

Cheat sheet

Core recursion: starting from δ(L)\delta^{(L)}, repeat for each layer:

∂L∂W=δain⊤,∂L∂b=δ,δprevious=W⊤δ⊙g′(z).\begin{aligned} \frac{\partial L}{\partial W} &= \delta a_{\text{in}}^\top, \\ \frac{\partial L}{\partial b} &= \delta, \\ \delta_{\text{previous}} &= W^\top\delta \odot g'(z). \end{aligned}
OpLocal backward rule
Dense z=Wa+bz = Wa + bdW=δa⊤dW = \delta a^\top, db=δdb = \delta, da=W⊤δda = W^\top \delta
ReLUpass δ\delta where z>0z > 0, zero elsewhere
Sigmoid (generic)δ⋅σ(z)(1−σ(z))\delta \cdot \sigma(z)(1 - \sigma(z))
Sigmoid + BCE (fused)y^−y\hat{y} - y directly at the logit
Softmax + CE (fused)p−yonehotp - y_{\text{onehot}} directly at the logits
Residual y=x+f(x)y = x + f(x)gradients split and add at the junction: identity branch passes δ\delta unchanged, residual branch contributes f′(x)⊤δf^{\prime}(x)^\top \delta — the identity term is the gradient highway
Branch reused twicegradients from both consumers sum