🔥Limited Offer: Get 50% OFFon AI & Full Stack Courses🔥
Back to Deep Learning Notes
Topic #473

Practice: RNN & LSTM

Implementation exercises for recurrent networks — implementing an RNN cell manually, then building a real LSTM-based sequence classifier in PyTorch.

🟢 Problem 1: Implement a single RNN cell's forward step manually

Task: Implement one time step of a vanilla RNN's hidden state update: \(h_t = \tanh(W_{xh}x_t + W_{hh}h_{t-1} + b)\).

def rnn_cell_forward(x_t, h_prev, W_xh, W_hh, b):
    return np.tanh(x_t @ W_xh + h_prev @ W_hh + b)

input_size, hidden_size = 4, 3
W_xh = np.random.randn(input_size, hidden_size) * 0.1
W_hh = np.random.randn(hidden_size, hidden_size) * 0.1
b = np.zeros(hidden_size)

x_t = np.random.randn(1, input_size)
h_prev = np.zeros((1, hidden_size))
h_t = rnn_cell_forward(x_t, h_prev, W_xh, W_hh, b)
print(f"New hidden state: {h_t}")

🟡 Problem 2: Unroll the RNN cell across a full sequence

Task: Given a sequence of 5 time steps, apply your RNN cell repeatedly, carrying the hidden state forward, and collect all hidden states.

def rnn_forward_sequence(X_seq, W_xh, W_hh, b, hidden_size):
    batch_size = X_seq.shape[0]
    h_t = np.zeros((batch_size, hidden_size))
    all_hidden_states = []

    for t in range(X_seq.shape[1]):   # iterate over time steps
        x_t = X_seq[:, t, :]
        h_t = rnn_cell_forward(x_t, h_t, W_xh, W_hh, b)
        all_hidden_states.append(h_t)

    return np.stack(all_hidden_states, axis=1)   # (batch, seq_len, hidden_size)

X_seq = np.random.randn(2, 5, input_size)   # batch=2, seq_len=5
hidden_states = rnn_forward_sequence(X_seq, W_xh, W_hh, b, hidden_size)
print(hidden_states.shape)   # (2, 5, 3)

Hint if stuck: The key idea is that h_t from one iteration becomes h_prev for the next — this is exactly what "recurrent" means, and is the only thing carrying information across time steps.

🟡 Problem 3: Build an LSTM-based sentiment classifier in PyTorch

Task: Build a model that embeds input tokens, processes them with an LSTM, and classifies the final hidden state as positive/negative sentiment.

class LSTMClassifier(nn.Module):
    def __init__(self, vocab_size, embed_dim=64, hidden_dim=128, num_classes=2):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size, embed_dim)
        self.lstm = nn.LSTM(embed_dim, hidden_dim, batch_first=True)
        self.fc = nn.Linear(hidden_dim, num_classes)

    def forward(self, x):
        embedded = self.embedding(x)                  # (batch, seq_len, embed_dim)
        _, (h_n, c_n) = self.lstm(embedded)              # h_n: (1, batch, hidden_dim)
        final_hidden = h_n.squeeze(0)                     # (batch, hidden_dim)
        return self.fc(final_hidden)

model = LSTMClassifier(vocab_size=5000)
sample_input = torch.randint(0, 5000, (4, 20))   # batch=4, seq_len=20
logits = model(sample_input)
print(logits.shape)   # (4, 2)

Hint if stuck: nn.LSTM returns two things: the output at every time step, and a tuple of the final hidden and cell states — for classification using only the final summary of the sequence, you typically want h_n, the final hidden state.

🔴 Problem 4: Compare a vanilla RNN vs LSTM on a long-dependency task

Task: Create a synthetic task where the correct output depends on information from early in a long sequence (e.g. classify based on the first token, with 50 irrelevant tokens after it). Train both a vanilla RNN and an LSTM on this task and compare their accuracy.

# Synthetic task: label = 1 if first token > 0, else 0 -- but the sequence is 50 tokens long
def generate_long_dependency_data(num_samples, seq_len=50):
    X = np.random.randn(num_samples, seq_len, 1)
    y = (X[:, 0, 0] > 0).astype(int)   # label depends ONLY on the very first time step
    return torch.tensor(X, dtype=torch.float32), torch.tensor(y, dtype=torch.long)

# Train both nn.RNN and nn.LSTM based classifiers on this data with identical
# hyperparameters, and compare final test accuracy -- the LSTM should notably
# outperform the vanilla RNN, directly demonstrating why LSTM's gating helps
# preserve information over long sequences that a vanilla RNN tends to lose

Hint if stuck: If both models perform similarly, try increasing seq_len further — the vanilla RNN's disadvantage becomes more pronounced as the dependency distance grows, which is exactly the point this exercise is designed to demonstrate.

Want to go beyond the notes?

Join CodingNow 2.0's Deep Learning course — live mentorship, real projects, and 100% placement support.

Enroll Now — Free Demo Available

Practice: RNN & LSTM – FAQs

Quick answers about learning Practice: RNN & LSTM in Deep Learning.

This free note from CodingNow 2.0 explains Practice: RNN & LSTM in Deep Learning — concept, syntax and worked code examples you can copy, run and revise before interviews.
Yes. Every Deep Learning topic on CodingNow 2.0, including Practice: RNN & LSTM, is 100% free with no signup required.
With focused practice, most students grasp Practice: RNN & LSTM in 1–3 days from these notes; pairing it with CodingNow 2.0's mentor-led course takes you to job-ready depth faster.
Use the code examples in this note, then ask doubts for free on the CodingNow 2.0 Community (/community) — expert instructors answer within 24 hours.
WhatsApp
Call NowEnroll Now