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.
- 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 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 . Its derivative at a point is not a single number but an matrix, the Jacobian, whose entry is . This matrix is the best linear approximation to near : for a small perturbation ,
Now suppose we compose two such functions, , with and . The multivariable chain rule states that the Jacobian of the composition is the matrix product of the Jacobians:
The order matters: is a matrix and is , so the product is well-defined and gives a matrix, exactly the shape a Jacobian of should have. This is the exact generalization of the familiar scalar identity ; 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 , where is the function computed by layer (an affine map followed by a nonlinearity, say) and is the loss function producing a single scalar. Applying the chain rule repeatedly,
Because is scalar-valued, is a row vector — this is exactly the gradient (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:
Each takes the previous activation and layer parameters (weights, biases) and produces the next activation. We want for every , and often as well.
Reverse accumulation. Define the upstream gradient at each stage as the row vector
By the chain rule applied one layer at a time,
where is the Jacobian of layer '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
using the Jacobian of with respect to instead. This recursive relation is initialized at and run from down to — hence "reverse mode," "backward pass," or, in the neural network context, backpropagation. Crucially, layer never needs to construct or store the full Jacobian as a matrix. It only needs to compute the vector–Jacobian product 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 : the backward pass needs these values to evaluate each local Jacobian, since is generally evaluated at the point 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 weight matrix, the Jacobian with respect to the input is that weight matrix, and for a layer with parameters, materializing the parameter-Jacobian explicitly would be enormous and wasteful.
Complexity & correctness
Why reverse mode is asymptotically the right choice. Suppose the network has layers and, across all layers, scalar parameters in total, with the input dimension. There are two natural ways to accumulate the chain of Jacobian products :
- 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 this way for one parameter costs roughly the cost of one forward pass; doing this independently for every one of the parameters costs , where is the cost of one forward pass.
- Reverse-mode accumulation multiplies the chain right-to-left, starting from the scalar loss. Because is scalar, every intermediate quantity is a vector, not a matrix (a row rather than an 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 layers therefore costs 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 (or ) variables costs a small constant multiple of the cost of evaluating the function itself, independent of or . For neural networks with in the millions or billions, the difference between and is the difference between infeasible and routine.
Space complexity. The tradeoff for this time saving is memory: reverse mode requires caching every intermediate activation (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 where 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 is differentiable at and is differentiable at , then is differentiable at with . This follows because the composition of two best-linear-approximations is itself a best linear approximation to the composed function: writing and substituting into the analogous expansion of shows the first-order term is exactly , with all higher-order terms absorbed into the remainder. 2. Induction over the composition length. Applying fact (1) repeatedly to the -fold composition gives by induction on . The reverse recursion 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 can be computed as or and get the same answer either way, just possibly at different cost.
Honest caveats. The chain rule requires each 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 at ) — 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 , and define:
with concrete numbers
Forward pass.
Backward pass. Work from back to , one vector–Jacobian product at a time. Step 1 — loss w.r.t. : Step 2 — through . The Jacobian of w.r.t. is the row vector , and w.r.t. it is :
Step 3 — through ReLU. Its Jacobian is diagonal with entries : since , the diagonal is . Elementwise multiply:
Step 4 — through . The Jacobian w.r.t. is , w.r.t. is the identity, and w.r.t. each row of pairs with :
The table below traces every quantity, forward then backward, so the two passes can be checked against each other:
| Stage | Forward value | Local Jacobian used going backward | Upstream gradient produced |
|---|---|---|---|
| Loss | |||
| Layer 2 (linear) | |||
| ReLU | |||
| Layer 1 (affine) |
One can sanity-check Step 3 with a finite-difference estimate: perturbing by and recomputing numerically gives , matching computed above — confirming the chain of local Jacobian products reproduces the true derivative, not merely a plausible-looking approximation.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Confusing Jacobian shape/order | Writing instead of , or transposing a gradient row vs. column inconsistently | Track shapes explicitly: outer function's Jacobian left-multiplies inner function's |
| Evaluating local Jacobian at the wrong point | Using a stale or default value instead of the cached forward activation | Always cache forward activations; evaluate local Jacobians at the recorded value from that same forward pass |
| Forgetting non-differentiable points | Assuming ReLU/max-pool are smooth everywhere | Use the standard subgradient convention (e.g., derivative at the kink) — understand it's an approximation, not exact calculus |
| Materializing full Jacobians unnecessarily | Explicitly building an Jacobian matrix for an elementwise or diagonal operation | Use vector–Jacobian products / implicit operators (diagonal ⇒ elementwise multiply, no matrix needed) |
| Treating shared parameters as independent | A weight reused in multiple places (weight tying, recurrent nets) gets only one gradient term instead of summed contributions | Sum gradients over all paths through which a variable influences the loss (multivariate chain rule with multiple paths) |
Pioneers & history
Origins · 1 minGottfried Wilhelm Leibniz and how this was discovered
Leibniz's notation 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.
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, where . 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 is . A single number cannot describe how an -dimensional input change affects an -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 (or sometimes ) 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.