Backward Pass & Backpropagation Through Time

Comic showing robots playing telephone: the first robot shouts 'FIX THIS!' after seeing a wrong answer, but the message fades to 'fix this', 'fix...', 'fi...', '...' as it passes down the line, until the last robot just shrugs with a question mark. Caption: The error message fades over long distances.
What You’ll Learn

You’ll learn how Backpropagation Through Time (BPTT) unrolls an RNN so gradients can flow backward from the loss to every shared weight. You’ll also see why repeated multiplication creates vanishing or exploding gradients, and how gradient clipping keeps training stable.

For your first pass, follow the backward-pass animation and the six-step explanation. The detailed derivative and implementation sections are optional. In the GPT training lab, you’ll use automatic differentiation while keeping this same idea: trace the loss back to the weights that produced it.

In the forward pass, we computed predictions and measured our error. The backward pass calculates how a change to each weight affects that error. We use those gradients to choose an update.

Why Gradients Matter

How do we know which direction to adjust each weight? Explore below. Drag the weight along the loss curve and watch what happens when you nudge it:

What Is a Gradient?

Drag on the curve to move the weight
Model: prediction = w × 2,   target = 6,   Loss = (prediction − 6)²
0102030400123456weight wLossoptimal (w=3)w−εw+ε18.532.5updatew=5.50, L=25.0
Weight 5.50
Loss 25.00
Gradient +20.00
Sensitivity high
w − ε = 5.15 → Loss = 18.49
w + ε = 5.85 → Loss = 32.49
Gradient ≈ (32.49 − 18.49) / 0.70 = 20.00
← Positive gradient: loss increases when w increases, so decrease w to reduce loss.

What to look for:

  • Drag the dot along the curve. Far from the minimum, the loss is high and the gradient is large (steep slope). Near the minimum, everything flattens out.
  • The nudge (the two smaller dots) shows the loss at w+ε and w−ε. The ratio of loss change to weight change IS the gradient.
  • The sign tells direction: a positive gradient means “loss goes up when w goes up,” so we decrease w. A negative gradient means the opposite.
  • The magnitude tells sensitivity: a large gradient means this weight has a big effect on the error right now. A small gradient means we’re close to where we want to be.
  • Click Gradient Step to apply one update, or Train to watch gradient descent converge step by step.

A gradient tells us: “If I nudge this weight by a tiny amount, how much does the loss change?” Training is just repeated gradient descent: at each step, adjust every weight in the direction that reduces the error.

See the Backward Pass First

Before diving into the mechanics, explore the backward pass interactively. Click any node to inspect its gradient — watch how the error signal flows backward from the loss through every computation:

RNN Computation Graph

Forward
vectors matrices ops activations
100%
p (softmax)y (logits)h (hidden)x (input)→ forward
V=0 H=4 L=—

What to look for:

  • Gradients start at the loss (right side) and flow leftward through time
  • Each hidden state receives gradients from two sources: its own output and the next timestep
  • The gradient signal gets weaker as it travels further back in time — this is the vanishing gradient problem in action

The Challenge: Shared Weights

In a feedforward network, each layer has independent weights. In an RNN, the same weights are reused at every timestep:

Feedforward:  x → W₁ → W₂ → W₃ → y    (3 separate weight matrices)
RNN:          x₀ → W → h₁ → W → h₂ → W → h₃    (same W reused)

Consequence: we must account for all uses of the weight across time — the total gradient sums contributions from every timestep. This is what makes RNN backpropagation special — and why it’s called Backpropagation Through Time (BPTT).

The Chain Rule: Our Main Tool

The backward pass is built entirely on the chain rule. Think of it as a chain of gears — pushing one gear moves the next, which moves the next. The total effect is the product of each link.

Everyday analogy: If you eat 2x more food → you gain 3x more weight → your doctor is 1.5x more concerned. The total effect of eating on doctor-concern is 2 x 3 x 1.5 = 9x. That’s the chain rule.

In our network, the loss depends on the output, which depends on the hidden state, which depends on the weights. We compute these pieces one at a time, starting from the loss and working backward — hence “backward pass.”

The Six Steps (Intuition)

Here’s what happens at each step of the backward pass, without the math:

StepWhat happensIntuition
1. Output errorCompare prediction to target”How far off was I?” — subtract the correct answer
2. Output weightsUse error to update output layer”How should I adjust my scoring?“
3. Hidden gradientError flows into the memoryGets error from two sources: current output + future timesteps
4. Through tanhError passes through squashingSaturated neurons (near ±1) block the gradient — only 2% passes through
5. Hidden weightsAccumulate weight updatesSame weights used everywhere, so add up contributions from all timesteps
6. Time chainSend error one step further backThis is the “through time” — the loop that repeats for every timestep

Key insight about Step 4: When the hidden state is saturated (near +1 or -1), the gradient gets nearly killed. This is one reason RNNs struggle with long sequences — the signal weakens at every step.

Hidden state valueGradient that passes throughEffect
0.0100%Full signal
±0.575%Mild reduction
±0.919%81% lost
±0.992%Nearly killed
Quick Check
If a hidden unit has value h_t = 0.99, what happens to the gradient flowing through it?
Your turn
Choose an answer to check your understanding.
Fill in the Blanks
The hidden state gradient has two sources: the layer at the current timestep, and the timestep flowing backward through time.
Fill in every blank, then check your answer.
Quick Check
If the model predicts the correct character with probability 0.95, what can you say about the gradient at the target index?
Your turn
Choose an answer to check your understanding.

A Concrete Example: BPTT with Real Numbers

Let’s trace backward through a tiny example. Suppose at timestep 2, our RNN predicted probabilities [0.1, 0.2, 0.6, 0.1] and the correct answer was index 2 (probability 0.6).

Step 1 — Output error: Subtract 1 from the correct index’s probability: dy = [0.1, 0.2, 0.6−1.0, 0.1] = [0.1, 0.2, −0.4, 0.1]

The negative value says “increase this logit.” The positives say “decrease those.”

Step 2 — Output weight gradient: Multiply the error by the hidden state. If the hidden state was [0.3, −0.7], the gradient for the output weight matrix is the outer product — a 4×2 matrix telling us how to adjust each connection.

Step 3 — Error flows into memory: The error reaches the hidden state from two directions: the current output (transpose of output weights times dy) and the next timestep (passed backward through time). These add together.

Step 4 — Through the squashing function: If the hidden state was [0.3, −0.7], the tanh derivative is [1−0.09, 1−0.49] = [0.91, 0.51]. The first element (0.3) keeps 91% of its strength, but the second (-0.7) loses nearly half. If the values were closer to ±1, almost nothing would pass through.

Step 5 — Hidden weight gradients: Same as step 2, but for the hidden-to-hidden and input-to-hidden weights. Crucially, we add (not replace) these gradients across all timesteps, because the same weights are used at every step.

Step 6 — Pass it back: The error signal is sent one step further back in time, and we repeat from step 3 for the previous timestep.

Quick Summary

StepWhat happensIntuition
1. Output errorCompare prediction to target”How far off was I?” — subtract 1 from the correct answer’s probability
2. Output weightsCompute gradient for scoring layer”How should I adjust my scoring to be less wrong?“
3. Hidden gradientError flows into the memory from two directionsCurrent output + future timesteps both contribute
4. Through tanhError passes through squashing functionSaturated neurons block most of the signal
5. Hidden weightsAccumulate weight updates across all timestepsSame weights everywhere → add up all contributions
6. Time chainSend error one step further backThe “through time” loop — repeat for every timestep

Gradient Clipping: Taming Explosions

When sequences are long, the repeated multiplication can cause gradients to grow exponentially. Imagine multiplying by 1.1 a hundred times: 1.1^100 ≈ 13,780 — the gradient explodes!

Norm clipping is like a speed limit for gradients: if the gradient is too large, scale it down while preserving its direction. This prevents wild updates that would destabilize training.

Use the sliders below to see how the weight matrix properties and sequence length affect gradient magnitude. Try setting the eigenvalue below 0.8 to see vanishing gradients, or above 1.2 to see exploding gradients.

Gradient Magnitude Through Time

||dh|| (log)
6e-3
0
8e-3
0.01
2
0.01
0.02
4
0.02
0.03
6
0.04
0.05
8
0.07
0.09
10
0.12
0.15
12
0.20
0.26
14
0.34
0.45
16
0.59
0.77
18
1.0
19
Timestep (t)
Gradients decaying: With |λ| = 0.90, gradients shrink to 0.006 at t=0. Short sequences work, but long-range dependencies are hard to learn.
Effective per-step factor: |λ| × tanh'(h) ≈ 0.77 — over 19 steps: 0.77^19 = 0.0062

What to look for:

  • Set the eigenvalue below 0.8 and watch the bars shrink toward zero on the left (early timesteps). Those tokens receive almost no learning signal.
  • Set it above 1.2 and watch the bars explode. Without clipping, a single update would wreck the weights.
  • Increase the sequence length to 30+ and notice how even a slight deviation from 1.0 gets amplified over many steps.
  • The “effective per-step factor” at the bottom shows the combined eigenvalue × tanh attenuation. When it’s below 1, gradients vanish; above 1, they explode. The sweet spot (near 1.0) is narrow and unstable.
Quick Check
Why do we use (L(w+e) - L(w-e)) / 2e instead of (L(w+e) - L(w)) / e for gradient checking?
Your turn
Choose an answer to check your understanding.

Exercises

  1. Gradient accumulation: In a 3-step sequence with h−1=0h_{-1} = 0, why does t=0t=0 contribute nothing to ∂L∂Whh\frac{\partial L}{\partial W_{hh}}?
  1. Gradient depth: In a 5-step sequence, how many times does WhhW_{hh} appear in the gradient path from L4L_4 to h0h_0?
  1. Implement and verify: Write BPTT and verify with numerical gradient checking (error < 1e-5 for all parameters).
Learning Checklist
  • I can explain why RNN backpropagation sums gradient contributions across all timesteps
  • I understand each step of the backward pass: from softmax gradient through to weight updates
  • I know why the tanh derivative causes gradient saturation when hidden units are near +/-1
  • I can explain why long sequences cause vanishing or exploding gradients
  • I understand how gradient clipping preserves direction while bounding magnitude

Next Steps

You now understand how gradients flow backward through an RNN. But there’s a fundamental problem: for long sequences, the repeated multiplication through the hidden-to-hidden weights causes gradients to either vanish (most common) or explode. Next up: Vanishing Gradients & Gated RNNs →, where we’ll see why this happens and the architectures that fix it.