13-Deep and Bi-directional RNNs

Understanding Bidirectional and Deep RNNs: How They Work and Why They Matter

Recurrent Neural Networks (RNNs) are powerful tools for working with sequential data like text, speech, or time-series data. But standard (or shallow) RNNs can struggle when it comes to learning long-range dependencies.

Deep recurrent neural networks are useful because they allow you to capture dependencies that you could not have otherwise captured using shallow RNNs. In this blog, you will understand the equations used when implementing these deep RNNs, and I'll show you how that factors in, into the cost function. Let's dive in.

That’s where deep RNNs and bidirectional RNNs come in.

In this post, we’ll break down:

  • What deep RNNs and bidirectional RNNs actually do

  • Why they're useful in NLP tasks

  • How they work under the hood (no heavy math)

  • A simple Python example to reinforce the concepts

Why Go Deeper Than a Basic RNN?

A vanilla RNN processes input from the start of a sequence to the end. It keeps updating its internal state (called the hidden state) as it reads each word or data point.

This works okay — if the important info is near the beginning of the sequence.

But what if the relevant context shows up later? Or in both directions?

I will show you how bidirectional neural networks work and how stacking RNNs together can produce a deep neural network. To illustrate the importance of bidirectional RNNs, take the following example.

Enter Deep RNNs

A deep RNN stacks multiple RNN layers on top of each other. This lets the model build more complex features across layers — like how deeper neural networks do in image recognition.

Each layer passes its activation (output) to the next. The depth allows the network to detect richer patterns and learn better representations.

Enter Bidirectional RNNs

A bidirectional RNN (BiRNN) processes the input twice:

  • Once from left to right (forward in time)

  • And once from right to left (backward in time)

Then it combines both hidden states before making a prediction. This is helpful in many NLP tasks because understanding a word often depends on what comes before and after it.

Let’s look at a sentence to see why this matters.

_"I was trying really hard to get a hold of __." Louise finally answered when I was about to give up.

A standard RNN might guess “him” or “them,” because it hasn’t seen “Louise” yet.
But a BiRNN sees both the past and the future — so it knows the correct word is likely “her.”

 

pic1.png

I was trying really hard to get a hold of blank. Louise finally answered when I was about to give up. As a clever human, you would able to fill in the blank without having to think very hard.

An RNN that's propagates information from the beginning to the end of sequences, would be able to make a prediction tool.

It would take the words before the blank as inputs and do its best to predict the missing word. However, because Louise doesn't appear until the beginning of the next sentence, it would have to guess between her, him and them.

How Bidirectional RNNs Work (Without the Math)

Here’s the intuition:

  • A forward RNN reads the sequence from start to end.

  • A backward RNN reads from end to start.

  • Both generate hidden states for each timestep.

  • We combine both hidden states at each point in time before making a prediction.

And no — the two directions don’t affect each other during computation. They’re processed independently and combined later.

pic2.png

Bidirectional RNNs work in much the same way that simple RNNs do. They take an input sequence x and make the predictions y hat. In the RNNs I

showed you earlier, the information flows from the beginning to the end of the sequence.

However, you could have another architecture where the information flowed from the end to the beginning. Just imagine going from the future to the present instead, when information flows in both directions, that's a bidirectional RNN.

pic3.png

It is important for you to note that this is an acyclic graph, which means that the information flows independently in both directions. The computations from left to right are completely independent of the computations from right to left.

pic 4.png

To get the predictions y hat, in a bidirectional RNN, you have to start propagating information from both directions. When you have computed both of the hidden states for a timestep, you can get the prediction y-hat for that time using this formula, which is the same one used for unidirectional or vanilla RNNs, but appending both hidden states this time. After you compute all the hidden states for both directions, you can get all of the remaining predictions. 

What About Deep RNNs?

Deep RNNs are like stacking multiple RNNs layer by layer. At each time step, one layer’s output becomes the next layer’s input. Think of it as going "deeper" after you've gone "forward" in time.

It’s like this:

  1. You move forward through time (sequence steps).

  2. Then you move upward through layers (network depth).

This structure lets the model learn temporal features at different levels of abstraction.

pic 5.png

Deep RNNs are similar to regular deep neural networks. Deep RNNs have a layer which takes the input sequence x and multiple additional hidden layers. As you can see, deep RNNs are just RNNs stack together. The intermediates connections pass information through the values of activations, just as in conventional deep neural networks. 

But for every timestep, for vanilla deep RNNs, you have the following two equations. They're the same as the ones that you have seen before. But let's see how information flows in this case. First, you compute the hidden states for the current layer. Then you get the activations and pass those values to the next hidden layer and repeat this process. In other words, at first you propagate information through time. Then you go deeper in the network and repeat the process for each layer until you get your predictions. 

 

yyyyyyyyy.png

 


Python Example: Understanding RNNs with a Simple Dataset

Let’s run a basic example using the digits dataset from sklearn. While this isn’t text data, we can still use a sequence-like approach for educational purposes.

import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import SimpleRNN, Dense
# Load dataset
digits = load_digits()
X = digits.images # shape: (1797, 8, 8)
y = digits.target
# Reshape input: we treat each row (8 pixels) as a timestep
X = X / 16.0 # Normalize to 0-1
X = X.astype("float32")
# Split dataset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Build simple RNN model (shallow)
model = Sequential()
model.add(SimpleRNN(32, input_shape=(8, 8))) # 8 timesteps, 8 features each
model.add(Dense(10, activation='softmax')) # 10 digit classes
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Train
model.fit(X_train, y_train, epochs=10, validation_data=(X_test, y_test))

Notes:

  • We reshaped each image into a sequence of 8 rows (timesteps) with 8 features each — just to simulate a sequence.

  • A SimpleRNN is used here, but you can swap it with Bidirectional(SimpleRNN(...)) or stack multiple RNN layers for depth.

When Should You Use Deep or Bidirectional RNNs?

Use bidirectional RNNs when:

  • The entire sequence is available before prediction (e.g., sentence classification)

  • Future context helps (e.g., filling in blanks, named entity recognition)

Use deep RNNs when:

  • The task is complex (e.g., speech recognition, long texts)

  • You need hierarchical feature learning

You can even combine both: a deep bidirectional RNN. Just remember: more complexity needs more data and computation.

Summary 

Now you've become familiar with the two interesting and useful varieties of RNNs. Bidirectional RNNs propagates information through time from the

future and from the past. Deep RNNs can help you solve more complex tasks

than are possible, which allow neural networks. Both architectures are

relatively simple compositions derived from the vanilla RNN model that you've already seen. It isn't such a big conceptual leap to understand their math. Congratulations on

completing this week. You have learned about RNNs, gated recurrent units by directional and deep RNNs. 

Final Thoughts

Deep and bidirectional RNNs extend the basic RNN structure to handle more complex, real-world problems. Whether you're building a chatbot or a sentiment classifier, understanding these models will help you design better NLP systems.

 

Last modified: Sunday, 27 July 2025, 8:49 AM