Paul’s learnings

Neural networks › Backpropagation

Backpropagation

Backpropagation is reverse-mode automatic differentiation applied to a directed acyclic computational graph. This chapter proves why reverse accumulation evaluates all parameter gradients in a single sweep, derives the multivariate fan-out chain rule, traces a complete 2-2-1 network step by step, and analyzes the memory-compute tradeoff of activation checkpointing.

Run it first

The interactive playground below traces forward evaluation and reverse-mode gradient propagation through a 2-2-1 network. Step forward to compute preactivations and outputs; step backward to inspect how adjoint errors propagate and accumulate into weight sensitivities.

Enable JavaScript to use this local playground. The explanation and derivations below work without it.

Forward-mode vs. reverse-mode computational complexity

Consider differentiating a general mapping f:ℝn→ℝm whose Jacobian matrix has dimension m×n:

  • Forward-Mode Automatic Differentiation computes directional derivatives (Jacobian-Vector Products, JVPs). Evaluating the full Jacobian requires seeding the forward pass with n standard basis vectors: O(n) forward sweeps.
  • Reverse-Mode Automatic Differentiation propagates adjoint sensitivities backwards (Vector-Jacobian Products, VJPs). Seeding the backward pass at the output requires m backward sweeps: O(m) sweeps.

In deep learning, the objective function produces a single scalar loss: m=1. The parameter space contains n=P weights (millions or billions). Forward-mode autodiff would require P forward passes per training step—an impossible computational cost. Reverse-mode backpropagation computes the exact analytical gradient for all P parameters simultaneously in a single reverse sweep (m=1) at the cost of approximately two forward passes.

The multivariate chain rule: summing over fan-out paths

When an intermediate variable x fans out and influences multiple downstream operations y1,y2,…,yk, the total derivative of the scalar loss L with respect to x is the sum of partial derivatives across all outgoing dependency paths:

∂L∂x=∑j=1k∂L∂yj∂yj∂x

In implementation, this multivariate rule requires that backward passes initialize parameter gradient buffers with zero and accumulate with addition (+=) as incoming signals arrive. Overwriting gradients instead of adding them drops downstream dependency branches.

Analytical trace of the 2-2-1 network

The playground above executes a complete 2-2-1 network with input x∈ℝ2, target y, and parameters W∈ℝ2×2,b∈ℝ2,v∈ℝ2,c∈ℝ:

1. Forward equations

z1=Wx+b,h=tanh(z1) z2=vTh+c,y^=σ(z2)=11+e−z2,L=(y^−y)2

2. Backward equations

δout=∂L∂z2=∂L∂y^σ′(z2)=2(y^−y)·y^(1−y^) ∂L∂v=δouth,∂L∂c=δout ∂L∂h=δoutv,δhidden=∂L∂z1=∂L∂h⊙(1−h2) ∂L∂W=δhiddenxT,∂L∂b=δhidden

Each weight gradient is the outer product of the local output sensitivity δ and the incoming input activation x. Computing these derivatives requires storing all forward activations in memory until the reverse pass reaches their corresponding layer.

Memory vs. compute: activation checkpointing

In standard backpropagation, peak memory consumption scales linearly with model depth: O(L·B·d) for L layers, batch size B, and activation width d. For frontier LLMs, caching intermediate activations across 80+ layers with 32K context windows rapidly exhausts GPU VRAM before model weights even load.

Activation checkpointing (Griewank, 1992; Chen et al., 2016)

Activation checkpointing discards intermediate activations during the forward pass, retaining only the inputs to coarse block boundaries (e.g. every L layers):

By re-evaluating the forward pass of one block at a time during the backward pass, activation memory drops from O(L) to O(L), at the cost of running approximately one extra forward pass (+33% arithmetic compute).

Sources and further reading