A model predicts that a support ticket is safe to wait. The target says it was urgent. Knowing the prediction was wrong is not enough: the system needs to know which of thousands or billions of adjustable numbers should change, and in which direction.
BackpropagationBackpropagationAn efficient method for calculating how a model’s loss changes with respect to each parameter. It works backwards through a computation graph, combining local derivatives with the chain rule. Backpropagation calculates gradients; an optimiser uses them to update parameters. is the accounting method that assigns that local credit. It is the bridge between a forward-pass calculator and a model that can learn.
Lesson details
- Module
- Deep learning
- Lesson
- 2 · Backpropagation from scratch
- Difficulty
- Beginner
- Learning time
- 60 minutes
Before you start
- Perceptrons, activations, hidden layers, and a forward pass
- Derivatives, gradients, and the chain rule from Maths I
Skills you will gain
- Draw a computation graph for a small prediction and loss
- Use the chain rule to calculate one parameter gradient
- Explain the distinct jobs of a forward pass, backpropagation, and an optimiser
- Make and verify one gradient-descent update in Python
- Use a finite-difference check as a small gradient debugging tool
Why this matters
Every trainable neural network needs a way to improve its parameters from examples. Backpropagation makes this practical: it calculates a gradient for each parameter without separately redoing the whole calculation for every parameter. Frameworks automate the arithmetic, but debugging a training run requires knowing what they are doing.
Plain-English mental model
Step 1 — Turn an error into a number the model can reduce
A model needs a numeric target for improvement. A loss functionLoss functionA numerical score describing how costly a model's prediction is relative to the training target. Fitting adjusts parameters to reduce an aggregate training loss, but lower training loss does not guarantee better real-world behaviour. measures how costly a prediction is compared with the training target. For one numeric prediction, a simple choice is squared error:
loss = (prediction − target)²
Let input x = 2, target t = 1, and one parameter w = 0. Our tiny model predicts:
y = w × x = 0 × 2 = 0
error = y − t = 0 − 1 = −1
loss = error² = (−1)² = 1
The loss is not a moral judgement and it is not the same as user harm. It is the training signal we chose. In a real system, choosing the wrong target or loss can optimise the wrong behaviour very efficiently.
Step 2 — Put the forward pass on a computation graph
A computation graphComputation graphA diagram or data structure that represents a calculation as connected operations and values. It makes clear what was calculated in the forward pass and provides the paths used to apply the chain rule backwards. makes the calculation explicit as connected values and operations. Our graph has three operations: multiply, subtract, and square.
The forward pass goes left to right. Backpropagation goes right to left. It does not reverse the model’s answer. It calculates how a small change in an earlier value would change the final loss.
Step 3 — Use the chain rule, one local slope at a time
A derivativeDerivativeA number describing how a small change in one value changes another value nearby. In model training, a derivative of loss with respect to a parameter tells whether increasing that parameter would locally increase or decrease loss, and by how much. is a local rate of change. For squared error, the derivative of error² with respect to error is 2 × error. At error = −1, that is −2.
We need the derivative of loss L with respect to weight w. The chain rule says multiply the local effects along the path:
dL/dw = dL/derror × derror/dy × dy/dw
For our example:
dL/derror = 2 × error = −2
derror/dy = 1
dy/dw = x = 2
dL/dw = −2 × 1 × 2 = −4
dL/dw = −4 means a small increase in w would locally decrease loss. The sign matters. A gradient is not “the amount to subtract”; it points uphill. To reduce loss, gradient descent goes in the opposite direction.
Worked example — make one update and check it
Gradient descentGradient descentAn optimisation procedure that repeatedly changes parameters in the direction opposite the loss gradient. The gradient supplies a local direction; practical training also needs a learning rate, batches, stability checks, and validation evidence. updates a parameter using a learning rateLearning rateA positive setting that controls the size of an optimiser’s parameter update. Too large can overshoot or diverge; too small can make training impractically slow. It must be evaluated with the full training and validation process., a positive step-size setting:
new_weight = old_weight − learning_rate × gradient
With learning rate 0.1 and gradient −4:
new_weight = 0 − 0.1 × (−4)
new_weight = 0.4
Now run a new forward pass, using w = 0.4:
new prediction = 0.4 × 2 = 0.8
new error = 0.8 − 1 = −0.2
new loss = (−0.2)² = 0.04
Loss fell from 1 to 0.04 on this example. That is a useful sanity check, not a generalisation result. A real training step averages or sums loss over a batch, repeats across training data, and still needs validation data to reveal whether the improvement survives unseen examples.
Try it — manual forward, backward, and update in Python
x = 2.0
target = 1.0
weight = 0.0
learning_rate = 0.1
# Forward pass
prediction = weight * x
error = prediction - target
loss_before = error ** 2
# Backward pass: local derivatives multiplied by the chain rule
d_loss_d_error = 2 * error
d_error_d_prediction = 1.0
d_prediction_d_weight = x
gradient = d_loss_d_error * d_error_d_prediction * d_prediction_d_weight
# Optimiser step
new_weight = weight - learning_rate * gradient
new_loss = (new_weight * x - target) ** 2
print('loss before:', loss_before)
print('dL/dw:', gradient)
print('new weight:', new_weight)
print('loss after:', new_loss)Important lines
error = prediction - target- The signed error says which side of the target the prediction lies on.
d_loss_d_error = 2 * error- This is the local slope of squared error at the current error.
d_prediction_d_weight = x- For y=w×x, increasing w by a tiny amount changes y in proportion to x.
weight - learning_rate * gradient- The gradient points uphill, so subtracting it takes a controlled downhill step.
Step 4 — Check a gradient before trusting it
A small automatic differentiationAutomatic differentiationA technique used by machine-learning frameworks to calculate exact derivatives of a program’s composed operations, up to floating-point precision. It is not numerical approximation by tiny input changes and it is not symbolic algebra; frameworks commonly implement reverse-mode automatic differentiation for neural-network training. system calculates chain-rule gradients for framework operations. It is exact for those operations up to normal floating-point effects. It cannot detect a wrong target, incorrect data, an unsuitable loss, a missing mask, or a model that is unsafe to deploy.
For a small debugging check, estimate a slope with two nearby forward passes. This finite difference is slower and approximate, so it is for checking—not for training a large network.
def loss_for(weight: float) -> float:
prediction = weight * 2.0
return (prediction - 1.0) ** 2
weight = 0.0
epsilon = 0.0001
numerical = (loss_for(weight + epsilon) - loss_for(weight - epsilon)) / (2 * epsilon)
manual = 2 * (weight * 2.0 - 1.0) * 2.0
print('numerical:', round(numerical, 4))
print('manual:', round(manual, 4))If these disagree for a small test, stop and inspect the calculation before launching a long training run. In larger systems, test a few parameters and keep tolerances realistic because floating-point arithmetic and very small epsilon values can introduce numerical noise.
Real-world AI engineering example — a training run that starts to fail
Common mistakes
Saying backpropagation “updates the weights”.
Fix — Separate the jobs: backpropagation calculates gradients; an optimiser applies an update using those gradients and settings such as learning rate.
Dropping the sign of a gradient.
Fix — Write the update rule explicitly: parameter minus learning rate times gradient. Check whether a tiny step lowers loss on a toy example.
Treating lower loss on one batch as success.
Fix — Use it only as a local sanity check. Measure held-out performance, error slices, calibration, latency, and user impact separately.
Changing learning rate, model shape, data, and loss at the same time after NaNs appear.
Fix — Return to a known-good run, log finite values and magnitudes, then change one controlled factor at a time.
Assuming automatic differentiation makes any model correct.
Fix — Autodiff differentiates implemented operations. It cannot validate the target, data pipeline, masking, metric, or decision policy.
Using finite differences as the main training method.
Fix — Use backpropagation/autodiff for efficient training. Use finite differences only on tiny cases to catch implementation mistakes.
Knowledge check
Knowledge check
Practice activity
Practice · 10–20 minutes
Follow one error backwards
Goal: Calculate a loss gradient by hand, make one update, and verify that the local loss falls.
- Use x=3, target=1, and weight=0 with y=w×x and squared error.
- Write y, error, and loss for the forward pass.
- Calculate dL/de, de/dy, dy/dw, and dL/dw.
- Apply learning rate 0.1 and calculate the new loss.
- Run the starter code and compare it with your working.
- State one reason this single-example result is not sufficient for deployment.
Expected result: Your gradient is -6, the updated weight is 0.6, and loss decreases from 1 to 0.64. You should identify validation on relevant unseen cases as a missing step.
Optional challenge: Add a bias parameter, derive its gradient, and confirm a numerical gradient check for both w and b.
Reveal solution
x = 3.0
target = 1.0
weight = 0.0
learning_rate = 0.1
prediction = weight * x
error = prediction - target
loss = error ** 2
gradient = 2 * error * x
new_weight = weight - learning_rate * gradient
new_loss = (new_weight * x - target) ** 2
print('loss:', loss)
print('gradient:', gradient)
print('new weight:', new_weight)
print('new loss:', new_loss)Solution: the forward pass gives prediction=0, error=-1, and loss=1.
The local derivatives are dL/de=-2, de/dy=1, and dy/dw=3, so the gradient
is -6. The update is 0 - 0.1×(-6) = 0.6. The new prediction is 1.8, with
error 0.8 and loss 0.64. The loss fell, but this is only one training example.
A deployable model still needs representative data, protected validation and test
evidence, an error policy, and monitoring.
Key takeaways
- A loss converts one prediction error into a numeric training signal, not a complete measure of product success.
- A computation graph records the forward operations that backpropagation differentiates in reverse.
- The chain rule multiplies local derivatives to assign a gradient to an earlier parameter.
- Gradient descent subtracts learning rate times gradient; the sign tells the update direction.
- Autodiff makes gradients practical, while data, loss design, validation, and monitoring remain engineering responsibilities.
Flashcards
Flashcards
1 of 6Revision and interview questions
- Draw a computation graph for y=w×x, e=y−t, L=e². Label the forward values and local derivatives.
- Derive dL/dw for squared error and explain every factor in the chain-rule product.
- Explain why backpropagation and gradient descent are different operations.
- Design a small gradient-debugging plan for a model whose loss becomes NaN after a configuration change.
One-page sketchnote summary
Print me · one-page revision sheet
Backpropagation from scratch
Main idea
Backpropagation breaks one final error into local responsibilities for each parameter. The chain rule moves backward through the forward calculation; an optimiser then makes a measured move downhill.
Core terms
- Loss — numeric training signal
- Computation graph — connected operations
- Derivative — local rate of change
- Chain rule — multiply local effects
- Gradient — loss change per parameter
- Learning rate — update step size
One picture
Code pattern
forward → loss
backward → gradient
parameter ← parameter − rate × gradientWatch out
- Do not confuse gradients with updates
- Do not lose the gradient sign
- Do not trust one-batch loss alone
- Do not treat autodiff as data validation
Remember
- Forward computes loss
- Backward assigns gradients
- Optimiser changes parameters
- Tiny checks catch big training bugs
- Validation judges useful learning
Three quick questions
- What is dL/dw?
- Which direction lowers loss?
- What does autodiff not know?
Lesson checklist
0 of 7 completeResources
- docsPyTorch — Autograd mechanicsOfficial explanation of PyTorch’s dynamic computation graph and automatic differentiation behaviour.
- repomicrogradA small educational automatic-differentiation engine; read it after you can trace the manual example in this lesson.
- docsDeep Learning — back-propagation and other differentiation algorithmsMore formal reference material for the same computation-graph and chain-rule idea.