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.
Discussion
💡 Discussion rules
- Ask and answer about this concept. Off-topic gets removed.
- No homework dumps. Show what you tried first.
- Corrections are welcome. Cite a source when you claim an error.
Loading discussion…
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