Backpropagation gets treated like the hidden room in the building.
Forward pass, loss, gradients, update. The words are right, but the explanation often makes the mechanism sound more mystical than it is. That is where beginners lose the thread. By the time the weights move, the lesson has already slipped into jargon.
The ordinary version is easier to hold onto.
Backpropagation is dependency tracking with consequences. The forward pass records what the network did. The loss turns the mistake into a number. The backward pass asks which earlier values helped produce that mistake. The update uses that answer to move the weights.
That is still math. It just does not need smoke around it.
the forward pass leaves evidence behind
Backprop depends on the forward pass. It is not working from memory.
The model computes weighted sums, activations, and outputs layer by layer:
z = W x + b
a = ReLU(z)
Those intermediate values matter because the gradient depends on them. If a ReLU output was zero, that path is different from a path where the unit stayed active. If a hidden activation was large, it can carry more responsibility for the final prediction.
That is why the interactive module is helpful. You can inspect the input, the weights, the raw z values, the activations, the prediction, the target, and the gradients in one place. Backprop looks less magical when you can point at the values it is using.
loss gives the model one number to chase
Training needs a target for the error, not a general feeling that the answer was bad.
That is the loss function’s job. It turns the prediction gap into a scalar the optimizer can work with. If the prediction is close, the loss is small. If the prediction is far off, the loss is larger. Everything downstream starts from that gap.
The more useful question is not just “how wrong was the output?”
It is:
which earlier values made this wrong output more likely?
Backpropagation answers that by walking the dependencies backward.
gradients point, they do not judge
A gradient is a direction, not a verdict.
It says how the loss would change if one value changed a little. If increasing a weight would raise the loss, the update should probably lower that weight. If increasing it would lower the loss, the update should probably push it up.
That is what the familiar update rule is doing:
new_weight = old_weight - learning_rate * gradient
The minus sign is there because the gradient points uphill in loss. Training usually wants to move downhill. The learning rate decides how far to step. Too small and nothing seems to happen. Too large and the update can bounce past the useful region or destabilize training.
Even in a tiny network, that step size matters. The same gradient can produce a calm adjustment or a bad lurch.
relu decides which paths stay open
ReLU changes what can learn because it changes what can flow backward.
When a neuron’s pre-activation is positive, ReLU passes the value through. When it is negative, ReLU outputs zero. During backprop, that also affects the gradient. A unit that was off does not behave the same as a unit that stayed active.
That is why hidden activations matter. If a unit is off for an input, the weights feeding into it may not get the update you expected for that example. The network is not adjusting every weight evenly. It is adjusting the paths that actually contributed.
This is the point where backprop starts to feel like circuitry instead of a spreadsheet.
the chain rule is just a map of dependencies
The chain rule sounds more intimidating than it is.
If the loss depends on the output, the output depends on a hidden activation, and the hidden activation depends on a weight, then the loss depends on that weight through those links. Backprop works backward along those links.
It asks simple questions:
how did the loss change when the output changed?
how did the output change when this hidden value changed?
how did this hidden value depend on the earlier weight?
Each relationship is small. The trick is reusing those local derivatives so the model does not have to recompute the whole network for every weight.
That is why I keep calling it bookkeeping. It remembers which values fed which others, then walks that graph in reverse.
updates are guesses, not promises
The gradient gives you a local guess.
It says, “from here, this direction should reduce loss.” It does not promise the next model is globally better. It does not know the whole landscape. It does not guarantee every example improves.
That matters because training is messier than the clean version people sometimes imagine.
A batch can average signals that disagree. A high learning rate can overshoot. A bad dataset can teach the wrong behavior very efficiently. A loss can improve while the product metric stays flat.
Backprop is powerful, but it is obedient. It follows the signal it is given.
use the module like a debugger
The interactive example is most useful when you slow down and predict first.
Pick one weight. Guess whether increasing it should raise or lower the loss. Change it and inspect the gradient. Look at which activations were on. Check whether ReLU blocked part of the path. See how the update changes when the target changes.
Useful questions here are plain:
- which output was wrong?
- which hidden units were active?
- which weights got large gradients?
- did ReLU block the path?
- would the update move this weight up or down?
- does the direction match what you expected?
If the answer is no, that is the lesson. Backpropagation is not a fog machine. It is a trail of dependencies from loss back to weights, and once you can follow that trail in a tiny network, the larger version is still complicated but no longer mysterious.
Related posts

About Jeremy London
Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.