DEEP LEARNING LESSON 11 RECURRENT NEURAL NETWORKS

Understand the Python Code

In the previous lesson, we built a simple RNN. Now we will understand that code line by line and see exactly how the data moves through the RNN.

Complete RNN Code

import numpy as np
import tensorflow as tf

# Training data
X = np.array([
    [10, 20, 30],
    [20, 30, 40],
    [30, 40, 50]
])

y = np.array([
    40,
    50,
    60
])

# Reshape for RNN
X = X.reshape(3, 3, 1)

# Create model
model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(
        16,
        activation="tanh"
    ),
    tf.keras.layers.Dense(1)
])

# Compile model
model.compile(
    optimizer="adam",
    loss="mse"
)

# Train model
model.fit(
    X,
    y,
    epochs=500,
    verbose=0
)

# Test data
test_input = np.array([
    [
        [40],
        [50],
        [60]
    ]
])

# Make prediction
prediction = model.predict(test_input)

print("Predicted next value:", prediction[0][0])

Now let's understand each part.

1. Import NumPy

import numpy as np

NumPy is a Python library used for working with numerical data and arrays.

We use NumPy here to create the input and target data.

X = np.array([
    [10, 20, 30],
    [20, 30, 40],
    [30, 40, 50]
])

np.array() converts the values into a NumPy array.

2. Import TensorFlow

import tensorflow as tf

TensorFlow is the deep learning framework we use to create and train the RNN.

We use the name tf as a short name for TensorFlow.

3. Create the Input Data

X = np.array([
    [10, 20, 30],
    [20, 30, 40],
    [30, 40, 50]
])

X contains the input sequences.

We have three training examples:

Example 1:

10 → 20 → 30


Example 2:

20 → 30 → 40


Example 3:

30 → 40 → 50

Each sequence contains three values.

4. Create the Target Values

y = np.array([
    40,
    50,
    60
])

y contains the correct answer for each sequence.

10 → 20 → 30 → 40

20 → 30 → 40 → 50

30 → 40 → 50 → 60

So the relationship between X and y is:

X                    y

[10, 20, 30]  →       40

[20, 30, 40]  →       50

[30, 40, 50]  →       60

5. Reshape the Data

X = X.reshape(3, 3, 1)

This is one of the most important lines in the code.

RNN layers expect input in this format:

(samples, time steps, features)

Our shape is:

(3, 3, 1)

This means:

3 samples
↓
3 sequences are available


3 time steps
↓
Each sequence contains 3 values


1 feature
↓
Each time step contains 1 number

So the RNN sees the data approximately like this:

Sample 1

10 → 20 → 30


Sample 2

20 → 30 → 40


Sample 3

30 → 40 → 50

6. Create the Model

model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(
        16,
        activation="tanh"
    ),
    tf.keras.layers.Dense(1)
])

This creates a neural network using Keras.

Sequential means the layers are arranged one after another.

Input
  ↓
SimpleRNN
  ↓
Dense
  ↓
Output

7. Understand SimpleRNN(16)

tf.keras.layers.SimpleRNN(
    16,
    activation="tanh"
)

This creates the RNN layer.

The 16 means the RNN has 16 hidden units.

It does NOT mean:

"Remember the last 16 numbers"

That is a common misunderstanding.

Instead, the RNN maintains a hidden-state vector with 16 values.

[
    h1,
    h2,
    h3,
    ...
    h16
]

These values are learned representations of information from the sequence.

8. Understand tanh

activation="tanh"

tanh is an activation function.

It converts values into a range between approximately -1 and 1.

Large negative value → close to -1

0                   → 0

Large positive value → close to 1

In a basic RNN, tanh is commonly used to calculate the new hidden state.

9. Understand Dense(1)

tf.keras.layers.Dense(1)

This is the output layer.

The number 1 means the layer produces one output value.

We need one value because we are predicting the next number.

RNN
 ↓
Learn sequence information
 ↓
Dense(1)
 ↓
One predicted number

10. Compile the Model

model.compile(
    optimizer="adam",
    loss="mse"
)

Before training, Keras needs to know how the model should learn.

We specify two important things:

optimizer="adam"

loss="mse"

11. Understand the Adam Optimizer

optimizer="adam"

Adam is an optimization algorithm.

Its job is to help update the neural network's weights during training.

Prediction
    ↓
Loss
    ↓
Gradients
    ↓
Adam
    ↓
Updated Weights

You can think of Adam as the mechanism that helps the model decide how to adjust its weights based on the gradients.

12. Understand MSE

loss="mse"

MSE stands for Mean Squared Error.

It measures how far the prediction is from the correct answer.

Suppose:

Actual value     = 40
Predicted value  = 35

The error is:

40 - 35 = 5

MSE squares the error:

5² = 25

During training, the model tries to reduce this loss.

13. Train the Model

model.fit(
    X,
    y,
    epochs=500,
    verbose=0
)

model.fit() starts the training process.

We give it:

X
↓
Input sequences


y
↓
Correct answers

The model then performs:

X
 ↓
RNN
 ↓
Prediction
 ↓
Loss
 ↓
Backpropagation
 ↓
Weight Update
 ↓
Repeat

14. Understand epochs=500

epochs=500

One epoch means the model has gone through the complete training dataset once.

Therefore:

epochs=1
↓
Training data processed once


epochs=500
↓
Training data processed 500 times

More epochs do not automatically mean a better model. Too many can lead to overfitting.

15. Understand verbose=0

verbose=0

This controls how much training information Keras prints to the screen.

verbose=0
↓
Show nothing


verbose=1
↓
Show progress


verbose=2
↓
Show one line per epoch

16. Create Test Data

test_input = np.array([
    [
        [40],
        [50],
        [60]
    ]
])

This is a new sequence that the model has not seen as a training example.

40 → 50 → 60

Based on the pattern it learned:

40 → 50 → 60 → 70

So we expect the prediction to be close to 70.

17. Make the Prediction

prediction = model.predict(test_input)

This sends the test sequence through the trained model.

40 → 50 → 60
       ↓
     RNN
       ↓
    Dense(1)
       ↓
    Prediction

The prediction should be close to:

70

It may not be exactly 70 because the model learned the pattern numerically rather than using a hard-coded rule.

18. Understand prediction[0][0]

print(
    "Predicted next value:",
    prediction[0][0]
)

Keras returns predictions inside an array.

For one sample and one output, the structure is roughly:

[
    [69.8]
]

Therefore:

prediction[0]
↓
First sample

prediction[0][0]
↓
First output of that sample

Understand the Whole Code as One Flow

1. Import libraries
        ↓
2. Create X
        ↓
3. Create y
        ↓
4. Reshape X
        ↓
5. Create SimpleRNN
        ↓
6. Add Dense output layer
        ↓
7. Compile model
        ↓
8. Train model
        ↓
9. Create new sequence
        ↓
10. Predict next value

Example: What Happens During Training?

Suppose the model sees:

10 → 20 → 30

Initially, the model does not know that the answer should be 40.

It might predict:

Prediction = 25

The correct answer is:

Actual = 40

The loss measures the difference.

Prediction = 25
Actual     = 40

       ↓

Calculate Loss

       ↓

Backpropagation

       ↓

Adam updates weights

       ↓

Model tries again

After many training steps, the model should become better at predicting the target values.

Another Example: Temperature

The same code structure can be used with sequence data such as temperature.

25 → 27 → 29 → 31

Training examples could be:

[25, 27, 29] → 31

[27, 29, 31] → 33

[29, 31, 33] → 35

The RNN learns from the ordered sequence and tries to predict the next value.

The code structure remains almost the same:

Sequence
   ↓
SimpleRNN
   ↓
Dense
   ↓
Prediction

The Most Important Lines

model = tf.keras.Sequential([
    tf.keras.layers.SimpleRNN(16),
    tf.keras.layers.Dense(1)
])

This creates the RNN architecture.

model.compile(
    optimizer="adam",
    loss="mse"
)

This tells the model how to learn.

model.fit(X, y, epochs=500)

This trains the model.

model.predict(test_input)

This uses the trained model to make a prediction.

Training vs Prediction

There are two different phases.

TRAINING

X + y
 ↓
Model
 ↓
Loss
 ↓
Backpropagation
 ↓
Update weights

During training, the model knows the correct answers because y is provided.

PREDICTION

New X
 ↓
Trained Model
 ↓
Prediction

During prediction, we give the model new input and ask it for an answer.

Final Summary

NumPy
 ↓
Create numerical sequence data

Reshape
 ↓
Convert data to:
(samples, time steps, features)

SimpleRNN
 ↓
Learn patterns from sequence

Dense(1)
 ↓
Produce one output

Adam
 ↓
Update weights

MSE
 ↓
Measure prediction error

fit()
 ↓
Train the model

predict()
 ↓
Make a prediction

If you understand this flow, you understand the basic structure of building an RNN with Keras.

Data
 ↓
RNN
 ↓
Prediction
 ↓
Loss
 ↓
Backpropagation
 ↓
Weight Update
 ↓
Better Model
QUICK CHECK

Check Your Understanding

1. Why do we reshape the input?
Because an RNN expects data in the form (samples, time steps, features).

2. What does SimpleRNN(16) mean?
The RNN has 16 hidden units. It does not mean it remembers exactly 16 previous values.

3. What does Dense(1) do?
It produces one output value.

4. What does model.fit() do?
It trains the model by calculating errors, computing gradients, and updating weights.

5. What does model.predict() do?
It uses the trained weights to generate predictions for new input data.