Visualize how memory is passed forward to perform Sentiment Analysis (a Sequence-to-Vector task).
Standard neural networks have a major limitation: they have no memory of the past. They process each input independently. This is a problem for language, where the order of words is crucial. For example, "dog bites man" and "man bites dog" use the same words but have completely different meanings.
Recurrent Neural Networks (RNNs) solve this by introducing a memory loop. As an RNN reads a sentence word by word, it passes a summary of what it has seen so far to the next step. This summary is called the hidden state.Discover how Recurrent Neural Networks (RNNs) use an internal memory loop to understand the order and context of words in a sentence.
The visualization above "unrolls" the RNN loop, showing it as a sequence of identical cells, one for each word (or "time step"). Here’s how the information flows:
A crucial concept in RNNs is shared weights. The same set of calculations (the same "brain") is used at every single time step. This is incredibly efficient. Instead of learning a new set of rules for the first word, second word, etc., the RNN learns a single set of rules for how to update its memory based on a new word and its previous memory. The "Parameters" calculation in the visualization shows the size of these shared weights.
A recurrent network processes a sequence step by step. At each step it combines the current input with what it remembers from before:
hᵗ = tanh(Wₕₕ hᵗ₋₁ + Wₓₕ xᵗ + b)
hₜ is the hidden state — a fixed-size vector summarising everything seen so far. xₜ is the current word's embedding. The same weight matrices are used at every step, which is parameter sharing along the time axis.
Walking through "the cat sat":
| Step | Input | State contains |
|---|---|---|
| 1 | "the" | A determiner has appeared |
| 2 | "cat" | A noun phrase, subject-like |
| 3 | "sat" | A subject and its verb |
Each state is a function of the current word and the previous state, so information propagates forward by being repeatedly transformed.
That single design choice — one weight matrix reused at every step — is what lets an RNN handle sequences of any length with a fixed number of parameters.
| Shape | Input → output | Example |
|---|---|---|
| Many-to-one | Sequence → one label | Sentiment classification |
| Many-to-many, aligned | Sequence → sequence of the same length | Part-of-speech tagging |
| Many-to-many, unaligned | Sequence → different-length sequence | Translation (encoder-decoder) |
| One-to-many | One input → sequence | Image captioning |
For classification, use the final hidden state — or better, pool over all states, since the final one is biased towards the end of the sequence.
For an encoder-decoder, the encoder's final state is the "thought vector" passed to the decoder. That design is exactly where attention was invented: compressing a whole sentence into one fixed vector is a bottleneck, and letting the decoder look back at every encoder state instead removed it.
Vanishing gradients. Backpropagation through 50 steps multiplies 50 Jacobian factors. If they average below 1, the gradient reaching step 1 is effectively zero, so the network cannot learn that step 1 mattered. Tanh's derivative is at most 1 and usually well below it, so decay is the default.
No parallelism. Step t needs hₜ₋₁, so the steps must run in order. A GPU's thousands of cores sit mostly idle, and training time scales with sequence length. This is a hardware-utilisation problem, and it is the reason transformers displaced RNNs at scale rather than any single quality issue.
The first was addressed by gating (LSTM, GRU). The second was not addressable within the recurrent framework at all — which is why the field moved to attention.
An RNN reads one token at a time and updates one state. Where you take the output from decides whether you have a classifier, a tagger, a generator or a translator -- four architectures from the same loop.
Use the simulation to see how an RNN performs sentiment analysis (classifying a sentence as positive or negative):
RNNs are designed for sequential data like text. Their core feature is the hidden state, a memory that is passed through time, allowing the network to remember previous inputs and understand context. By using shared weights, they can efficiently process sequences of any length, making them a cornerstone of modern Natural Language Processing.
Training an RNN means unrolling it. A 50-word sentence becomes a 50-layer feed-forward network that happens to share weights, and ordinary backpropagation is applied to that unrolled graph.
The gradient for a shared weight is the sum of its gradients from every time step, since it was used at all of them.
Two practical consequences:
Memory grows with sequence length, because every step's activations must be stored for the backward pass. Long sequences exhaust memory quickly.
Truncated BPTT is the standard remedy: backpropagate only k steps back (typically 20–50) rather than to the beginning. It bounds memory and compute, at the cost of not learning dependencies longer than k.
Gradient clipping is essentially mandatory here. The same multiplication that vanishes gradients can explode them, and a single large gradient destroys the weights in one step.
import torch.nn as nn
rnn = nn.LSTM(300, 256, batch_first=True) # prefer LSTM/GRU over nn.RNN
out, (h, c) = rnn(packed_input)nn.RNN — the plain version — is almost never the right choice; use an LSTM or GRU, which cost little more and train far better.
Three details that matter with real text:
Pack variable-length sequences. pack_padded_sequence tells the RNN to stop at each sequence's real end. Without it, the final hidden state summarises the padding rather than the sentence.
Sort or bucket by length when batching, so batches contain similar lengths and less padding is wasted.
Consider bidirectionality for classification and tagging — running one RNN forward and another backward and concatenating gives each position both left and right context. Not available for generation or streaming.
Are RNNs still used? Yes, in streaming inference with bounded memory, on-device models, small datasets and classical time-series work. Not for large-scale language modelling.
Why does the same weight matrix apply at every step? Parameter sharing along time — the same reason a convolution shares filters across space. It lets one model handle any length.
How long a sequence can an LSTM handle? Hundreds of steps in practice; thousands is unreliable. Transformers handle far longer, at quadratic cost.
What is the hidden state size? A hyperparameter, typically 128–512. Larger means more memory capacity and more parameters.
Can I stack RNN layers? Yes, and two is usually the practical limit — deeper stacks are hard to train.
Why did transformers replace them? Parallelism across the sequence and constant path length between positions. Both are structural advantages that gating cannot provide.
Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.
What does this module say about “The Power of Memory in Language”?
Standard neural networks have a major limitation: they have no memory of the past. They process each input independently. This is a problem for language, where the order of words is crucial. For example, "dog bites man" and "man bites dog" use the same words but have completely different meanings.
What does this module say about “The Unrolled RNN: Step-by-Step Processing”?
The visualization above "unrolls" the RNN loop, showing it as a sequence of identical cells, one for each word (or "time step"). Here’s how the information flows:
What does this module say about “Shared Weights: The Key to Learning”?
A crucial concept in RNNs is shared weights . The same set of calculations (the same "brain") is used at every single time step. This is incredibly efficient. Instead of learning a new set of rules for the first word, second word, etc., the RNN learns a single set of rules for how to update its memory based on a new word and its previous memory.
Standard neural networks have a major limitation: they have no memory of the past. They process each input independently. This is a problem for language, where the order of words is crucial. For example, "dog bites man" and "man bites dog" use the same words but have completely different meanings.