TensorFlow LSTM Layer

Long Short-Term Memory (LSTM) is an improved recurrent unit that solves the vanishing gradient problem of SimpleRNN. It introduces a separate cell state — a "memory highway" that runs alongside the hidden state — and three gating mechanisms that control what information gets added, removed, or passed forward. LSTMs remember relevant information across hundreds of time steps and remain the gold standard for many sequence tasks.

The Filing Cabinet Analogy

Imagine a researcher reading a long document. They maintain a notebook (cell state) where they jot key facts. When they read a new paragraph, they decide: which old notes are no longer relevant (forget gate), which new facts from this paragraph are worth adding (input gate), and which notes should inform their current thinking (output gate). LSTMs do exactly this for sequences.

The Three Gates

At each time step, LSTM computes with these gates:

FORGET GATE — What to erase from cell state
  f_t = sigmoid(W_f × [h_{t-1}, x_t] + b_f)
  Values near 0: forget this information
  Values near 1: keep this information

INPUT GATE — What new information to store
  i_t = sigmoid(W_i × [h_{t-1}, x_t] + b_i)
  g_t = tanh(W_g × [h_{t-1}, x_t] + b_g)
  New candidate values to potentially add: g_t
  How much to add:                         i_t × g_t

OUTPUT GATE — What to expose as hidden state
  o_t = sigmoid(W_o × [h_{t-1}, x_t] + b_o)
  h_t = o_t × tanh(c_t)

CELL STATE UPDATE:
  c_t = f_t × c_{t-1}  +  i_t × g_t
        ↑                  ↑
    (keep old)          (add new)

Visualizing the Cell State Highway

Cell State (long-term memory):
  c_0 ──[× f_1]──[+ i_1×g_1]──► c_1 ──[× f_2]──[+ i_2×g_2]──► c_2 ...

Hidden State (short-term memory exposed at each step):
  h_0 ──► [LSTM cell] ──► h_1 ──► [LSTM cell] ──► h_2 ...
               ▲                        ▲
               │ x_1 (input)            │ x_2 (input)

The cell state c_t flows through with minimal transformation.
This unobstructed highway lets gradients flow back
through many time steps without vanishing.

LSTM in TensorFlow

import tensorflow as tf

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(input_dim=10000, output_dim=128, input_length=200),
    tf.keras.layers.LSTM(units=256),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])
model.summary()

Key LSTM Parameters

tf.keras.layers.LSTM(
    units=256,              # Size of hidden state (and cell state)
    activation='tanh',      # Activation for cell state update
    recurrent_activation='sigmoid',  # Activation for gates
    return_sequences=False, # False: return final h_t only
                            # True: return h_t at every time step
    return_state=False,     # True: also return h_t and c_t separately
    dropout=0.0,            # Dropout on input connections
    recurrent_dropout=0.0,  # Dropout on recurrent connections
    stateful=False          # True: carry state across batches
)

Stacking LSTM Layers

model = tf.keras.Sequential([
    tf.keras.layers.Embedding(10000, 128, input_length=200),

    # First LSTM — return sequences for next LSTM to consume
    tf.keras.layers.LSTM(256, return_sequences=True, dropout=0.2,
                         recurrent_dropout=0.1),

    # Second LSTM — return final state only
    tf.keras.layers.LSTM(128, dropout=0.2),

    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dense(5, activation='softmax')  # 5-class classification
])

Bidirectional LSTM

# Reads sequence both forward and backward
# Doubles the output size
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(10000, 128, input_length=200),
    tf.keras.layers.Bidirectional(
        tf.keras.layers.LSTM(128, return_sequences=True)
    ),
    # output: (batch, 200, 256) ← 128 forward + 128 backward
    tf.keras.layers.Bidirectional(
        tf.keras.layers.LSTM(64)
    ),
    # output: (batch, 128)
    tf.keras.layers.Dense(1, activation='sigmoid')
])

Returning Cell State and Hidden State

# When return_state=True, LSTM returns 3 tensors:
# output, final_hidden_state, final_cell_state

lstm_layer = tf.keras.layers.LSTM(256, return_state=True)

inputs = tf.keras.Input(shape=(100, 64))
output, h_state, c_state = lstm_layer(inputs)

print(output.shape)   # (batch, 256)    — same as h_state here
print(h_state.shape)  # (batch, 256)    — final hidden state
print(c_state.shape)  # (batch, 256)    — final cell state

# Use h_state and c_state to initialize a decoder (encoder-decoder models)

Complete Example: Movie Review Sentiment

import tensorflow as tf
import numpy as np

# Load IMDB dataset (25,000 movie reviews, binary sentiment)
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.imdb.load_data(
    num_words=10000
)

# Pad sequences to same length
x_train = tf.keras.preprocessing.sequence.pad_sequences(
    x_train, maxlen=200, padding='post', truncating='post'
)
x_test = tf.keras.preprocessing.sequence.pad_sequences(
    x_test, maxlen=200, padding='post', truncating='post'
)

# Build LSTM model
model = tf.keras.Sequential([
    tf.keras.layers.Embedding(10000, 128, input_length=200),
    tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(64)),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(0.4),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])

model.fit(x_train, y_train,
          epochs=5,
          batch_size=64,
          validation_split=0.2)

loss, acc = model.evaluate(x_test, y_test)
print(f"Test accuracy: {acc:.2%}")
# Typically achieves ~87–89% accuracy

LSTM vs SimpleRNN vs GRU

Property             SimpleRNN     LSTM          GRU
────────────────────────────────────────────────────────────
Gates                0             3 (f, i, o)   2 (r, z)
Memory               Hidden state  Cell + hidden  Hidden only
Parameters (units=u) u²            4u²            3u²
Long-range memory    Poor          Excellent      Good
Training speed       Fastest       Slowest        Fast
Accuracy (long seq)  Low           High           High (≈ LSTM)
Preferred use        Short seqs    All seq tasks  When speed matters
────────────────────────────────────────────────────────────

When LSTM Struggles

  • Very long sequences (>1000 steps) — even LSTM degrades; use Transformers
  • Parallel training — LSTM is sequential by nature; Transformers run in parallel
  • Small datasets — fewer parameters (GRU) often outperforms LSTM

LSTM is the workhorse of sequence modeling and one of the most proven architectures in deep learning history. Its gating mechanism solves the core weakness of SimpleRNN, making it effective for text classification, sentiment analysis, time series forecasting, and language modeling. The next topic covers the GRU layer — a streamlined version of LSTM that achieves comparable accuracy with fewer parameters and faster training.

Leave a Comment

Your email address will not be published. Required fields are marked *