RNN & LSTM Cheat Sheet β€” Recurrent Networks, Gates, GRU, Bidirectional Dataplexa
RNN & LSTM icon

RNN & LSTM

sequence Β· gates Β· vanishing gradient Β· GRU Β· bidirectional Β· seq2seq Β· attention

Sheet 3 of 4 Deep Learning Intermediate Printable

What Is an RNN?

Foundations

A Recurrent Neural Network (RNN) processes sequential data by maintaining a hidden state that carries information from previous time steps β€” giving the network a form of memory.

Vanilla RNN Equations
hβ‚œ = tanh(Wβ‚• Β· hβ‚œβ‚‹β‚ + Wβ‚“ Β· xβ‚œ + b) Ε·β‚œ = Wα΅§ Β· hβ‚œ + bα΅§
hβ‚œ = hidden state Β· xβ‚œ = input Β· Ε·β‚œ = output Β· W = weight matrices
RNN ModeInput β†’ OutputExample Use
One-to-One1 β†’ 1Standard classification
One-to-Many1 β†’ sequenceImage captioning
Many-to-OneSequence β†’ 1Sentiment analysis
Many-to-Many (sync)Seq β†’ Seq (same len)POS tagging
Many-to-Many (async)Seq β†’ Seq (diff len)Machine translation

Vanishing Gradient Problem

Key Challenge

During backpropagation through time (BPTT), gradients are multiplied by weight matrices at each step. With long sequences, gradients shrink exponentially β€” early time steps receive near-zero updates.

Gradient Magnitude Over T Steps
βˆ‚L/βˆ‚hβ‚€ = ∏ᡒ (βˆ‚hα΅’/βˆ‚hᡒ₋₁) Β· βˆ‚L/βˆ‚hα΅€
If βˆ‚hα΅’/βˆ‚hᡒ₋₁ < 1 repeatedly β†’ gradient β†’ 0 (vanishing)
ProblemFix
Vanishing gradientLSTM / GRU gating Β· ReLU activations Β· gradient clipping
Exploding gradientGradient clipping Β· weight regularization
Long-range dependenciesLSTM Β· Attention Β· Transformers
Slow trainingTruncated BPTT Β· smaller sequence chunks
Gradient Clipping (Keras)
optimizer = keras.optimizers.Adam(
 learning_rate=1e-3,
 clipnorm=1.0 # clip gradient norm to 1
)

LSTM β€” Long Short-Term Memory

Gate Equations

LSTM introduces a cell state (Cβ‚œ) β€” a conveyor belt running through the sequence β€” protected by three learnable gates that control information flow.

LSTM Gate Equations
Forget fβ‚œ = Οƒ(WfΒ·[hβ‚œβ‚‹β‚, xβ‚œ] + bf) Input iβ‚œ = Οƒ(WiΒ·[hβ‚œβ‚‹β‚, xβ‚œ] + bi) Cell CΜƒβ‚œ = tanh(WcΒ·[hβ‚œβ‚‹β‚, xβ‚œ] + bc) Output oβ‚œ = Οƒ(WoΒ·[hβ‚œβ‚‹β‚, xβ‚œ] + bo) Cβ‚œ = fβ‚œ βŠ™ Cβ‚œβ‚‹β‚ + iβ‚œ βŠ™ CΜƒβ‚œ hβ‚œ = oβ‚œ βŠ™ tanh(Cβ‚œ)
Οƒ = sigmoid (0–1 gate) Β· tanh = cell/hidden Β· βŠ™ = element-wise multiply

What Each Gate Does

GateControlsValue
Forget (fβ‚œ)How much of old cell state Cβ‚œβ‚‹β‚ to keep0 = forget all Β· 1 = keep all
Input (iβ‚œ)How much new info CΜƒβ‚œ to write to cell0 = write nothing Β· 1 = write all
Cell (CΜƒβ‚œ)Candidate new info from current inputβˆ’1 to +1 (tanh range)
Output (oβ‚œ)How much cell state to expose as hidden hβ‚œ0 = hide Β· 1 = expose
LSTM in Keras
# Return last hidden state only
keras.layers.LSTM(128)

# Return all hidden states (for seq2seq)
keras.layers.LSTM(128, return_sequences=True)

# Return state + sequences
keras.layers.LSTM(128,
 return_sequences=True,
 return_state=True)

# Stack two LSTM layers
keras.layers.LSTM(128, return_sequences=True),
keras.layers.LSTM(64)

GRU β€” Gated Recurrent Unit

Simplified LSTM

GRU merges the forget and input gates into a single update gate and removes the separate cell state β€” simpler, faster, often matches LSTM performance.

GRU Equations
Reset rβ‚œ = Οƒ(WrΒ·[hβ‚œβ‚‹β‚, xβ‚œ]) Update zβ‚œ = Οƒ(WzΒ·[hβ‚œβ‚‹β‚, xβ‚œ]) New Γ±β‚œ = tanh(WnΒ·[rβ‚œβŠ™hβ‚œβ‚‹β‚, xβ‚œ]) hβ‚œ = (1βˆ’zβ‚œ)βŠ™hβ‚œβ‚‹β‚ + zβ‚œβŠ™Γ±β‚œ
No separate cell state β€” hidden state hβ‚œ carries everything
LSTMGRU
Gates3 (forget, input, output)2 (reset, update)
StatesCell state + hidden stateHidden state only
ParametersMore (~4Γ— hiddenΒ²)Fewer (~3Γ— hiddenΒ²)
SpeedSlower~33% faster
Best forLong dependencies; NLPShorter seq; less data
GRU in Keras
keras.layers.GRU(128, return_sequences=True)
keras.layers.GRU(64)

Bidirectional RNNs

Both Directions

A Bidirectional RNN runs two RNNs — one forward (left→right) and one backward (right→left) — and concatenates their outputs at each step, giving each position context from both directions.

DirectionSeesUsed In
Forward β†’Past context onlyLanguage generation (GPT style)
Backward ←Future context onlyβ€”
BidirectionalPast + futureNER, POS tagging, BERT encoder
Bidirectional LSTM (Keras)
# Wraps any RNN layer
keras.layers.Bidirectional(
 keras.layers.LSTM(64, return_sequences=True)
)
# Output size = 2 Γ— 64 = 128 (concat)

# merge_mode options:
# 'concat' (default) 'sum' 'mul' 'ave'
keras.layers.Bidirectional(
 keras.layers.LSTM(64),
 merge_mode='sum' # β†’ output size = 64
)
Use bidirectional when the full sequence is available at inference time (classification, translation encoder). Avoid for real-time/streaming where future tokens aren't yet known.

Input Preparation

Sequences
Tokenize & Pad Text Sequences
# Tokenize
tokenizer = keras.preprocessing.text.Tokenizer(
 num_words=10000, oov_token="<OOV>"
)
tokenizer.fit_on_texts(train_texts)
seqs = tokenizer.texts_to_sequences(train_texts)

# Pad to fixed length
X = keras.preprocessing.sequence.pad_sequences(
 seqs, maxlen=200, padding='post',
 truncating='post'
)
# Shape: (num_samples, 200)
RNN Input ShapeMeaning
(batch, timesteps, features)3D tensor required by all Keras RNN layers
(32, 200, 1)32 samples Β· 200 time steps Β· 1 feature each
(32, 200, 128)32 samples Β· 200 tokens Β· 128-dim embedding
Masking: Use keras.layers.Masking(mask_value=0) before your RNN to tell Keras which timesteps are padding β€” the RNN will ignore them during training.

Embeddings

Token Representation

An Embedding layer maps integer token IDs to dense vectors β€” learnable lookup table of shape (vocab_size, embed_dim).

Embedding Layer (Keras)
# Learned from scratch
keras.layers.Embedding(
 input_dim=10000, # vocab size
 output_dim=128, # embedding dimension
 input_length=200, # sequence length
 mask_zero=True # auto-mask padding
)

# Pretrained GloVe / Word2Vec weights
keras.layers.Embedding(
 vocab_size, 300,
 weights=[embedding_matrix],
 trainable=False # freeze pretrained
)
EmbeddingDimVocab
GloVe 6B50 / 100 / 200 / 300400K words
Word2Vec3003M words
FastText300Handles OOV via subwords
Learned64–256Task-specific vocab

Sequence-to-Sequence (Seq2Seq)

Encoder–Decoder

Seq2Seq uses an encoder to compress the input sequence into a context vector (final hidden state), then a decoder generates the output sequence one token at a time using that context.

ComponentRole
EncoderReads input sequence β†’ context vector (hβ‚™, Cβ‚™)
Context vectorFinal encoder hidden + cell state
DecoderGenerates output seq token-by-token, conditioned on context
Teacher forcingFeed true output as decoder input during training
Greedy decodeAt inference, feed predicted token as next input
Beam searchKeep top-k candidates at each step β€” better quality
Bottleneck problem: All source information is compressed into one fixed-size vector β€” hurts long sequences. Solution: Attention mechanism.
Seq2Seq Encoder (Keras)
# Encoder
enc_inputs = keras.Input(shape=(None,))
enc_emb = keras.layers.Embedding(
 src_vocab, 256)(enc_inputs)
enc_out, h, c = keras.layers.LSTM(
 256, return_state=True)(enc_emb)
enc_states = [h, c]

# Decoder
dec_inputs = keras.Input(shape=(None,))
dec_emb = keras.layers.Embedding(
 tgt_vocab, 256)(dec_inputs)
dec_lstm = keras.layers.LSTM(
 256, return_sequences=True,
 return_state=True)
dec_out, _, _ = dec_lstm(
 dec_emb, initial_state=enc_states)
dec_dense = keras.layers.Dense(
 tgt_vocab, activation='softmax')
outputs = dec_dense(dec_out)

Attention Mechanism

Context Alignment

Attention lets the decoder look back at all encoder outputs at each decoding step β€” computing a weighted sum to focus on the most relevant input positions.

Scaled Dot-Product Attention
Attention(Q,K,V) = softmax(QKα΅€/√dβ‚–)Β·V
Q = query Β· K = key Β· V = value Β· dβ‚– = key dimension (scaling factor)
TypeDescription
Bahdanau (Additive)Score = Vα΅€Β·tanh(W₁·hβ‚› + Wβ‚‚Β·hβ‚œ) β€” original attention
Luong (Multiplicative)Score = hβ‚œα΅€Β·Wβ‚›Β·hβ‚› β€” simpler, faster
Scaled Dot-ProductScore = QKα΅€/√dβ‚– β€” Transformer standard
Multi-HeadRun attention h times in parallel, concat β€” Transformers
Self-AttentionQ, K, V all from same sequence β€” BERT, GPT
Attention β†’ Transformers: When you apply self-attention without any RNN, stacked with positional encoding and feed-forward layers, you get a Transformer β€” see Sheet 4.

Practical RNN Patterns

Keras Recipes
Sentiment Classifier (Many-to-One)
model = keras.Sequential([
 keras.layers.Embedding(10000, 128,
 mask_zero=True),
 keras.layers.Bidirectional(
 keras.layers.LSTM(64)),
 keras.layers.Dense(64, activation='relu'),
 keras.layers.Dropout(0.4),
 keras.layers.Dense(1, activation='sigmoid')
])
Time Series Forecasting (Many-to-One)
model = keras.Sequential([
 keras.layers.LSTM(64,
 return_sequences=True,
 input_shape=(30, 1)), # 30 steps, 1 feature
 keras.layers.LSTM(32),
 keras.layers.Dense(1) # predict next value
])
Stateful RNNs: Set stateful=True to carry hidden state across batches β€” useful for very long time series where you split into chunks.

Hyperparameters, Tips & Troubleshooting

Tuning Guide

Key Hyperparameters

ParamTypical Range
Hidden units64 – 512
Num layers1 – 4 stacked
Dropout0.2 – 0.5
Recurrent dropout0.1 – 0.3
Embedding dim64 – 300
Sequence length50 – 500 (NLP)
Batch size32 – 128
Learning rate1e-3 (Adam)
Gradient clipclipnorm=1.0

Common Problems & Fixes

ProblemFix
Loss not decreasingGradient clipping Β· lower LR Β· check input shape
OverfittingDropout Β· recurrent_dropout Β· smaller model
Forgetting long contextUse LSTM or GRU instead of vanilla RNN
Slow trainingUse CuDNN-compatible (no recurrent_dropout on GPU)
NaN lossGradient clipping Β· lower LR Β· check embeddings
Poor seq2seq qualityAdd attention Β· use beam search Β· more data

When to Use What

TaskBest Choice
Sentiment analysisBiLSTM or BERT
Time series forecastLSTM / GRU
Machine translationTransformer (Seq2Seq + attention)
Named entity recognitionBiLSTM-CRF or BERT
Speech recognitionBiLSTM + CTC loss
Text generationLSTM or GPT-style Transformer
Short sequences (<50)GRU (faster, fewer params)
Long sequences (>200)Transformer (no vanishing gradient)

RNN vs LSTM vs GRU vs Transformer

Full Comparison
ModelLong-Range DepsSpeedParallelizableMemoryBest For
Vanilla RNNNo PoorFastNo SequentialLowVery short sequences only
LSTM GoodMediumNo SequentialMediumNLP, time series, audio
GRU GoodFaster than LSTMNo SequentialLow–MedWhen LSTM is too slow/large
BiLSTM Best RNNSlowest RNNNo SequentialHighNER, encoding, classification
Transformer GlobalSlow train, fast inf Full parallelVery HighNLP SOTA β€” BERT, GPT, T5
2024 reality: For most NLP tasks, pretrained Transformers (BERT, GPT-2, T5) outperform LSTM-based models significantly. Use LSTM/GRU for time series, resource-constrained environments, or when interpretability of recurrence matters.

RNN & LSTM β€” Mastery Checklist

Self-Assessment

RNN Foundations

  • Write the vanilla RNN equation hβ‚œ = tanh(Wβ‚•hβ‚œβ‚‹β‚ + Wβ‚“xβ‚œ + b) from memory
  • Explain the 5 RNN modes (one-to-one through many-to-many)
  • Explain why vanishing gradients occur during BPTT
  • Apply gradient clipping with clipnorm in Keras
  • Prepare and pad a text sequence for RNN input
  • Shape a 3D input tensor (batch, timesteps, features) correctly

LSTM & GRU

  • Name all 4 LSTM gates and what each controls
  • Trace the cell state update: Cβ‚œ = fβ‚œβŠ™Cβ‚œβ‚‹β‚ + iβ‚œβŠ™CΜƒβ‚œ
  • Compare GRU vs LSTM β€” gates, states, speed, use case
  • Stack two LSTM layers using return_sequences=True
  • Wrap an LSTM with Bidirectional and explain output size
  • Choose between LSTM and GRU for a given task and dataset size

Seq2Seq & Attention

  • Describe the encoder-decoder architecture and context vector
  • Explain the bottleneck problem in vanilla seq2seq
  • Write the scaled dot-product attention formula
  • Distinguish self-attention from cross-attention
  • Explain when to use BiLSTM vs Transformer for NLP
  • Build a sentiment classifier with Embedding + BiLSTM in Keras
Next in Deep Learning Series
Sheet 4 Β· Transformers
attention Β· encoder Β· decoder Β· BERT Β· GPT Β· positional encoding Β· fine-tuning
Transformers Sheet β†’
← Back