The Chain Rule for Neural Networks

Imagine training a network with fifty layers and millions of parameters. There is one scalar loss at the very end. You need to know how nudging any single weight changes that final loss. This weight may be buried deep inside layer thirty. Computing this directly would mean perturbing each weight and re-running the whole network. That would take millions of forward passes per training step. This is computationally hopeless. Yet every modern deep learning system solves exactly this problem. It does so for every parameter, in roughly the same time as a single forward pass. The multivariable chain rule is the mathematical fact that makes this possible. Neural networks are compositions of functions. There is a linear transform, then a nonlinearity, then another linear transform, and so on. This composition ends in a loss function. Differentiating a composition of functions is precisely what the chain rule was invented for. The scalar chain rule from single-variable calculus is not enough. Each layer is a vector-valued function of a vector argument. The derivative at each stage is a matrix (a Jacobian). Composing derivatives means composing matrices, not just multiplying numbers. This article develops the multivariable chain rule in the exact form needed for neural networks. It is a rule for propagating sensitivities backward through a computational graph. We derive it from first principles. We show why the "local Jacobian times upstream gradient" pattern is both correct and efficient. We trace it through worked numerical examples with real matrices. Understanding this rule precisely is important. It is not enough to just know that "backprop uses the chain rule." This precise understanding separates being able to use a deep learning framework from being able to reason about one. It lets you debug vanishing gradients, write a custom autograd function, or understand why certain architectures train better than others. By the end, you will be able to write the chain rule for an arbitrary composition of vector functions. You will be able to explain why it is computed backward rather than forward for typical networks. You will connect this exactly to how Backpropagation and Automatic Differentiation implement it in practice.

Key takeaways
  • The chain rule extends from scalars to vectors: derivatives become Jacobian matrices, and composition becomes matrix multiplication.
  • For a scalar loss depending on a long composition of functions, gradients are most efficiently computed as a sequence of vector–Jacobian products, computed back-to-front.
  • Each layer only needs to know its own local Jacobian; it never needs to know about any other layer — this locality is what makes deep networks modular and trainable.
  • Computing all partial derivatives backward costs about the same as one extra forward pass, total; computing them forward (one variable at a time) costs one pass per parameter.
  • The rule is applied at every edge of a computational graph, and its correctness follows from a total-derivative argument, not from any neural-network-specific fact.
  • This chain rule is the mathematical content of Backpropagation; frameworks that implement it generically are performing Automatic Differentiation.
The core insight

The gradient of a composition of functions is the product of the local Jacobians of each function, evaluated at the point of composition and combined from the output backward to the input.

The idea

Consider a differentiable function f:Rn→Rmf: \mathbb{R}^n \to \mathbb{R}^m. Its derivative at a point x\mathbf{x} is not a single number but an m×nm \times n matrix, the Jacobian, whose (i,j)(i,j) entry is ∂fi/∂xj\partial f_i / \partial x_j. This matrix is the best linear approximation to ff near x\mathbf{x}: for a small perturbation Δx\Delta \mathbf{x},

f(x+Δx)≈f(x)+Jf(x) Δx.f(\mathbf{x} + \Delta \mathbf{x}) \approx f(\mathbf{x}) + J_f(\mathbf{x}) \, \Delta \mathbf{x}.

Now suppose we compose two such functions, h=g∘fh = g \circ f, with f:Rn→Rmf: \mathbb{R}^n \to \mathbb{R}^m and g:Rm→Rpg: \mathbb{R}^m \to \mathbb{R}^p. The multivariable chain rule states that the Jacobian of the composition is the matrix product of the Jacobians:

Jh(x)=Jg(f(x)) Jf(x).J_h(\mathbf{x}) = J_g\big(f(\mathbf{x})\big) \, J_f(\mathbf{x}).

The order matters: JgJ_g is a p×mp \times m matrix and JfJ_f is m×nm \times n, so the product is well-defined and gives a p×np \times n matrix, exactly the shape a Jacobian of h:Rn→Rph: \mathbb{R}^n \to \mathbb{R}^p should have. This is the exact generalization of the familiar scalar identity dhdx=dgdf⋅dfdx\frac{dh}{dx} = \frac{dg}{df}\cdot\frac{df}{dx}; the only change is that scalar multiplication becomes matrix multiplication, and the order of the factors is now fixed by matrix-shape compatibility rather than being commutative. A neural network is a long composition L=ℓ∘fK∘fK−1∘⋯∘f1L = \ell \circ f_K \circ f_{K-1} \circ \cdots \circ f_1, where fkf_k is the function computed by layer kk (an affine map followed by a nonlinearity, say) and ℓ\ell is the loss function producing a single scalar. Applying the chain rule repeatedly,

JL(x)=Jℓ JfK JfK−1⋯Jf1.J_L(\mathbf{x}) = J_\ell \, J_{f_K} \, J_{f_{K-1}} \cdots J_{f_1}.

Because LL is scalar-valued, JLJ_L is a row vector — this is exactly the gradient ∇xL\nabla_{\mathbf{x}} L (as a row) that we want for every parameter in the network. The key structural fact, used throughout this article, is that this long chain of matrix products can be evaluated in two very different orders — left-to-right ("forward mode") or right-to-left ("reverse mode") — and for networks with millions of parameters feeding into one scalar loss, right-to-left is dramatically cheaper. That asymmetry is the entire computational reason backpropagation is organized the way it is.

How it works

Setting up the composition. Model a network's forward computation as a sequence of intermediate variables:

z0=x,zk=fk(zk−1,θk) for k=1,…,K,L=ℓ(zK).\mathbf{z}_0 = \mathbf{x}, \quad \mathbf{z}_k = f_k(\mathbf{z}_{k-1}, \boldsymbol{\theta}_k) \text{ for } k = 1, \dots, K, \quad L = \ell(\mathbf{z}_K).

Each fkf_k takes the previous activation zk−1\mathbf{z}_{k-1} and layer parameters θk\boldsymbol{\theta}_k (weights, biases) and produces the next activation. We want ∂L/∂θk\partial L / \partial \boldsymbol{\theta}_k for every kk, and often ∂L/∂x\partial L/\partial \mathbf{x} as well.

Reverse accumulation. Define the upstream gradient at each stage as the row vector

zˉk≡∂L∂zk.\bar{\mathbf{z}}_k \equiv \frac{\partial L}{\partial \mathbf{z}_k}.

By the chain rule applied one layer at a time,

zˉk−1=zˉk Jfk(zk−1),\bar{\mathbf{z}}_{k-1} = \bar{\mathbf{z}}_k \, J_{f_k}(\mathbf{z}_{k-1}),

where JfkJ_{f_k} is the Jacobian of layer kk's output with respect to its input, evaluated at the activations recorded during the forward pass. Similarly, the gradient with respect to that layer's own parameters is

∂L∂θk=zˉk Jfkθ(θk),\frac{\partial L}{\partial \boldsymbol{\theta}_k} = \bar{\mathbf{z}}_k \, J_{f_k}^{\theta}(\boldsymbol{\theta}_k),

using the Jacobian of fkf_k with respect to θk\boldsymbol{\theta}_k instead. This recursive relation is initialized at zˉK=∂L/∂zK=Jℓ\bar{\mathbf{z}}_K = \partial L/\partial \mathbf{z}_K = J_\ell and run from k=Kk=K down to k=1k=1 — hence "reverse mode," "backward pass," or, in the neural network context, backpropagation. Crucially, layer kk never needs to construct or store the full Jacobian JfkJ_{f_k} as a matrix. It only needs to compute the vector–Jacobian product zˉkJfk\bar{\mathbf{z}}_k J_{f_k} directly, which for common layers (linear, elementwise nonlinearity, convolution) has a closed form that costs about the same as the forward computation of that layer itself. ```

# Reverse-mode chain rule (as in backpropagation)

# Forward pass: compute and CACHE all intermediate activations z[0] = x for k = 1 to K: z[k] = f_k(z[k-1], theta[k]) # cache z[k] and any values needed

# to build the local Jacobian later L = loss(z[K])

# Backward pass: propagate the gradient from the scalar loss backward zbar[K] = d(loss)/d(z[K]) # local Jacobian of the loss, evaluated at z[K] for k = K downto 1:

# vector-Jacobian product: local Jacobian w.r.t. INPUT of layer k zbar[k-1] = zbar[k] @ J_input(f_k, z[k-1], theta[k])

# vector-Jacobian product: local Jacobian w.r.t. PARAMETERS of layer k grad_theta[k] = zbar[k] @ J_param(f_k, z[k-1], theta[k]) return grad_theta[1..K], zbar[0] # zbar[0] = dL/dx, if needed ``` Two design choices in this pseudocode deserve emphasis. First, the forward pass caches every intermediate zk\mathbf{z}_k: the backward pass needs these values to evaluate each local Jacobian, since JfkJ_{f_k} is generally evaluated at the point zk−1\mathbf{z}_{k-1} that was seen during the forward pass, not at some fixed reference point. Second, `J_input` and `J_param` are never materialized as dense matrices in practice — they are applied as functions (vector-Jacobian products), because for a linear layer with a 1000×10001000\times1000 weight matrix, the Jacobian with respect to the input is that weight matrix, and for a layer with 10610^6 parameters, materializing the parameter-Jacobian explicitly would be enormous and wasteful.

Figure
Reverse-mode chain rule through a composed network
x z₁ z₂ z_K L f₁ f₂ … ℓ forward pass: cache each zₖ z̄_K = ∂L/∂z_K z̄₁·J(f₂) z̄₀ = ∂L/∂x backward pass: vector–Jacobian products, right to left ∂L/∂θ₁ ∂L/∂θ₂ ∂L/∂θ_K

Complexity & correctness

Why reverse mode is asymptotically the right choice. Suppose the network has KK layers and, across all layers, PP scalar parameters in total, with nn the input dimension. There are two natural ways to accumulate the chain of Jacobian products JℓJfK⋯Jf1J_\ell J_{f_K} \cdots J_{f_1}:

  • Forward-mode accumulation multiplies the chain left-to-right starting from the input side, propagating a Jacobian (a full matrix, not just a vector) forward through the network for each input direction or parameter direction you care about. Computing ∂L/∂θk\partial L/\partial \theta_k this way for one parameter costs roughly the cost of one forward pass; doing this independently for every one of the PP parameters costs O(P⋅C)O(P \cdot C), where CC is the cost of one forward pass.
  • Reverse-mode accumulation multiplies the chain right-to-left, starting from the scalar loss. Because LL is scalar, every intermediate quantity zˉk\bar{\mathbf{z}}_k is a vector, not a matrix (a 1×m1\times m row rather than an m×mm\times m or larger object). Each step is one vector–Jacobian product, costing about the same as the corresponding forward step. A single backward pass over all KK layers therefore costs O(C)O(C) total and yields the gradient with respect to every parameter simultaneously.

This is the Baur–Strassen-type observation underlying all reverse-mode automatic differentiation: computing the gradient of a scalar function of nn (or PP) variables costs a small constant multiple of the cost of evaluating the function itself, independent of nn or PP. For neural networks with PP in the millions or billions, the difference between O(P⋅C)O(P \cdot C) and O(C)O(C) is the difference between infeasible and routine.

Space complexity. The tradeoff for this time saving is memory: reverse mode requires caching every intermediate activation zk\mathbf{z}_k (and any auxiliary values a layer's Jacobian needs) computed during the forward pass, because the backward pass needs them to evaluate local Jacobians at the correct point. Memory cost is O(K⋅mˉ)O(K \cdot \bar{m}) where mˉ\bar{m} is average activation width — linear in depth. This is precisely why very deep or memory-constrained networks use gradient checkpointing (recomputing some activations during the backward pass instead of storing all of them), trading extra compute for lower memory.

Correctness argument. The correctness of the whole scheme rests on two facts, both provable from the definition of the derivative as a local linear approximation: 1. Chain rule for two functions. If ff is differentiable at x\mathbf{x} and gg is differentiable at f(x)f(\mathbf{x}), then g∘fg\circ f is differentiable at x\mathbf{x} with Jg∘f(x)=Jg(f(x))Jf(x)J_{g\circ f}(\mathbf{x}) = J_g(f(\mathbf{x}))J_f(\mathbf{x}). This follows because the composition of two best-linear-approximations is itself a best linear approximation to the composed function: writing f(x+Δ)=f(x)+JfΔ+o(∥Δ∥)f(\mathbf{x}+\Delta) = f(\mathbf{x}) + J_f\Delta + o(\|\Delta\|) and substituting into the analogous expansion of gg shows the first-order term is exactly JgJfΔJ_g J_f \Delta, with all higher-order terms absorbed into the o(∥Δ∥)o(\|\Delta\|) remainder. 2. Induction over the composition length. Applying fact (1) repeatedly to the K+1K{+}1-fold composition ℓ∘fK∘⋯∘f1\ell\circ f_K\circ\cdots\circ f_1 gives JL=JℓJfK⋯Jf1J_L = J_\ell J_{f_K}\cdots J_{f_1} by induction on KK. The reverse recursion zˉk−1=zˉkJfk\bar{\mathbf{z}}_{k-1} = \bar{\mathbf{z}}_k J_{f_k} is exactly this product evaluated right-to-left, one factor at a time, which is legal because matrix multiplication is associative — the value of the product does not depend on the order in which we group the multiplications, only the cost of computing it does. So reverse-mode backpropagation is not an approximation or a heuristic: it computes the exact analytic gradient (up to floating-point rounding), for the same reason 2×3×42\times 3\times 4 can be computed as (2×3)×4(2\times3)\times4 or 2×(3×4)2\times(3\times4) and get the same answer either way, just possibly at different cost.

Honest caveats. The chain rule requires each fkf_k to be differentiable at the relevant point; nonsmooth functions like ReLU or max-pooling have a measure-zero set of non-differentiable points, handled in practice by choosing a subgradient (e.g., defining ReLU's derivative to be 00 at x=0x=0) — this is technically not a chain rule but a chain rule for subgradients, and it works empirically but is not covered by the classical smooth chain-rule proof. Also, reverse mode is efficient specifically because the output is low-dimensional (scalar loss); if instead one needed the full Jacobian of a high-dimensional output with respect to a low-dimensional input, forward mode can be cheaper — the choice of mode is a genuine engineering tradeoff, not a universal rule.

Worked example

Take a tiny two-layer network with scalar output, so every matrix is small enough to write out fully. Let the input be x=[1, 2]⊤\mathbf{x} = [1,\,2]^\top, and define:

z1=W1x+b1,a1=ReLU(z1),y=w2⊤a1,L=(y−t)2\mathbf{z}_1 = W_1 \mathbf{x} + \mathbf{b}_1, \qquad \mathbf{a}_1 = \mathrm{ReLU}(\mathbf{z}_1), \qquad y = \mathbf{w}_2^\top \mathbf{a}_1, \qquad L = (y - t)^2

with concrete numbers

W1=[1−121],b1=[0−3],w2=[11],t=5.W_1 = \begin{bmatrix} 1 & -1 \\ 2 & 1 \end{bmatrix}, \quad \mathbf{b}_1 = \begin{bmatrix} 0 \\ -3 \end{bmatrix}, \quad \mathbf{w}_2 = \begin{bmatrix} 1 \\ 1 \end{bmatrix}, \quad t = 5.

Forward pass.

z1=W1x+b1=[1⋅1+(−1)⋅22⋅1+1⋅2]+[0−3]=[−14]+[0−3]=[−11]\mathbf{z}_1 = W_1\mathbf{x} + \mathbf{b}_1 = \begin{bmatrix}1\cdot1 + (-1)\cdot2\\ 2\cdot1 + 1\cdot2\end{bmatrix} + \begin{bmatrix}0\\-3\end{bmatrix} = \begin{bmatrix}-1\\4\end{bmatrix} + \begin{bmatrix}0\\-3\end{bmatrix} = \begin{bmatrix}-1\\1\end{bmatrix}
a1=ReLU(z1)=[max⁡(0,−1)max⁡(0,1)]=[01]\mathbf{a}_1 = \mathrm{ReLU}(\mathbf{z}_1) = \begin{bmatrix}\max(0,-1)\\ \max(0,1)\end{bmatrix} = \begin{bmatrix}0\\1\end{bmatrix}
y=w2⊤a1=1⋅0+1⋅1=1,L=(1−5)2=16.y = \mathbf{w}_2^\top \mathbf{a}_1 = 1\cdot0 + 1\cdot1 = 1, \qquad L = (1-5)^2 = 16.

Backward pass. Work from LL back to x\mathbf{x}, one vector–Jacobian product at a time. Step 1 — loss w.r.t. yy: yˉ=∂L∂y=2(y−t)=2(1−5)=−8.\bar{y} = \dfrac{\partial L}{\partial y} = 2(y-t) = 2(1-5) = -8. Step 2 — through y=w2⊤a1y = \mathbf{w}_2^\top \mathbf{a}_1. The Jacobian of yy w.r.t. a1\mathbf{a}_1 is the row vector w2⊤=[1, 1]\mathbf{w}_2^\top = [1,\,1], and w.r.t. w2\mathbf{w}_2 it is a1⊤=[0, 1]\mathbf{a}_1^\top = [0,\,1]:

aˉ1=yˉ w2⊤=−8⋅[1,1]=[−8, −8],∂L∂w2=yˉ a1⊤=−8⋅[0,1]=[0, −8].\bar{\mathbf{a}}_1 = \bar{y}\,\mathbf{w}_2^\top = -8\cdot[1,1] = [-8,\,-8], \qquad \frac{\partial L}{\partial \mathbf{w}_2} = \bar{y}\,\mathbf{a}_1^\top = -8\cdot[0,1] = [0,\,-8].

Step 3 — through ReLU. Its Jacobian is diagonal with entries 1[z1,i>0]\mathbb{1}[z_{1,i}>0]: since z1=[−1,1]⊤z_1 = [-1, 1]^\top, the diagonal is diag(0,1)\mathrm{diag}(0, 1). Elementwise multiply:

zˉ1=aˉ1⊙[1(−1>0), 1(1>0)]=[−8, −8]⊙[0, 1]=[0, −8].\bar{\mathbf{z}}_1 = \bar{\mathbf{a}}_1 \odot [\mathbb{1}(-1>0),\ \mathbb{1}(1>0)] = [-8,\,-8]\odot[0,\,1] = [0,\,-8].

Step 4 — through z1=W1x+b1\mathbf{z}_1 = W_1\mathbf{x}+\mathbf{b}_1. The Jacobian w.r.t. x\mathbf{x} is W1W_1, w.r.t. b1\mathbf{b}_1 is the identity, and w.r.t. each row of W1W_1 pairs with x⊤\mathbf{x}^\top:

∂L∂b1=zˉ1=[0, −8],∂L∂x=zˉ1 W1=[0,−8][1−121]=[−16, −8].\frac{\partial L}{\partial \mathbf{b}_1} = \bar{\mathbf{z}}_1 = [0,\,-8], \qquad \frac{\partial L}{\partial \mathbf{x}} = \bar{\mathbf{z}}_1\, W_1 = [0,-8]\begin{bmatrix}1&-1\\2&1\end{bmatrix} = [-16,\,-8].
∂L∂W1=zˉ1⊤x⊤=[0−8][1, 2]=[00−8−16].\frac{\partial L}{\partial W_1} = \bar{\mathbf{z}}_1^\top \mathbf{x}^\top = \begin{bmatrix}0\\-8\end{bmatrix}[1,\,2] = \begin{bmatrix}0&0\\-8&-16\end{bmatrix}.

The table below traces every quantity, forward then backward, so the two passes can be checked against each other:

StageForward valueLocal Jacobian used going backwardUpstream gradient produced
LossL=16L=16∂L/∂y=2(y−t)\partial L/\partial y = 2(y-t)yˉ=−8\bar y = -8
Layer 2 (linear)y=1y=1J=w2⊤=[1,1]J = \mathbf{w}_2^\top=[1,1]aˉ1=[−8,−8]\bar{\mathbf a}_1 = [-8,-8]
ReLUa1=[0,1]\mathbf a_1=[0,1]J=diag(0,1)J=\mathrm{diag}(0,1)zˉ1=[0,−8]\bar{\mathbf z}_1=[0,-8]
Layer 1 (affine)z1=[−1,1]\mathbf z_1=[-1,1]J=W1J=W_1xˉ=[−16,−8]\bar{\mathbf x}=[-16,-8]

One can sanity-check Step 3 with a finite-difference estimate: perturbing x1x_1 by ϵ=10−4\epsilon=10^{-4} and recomputing LL numerically gives ΔL/ϵ≈−16.0\Delta L/\epsilon \approx -16.0, matching ∂L/∂x1=−16\partial L/\partial x_1 = -16 computed above — confirming the chain of local Jacobian products reproduces the true derivative, not merely a plausible-looking approximation.

Common pitfalls & traps

PitfallWhy it happensFix
Confusing Jacobian shape/orderWriting JfJgJ_f J_g instead of JgJfJ_g J_f, or transposing a gradient row vs. column inconsistentlyTrack shapes explicitly: outer function's Jacobian left-multiplies inner function's
Evaluating local Jacobian at the wrong pointUsing a stale or default value instead of the cached forward activationAlways cache forward activations; evaluate local Jacobians at the recorded value from that same forward pass
Forgetting non-differentiable pointsAssuming ReLU/max-pool are smooth everywhereUse the standard subgradient convention (e.g., derivative 00 at the kink) — understand it's an approximation, not exact calculus
Materializing full Jacobians unnecessarilyExplicitly building an m×mm\times m Jacobian matrix for an elementwise or diagonal operationUse vector–Jacobian products / implicit operators (diagonal ⇒ elementwise multiply, no matrix needed)
Treating shared parameters as independentA weight reused in multiple places (weight tying, recurrent nets) gets only one gradient term instead of summed contributionsSum gradients over all paths through which a variable influences the loss (multivariate chain rule with multiple paths)

Pioneers & history

!A mathematician's contribution to differential calculus underlies the chain rule used throughout deep learning

Origins · 1 minGottfried Wilhelm Leibniz and how this was discovered
GW
Gottfried Wilhelm Leibniz
1646–1716 · co-inventor of calculus and originator of the chain-rule notation still used today

Leibniz's notation dydx=dydu⋅dudx\frac{dy}{dx} = \frac{dy}{du}\cdot\frac{du}{dx} made the chain rule for single-variable functions mechanically obvious, and this notational habit of "cancelling" intermediate variables carries directly into how deep learning practitioners reason informally about gradient flow through layers, even though the rigorous multivariable statement requires Jacobian matrices rather than literal fraction cancellation.

History
1846–1850
s: augmented-Lagrangian and adjoint-style sensitivity methods emerge in control theory, an early precursor to reverse-mode differentiation.
1970
Seppo Linnainmaa's thesis formalizes reverse-mode automatic differentiation of nested differentiable functions.
1974–1982
Paul Werbos and later David Parker independently describe applying reverse-mode differentiation to train multilayer networks.
1986
Rumelhart, Hinton, and Williams popularize the backpropagation algorithm for training multilayer neural networks, making the chain-rule-based method the standard.
2010
s: automatic differentiation libraries (Theano, TensorFlow, PyTorch) generalize the chain rule into reusable, arbitrary computational-graph engines.

Where this matters

Every deep learning framework — PyTorch's `autograd`, TensorFlow's `GradientTape`, JAX's `grad` — is a generic engine for exactly the reverse-mode chain-rule recursion described above, applied to an arbitrary computational graph rather than a fixed layer stack. Training image classifiers, language models, diffusion models, and reinforcement learning policies all reduce, at the lowest level, to constructing a forward computational graph and running this backward recursion to get gradients for gradient descent. Compiler-level optimizations in these frameworks (operator fusion, memory planning, gradient checkpointing) are all optimizations of this chain-rule computation, not alternatives to it. Understanding the chain rule precisely is also what lets practitioners diagnose vanishing or exploding gradients — a direct consequence of repeatedly multiplying many Jacobians whose eigenvalues are consistently below or above one — and motivates architectural fixes like residual connections and normalization layers, which are explicitly designed to keep the product of local Jacobians well-conditioned across many layers.

Ask the tutor: Can you walk me through why reverse-mode accumulation is cheaper than forward-mode when there are many parameters but only one output?

Is the chain rule used in neural networks any different from the one taught in calculus class?

No — it is the same mathematical fact, generalized from scalars to vectors. In single-variable calculus, dhdx=dgdu⋅dudx\frac{dh}{dx} = \frac{dg}{du}\cdot\frac{du}{dx} where u=f(x)u=f(x). In neural networks, each "derivative" becomes a Jacobian matrix because layers map vectors to vectors, and the multiplication becomes matrix multiplication rather than scalar multiplication. The underlying proof — that composing two best-linear-approximations yields the best linear approximation of the composition — is identical in both settings; only the algebraic objects involved (numbers versus matrices) change. What is specific to neural networks is not the rule itself but the engineering pattern of applying it efficiently, backward through a long chain, which is what backpropagation formalizes.

Why compute gradients backward instead of forward through the network?

Because the loss is a single scalar while the network typically has millions of parameters. Reverse-mode accumulation propagates a vector upstream gradient backward through the graph, and a single backward pass yields the gradient with respect to every parameter at once, at roughly the cost of one extra forward pass. Forward-mode accumulation, by contrast, would need to propagate a full Jacobian forward for each parameter (or parameter direction) separately, costing one traversal per parameter. For a network with a million parameters, that is the difference between one backward pass and a million forward passes — reverse mode wins whenever outputs are far fewer than inputs, which is exactly the situation in supervised training with a scalar loss.

What exactly is a Jacobian, and why can't we just use a single derivative number for each layer?

A Jacobian is the matrix of all partial derivatives of a vector-valued function's outputs with respect to its inputs: entry (i,j)(i,j) is ∂(outputi)/∂(inputj)\partial (\text{output}_i)/\partial(\text{input}_j). A single number cannot describe how an nn-dimensional input change affects an mm-dimensional output, because each output coordinate can depend on each input coordinate differently. The Jacobian captures the full linear map that best approximates the layer's behavior near a given point; composing layers correctly requires composing these full linear maps (via matrix multiplication), not just multiplying a handful of scalar slopes together.

Does the chain rule still apply if a layer uses a non-differentiable function like ReLU?

Strictly, the classical chain rule requires differentiability everywhere, and ReLU is not differentiable exactly at zero. In practice, frameworks use a subgradient convention — commonly defining ReLU's derivative to be 00 (or sometimes 11) at the kink — and apply the chain rule using this subgradient in place of the true derivative. This is a deliberate engineering approximation: it is exact almost everywhere (the non-differentiable point is a single value, essentially never hit exactly by continuous-valued activations), and empirically it produces gradients that work well for optimization, even though it is not covered by the classical smooth chain-rule proof.

How does the chain rule relate to backpropagation and automatic differentiation?

The chain rule is the mathematical content; backpropagation and automatic differentiation are the algorithms that apply it systematically. Backpropagation is the specific historical name for applying reverse-mode chain-rule accumulation to the layered structure of a neural network. Automatic differentiation is the more general framework: given any computational graph of differentiable operations, it builds and executes this same backward (or forward) chain-rule recursion automatically, without a human deriving gradients by hand for each new architecture. Understanding the chain rule precisely is a prerequisite for understanding why both of these algorithms are correct and efficient, rather than just accepting them as black boxes.

Why does memory usage grow with network depth if we're just computing derivatives?

Because reverse-mode accumulation needs each local Jacobian evaluated at the exact activation values seen during the forward pass, all intermediate activations for all layers must be kept in memory until the corresponding backward step uses them. This gives a memory cost proportional to the number of layers (and their activation sizes), which is why very deep networks or very large batch sizes can run into memory limits well before compute limits. Gradient checkpointing addresses this by storing only a subset of activations and recomputing the rest on demand during the backward pass, trading extra forward computation for reduced memory — a direct consequence of understanding exactly what the chain rule's backward recursion requires as input.

What's a common way this rule breaks down or gets applied incorrectly in practice?

The most frequent real bug is failing to sum gradient contributions when a variable is used in more than one place — for example, a weight matrix shared across time steps in a recurrent network, or an activation feeding both a skip connection and a main path. The multivariable chain rule requires adding the sensitivity contributed through every path from that variable to the loss; overwriting instead of accumulating silently understates the true gradient. This kind of bug is dangerous precisely because the network often still trains, just suboptimally, making it hard to detect without carefully checking gradients against finite-difference estimates.

Before this

Where this leads