Backprop Through a Two-Layer Network by Hand
Walking every number through a small two-layer network's forward and backward pass, with no shortcuts, is the fastest way to trust that backpropagation is just arithmetic — not magic.
Prerequisites: Backpropagation, Computational Graphs and Automatic Differentiation
Reading about backpropagation and actually pushing real numbers through a real network by hand are two different levels of understanding, and only the second one leaves you able to spot a bug in someone else's implementation. This page does exactly that: one small network, two inputs, two hidden neurons, one output, every single number written down, forward and backward, with a check at the end that proves the gradients are correct.
The analogy: a two-stage supply chain
A raw material's price moves. To know how much that move affects the price of a finished product, you cannot look at the raw material and the finished product alone — the effect passes through an intermediate processing stage first. If a 2 to the cost of an intermediate part, and a 3 to the finished product, then the raw material's total effect on the finished product is dollars, found by multiplying the effect at each stage. A two-layer network has exactly this structure: an input affects a hidden neuron, and that hidden neuron affects the output, and the input's total effect on the output is the product of the two local effects — chained twice instead of once.
The network
Two inputs , . Two hidden neurons, each a weighted sum of the inputs passed through a sigmoid, :
with weights and . A single linear output neuron combines the two hidden activations: , with , , . Target , loss .
Worked example 1: the full forward and backward pass
Forward pass, computed and kept for later:
Backward pass. Start at the output, whose local slope is . Because the output layer is linear, that is also .
Output weights — each output weight's gradient is times the hidden activation it multiplied:
Into the hidden layer — each hidden unit's incoming gradient is times the output weight it fed into, times its own sigmoid's local slope :
Notice came out positive even though is negative, because is negative — the second hidden neuron helps the output by shrinking, and backprop finds that sign flip automatically, exactly as it must.
Hidden weights — each hidden weight's gradient is its unit's times the input it multiplied:
Nine numbers, six weights and three biases, all obtained from one forward pass and one backward sweep — never re-running the network from scratch for each one.
Worked example 2: verifying two gradients by finite difference
Nudge up by to , holding everything else fixed, and redo only the parts of the forward pass that change: , giving .
That is within rounding of the backprop value computed above — a genuine, independent check, not a restatement of the same calculation. Now nudge up by to instead: , , , .
Matching backprop's . Both checks land within finite-difference rounding error of the analytic values, confirming the backward sweep is correct — and this is exactly the gradient-checking routine every hand-rolled implementation should run once before trusting it.
Every weight's gradient is the product of a chain of local slopes running from that weight all the way to the loss. A single backward sweep computes every one of those chains at once by reusing each unit's for every weight that feeds into it — that reuse, not any deeper trick, is what makes backprop cheap.
Every one of the nine gradients above feeds into exactly the kind of step the explorer above shows: a small move opposite the gradient's direction, one number at a time. Drag the step size and watch how the same mechanics that update and by hand here can overshoot or crawl depending on how big a step is taken.
What this means in practice
The one-step gradient descent update at learning rate moves every parameter a small amount opposite its gradient — , , and so on for all nine. Recomputing the forward pass with the updated weights would show the loss has dropped from , confirming the step moved in a genuinely useful direction. Real networks repeat this exact nine-number (or nine-million-number) update, unchanged in kind, thousands of times per training run; nothing about a production-scale network is different in principle from what happened by hand above, only in size.
Practice
- Using the deltas already computed, find and check your arithmetic against the value given in the worked example.
- Suppose had been instead of . Redo the sign of only, using the chain , and explain in words what that sign change means for how hidden neuron 2 should move.
- Why does the finite-difference check use a small perturbation like rather than, say, ?
It is easy to think each hidden neuron's gradient depends only on the weight connecting it to the output, but and both also depend on the sigmoid's own local slope, , which is largest near and shrinks toward zero as approaches 0 or 1. A hidden neuron whose activation is saturated near 0 or 1 will pass almost no gradient backward no matter how large its output weight is — this is the small-scale version of the vanishing-gradient problem, visible here in a network with only two hidden units.
Related concepts
Practice in interviews
Further reading
- Rumelhart, Hinton & Williams, Learning Representations by Back-Propagating Errors (1986)
- Nielsen, Neural Networks and Deep Learning, ch. 2