Multivariable Chain Rule
When one input reaches the output through several routes at once, multiply along each route and add the routes up. That sum is the whole of backpropagation.
Why Does This Exist?
The single-variable chain rule handles chains: A feeds B feeds C. But real models are trees, not chains. A parameter feeds two layers that later recombine. A hidden state feeds every future step of a recurrence. An embedding matrix is read at the input and again at the output. In each case one input reaches the loss through several routes at once, and the single-chain formula silently drops all but one of them.
The multivariable chain rule fixes exactly that. It says: multiply along each route, then add across routes. Backpropagation over any computational graph is this rule executed mechanically, which makes it the single most-run equation in deep learning.
The one idea you need first
A partial derivative measures the response of to with every other input frozen. The multivariable rule is built from these frozen readings plus the rates at which the frozen variables themselves move. If partials are fuzzy, reread that page first, because every term below is one.
Think of It Like This
Two roads into town, counted separately
Commuters reach downtown by the bridge or by the tunnel, and you want the total flow per minute. You would never count one road and declare the job done. You count the bridge rate, count the tunnel rate, and add.
Derivatives through a tree work the same way. Each route from input to output carries its own product of local rates, and the total rate is the sum over routes. A shared upstream variable is a commuter hub serving several roads: busy on each, and the total is all of them. Forgetting a route undercounts exactly the way ignoring the tunnel would.
The analogy stops at linearity. Traffic on one road slows the other, but derivative routes add cleanly with no interference. The sum is exact, not an approximation, which is why the rule can be trusted inside an optimizer loop running millions of times.
How It Actually Works
Suppose depends on and , and both depend on . The total rate of with respect to is:
In plain words: the route contributes its product, the route contributes its product, and the answer is both. Note the notation doing its job: is partial because has another input, while is ordinary because depends only on .
With more variables the pattern extends by summation, and in matrix form the sum becomes a Jacobian product. A layer with 1,000 inputs and 1,000 outputs chains through a matrix of partials, and reverse-mode differentiation multiplies by it from the left so one backward sweep serves all parameters.
Worked example
Take with and , evaluated at .
Forward values first: , , .
Now each route. The route: and , giving . The route: and , giving . Total: .
Check it independently by substituting first: , so . The tree agreed. Dropping either route would have answered 32 or 36, both wrong, which is the entire pitfall below.
Code
The snippet computes the tree answer and checks it against a finite difference, the same gradient-check habit the gradients page recommends.
def forward_backward(t: float) -> tuple[float, float]: x = t**2 y = 3 * t z = x**2 + y**2 dz_dt = 2 * x * 2 * t + 2 * y * 3 # one product per route, then add return z, dz_dt
def numeric(t: float, h: float = 1e-5) -> float: f = lambda v: (v**2) ** 2 + (3 * v) ** 2 return (f(t + h) - f(t - h)) / (2 * h)
z, dz = forward_backward(2.0)print((z, dz)) # -> (52.0, 68.0)print(abs(dz - numeric(2.0)) < 1e-6) # -> TrueFifty-two and sixty-eight, matching the hand calculation. The dz_dt line is the rule in code: each term pairs a frozen partial with the rate of its own variable.
Watch Out For
Summing only the route you remembered
When a variable is used twice, every hand derivation risks counting one use. The result has the right shape and roughly the right size, pointing slightly wrong, so training merely underperforms and nobody suspects the derivative. Weight tying, residual adds, and recurrent steps all create multi-route variables at scale. Any derivative you derived yourself, check numerically.
Writing partial d where the total belongs
is meaningless here because is not directly a function of alone, and is the quantity training needs. Mixing the two notations in a derivation is how terms quietly go missing: a partial where a total belongs drops every indirect route. Read each symbol as a question. Partial asks one input while the rest sit still. Total asks everything that moves.
The Quick Version
- One input reaching the output through several routes contributes along every route, and the contributions add.
- Each route contributes a product of local rates: frozen partials times single-variable rates.
- In matrix form the sum becomes a Jacobian product, which is what layers chain through.
- Reverse mode wins for training because one scalar loss fans out to millions of parameters.
- Dropping a route gives a plausible wrong gradient, so check hand-derived trees numerically.