Backpropagation Through Time › Unrolling the RNN
Language AI HandbookAll chapters Backpropagation Through Time › Unrolling the RNNOne section · Sections in this chapter2 / 15 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
To understand BPTT, you first need a clear picture of what "unrolling" means, why it is conceptually useful, and what it costs in terms of computation and memory.
A standard RNN update at timestep is:
where:
- : the hidden state at timestep , a -dimensional vector that summarizes sequence history up to that point
- : the hidden state at the previous timestep, carrying information forward
- : the recurrent weight matrix, applied to the previous hidden state at every step
- : the input weight matrix, mapping inputs to the hidden space
- : the input vector at timestep
- : the bias vector
- : the hyperbolic tangent activation applied elementwise, squashing values to
This equation describes a computation that is deeply self-referential: to compute , you need . To compute , you need . The chain extends all the way back to , the initial hidden state (typically a zero vector). This is why RNNs are powerful: they can, in principle, let information from the very beginning of a sequence influence predictions at the very end.
From Loop to Graph
When you express an RNN as a recurrence relation, you are describing a loop: the same operation executed repeatedly, each time consuming the hidden state from the previous iteration. This compact representation is convenient for describing the model, but it is not the right representation for computing gradients.
Gradient computation requires a directed acyclic graph (DAG). The chain rule can only traverse a graph that does not have cycles, because cycles would create circular dependencies in the gradient equations. An RNN's loop is inherently cyclic: depends on which depends on , and so on. The way to resolve this is to expand the loop along the time dimension and treat each step as a distinct node in the graph.
Unrolling makes this expansion explicit. Instead of showing the RNN as a loop that re-uses a single node, you draw out a separate copy of the computation for each timestep. For a sequence of length , you get a graph with hidden state nodes connected in a chain: . Each node receives the previous hidden state and the current input and produces the next hidden state. The weight matrices and are shared across all copies, meaning they are the same physical parameters, but the intermediate values they produce at each step are all distinct and stored separately.
This is an important subtlety. Unrolling does not create new parameters; it creates new nodes in the computation graph that reference the same parameters. The implication for gradient computation is that each weight participates in computation paths, and its total gradient must account for all of them.
Outputs and the Loss Function
An output is computed from at each timestep (or at the final timestep only, depending on the task):
where:
- : the output weight matrix, mapping hidden state to output space (e.g., a vocabulary in language modeling)
- : the output bias
- : the output dimensionality (e.g., vocabulary size)
In many applications, an output is produced at every timestep. Language modeling is the canonical example: at each position in a sentence, the model predicts the next word. In sequence classification, outputs are produced only at the final step. In sequence-to-sequence models, outputs appear only during the decoding phase. BPTT applies in all of these cases, though the gradient structure differs slightly depending on where losses originate.
The total loss over a sequence is the sum of per-timestep losses:
where:
- : total sequence loss
- : loss at timestep , measuring prediction error at that step
- : sequence length
The additivity of the loss is important: it means the gradient of the total loss is the sum of gradients from each individual timestep. Each only directly depends on , which depends on . But is a function of all earlier hidden states and therefore of all earlier inputs and all applications of . So even though does not directly reference steps before , its gradient with respect to reaches all the way back through the entire history.
Unrolling converts the implicit loop of an RNN into an explicit feedforward computation graph. Each timestep becomes a distinct layer in this expanded graph. the same weight matrices appear at every layer, which means their gradients must be summed across all positions.