A network learns by adjusting its parameters: the numbers inside it, such as the entries of its weight matrices. Training repeats one step millions of times: measure how wrong the network is (the loss , a single number), then nudge every parameter a little in the direction that makes smaller. To know that direction, we need a derivative for every parameter. This page explains what those derivatives are and how backpropagation computes all of them at once.
Derivatives and gradients
The derivative of the loss with respect to one parameter (theta) answers one question: if I change by a tiny amount, how much does change, and in which direction? It is written .
Example. Take at , so . Move to : now . The loss grew by about for a step of , a ratio of about . That ratio is the derivative: .
A positive derivative means "increasing increases the loss", so training decreases . With a step size of : , and the loss drops from to .
The gradient is the list of these derivatives, one per parameter. A small LLM (large language model) has millions of parameters, so we need millions of derivatives, at every training step, cheaply. Frameworks such as PyTorch compute them automatically, and every one of them uses the same idea, which you will code in this section.
The chain rule
A network is a long chain of simple operations: add, multiply, matrix product, tanh, and so on. Each operation takes the result of earlier ones. Drawn as a diagram, with one box per operation and arrows from inputs to outputs, this is the computational graph. The loss is the last box.
Suppose depends on only through an intermediate value . The chain rule says:
where:
- is the upstream gradient: how the loss reacts to . It is computed first, coming back from the end of the graph;
- is the local gradient: how reacts to . It depends only on the operation itself.
In words: how affects the loss = how affects , times how affects the loss.
Example. Take and , at (so and ).
- Upstream: , so .
- Local: , so .
- Chain rule: .
Check directly: , whose derivative is at .
So each operation needs just one rule: "given the upstream gradient, produce the gradient for my inputs". It never needs to know what the rest of the network looks like. A few rules cover most of a network. In the table, is the upstream gradient :
| Forward | Backward |
|---|---|
| , | |
| , | |
| where , else |
How to read the rows:
- addition passes the gradient unchanged to both inputs;
- multiplication sends each input the gradient times the other input;
- tanh multiplies the gradient by , using its own output ;
- , called ReLU (rectified linear unit), lets the gradient through only where the input was positive.
Backpropagation, step by step
Backpropagation applies these rules from the end of the graph to the start: first the forward pass computes every value, then the backward pass computes every gradient, in the opposite order.
Example. with and .
Forward. , then .
Backward, starting from :
- is an addition: it passes to and to . So far and has received .
- is a multiplication with upstream gradient : receives , and receives .
- was used twice, so its two contributions add up: .
Result: and . Check directly: , so and .
The backward pass visits the operations in reverse topological order: every operation comes after all the operations that use its result. In the example, comes before , because uses . This guarantees that when the pass reaches a value, every path from that value to has already sent its contribution, so its gradient is complete.
The total cost is a small constant times the cost of the forward pass, whatever the number of parameters. This is reverse-mode automatic differentiation. Linnainmaa's 1970 master's thesis is usually cited as its first published description (the idea was found independently several times), and Rumelhart, Hinton and Williams popularized it for training neural networks in 1986.
Two rules that prevent most bugs
Gradients add up. When a value is used in more than one place, each use sends back its own contribution, and these must be summed: in code grad += ..., never grad = .... In the example above, received and . Another case: sends back twice, once per factor, for a total of , the derivative of .
Broadcasting is the same rule in disguise. A bias added to every row of a batch is used once per row, so its gradient is the sum of the gradients of all the rows.
Shapes match. The gradient with respect to an array always has the shape of that array. For a matrix product , with upstream gradient , this alone almost forces the answer:
where is transposed: rows become columns. These are the only two products whose shapes work.
Example. has shape and has shape , so and have shape .
- is : the shape of .
- is : the shape of .
Any other combination, such as , does not even have shapes that can be multiplied.
Gradient checking
A wrong backward pass can still make the loss go down a little, so you cannot trust it just because training "works". Test it against the definition of the derivative instead: nudge a parameter a tiny amount and measure how the loss moves. The central difference nudges it both ways:
where:
- (epsilon) is the small nudge, such as ;
- and are the loss with nudged up and down;
- dividing by , the distance between the two points, gives the slope.
Its error shrinks like , while the one-sided version, , only shrinks like .
Example. at , where the true derivative is . With :
- central: ;
- one-sided: , a hundred times further off.
To compare your gradient with the numerical one , use a relative error, because gradients can be tiny or huge, and a difference of means nothing until you know the size of the numbers:
where and are entry of the two gradients. In words: the largest difference, divided by the size of the numbers being compared.
How to read it: around or below is a pass; means a bug. Use float64 and between about and . A check costs two forward passes per parameter, so run it on small inputs only, never during real training.
References
- D. E. Rumelhart, G. E. Hinton, R. J. Williams, Learning representations by back-propagating errors, Nature 323, 533–536, 1986.
- S. Linnainmaa, Taylor expansion of the accumulated rounding error, BIT 16(2), 146–160, 1976. The journal paper based on his 1970 thesis.
- A. Griewank, Who invented the reverse mode of differentiation?, Documenta Mathematica, Extra Volume: Optimization Stories, 389–400, 2012. A short history.
- A. G. Baydin, B. A. Pearlmutter, A. A. Radul, J. M. Siskind, Automatic differentiation in machine learning: a survey, JMLR 18(153), 1–43, 2018.
- A. Griewank, A. Walther, Evaluating Derivatives, 2nd ed., SIAM, 2008. The reference book on automatic differentiation.
- I. Goodfellow, Y. Bengio, A. Courville, Deep Learning, MIT Press, 2016. Chapter 6: Deep Feedforward Networks, section 6.5 on back-propagation.
- V. Nair, G. E. Hinton, Rectified linear units improve restricted Boltzmann machines, ICML, 2010.
- Stanford CS231n notes: Backpropagation, intuitions and gradient checks.
- A. Karpathy, micrograd: a scalar autograd engine in about 100 lines, the model for the last exercise of this section.