Deep learning
A worked training step
One full forward pass, backward pass and weight update for a tiny two-unit network, with every number shown. It ends with a dead ReLU unit that receives no gradient.
Here is one training step for a tiny network, by hand. It has two inputs, two hidden units with ReLU, and one output with squared-error loss. The numbers are small enough to check on paper. Once you can trace this, you can trace a real network the same way, one layer at a time.
The setup
x = [1.0, 2.0], target y = 1.0
W1 = [[0.1, 0.2], b1 = [0, 0] (two hidden units)
[-0.1, 0.3]]
W2 = [0.5, -0.4], b2 = 0Forward pass
z1 = W1 x + b1 = [0.5, 0.5]
h = ReLU(z1) = [0.5, 0.5]
z2 = W2 · h + b2 = 0.5·0.5 + (−0.4)·0.5 = 0.05
L = (z2 − y)² = (0.05 − 1)² = 0.9025The prediction is 0.05, and the target is 1.0, so the loss is large.
Backward pass
Work from the loss back toward the inputs. Each line multiplies the incoming gradient by the local derivative.
∂L/∂z2 = 2(z2 − y) = 2(0.05 − 1) = −1.9
∂L/∂W2 = ∂L/∂z2 · h = −1.9 · [0.5, 0.5] = [−0.95, −0.95]
∂L/∂h = ∂L/∂z2 · W2 = −1.9 · [0.5, −0.4] = [−0.95, 0.76]
∂L/∂z1 = ∂L/∂h · 1[z1 > 0] = [−0.95, 0.76] (both units are active)
∂L/∂W1 = outer(∂L/∂z1, x) = [[−0.95, −1.9], [0.76, 1.52]]Each unit's gradient for W1 is its ∂L/∂z1 times the input x. The ReLU term 1[z1 > 0] is 1 for both units here, so the gradient passes through.
One update
With learning rate η = 0.1, each weight moves against its gradient: W ← W − η ∂L/∂W.
W2 ← [0.5, −0.4] − 0.1 · [−0.95, −0.95] = [0.595, −0.305]The output weights move in the direction that raises the prediction. Repeating forward, backward and update is training.
A dead unit
Now shift the first hidden unit's bias to b1 = [0, −1]. The first unit still works, but the second one is pushed below zero:
z1 = [0.5, −0.5] h = [0.5, 0]
z2 = 0.25 L = (0.25 − 1)² = 0.5625
∂L/∂z2 = −1.5 ∂L/∂W2 = [−0.75, 0]
∂L/∂h = [−0.75, 0.6]
∂L/∂z1 = ∂L/∂h · 1[z1 > 0] = [−0.75, 0]
∂L/∂W1 = [[−0.75, −1.5], [0, 0]]The second row of ∂L/∂W1 is zero. ReLU blocks the gradient wherever its input is not positive, so that unit cannot learn from this example. If it stays negative on every example, it is a dead unit. Its weights never move.
Warning
A unit whose pre-activation is exactly zero also gets no gradient through ReLU. Initialization and learning rate both affect how often this happens.
Common mistakes
- Forgetting the ReLU mask. The backward pass must zero the gradient wherever the forward input was not positive.
- Mixing up the outer product.
∂L/∂W1is the outer product of the gradient atz1with the inputx, so its shape matchesW1. - Changing the learning rate and the gradient together. Update one number at a time when you debug.
Check yourself
- Why is the second row of
∂L/∂W1zero in the dead-unit example? Becausez1for that unit is negative, so ReLU's local derivative is 0 and blocks the gradient. - After one step with
η = 0.1, why doesW2move toward[0.595, −0.305]? Its gradient is negative, so subtractingηtimes the gradient increases both entries.
Key takeaways
- Forward: compute each layer's values and the loss. Backward: multiply each local derivative by the incoming gradient.
- An update subtracts the learning rate times the gradient from every weight.
- ReLU blocks gradients wherever its input is not positive, so a unit can go dead.
- Tracing one example by hand shows exactly where each gradient comes from.
Further learning
The training neural nets page covers what happens across many steps, including learning rates and initialization.
Related
Backpropagation from scratch
How training computes the gradient of the loss for every weight in one backward pass. Covers computational graphs, reverse-mode autodiff and the bugs that break training.
Gradients for linear layers and softmax
The backward formulas for a batched linear layer, and why softmax with cross-entropy has the simple gradient "probabilities minus the label."
Training neural networks well
Optimizers, schedules, initialization, normalization, regularization and a practical recipe for debugging loss curves.