Lesson 2 of 13

Before transformers: recurrent networks

Recurrent networks read a sequence one step at a time and carry a hidden state forward. See why their gradients vanish or explode, how gates help, and why attention replaced the loop.

Advanced20 min

Builds on Predicting the next token and Backpropagation (Neural networks)

In this lesson you will

  • Describe how a recurrent network carries a hidden state through a sequence with the same weights at every step
  • Explain backpropagation through time and why its gradients shrink or grow exponentially with distance
  • Describe how LSTM and GRU gates keep information and gradients alive
  • Explain why step-by-step processing limits parallel training, and how attention removed the recurrence

Read this sentence one word at a time: The keys to the cabinet in the hall by the door … When you reach the end, you know the next word should be “are”, not “is”. Somewhere in your head you kept track of the fact that the subject was plural, through nine words that had nothing to do with it.

The transformers in the rest of this track solve that problem by looking back at every earlier word directly. Before 2017, the leading approach was different: read the words in order and carry a running summary forward. This lesson is about those networks, what made them hard to train, and why attention replaced them.

A network with a loop

A Neural networkA model built from layers of artificial neurons, where each layer's outputs become the next layer's inputs. Training adjusts all of the weights together.Taught in Networks of neuronsOpen in glossary layer takes a fixed number of inputs. Sentences come in every length. A Recurrent neural networkA network that reads a sequence one step at a time, applying the same weights at every step and passing a hidden state from each step to the next.Open in glossary (RNN) handles any length by applying the same small network once per word, and feeding each step’s output back in as an input to the next step.

What it feeds back is a vector called the Hidden stateThe vector a recurrent network carries from one step of a sequence to the next. It is the network's only memory of the inputs it has read so far.Open in glossary, hth_t. At step tt the network combines the previous hidden state with the current input xtx_t:

ht=tanh⁡ ⁣(Wht−1+Uxt+b)h_t = \tanh\!\left(W h_{t-1} + U x_t + b\right)

The weights WW, UU, and bb are the same at every step. The hidden state starts at zero and is the network’s only memory: everything it knows about the words so far must fit into this one vector. To use it as a language model, a final layer turns each hth_t into logits over the vocabulary, exactly as in the previous lesson, and the network predicts the next token at every step.

Elman (1990) trained small networks of this kind, now often called Elman networks or simple recurrent networks, to predict the next letter or word. Their prediction errors rose at the start of each new word, and their hidden states grouped words into categories such as nouns and verbs, though they were never told about words or categories.

Watch a hidden state carry a signal

The demo shrinks this to the smallest possible case: a hidden state of one number. The subject word adds +1+1 for one key or −1-1 for several; every other word adds 0. At the blank, a positive state means “is” and a negative one means “are”. With a single number, the matrix WW becomes a single recurrent weight ww, so you can see exactly what it does.

A hidden state through time

A one-number recurrent network reads a sentence and must remember whether the subject was one key or many.

Plain recurrent network reading "The key to the cabinet in the hall by the door". At the blank the state is 0.19, so it predicts "is". The gradient reaching the subject is 0.1.
WordHidden state hGradient from the blank
The
0.00
0.038
key+1
0.76
0.1
to
0.60
0.17
the
0.49
0.25
cabinet
0.41
0.34
in
0.36
0.43
the
0.31
0.53
hall
0.27
0.63
by
0.24
0.75
the
0.21
0.87
door
0.19
1
___State above 0, so it predicts "is". The right verb is "is".

Weights set by hand: the subject adds +1 for one key or −1 for several, and every other word adds 0. A trained network learns its own weights and would also have to learn to ignore the other nouns.

Cell
0.90
Sentence
Subject
Prediction at the blank"is" (right)
State at the blank0.19
Gradient reaching the subject0.1

Challenges

0 of 4 complete

  1. With the plain RNN and the long sentence, make the network still predict the right verb with a state above 0.5 at the blank. (not yet)
  2. Still with the plain RNN on the long sentence, find a weight that sends at least 4% of the gradient back to the subject. (not yet)
  3. Remove the squashing and make the gradient at the subject more than 1,000 times the gradient at the blank. (not yet)
  4. Switch to the gated cell and, on the long sentence, keep the state at the blank above 0.5 while at least half the gradient reaches the subject. (not yet)

Try this

  • Press Read it and watch the state jump at “key”, then shrink word by word. With w=0.9w = 0.9, each step multiplies the memory by a bit less than 0.9. Before you switch to Long, guess whether anything will be left at the blank.
  • Raise ww above 1. The state stops fading and settles at a fixed value, and the prediction holds even on Long. Now read the gradient column for the subject.
  • Choose No squashing and push ww to 1.5 on Long. The state and the gradient run off the scale.
  • Choose Gated cell and set the forget gate to 1. The memory and the gradient both pass through untouched.
The demo's network in a few linesPython with NumPy
import numpy as np

# The demo's long sentence: "The key that my grandmother hid ... last winter ___".
# Input is +1 at the singular subject ("key") and 0 for every other word.
x = np.zeros(20)
x[1] = 1.0

def run(w, u=1.0, cell="tanh"):
    h, states, factors = 0.0, [], []
    for xt in x:
        if cell == "tanh":
            h = np.tanh(w * h + u * xt)
            factors.append(w * (1 - h**2))  # d h_t / d h_(t-1)
        else:  # no squashing
            h = w * h + u * xt
            factors.append(w)
        states.append(h)
    return np.array(states), np.array(factors)

def gradient_to(step, factors):
    # Backpropagation through time: multiply the factors of every later step.
    return np.prod(factors[step + 1:])

for cell, w in [("tanh", 0.5), ("tanh", 1.0), ("tanh", 1.5), ("linear", 1.5)]:
    states, factors = run(w, cell=cell)
    print(f"{cell:6} w={w}: state at blank {states[-1]:8.4f}, "
          f"gradient reaching 'key' {gradient_to(1, factors):.2e}")

# Gated cell: the input gate opens only at the subject, the forget gate is f.
f = 0.97
c = 0.0
for xt in x:
    c = f * c + (1.0 if xt != 0 else 0.0) * xt
print(f"gated  f={f}: state at blank {np.tanh(c):8.4f}, "
      f"gradient reaching 'key' {f ** 18:.2e}")
tanh   w=0.5: state at blank   0.0000, gradient reaching 'key' 3.17e-06
tanh   w=1.0: state at blank   0.2679, gradient reaching 'key' 4.12e-02
tanh   w=1.5: state at blank   0.8586, gradient reaching 'key' 8.18e-08
linear w=1.5: state at blank 1477.8919, gradient reaching 'key' 1.48e+03
gated  f=0.97: state at blank   0.5212, gradient reaching 'key' 5.78e-01

With ww below 1 the memory leaks away: by the end of the long sentence nothing is left and the network cannot tell “is” from “are”. With ww above 1 the state settles at a stable value, a little like a switch that stays flipped, and the memory survives. Here the weights are set by hand. A real network has to learn them, and that is where the trouble starts.

Backpropagation through time

To train an RNN, you unroll the loop: draw one copy of the network per step, each passing its hidden state to the next. The result is an ordinary deep network, as deep as the sequence is long, in which every layer shares the same weights. Run BackpropagationHow a network works out which way to nudge every weight: one backward pass carries the error from the output back through the layers, giving each weight its share of the blame (its gradient, found with the chain rule).Taught in BackpropagationOpen in glossary on it and add up the gradient each copy contributes to the shared weights. This is Backpropagation through timeTraining a recurrent network by unrolling it into one copy per step, running ordinary backpropagation, and adding up the gradients each copy contributes to the shared weights.Open in glossary, set out in its standard form by Werbos (1990).

The loop

A recurrent network as a loopOne cell, labeled tanh, reads the input x t from below. Its output, the hidden state h t, goes up and also loops back into the cell as h t minus 1 for the next step.tanhxththt−1

Unrolled for training: one copy per step, the same W, U, and b in each

The same network unrolled over the words of a sentenceFour copies of the cell, for steps 1, 2, 3, and the last step T, read the words The, keys, to, and door. The hidden state starts at zero and passes from each copy to the next. The last copy's output feeds a loss for predicting the next word, are. A dashed gradient path runs back from the loss to step 1, passing a multiplication sign between every pair of steps: one factor per step.0h1h2…tanhThetanhkeystanhtotanhdoorlosspredict "are"×××gradient to step 1
Unrolling turns the loop into a deep network, as deep as the sentence is long, with the same weights in every copy. A language model has a loss at every step; one is drawn. The gradient from it reaches step 1 only by passing back through every step in between, and each crossing (×) multiplies it by one factor.

The gradient that tells the network how the state at step tt affected a loss at a later step TT passes back through every step in between. By the Chain ruleThe calculus rule for nested functions: if L depends on a and a depends on z, then dL/dz = dL/da times da/dz. Backpropagation applies it over and over.Taught in BackpropagationOpen in glossary it is a product:

∂hT∂ht=∏k=t+1T∂hk∂hk−1=∏k=t+1Tdiag⁡ ⁣(1−hk2)W\frac{\partial h_T}{\partial h_t} = \prod_{k=t+1}^{T} \frac{\partial h_k}{\partial h_{k-1}} = \prod_{k=t+1}^{T} \operatorname{diag}\!\left(1 - h_k^2\right) W

In the demo’s one-number network, each factor is just w (1−hk2)w\,(1 - h_k^2). The gradient column shows the product, one step at a time, on a logarithmic scale.

Vanishing and exploding gradients

A product of many factors is fragile. If the factors are mostly below 1, it shrinks exponentially: 0.8 to the power 30 is about 0.001. If they are mostly above 1, it grows exponentially. These are the Vanishing gradientA gradient that shrinks toward zero as it is passed back through many steps or layers, because it is multiplied by many factors smaller than 1. Early steps then barely learn.Open in glossary and Exploding gradientA gradient that grows very large as it is passed back through many steps or layers, because it is multiplied by many factors larger than 1. Training steps then jump wildly.Open in glossary problems. Hochreiter analyzed them in his 1991 diploma thesis, and Bengio, Simard, and Frasconi (1994) showed that they make long-range dependencies hard to learn by gradient descent.

Bengio et al. also pointed out the dilemma you met in the demo. To store a bit of information reliably, despite noise in the inputs, the network’s state has to sit in a stable region where small disturbances die out. But “small disturbances die out” is the same thing as “the gradient vanishes”. At w=1.5w = 1.5 the network remembers the subject perfectly well, yet the gradient reaching the subject is less than one ten-millionth: training gets almost no signal about which early word caused a mistake at the end.

When must the gradient vanish?Optional

For the full network, the factor at each step is diag⁡(1−hk2) W\operatorname{diag}(1 - h_k^2)\,W. The tanh derivative 1−hk21 - h_k^2 is at most 1, so the size of the factor is at most the largest singular value of WW, the most any vector can be stretched by it. Pascanu et al. (2013) used this to show that if the largest singular value of WW is below 1, the long-range gradient must shrink exponentially. A largest singular value above 1 is necessary for gradients to explode, but not enough: saturated tanh units, with hkh_k near ±1\pm 1, can still squash the product, which is what happens at w=1.5w = 1.5 in the demo.

Gates: a memory that is added to

Long short-term memoryA recurrent network whose memory cell is updated by adding gated new information to a gated copy of the old cell, so information and gradients can survive many steps. Introduced in 1997.Open in glossary networks (Hochreiter and Schmidhuber, 1997) attack the vanishing gradient directly. Next to the hidden state they keep a cell state ctc_t, and they change it by addition rather than by squashing it through a weight matrix:

ct=ft⊙ct−1+it⊙gt,ht=ot⊙tanh⁡(ct)c_t = f_t \odot c_{t-1} + i_t \odot g_t, \qquad h_t = o_t \odot \tanh(c_t)

Here gtg_t is a proposed update computed from the input and the previous hidden state, and ⊙\odot multiplies element by element. The gates ftf_t, iti_t, and oto_t are vectors of numbers between 0 and 1, each computed by its own small layer with a sigmoid, from the current input and the previous hidden state:

  • The forget gate ftf_t decides how much of the old cell to keep.
  • The input gate iti_t decides how much of the new proposal to write.
  • The output gate oto_t decides how much of the cell to show as the hidden state.

Plain RNN: every step multiplies by W and squashes with tanh

A plain recurrent cellThe old hidden state h t minus 1 enters from the left, is multiplied by W, added to U times the input x t and the bias b, and passed through tanh to give the new hidden state h t. The highlighted path from old to new state goes through W and tanh at every step.ht−1W+btanhhtUxt

LSTM: the cell's own path only multiplies by f and adds i times g

An LSTM cellThe old cell state c t minus 1 runs straight across the top. It is multiplied by the forget gate f, then the input gate i times the proposal g is added, giving the new cell state c t. Below, h t minus 1 and the input x t feed four small layers: the gates f, i, and o, and the proposal g. The new hidden state h t is the output gate o times tanh of c t. The highlighted path from old to new cell state passes no weight matrix and no squashing function.ct−1ct×+×tanh×htfigoht−1xt
The highlighted line is the path from the old memory to the new one. In the plain cell it passes a weight matrix and a tanh at every step. In the LSTM it passes only a multiplication by the forget gate f and an addition, so when f stays near 1, the memory and its gradient pass through unchanged. The gates f, i, and o are vectors of numbers between 0 and 1, applied element by element; g is the proposed update.

The direct path from ct−1c_{t-1} to ctc_t is multiplied only by ftf_t. When the network learns to hold ftf_t near 1, both information and gradients pass through many steps nearly unchanged. The demo’s gated cell is this idea with the gates frozen: the input gate opens only on the subject, and you set the forget gate yourself. The original 1997 LSTM had no forget gate; its cell kept everything, which Hochreiter and Schmidhuber called a constant error carousel. Gers, Schmidhuber, and Cummins (2000) added the forget gate so a cell could learn to clear itself.

The Gated recurrent unitA simpler gated recurrent network than the LSTM, with an update gate that blends the old hidden state with a new candidate and a reset gate. Introduced by Cho et al. in 2014.Open in glossary (GRU) of Cho et al. (2014) is a lighter variant. It has no separate cell: an update gate blends the old hidden state with a new candidate, and a reset gate decides how much of the old state the candidate may use. With two gates instead of three it has fewer parameters, and in practice the two often perform comparably.

The cost of going one step at a time

Gates fixed much of the gradient problem, but not the loop itself. To compute h100h_{100} you need h99h_{99}, which needs h98h_{98}, and so on. During training the whole sentence is known in advance, yet the network still has to process it in order. A GPU is fast because it does thousands of multiplications at once; an RNN gives it one small step at a time per sequence. Vaswani et al. (2017) put it directly: this sequential nature “precludes parallelization within training examples”.

The fixed-size state was a second bottleneck. In translation, an encoder RNN read the source sentence and a decoder RNN wrote the translation (Sutskever, Vinyals, and Le, 2014). Everything the decoder knew about the source had to pass through one vector. Bahdanau, Cho, and Bengio (2014) let the decoder look back at all the encoder’s hidden states at every step, weighting them by relevance. That was AttentionA mechanism that lets each token build a new vector as a weighted mix of other tokens' value vectors, with weights set by how well its query matches their keys.Taught in Attention, step by stepOpen in glossary, added on top of recurrent networks.

The transformer (Vaswani et al., 2017) took the last step and removed the recurrence entirely. Every position attends directly to every earlier position, so:

  • Training is parallel. All positions of a training sequence are computed at once, with a few large matrix multiplications per layer.
  • Paths are short. Information from word 1 reaches word 100 in a single attention step, not through 99 multiplications, so its gradient does not have to survive a long product.

Recurrent network

Word 1 reaches word 6 in a recurrent networkSix words in a row, each passing the hidden state to the next. Information from word 1 reaches word 6 only after five steps, and each step has to wait for the one before.5 steps from word 1 to word 6123456computed one after another

Attention

Word 1 reaches word 6 with attentionThe same six words. Word 6 attends directly to each of words 1 to 5, so information from word 1 reaches it in a single step. Every word does the same for the words before it, and during training all six positions are computed at once.1 step from word 1 to word 6123456computed at the same time, in training
Both networks let word 6 use word 1. The recurrent network passes it along five links, each computed after the one before; attention connects every word to every earlier word directly. The price of attention is that every position compares itself with all the earlier ones, so its work grows with the square of the length.

The price is that attention compares every pair of positions, so its cost grows with the square of the sequence length, and generation is still one token at a time. You will see both costs, and how the KV cache reduces the second, later in this track. Recurrent ideas have also returned: state space models such as Mamba (Gu and Dao, 2023) keep a fixed-size state, like an RNN, but are designed so that training can still run in parallel.

Key ideas

  • A recurrent network applies the same weights at every step and carries a hidden state forward, its only memory of the sequence so far.
  • Backpropagation through time unrolls the loop into a deep network; the gradient reaching an early step is a product of one factor per step in between.
  • Products of many factors shrink or grow exponentially. Vanishing gradients make long-range dependencies hard to learn; exploding gradients are tamed by clipping.
  • LSTM and GRU gates update a memory by addition, controlled by learned gates, so information and gradients can survive many steps.
  • Attention replaced the loop: every position reaches every earlier one directly, and training runs in parallel across the sequence.

Check yourself

Pick an answer to see why it is right or wrong. Nothing is graded. Your first answer is saved in this browser so the question can come back for review.

1In a plain recurrent network, the gradient that reaches a word 30 steps back is a product of 30 factors. If each factor is about 0.8, roughly how big is it?
2What makes an LSTM's memory cell better at preserving gradients than a plain RNN's hidden state?
3Why do transformers train faster than recurrent networks on long sequences, even with the same number of parameters?

Progress is saved in this browser only.

Up nextAttention, step by step
Next
Transformers and LLMs
  1. 1Predicting the next token
  2. 2Before transformers: recurrent networks
  3. 3Attention, step by step
  4. 4Many heads and the causal mask
  5. 5Where words are
  6. 6The transformer block
  7. 7Inside a real language model
  8. 8How LLMs are trained
  9. 9Where training data comes from
  10. 10Fine-tuning and LoRA
  11. 11Generating fast: the KV cache
  12. 12Quantization: smaller numbers
  13. 13How a chat assistant works

Try "embedding", "softmax", "overfitting", or "backpropagation".