Machine learning
What backpropagation does before gradient descent takes a step
Follow one training step by hand to see how backpropagation calculates gradients, how gradient descent uses them, and where the learning rate enters the calculation.
In this article
For ŷ = wx + b with x = 2 and target y = 1, start at w = 1 and b = 0. The loss is ½(ŷ − y)². The final box uses learning rate η = 0.1.
Original worked example; values calculated from the model and loss shown.A typical PyTorch training loop calls loss.backward() and then optimizer.step(). Both happen after the model makes a prediction, which makes it easy to treat them as one operation. But you can stop between those calls and inspect something useful: the gradients have been calculated, while the parameters still have their old values.
Backpropagation computes how the loss changes with each parameter. Gradient descent uses those derivatives to choose new parameter values. In PyTorch, the backward call handles the first task; the optimizer handles the second. Its update depends on which optimizer you chose. The PyTorch optimization tutorial makes this separation explicit.
We can follow both tasks with a model small enough to calculate by hand. It has one weight and one bias, so we can account for every number without hiding the distinction inside a library.
Start with a prediction and a loss
Our model predicts . Give it the input with target , and start with weight and bias . The prediction is
The model predicts one unit too high. To measure that error, use the loss . The factor of one half makes the derivative simpler; it does not change where this loss is minimized. For the current prediction,
That completes the forward pass. We know what the model predicts and how much loss that prediction incurs. We have not yet calculated how either parameter affects the loss.
Work backward to find the gradients
First consider the last operation, which turns the prediction error into a loss. Its derivative with respect to the prediction is
At this prediction, a small increase in would increase the loss at a rate of one unit of loss per unit of prediction. To find how the weight affects the loss, we also need the rate at which the weight changes the prediction. Since , that rate is .
The chain rule multiplies these two local rates:
The bias enters the prediction directly, so its corresponding derivative is one:
We now have the gradient with respect to . Both entries are positive, so increasing either parameter slightly would increase the loss from this starting point. The weight has twice the local effect because the input multiplying it is two.
This backward calculation is the small version of what backpropagation does in a larger network. It starts at the loss and applies the chain rule through the operations that produced it, reusing intermediate results. When a value affects the loss through multiple paths, their derivative contributions add. Dive into Deep Learning develops that process for a multilayer model.
The parameters are still and . Calculating their derivatives has not changed them.
Use the gradients to update the parameters
Plain gradient descent subtracts a scaled gradient from the current parameters. The scale is the learning rate, written . With , the updates are
Both derivatives came from the same starting state. We do not update the weight and then recalculate the bias derivative halfway through this step.
Using the new parameters, the model predicts . Its new loss is , down from . This particular update improved the prediction on our single example.
| Point in the calculation | Weight | Bias | Loss at these parameters |
|---|---|---|---|
| After the forward pass | 1 | 0 | 0.5 |
| After backpropagation | 1 | 0 | 0.5 |
| After gradient descent and a new forward pass | 0.8 | −0.1 | 0.125 |
The second row is where the distinction becomes visible. Backpropagation gives us additional information about the current parameters; gradient descent then changes those parameters.
Changing the learning rate does not change this starting gradient
Suppose we return to the original parameters and choose . The derivatives at that point remain , but the update now gives and . The prediction becomes , and the loss rises to . We moved in the direction suggested by the gradient and still made the loss worse because we went too far.
For this example, the prediction after an update is , so the resulting loss is . The curve below shows how much the outcome depends on the step size.
Each point starts from w = 1 and b = 0 and takes one update. Changing η changes the result even though the starting gradient stays (2, 1). The minimum here fits one example; it is not a recommended learning rate for other models.
Calculated from L after one update = ½(1 − 5η)².A learning rate of happens to fit this one example exactly. That is a property of these numbers, not a rate to copy into a neural network. With a larger model and more data, the useful step size depends on the loss surface and the optimization method. Our explanation of gradient descent oscillation examines another case where the step size determines whether repeated updates converge.
Reproduce the whole step in Python
This code calculates the derivatives explicitly, so it needs no machine learning library. The backward section uses the chain rule we worked out above; an automatic differentiation system performs that bookkeeping for a larger graph.
x, target = 2.0, 1.0
w, b = 1.0, 0.0
eta = 0.1
# Forward pass at the current parameters.
prediction = w * x + b
residual = prediction - target
loss = 0.5 * residual ** 2
# Backward pass: calculate both derivatives before updating.
grad_w = residual * x
grad_b = residual
# Plain gradient descent.
w, b = w - eta * grad_w, b - eta * grad_b
new_prediction = w * x + b
new_loss = 0.5 * (new_prediction - target) ** 2
print(f"gradient: ({grad_w:.1f}, {grad_b:.1f})")
print(f"parameters: ({w:.1f}, {b:.1f})")
print(f"loss: {loss:.3f} -> {new_loss:.3f}")
It prints a gradient of (2.0, 1.0), parameters of (0.8, -0.1), and a loss change from 0.500 to 0.125.
In a PyTorch implementation, loss.backward() accumulates gradients in the parameters' .grad attributes. A usual training loop clears old gradients before calculating a fresh step, unless it deliberately accumulates them across batches. The autograd tutorial explains that behavior. Clearing a gradient is another separate operation; it does not reset the learned weight.
What changes when you use a different optimizer?
The gradient calculation can stay the same when the update rule changes. An optimizer such as SGD with momentum or Adam uses gradients together with its own state to determine the update. It therefore does more than subtract the current gradient multiplied by a single learning rate. These optimizers occupy the same part of the training loop, after the backward pass.
This separation is useful when debugging. If the derivatives are wrong, inspect the loss calculation and the graph used to differentiate it. If the derivatives are right but the loss grows after an update, examine how the optimizer turned them into parameter changes. In our example, changing only the learning rate was enough to turn an improving step into a harmful one.
Check the reasoning
Sources & notes
- PyTorch: Automatic Differentiation with torch.autograd ↗
Documents backward(), parameter gradients, and gradient accumulation.
- PyTorch: Optimizing Model Parameters ↗
Separates the backward pass from the optimizer update and explains the training loop.
- Dive into Deep Learning: Forward Propagation, Backward Propagation, and Computational Graphs ↗
Explains how derivatives are propagated through a computational graph. The numerical example in this article is our own.
Our figures use illustrative mathematical examples unless a dataset is explicitly identified. You can share the original Glacius figures with attribution and a link to this article; linked third-party material retains its own terms.
Make the connection
Practice these concepts
- Scalar chain ruleDifferentiate a composition of two scalar functions.
- GradientsAssemble a gradient from partial derivatives in coordinate order.
- Gradient descent stepsCompute one gradient descent update.