Backprop through time
A recurrent neural network (RNN) reads a sentence one word at a time. At each step it combines the vector for the current word with its hidden state, a short list of numbers that summarizes the words read so far, and it uses the same weights at every step. To train an RNN as a language model on "we sat on the bank of the river", we need to know how each weight should change so that "river" becomes more likely after "we sat on the bank of the". We'll unroll the network into a deep feed-forward network, run backpropagation through it, and then follow the gradient from "river" back to "we" in a network small enough to compute by hand.
Training needs a gradient for every weight
The RNN computes each new state from the vector of word and the previous state :
The matrix weighs the word, weighs the previous state and is a bias. The hyperbolic tangent, , squashes each number of the sum into the range from to , and the state starts at . After the seventh word, an output layer turns into a probability for every word in the vocabulary. With the context = "we sat on the bank of the", the loss for this prediction is the negative log probability of the correct word:
Training lowers by gradient descent. Each weight moves a small step against the derivative of the loss, scaled by a learning rate :
In a feed-forward network, backpropagation computes these derivatives [1]. A forward pass computes the output of every layer. A backward pass then applies the chain rule from the loss down through the layers, and each layer reuses the gradient already computed for the layer above it. An RNN has a loop where a feed-forward network has a stack of layers, so before we can run backpropagation we have to turn the loop into layers.
An unrolled RNN is a deep feed-forward network
We can draw a separate copy of the RNN step for every word. Each copy takes the state from the copy before it and passes its own state to the next, and the loop becomes a chain:
The chain is a feed-forward network with one layer per word: seven layers between "we" and the prediction of "river", and fifty for a sentence of fifty words. Two things set it apart from an ordinary deep network. Every layer reads an input of its own, the vector of its word. And every layer uses the same , and , where an ordinary network has separate weights in each layer.
Backpropagation through time
Running backpropagation on the unrolled chain is called backpropagation through time (BPTT) [2]. The forward pass runs the RNN over the sentence and keeps every state, to , along with the loss. The backward pass starts from the gradient of the loss with respect to the last state, , and moves one step to the left at a time:
Each step back multiplies the gradient by the derivative of one state with respect to the state before it. When the network predicts a word at every step, as a language model does, each step also adds the gradient of its own loss before passing the sum further back.
The derivative at each step depends on that step's state, so the backward pass needs every state the forward pass computed, and memory grows with the length of the text. On long texts a common compromise is truncated BPTT: the backward pass stops after a fixed number of steps, while the forward pass keeps carrying the state forward.
Shared weights add up their gradients
Because acts at all seven steps, the loss depends on it seven times. We can compute the gradient as if every step had its own copy , exactly as backpropagation would for a deep network with separate layers, and then add the gradients of the copies:
The gradients of and are sums over the steps in the same way. One update then changes the single shared matrix, so the copies stay identical. The part for step is built from the gradient that reached that step, . For , the part for step 1 is where "we" enters the update, and it can only be as large as the gradient that made it back from to .
Each step back multiplies by one factor
To see how much gradient reaches the early steps, we can shrink the network until the state and each word's vector are single numbers. With weights and and no bias, the step is
The derivative of is , so one step back multiplies the gradient by
The factor is the recurrent weight times the slope of at that step. The slope is when the state is and falls toward as the state nears or . Going from back to takes six steps, so the gradient picks up six factors:
Following the gradient from "river" back to "we"
Take and , and give each word one number:
The first state depends only on "we", and the second adds "sat" to what the first carried forward:
Continuing through "on the bank of the" gives the seven states in the boxes below. The factor between and is , and the red numbers are the factors for every step:
The states stay well inside the range of , so its slope stays close to and every factor lands just under . Multiplying the six factors gives the gradient that reaches :
Every step back roughly halves the gradient. After one step it is of what it was at , after three steps , and by the time it reaches the state after "we", :
Vanishing and exploding gradients
Nothing in this calculation is special to seven words. The gradient that travels steps back is a product of factors, so it changes exponentially with the distance. If every factor were or :
A gradient that shrinks toward zero over many steps is a vanishing gradient, and one that grows without bound is an exploding gradient. A 1994 analysis showed that gradient descent has an increasingly hard time learning a dependency as the number of steps it spans grows [3].
With vector states, each factor is a matrix, the derivative . It multiplies by the slope of for each number of the state, and those slopes are at most . If the largest eigenvalue of is smaller than in absolute value, the long-range parts of the gradient vanish, and they can explode only if it is larger than [4]. Weights that start small fall in the first case. The states also push toward it: whenever a number of the state nears or , its slope, and with it the factor, drops toward .
Clipping caps exploding gradients
An exploding gradient is the easier failure to see. One enormous gradient can throw the weights far from where training had brought them. A simple fix is gradient norm clipping [4]. Before each update, if the length of the gradient exceeds a threshold , we scale it back to length :
For the length is . With , clipping gives , which points the same way:
The update keeps its direction and takes a bounded step. The 2013 paper that proposed this rule built on an earlier version from work on RNN language models, which clipped each number of the gradient separately. Its authors suggest choosing by looking at the average length of the gradient over many updates, and report that training is not very sensitive to the exact value.
Early words stop influencing learning
Clipping only shortens a gradient that is too long. A vanished gradient is too short, so there is nothing to clip, and scaling the whole gradient up would not change how little of it comes from the early steps. In our network the gradient from "river" reaches the state after "we" at of its size at the last step. The parts of the update that come from the early steps are correspondingly small, and the sum is dominated by the last few words. Training learns how "bank of the" predicts "river" and gets almost no signal about "we sat on", the words that make this a bank someone sits beside. Truncated BPTT cuts the early words off at a fixed distance; vanishing gradients fade them out over a few steps even when the backward pass runs the full length of the sentence.
References
- Rumelhart, D. E., Hinton, G. E., & Williams, R. J. (1986). Learning representations by back-propagating errors. Nature 323. doi:10.1038/323533a0 ↩
- Werbos, P. J. (1990). Backpropagation through time: what it does and how to do it. Proceedings of the IEEE 78(10). doi:10.1109/5.58337 ↩
- Bengio, Y., Simard, P., & Frasconi, P. (1994). Learning long-term dependencies with gradient descent is difficult. IEEE Transactions on Neural Networks 5(2). doi:10.1109/72.279181 ↩
- Pascanu, R., Mikolov, T., & Bengio, Y. (2013). On the difficulty of training recurrent neural networks. Proceedings of the 30th International Conference on Machine Learning. proceedings.mlr.press ↩
Want to keep up with AI? Follow us on X (opens in a new tab) and Instagram (opens in a new tab), or check out our shirts.