Skip to content

Architectures Before Transformers

RNNs and LSTMs, the pre-transformer world

Processing sequences one step at a time

Before attention, models read a sentence strictly left to right through a single evolving memory - and the further back a word sat, the more surely it was forgotten.

For the decade before Transformers, a neural network that read text had no way to see a whole sentence at once. It processed one token at a time, folding each new word into a single fixed-size hidden state - a running summary of everything seen so far - and passing that summary forward to the next step. This is a recurrent neural network (RNN). The design is elegant and the failure is famous: by the time the model reaches the end of a long sentence, the beginning has faded almost to nothing, and the learning signal that should reconnect them vanishes on the way back. LSTMs patched the wound; attention removed it entirely. This lesson is the "before" picture that makes attention feel inevitable.

The one-line idea

An RNN is a loop with a memory. At every step it takes the previous memory plus the current word, mixes them, and writes a new memory: . The same weights are reused at every step, so the network is really one small cell run over and over - the sequence lives entirely inside how the hidden state evolves.

One token at a time: the hidden state

Give the model a vocabulary vector for the token at position and a hidden state carried in from the step before. The cell mixes them, squashes the result through a so values stay in , and emits . That is both the output at step and the memory handed to step . Start with and roll forward: knows the first word, knows the first two, and is supposed to know the whole sentence - all compressed into one vector of, say, a few hundred numbers. Nothing about the architecture reserves space for word 1 once word 40 arrives; older information simply gets overwritten as the state churns.

Learning across time: BPTT and the fading signal

To train the loop we unroll it into a deep feed-forward network - one layer per time step, all sharing the same weights - and run ordinary backpropagation along it. This is backpropagation through time (BPTT). The catch lives in the chain rule. To learn how an early word should influence a late prediction, the gradient must travel back across every step in between, and at each hop it is multiplied by the same recurrent Jacobian . Over steps that is roughly the factor raised to the : if the gradient shrinks geometrically toward zero - it vanishes; if it blows up - it explodes. Watch it happen.

RNN unroller - the vanishing gradient. Type a sentence, run the forward pass to fold it into one hidden state, then backpropagate and watch the learning signal fade before it reaches the first word.
λ ≈ 0.55
positive activationnegative activationgradient magnitude (flows backward)

Press Run forward to fold the sentence into the hidden state one token at a time. Then press Backpropagate and watch the learning signal fade as it travels back to the first word.

Why the signal dies: a product of Jacobians

The loss at the final step depends on an early hidden state through a chain of steps, so the chain rule stacks their derivatives into a product:

Because , each factor tends to contract. If the largest scale of the repeated factor is , the whole product behaves like : with it collapses to zero after a few dozen steps (vanishing), and with it detonates (exploding). Either way, gradients that must span long distances are unusable - the model can adjust its handling of nearby words but is nearly blind to how word 1 should shape word 40.

LSTMs & GRUs: a memory that survives

The fix, from Hochreiter & Schmidhuber, is to stop overwriting the memory on every step and instead gate it. An LSTM adds a second track, the cell state , that is updated additively rather than by a fresh matrix multiply: a forget gate decides how much of the old cell to keep, and an input gate decides how much new content to write. . The magic is the derivative along this track: , so whenever the network learns to hold a gate open () the local factor is and the gradient neither shrinks nor grows - a constant error carousel that carries the signal across hundreds of steps. A GRU is a lighter cousin with two gates instead of three and no separate cell state, but the same additive-highway idea. Toggle LSTM gates in the demo and re-run the backprop: the green pulse now reaches the first word almost intact.

The aha: addition, not multiplication

A vanilla RNN passes memory through a multiplicative gauntlet - one matrix per step - so gradients compound and detune. The LSTM cell state passes memory through an additive skip connection with a near-1 gate, so the default behaviour is "leave it alone." That is the same trick you will meet again as residual connections in Transformers: give the gradient a straight, un-multiplied path home. Gating did not make RNNs remember everything - it just bought enough range to be useful, at the cost that the sequence still had to be processed strictly in order.
import numpy as np

def rnn_step(h, x, Wh, Wx, b):
    return np.tanh(Wh @ h + Wx @ x + b)   # mix old memory h with new token x

h = np.zeros(D)
for x in sequence:                         # strictly one token at a time (sequential!)
    h = rnn_step(h, x, Wh, Wx, b)          # h carries everything seen so far

# BPTT multiplies the recurrent Jacobian once per step:
#   dL/dh_0  ~  prod_t ( diag(1 - h_t**2) @ Wh )     # tanh' = 1 - h**2
#   factor norm < 1  ->  gradient VANISHES over long spans
#   factor norm > 1  ->  gradient EXPLODES

# LSTM swaps the raw product for a gated, ADDITIVE cell state:
c = f * c_prev + i * g          # f = forget gate; f ~ 1  =>  dC_t/dC_(t-1) ~ 1
                                # a near-constant highway  =>  the signal survives
One RNN cell, unrolled - and where the gradient dies

The bottleneck Transformers escaped

Even a perfectly-tuned LSTM has one flaw it cannot gate away: step cannot begin until step is done. The recurrence is inherently sequential, so a thousand-token document is a thousand dependent steps - you cannot parallelize across the sequence, and training crawls. Attention (Lesson 31) breaks both curses at once: it lets every token look directly at every other token in a single parallel operation, with a constant-length path between any two positions. No loop, no recurrent Jacobian, no vanishing gradient, and the whole sequence computed at once on a GPU. Everything you just felt struggling here is exactly what attention was invented to fix.

Check yourself

In backprop through time the long-range gradient vanishes because its repeated per-step factor is:

The LSTM keeps long-range gradients alive mainly through its:

Why did vanilla RNNs struggle with long-range dependencies, and how did LSTMs help?

Try to state it, then check.

Lock it in

  • An RNN is a loop with memory, , reusing the same weights every step and folding each token into one fixed-size hidden state.
  • Training unrolls the loop (BPTT) and multiplies the recurrent Jacobian once per step, so the long-range gradient scales like - it vanishes when and explodes when .
  • LSTMs add an additive cell state gated by a forget gate: , so with the signal rides a constant error carousel across hundreds of steps.
  • Addition, not multiplication, is the trick - the same straight, un-multiplied gradient path you meet again as residual connections in Transformers.
  • Even a perfect LSTM is inherently sequential (step waits for ), so it cannot parallelize across the sequence; attention removes both the recurrence and the vanishing gradient at once.

Primary source

For the gate-by-gate diagrams that made LSTMs finally click for a generation of engineers, read Christopher Olah's Understanding LSTM Networks. For the sheer, surprising range of what a plain character-level RNN can do - and beautiful unrolled intuition - read Andrej Karpathy's The Unreasonable Effectiveness of Recurrent Neural Networks. Together they are the two texts that defined how this era was taught.

Ask your teacher

RNNs are why attention was invented. They processed text strictly in order and forgot the distant past, and no amount of gating fully cured either problem. Attention let every token see every other token in parallel - no recurrence, no vanishing gradient, and a constant-length path between any two words. Ask me how gradient clipping tamed the exploding side, why bidirectional and stacked RNNs helped, how a GRU differs from an LSTM in practice, or how the encoder-decoder RNN's single "thought vector" (next lesson) was the exact bottleneck that attention first bolted onto.