You've applied the chain rule to one function composed with another. Every framework you'll use from here on applies it automatically, to graphs with thousands of nodes. What does that automation actually have to do, node by node?
This is the entire computational graph for : two inputs, one multiply node, one add node. Tune and and watch every node's value update — that's the forward pass, nothing more than evaluating the graph in order.
The backward pass seeds the output's gradient at 1, then walks the graph in reverse, applying one local rule at each node:
- — a node, already visited, whose incoming gradient is known.
- — one of 's inputs, receiving a contribution to its own gradient.
- — 's local derivative with respect to that one input: for a sum, the other input's value for a product.
- This is the chain rule, applied one node at a time
Nothing here is new — it's the same chain rule from Chapter 3, just applied locally at every node instead of algebraically for the whole expression at once.
- += matters: a node used twice accumulates
If a value feeds two different downstream nodes, its total gradient is the sum of what flows back from each path — never just one of them.
- A product node's local rule swaps its inputs
For , and — each input's local derivative is literally the forward-pass value of the other one.
Toggle to "Backward pass" and watch the same graph now display gradients instead of values — and notice the readout cross-checks every one of them against a plain numerical (finite-difference) gradient, which never even looks at the graph.
Run both passes on at , using the graph , (the output):
- Forward pass
- Seed the output gradient and cross the add node
. The add node passes its incoming gradient through unchanged to both inputs: gradient into is , and already receives a direct contribution of .
- Cross the multiply node
: the gradient arriving at (which is ) distributes as to , and to .
- Sum every path into a
- received from the direct add-path and from the multiply-path: .
- , with no second path to add.
Both match the closed-form derivative, and , exactly.
At a = 5, b = −2, compute ∂f/∂a for f(a,b) = a·b + a. Remember: a feeds two nodes, so its gradient must combine both paths.
That's the whole engine: a forward pass that evaluates every node once, and a backward pass that applies one local multiply-and-accumulate rule per node, in reverse. Real autograd systems — PyTorch, and every framework since — do exactly this at far larger scale, on graphs with millions of nodes instead of two. There's no more machinery to add; there's only more graph.