RNNs, LSTM, and GRU
Processing sequences — from vanilla RNNs to gated architectures
The Sequential Data Problem
Many problems involve sequences: text, speech, time series, video. Standard neural networks fail because:
- Variable length: Sentences have different numbers of words
- Order matters: "dog bites man" ≠ "man bites dog"
- Long-range dependencies: "The cat, which sat on the mat, was..."
Why MLPs Fail
- Fixed input size (can't handle variable length)
- No parameter sharing across positions
- No notion of temporal order
Vanilla RNN
RNNs maintain a hidden state that gets updated at each timestep, creating a "memory" of previous inputs.
Architecture
At each timestep
Where:
= input at time = hidden state at time = output at time = weight matrices (shared across time)
Parameter Sharing
The same weights are used at every timestep — this is what enables handling variable-length sequences.
Backpropagation Through Time (BPTT)
Unroll the RNN and apply standard backpropagation:
x₁ → x₂ → x₃ → ... → xₜ
↓ ↓ ↓ ↓
h₁ → h₂ → h₃ → ... → hₜ
↓ ↓ ↓ ↓
y₁ y₂ y₃ yₜGradient flows backward through all timesteps.
The Vanishing Gradient Problem in RNNs
RNNs struggle with long sequences because gradients vanish (or explode) over many timesteps.
Why Gradients Vanish
The gradient from timestep
Each term
- If largest eigenvalue of
< 1: gradients shrink exponentially - If largest eigenvalue of
> 1: gradients explode

Consequence
Early timesteps receive near-zero gradients — the RNN can't learn long-range dependencies. "The cat [100 words later] was hungry" — RNN forgets about "cat."
LSTM: Long Short-Term Memory
LSTMs solve vanishing gradients with a cell state that acts as a highway for gradient flow, controlled by gates.
Architecture
Three gates + cell state:
- Forget gate
: What to discard from cell state - Input gate
: What new information to add - Output gate
: What to expose to the next layer
LSTM Equations
Forget gate (what to forget):
Input gate (what to update):
Candidate values (new information):
Cell state update:
Output gate (what to expose):
Hidden state:
Why LSTM Solves Vanishing Gradients
The cell state update is additive:
Gradient through cell state:
If
GRU: Gated Recurrent Unit
GRU simplifies LSTM with 2 gates instead of 3, and no separate cell state.
Architecture
Reset gate (how much past to forget):
Update gate (how much to update):
Candidate hidden state:
Final hidden state:
LSTM vs GRU
| Aspect | LSTM | GRU |
|---|---|---|
| Gates | 3 (forget, input, output) | 2 (reset, update) |
| States | Cell state + hidden state | Hidden state only |
| Parameters | More (~4x hidden²) | Fewer (~3x hidden²) |
| Performance | Often better for complex sequences | Comparable, sometimes better |
| Training speed | Slower | Faster |
Rule of thumb: Start with GRU (faster), try LSTM if GRU underperforms.
Bidirectional RNNs
Process sequence in both directions to capture future context:
Forward: h₁ → h₂ → h₃ → ... → hₜ
Backward: h₁ ← h₂ ← h₃ ← ... ← hₜ
Output: [h₁→;h₁←] [h₂→;h₂←] ...When Bidirectional Helps
- NLP: Understanding "bank" requires future context ("river bank" vs "bank account")
- Speech: Pronunciation depends on following sounds
- NOT for: Real-time prediction (can't see future)
RNNs vs Transformers
| Aspect | RNNs | Transformers |
|---|---|---|
| Processing | Sequential (can't parallelize) | Parallel (all positions at once) |
| Complexity | O(T) sequential steps | O(T²) attention, but parallelizable |
| Long-range | Struggles despite gates | Direct attention to any position |
| Memory | O(1) hidden state size | O(T) keys/values |
| Inductive bias | Sequential, local | None (learns from data) |
Where RNNs Still Matter
- Streaming/online: Process tokens one at a time
- Edge devices: Lower memory than storing all keys/values
- Very long sequences: Linear complexity vs O(T²) attention
- Causal modeling: Natural fit for sequential generation
Reality: Transformers have largely replaced RNNs for NLP, but RNNs remain relevant for specific use cases.
Implementation Tips
Gradient Clipping
Essential for RNN training:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)Packed Sequences
Handle variable-length sequences efficiently:
packed = nn.utils.rnn.pack_padded_sequence(x, lengths, batch_first=True)
output, hidden = rnn(packed)
output, _ = nn.utils.rnn.pad_packed_sequence(output, batch_first=True)Dropout for RNNs
Apply dropout to non-recurrent connections:
nn.LSTM(input_size, hidden_size, dropout=0.2) # between layersInterview Questions
Q1: "Explain why LSTMs solve the vanishing gradient problem."
The cell state acts as a gradient highway.
In vanilla RNNs, gradients multiply through
at each timestep. If eigenvalues < 1, gradients vanish exponentially. In LSTMs, the cell state update is additive:
The gradient through cell state:
When
(forget gate open), gradients pass through unchanged. Over many timesteps: Key insight: The forget gate learns which information to preserve, allowing gradients to flow to early timesteps. It's not that gradients can't vanish — but the network can learn to keep them flowing for important information.
Q2: "What's the difference between LSTM and GRU?"
LSTM has 3 gates and separate cell/hidden states:
- Forget gate: What to discard from cell
- Input gate: What new info to add
- Output gate: What to expose as hidden state
- Cell state: Long-term memory (gradient highway)
GRU has 2 gates and only hidden state:
- Reset gate: How much past to forget for candidate
- Update gate: Interpolate between old and new state
- No separate cell state
Practical differences:
- GRU has fewer parameters (3x vs 4x hidden²)
- GRU trains faster
- LSTM may capture more complex dependencies
- Performance is often similar
When to choose:
- Start with GRU (simpler, faster)
- Try LSTM if GRU underperforms
- For very complex sequences, LSTM may be better
Q3: "When would you still use RNNs over Transformers?"
Use RNNs when:
Online/streaming processing: Need to process tokens one at a time as they arrive (real-time speech, live transcription). Transformers need all tokens to compute attention.
Very long sequences: Transformer attention is O(T²). For sequences of 100K+ tokens, RNNs with O(T) complexity may be more practical. (Though efficient transformers like Longformer exist.)
Edge deployment: RNN hidden state is fixed size. Transformers store O(T) keys/values, which grows with sequence length.
Causal modeling: RNNs have natural sequential inductive bias, which may help with limited data.
Reality: Transformers dominate most NLP tasks. RNNs are still used in niche applications (streaming, embedded systems) and sometimes combined with transformers (transformer encoders + RNN decoders).
Key Takeaways
RNNs process sequences with shared weights and hidden state memory.
Vanilla RNNs suffer from vanishing gradients — can't learn long-range dependencies.
LSTM's cell state is a gradient highway — forget gates control what gradients flow through.
GRU is simpler than LSTM (2 gates vs 3) with comparable performance.
Bidirectional RNNs capture both past and future context.
Transformers have largely replaced RNNs but RNNs remain relevant for streaming and edge applications.