Recurrent language models
The MLP language model of §3.2 reads a fixed window of tokens with separate weights for each slot. Language does not respect windows. In "the keys that I left on the table by the door last night are gone", the verb agrees with keys, twelve words back, with a singular noun (night) right next to it. A 5-gram model cannot see it, and widening the window means more weights, separate for every position.
Here is a different design. Read the sentence one token at a time, like a person does, and keep a running summary in a vector. At each step, combine the summary so far with the new token to get the next summary, using the same function every time. The summary is a memory of unbounded history, and the parameters do not grow with sentence length. This is a recurrent neural network, the idea Elman (1990) made popular as the simple recurrent network, and the architecture that ruled language modeling from Mikolov et al. (2010) until the Transformer.
§0.8 sketched the recurrence, the product of Jacobians, and the gate in a few paragraphs. This section does it properly. It builds an RNN language model, derives backpropagation through time and checks it numerically, and then does the analysis every interviewer expects, namely why gradients through a recurrence vanish or explode, what the eigenvalues and singular values of the recurrent matrix have to do with it, and how the LSTM and GRU gates fix it. The linear algebra it leans on (eigendecomposition, spectral radius, singular values, and operator norms) is in §0.10.
A recurrent network reads one token at a time
At step the network looks up the embedding of the current token, and updates its hidden state ,
with , , and . To predict the next token it reads the state out through a softmax,
In plain words, the new memory is a squashed mix of the old memory and the new word, and the prediction is read off the memory. The loss is the same next-token cross-entropy as before, summed or averaged over all positions, so a sequence of tokens gives predictions and one loss.
Unrolled in time, the network is a very deep feed-forward network with one layer per token, and every layer shares the same weights.
target: w2 w3 w4
↑ ↑ ↑
softmax softmax softmax
↑ ↑ ↑
h0 ──W_hh──▶ h1 ──W_hh──▶ h2 ──W_hh──▶ h3
↑ ↑ ↑
W_xh W_xh W_xh
↑ ↑ ↑
input: w1 w2 w3
A scalar example shows what "memory" means. Take and feed in . Then , , , and . The single input echoes forward, halving at every step because the recurrent weight is 0.5. With a recurrent weight above 1 the echo would grow until the tanh caps it. Keep this picture in mind, because the whole vanishing-gradient story is this echo, run backward.
As in §3.2, the code stores each matrix transposed (Wxh has shape (d, dh)), so that row vectors and minibatches multiply on the left. The equations and the code compute the same thing.
Forward pass of an RNN language model
Implement rnn_forward(P, ids, h0). P holds E (V, d), Wxh (d, dh), Whh (dh, dh), bh (dh,), Why (dh, V), by (V,). The sequence ids has length . Feed tokens ids[0] to ids[T-1] as inputs, predict ids[1] to ids[T], and return (loss, H) where loss is the mean cross-entropy over the predictions and H stacks into shape (T, dh).
Backpropagation through time
To train the RNN we need the gradient of the loss with respect to the shared weights. Unroll the network over the sequence, and it is an ordinary computation graph, so ordinary backpropagation applies. Because the same appears at every step, its gradient is the sum of its gradients at every step. This is backpropagation through time (BPTT), named and explained by Werbos (1990).
The only new ingredient is that the hidden state influences the loss through two routes, through its own prediction at step and through the next state . So the error arriving at is a sum. Let , write for the predicted distribution at step and for its target (the token ), write for the error arriving at the state (the adjoint notation of §0.3), and let be the error at the pre-activation inside the tanh. Run the recursion backward from with ,
Then the weight gradients collect one outer product per step,
with , , and scatter-added into the embedding row of .
In plain words, walk backward through time carrying an error vector. At each step add the error from that step's own prediction, push the total back through the tanh, record outer products for the weights, and hand the error to the previous step through .
∂ Where the recursion comes from
Write for the pre-activation, so . The state affects only through (via the logits ) and through . By the multivariable chain rule, contributions along different routes add,
using the softmax-cross-entropy gradient and defining . The tanh acts elementwise with derivative , so .
For the weights, enters every , and . Summing over the steps where it is used gives . The same reasoning gives the other gradients. At the last step there is no future, which is why , and the gradient for the initial state is .
BPTT has a memory cost. The backward pass needs every , so a sequence of length stores hidden states per layer and per example. For a long stream of text, like a whole book, that is impossible. Truncated BPTT splits the stream into chunks of steps. The hidden state is carried forward from chunk to chunk, so the forward pass still sees the whole history, but gradients are stopped at chunk boundaries (in PyTorch, h = h.detach()). The cost is that the gradient cannot teach the model any dependency longer than steps, even though information can still flow forward further than that.
Backpropagation through time, checked numerically
Implement rnn_bptt(P, ids, h0) for the model of exercise 3.3a. Return (loss, grads), where loss is the mean cross-entropy and grads is a dict with the gradients of that mean loss for E, Wxh, Whh, bh, Why, by, and also h0. Every gradient is compared with finite differences.
Why gradients vanish or explode
This part of the story trips most people up, so let's go slowly. Look at how the error travels in the BPTT recursion. Ignoring the new error injected at each step, it is multiplied at every step by the transpose of
So the influence of the state steps back on the current state is a product of Jacobians,
In plain words, a signal from steps ago reaches the present only after being multiplied by and squashed by the tanh derivative times. A product of many matrices tends to shrink to nothing or blow up, and only a knife-edge in between keeps it stable.
Run the scalar echo from the start of the section backward to see it by hand. With the one-by-one Jacobian is . The states were , , , so , , and . The sensitivity of to is their product, , a little below the that the recurrent weight alone would give, because each tanh derivative shaves off a bit more. Going one step further back, to the input , multiplies by and leaves . Three steps cost a factor of twenty. Thirty steps would cost about .
The linear case is all about eigenvalues
Drop the nonlinearity for a moment, so and the product is . Suppose is diagonalizable (the eigendecomposition of §0.10), , with eigenvalues on the diagonal of . Then
Express any gradient vector in the eigenvector basis. Its component along eigenvector is multiplied by after steps. Let the spectral radius be . If , every component decays geometrically and the gradient from far in the past vanishes. If , the components along eigenvectors with grow geometrically and the gradient explodes. Pascanu, Mikolov, and Bengio (2013) state exactly this for the linear case. is sufficient for the long-term components to vanish, and is necessary for them to explode.
The numbers are brutal. With , a gradient 50 steps back is scaled by , and 100 steps back by . With , 50 steps back it is scaled by , and 100 steps back by about . Only very close to 1 gives anything usable, and training does not stay there by itself.
The tanh only makes vanishing worse
Now put the nonlinearity back. The tanh derivative lies in , equal to 1 only at and tiny when the unit saturates. Write for an upper bound on the derivative of the nonlinearity ( for tanh and for the logistic sigmoid) and for the largest singular value of . The operator norm (the largest factor by which can stretch a vector, which equals its largest singular value, see §0.10) is submultiplicative, , and a diagonal matrix stretches by at most its largest entry in absolute value, here at most . So
In plain words, each step can stretch the gradient by at most , so after steps by at most that number to the power . It follows that is sufficient for the gradient to vanish exponentially, and is necessary (but not sufficient) for it to explode. This is the theorem of Pascanu et al. (2013). It explains the observation of Bengio, Simard, and Frasconi (1994) and of Hochreiter's 1991 thesis that gradient descent struggles to learn long-term dependencies in recurrent networks.
Try three settings. With an orthogonal , inputs off (input scale 0), and or , the linear curve lies exactly on , the straight line on a log scale. Switch to a Gaussian with the same and the curve bulges above the line before falling, because is larger. Then raise the input scale. The tanh units saturate, the mean tanh derivative drops, and the tanh curve falls far below the linear one even when . In a saturating tanh network, vanishing is the common case and explosion needs large weights.
The linear column matches exactly, because an orthogonal matrix scaled by has every singular value equal to . The tanh column is far smaller in all three rows, because driven by inputs the units spend much of their time away from zero, where the derivative is less than one.
What does vanishing do to learning? The total gradient for is a sum over pairs of steps, a loss at step reaching back to a state at step . The terms with small are of ordinary size, and the terms with large are exponentially small. So the gradient is dominated by short-range dependencies, and the model learns local structure (spelling, short phrases) long before it learns anything that spans a clause, if it ever does. Exploding gradients do the opposite damage. A single huge step throws the parameters far away, and the loss spikes or becomes NaN.
Gradient clipping tames explosions
Explosions have a cheap fix that you already know from §0.6, clipping by global norm. If the norm of the whole gradient, taken over all parameters together, exceeds a threshold , rescale it to have norm , . The direction is kept and only the length of the step is capped. What is worth adding here is why recurrent networks need it so badly, because the reason is a picture.
Pascanu et al. (2013), who proposed norm clipping for RNNs, explained explosions as cliffs. A recurrent map can have several stable states (attractors), and a small change in the weights can move the trajectory from one basin to another. Near that boundary the final state, and so the loss, changes abruptly, so the loss surface has a nearly vertical wall with flat plateaus on either side. On the wall the gradient is huge. It is also only valid over a tiny distance, because it describes the wall's slope, not the plateau beyond it. A full gradient step there extrapolates the slope far past where it holds and throws the parameters somewhere arbitrary.
The smallest example is one unit with a self-weight of 2, which with no bias has two attractors near . Start it at , run it for 20 steps with a bias , and ask for . For small the state stays in the negative basin, for large it escapes to the positive one, and in between is the cliff.
Off the cliff the gradient is around a hundredth. On it, it is tens of thousands of times larger, and one unclipped step moves by about 30 when the whole interesting region is one unit wide. Clipping turns that step into an ordinary one in the same direction. In a real network with millions of weights the same thing happens along a few directions at a time, which is why training curves of RNNs (and of large Transformers) show sudden loss spikes, and why the norm before clipping is the number to log.
Two practical notes. The threshold is a hyperparameter, set relative to the typical gradient norm. Pascanu et al. suggested a value around the average norm over many updates, Sutskever, Vinyals, and Le (2014) clipped their translation model at 5, and large Transformer runs today clip at 1.0 (§8.8). And the norm must be global, over all parameters together, because clipping each tensor separately changes the direction of the update.
Clipping does nothing for vanishing gradients. You cannot rescale a gradient that carries no information about the distant past. Initialization helps a little. An orthogonal starts with every singular value at exactly 1 (Saxe, McClelland, and Ganguli 2014), and Le, Jaitly, and Hinton (2015) trained ReLU RNNs from an identity on tasks with long gaps. But training moves the weights off these points and the tanh still saturates, so initialization only delays the problem. A lasting fix needs a change of architecture.
The LSTM gives the gradient an additive path
The long short-term memory of Hochreiter and Schmidhuber (1997) attacks the product of Jacobians at its root. Instead of rewriting its memory at every step through a matrix and a squashing function, an LSTM keeps a separate cell state that is updated mostly by addition, and it uses learned gates (vectors of numbers between 0 and 1) to decide what to write, what to keep, and what to show.
At each step the LSTM computes four vectors from the current input and the previous hidden state, each with its own weights,
and then updates the cell and the hidden state,
Here each , each , and is the logistic sigmoid. In plain words, the cell is a notepad. The forget gate decides how much of the old note to keep, the input gate decides how much of the new candidate to add, and the output gate decides how much of the note to reveal as the hidden state that the rest of the network sees.
Now look at the gradient along the cell. Holding the gates fixed, , so
There is no weight matrix in this product and no tanh derivative. The gradient along the cell is scaled only by the forget gates, which the network itself controls. When it needs to remember something, it can hold and the gradient passes through many steps nearly undiminished. When it needs to forget, it closes the gate. In the original 1997 LSTM there was no forget gate at all, so the cell path was exactly the identity, which Hochreiter and Schmidhuber called the constant error carousel. The forget gate was added by Gers, Schmidhuber, and Cummins (2000) so that the network could also reset its memory.
The widget below is a single LSTM cell with its weights set by hand to count bracket depth. Its input gate opens on brackets, the candidate is for "(" and for ")", the forget gate is a constant set by its bias, and the output gate opens only on "?".
Play with three things. Load the "long gap" preset, three open brackets followed by forty distractors. With the default forget bias of 7 () the cell still holds a count of about 2.7 at the "?" (each bracket writes , and 41 steps of cost a few percent), and the product of forget gates (the gradient along the cell path) stays above 0.95. Lower the forget bias to 0, so every , and the count has leaked away after a few steps and the gradient product is around . Finally compare the cell with the plain tanh RNN row. The RNN state is squashed to at every step, so it cannot represent depth 4 differently from depth 2.
In practice the four gates' weights are stacked into single matrices so that one matrix multiply computes all of them. PyTorch's nn.LSTM stores weight_ih with shape (4 dh, d), weight_hh with shape (4 dh, dh), and two bias vectors, with the gates in the order input, forget, candidate, output. An LSTM layer therefore has parameters (PyTorch's two biases make it ), four times a plain RNN layer.
An LSTM cell, forward pass
Implement lstm_cell(x, h, c, W, U, b) for a batch. Shapes are x (B, d), h and c (B, dh), W (4 dh, d), U (4 dh, dh), and b (4 dh,). Compute the pre-activations as x @ W.T + h @ U.T + b, split them into four blocks of dh in the PyTorch order input, forget, candidate, output, and return (h_new, c_new).
Interviewers often follow "write the LSTM forward pass" with "now backpropagate through one cell". It is the same outer-product bookkeeping as BPTT, with one trap. The upstream gradient reaches the new cell by two routes, directly from the next step's cell and through .
∂ One LSTM cell, backward
Suppose the rest of the network hands back and along the direct cell route from step . A product of two vectors written side by side is elementwise ().
The cell, from both routes. gives , so the total error at the cell is
The four branches. From , . From , , , , and the error handed to the previous cell is . That last term is the additive cell path from above, , now as an explicit gradient.
Through the activations. The sigmoid has and the tanh has , so the errors at the four pre-activations are , , , and . Stack them in the order of the weight blocks into one vector .
The weights and inputs. The pre-activation is with the stacked and , so as for any linear layer, , , , , and (plus whatever receives from its own prediction). For a batch, sum the outer products over the batch.
Backpropagate through one LSTM cell
Implement lstm_cell_backward(x, h, c, W, U, b, dh_new, dc_new) for the cell of exercise 3.3d (same shapes and gate order). dh_new and dc_new, both (B, dh), are the gradients of the loss with respect to the cell's outputs h_new and c_new. Return a dict with the gradients for "x", "h", "c" (the previous state and cell), and "W", "U", "b", summed over the batch. Every gradient is checked against finite differences.
The GRU merges the gates
Cho et al. (2014) proposed a simpler gated unit in the same paper that introduced the RNN encoder-decoder (§3.5). They called it a new type of hidden unit, and Chung et al. (2014) named it the gated recurrent unit, or GRU. It has no separate cell and only two gates. With the update gate and the reset gate,
In plain words, the update gate interpolates between keeping the old state and replacing it with a candidate, and the reset gate decides how much of the old state the candidate may look at. When the state is copied forward and contains the term , an additive shortcut just like the LSTM cell. The GRU has three blocks of weights instead of four, so about 25% fewer parameters than an LSTM of the same width. Empirically the two are close. Jozefowicz et al. (2015) found the GRU slightly ahead of an LSTM with the default forget bias and roughly tied once the bias was set to 1, and Greff et al. (2017), in an extensive study of LSTM variants, found the forget gate and the output activation to be the most critical components.
A GRU cell, Cho et al. convention
Implement gru_cell(x, h, W, U, b) with the equations above. W has shape (3 dh, d), U has shape (3 dh, dh), and b has shape (3 dh,), with blocks in the order reset, update, candidate. Note that the reset gate multiplies before the candidate's matrix , and the update gate multiplies the old state.
Gates in action, measured
The cleanest way to see what gating buys is to measure the gradient directly. Below, a loss depends only on the last hidden state of a randomly initialized network, and we measure how large its gradient is with respect to the very first input as the sequence gets longer. This is the signal that would teach the network a dependency spanning the whole sequence.
The plain RNN's gradient falls by many orders of magnitude between 5 and 50 steps, the vanishing gradient in its rawest form. An LSTM with a zero forget bias does barely better, since is a leaky memory. A bias of 1 () decays much more slowly but still vanishes by 100 steps, which is fine as a starting point because training can raise the bias where memory pays. With the forget bias at 3 () the gradient stays of order one over 100 steps. That last row is more than the cell path alone explains, since . The rest arrives along the other paths of the derivation above (through and the gates), which at a random initialization can amplify as well as shrink, so read the table as a measurement rather than a formula. The architecture did not solve the problem by itself. It gave the network a knob, the forget gate, that can solve it.
Training an RNN language model the real way
Here is the complete training loop for a character-level LSTM language model with truncated BPTT, the recipe behind Karpathy's famous char-rnn experiments (Karpathy 2015) and Graves's (2013) handwriting and text generation. The stream is cut into chunks of characters. The hidden state is carried across chunks but detached, and the gradient's global norm is clipped.
Within 200 steps the loss falls from about to below 0.2, and the samples are mostly well-formed sentences of the toy language with the occasional misspelling. Run the same loop for longer on Shakespeare, Wikipedia, or the Linux source code, as Karpathy did, and the samples become convincing pastiches with balanced brackets and plausible indentation. Karpathy, Johnson, and Fei-Fei (2015) then looked inside such models and found individual cells with readable jobs, one tracking whether the text is inside a quotation, one the position along a line, one the nesting depth of code. The bracket-counting cell of the widget above is the hand-built version of what these networks learn on their own.
Three details in this loop are easy to get wrong in an interview. The state must be detached at every chunk boundary, or the graph grows forever and memory explodes. The streams must be laid out so that chunk of row continues chunk of row , otherwise carrying the state is meaningless. And clipping happens after backward and before step.
Stacking layers and regularizing them
Real recurrent language models have more than one layer. A stacked RNN feeds each layer's hidden states to the next layer as its inputs at the same time step. Writing for the state of layer at step , with ,
and the softmax reads the top layer (the same stacking works with LSTM or GRU cells). In plain words, depth in this direction adds computation at every step without making the path through time any longer. Two to four layers was typical. Sutskever et al. used four in their translation model (§3.5), and ELMo uses two (§3.4). In PyTorch this is the num_layers argument.
Large LSTM language models overfit quickly, and the obvious regularizer goes wrong. Dropout with a fresh mask at every step on the recurrent connection corrupts the memory over and over, so information cannot survive many steps. Zaremba, Sutskever, and Vinyals (2014) showed that dropout works well if it is applied only to the non-recurrent connections (on the embeddings, between layers, and before the softmax). PyTorch's nn.LSTM(..., num_layers=2, dropout=0.3) does the between-layer part, and you add the other two yourself. Gal and Ghahramani (2016) then showed that the recurrent connections can be dropped too, as long as the same mask is reused at every step of a sequence (variational dropout). AWD-LSTM combined that with DropConnect on the recurrent matrix itself, a mask on the entries of drawn once per batch, and with tying the softmax weights to the embedding table (§3.2). Those choices, not a new cell, produced its record perplexities.
| unit | memory update | path for the gradient | parameters per layer | notes |
|---|---|---|---|---|
| tanh RNN | product of | vanishes or explodes, needs clipping | ||
| LSTM | product of forget gates | separate cell, forget bias near 1 | ||
| GRU | product of update gates | fewer parameters, similar quality |
Gating solved the vanishing gradient well enough that LSTMs dominated language modeling, speech recognition, and translation for most of the 2010s. Two problems remained, and they will drive the rest of this chapter. First, the whole history still has to fit into one fixed-size vector. Second, step cannot be computed until step is done, so training cannot be parallelized across the sequence, which is why the Transformer of Chapter 5 won once hardware made parallelism the main currency. The recurrence itself has made a comeback in linear-time sequence models, where the same eigenvalue analysis returns as the stability condition of state-space models that keep a recurrent state but train in parallel.
Read more
- Elman (1990). Finding Structure in Time. The simple recurrent network and what its hidden states learn about language.
- Mikolov et al. (2010). Recurrent Neural Network Based Language Model. The paper that made RNN language models practical.
- Pascanu, Mikolov, and Bengio (2013). On the Difficulty of Training Recurrent Neural Networks. The eigenvalue and singular value analysis, and gradient norm clipping. Read Section 2.
- Hochreiter and Schmidhuber (1997). Long Short-Term Memory, and Gers, Schmidhuber, and Cummins (2000), Learning to Forget. The constant error carousel, then the forget gate.
- Zaremba, Sutskever, and Vinyals (2014). Recurrent Neural Network Regularization. Dropout on the non-recurrent connections only, the recipe for large LSTM language models.
- Jozefowicz, Zaremba, and Sutskever (2015). An Empirical Exploration of Recurrent Network Architectures. Ten thousand architectures, and the forget-bias result. Jozefowicz et al. (2016), Exploring the Limits of Language Modeling, is the LSTM at its largest.
- Karpathy (2015). The Unreasonable Effectiveness of Recurrent Neural Networks. Character-level LSTMs writing Shakespeare, LaTeX, and C. Karpathy, Johnson, and Fei-Fei (2015), Visualizing and Understanding Recurrent Networks, finds the interpretable cells.
- Olah (2015). Understanding LSTM Networks. The gates drawn one at a time, the clearest picture of the cell. Chapter 14 of Jurafsky and Martin (in the reading list of §3.4) is the textbook version.