DEEP LEARNING LESSON 12 LSTM AND GRU

Understand the Python Code

In the previous topic, we built an LSTM model. Now let's understand the Python code line by line, why each part is needed, and how the complete program works from input data to prediction.

Complete Python Code

First, look at the complete program. Then we will break it into small pieces.

import numpy as np

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense


# Create data
data = np.array([
    [1],
    [2],
    [3],
    [4],
    [5],
    [6],
    [7],
    [8],
    [9],
    [10]
], dtype=float)


# Create input and target
X = []
y = []

sequence_length = 3


# Create sequences
for i in range(len(data) - sequence_length):
    X.append(data[i:i + sequence_length])
    y.append(data[i + sequence_length])


# Convert to NumPy arrays
X = np.array(X)
y = np.array(y)


# Build LSTM model
model = Sequential([
    LSTM(32, input_shape=(3, 1)),
    Dense(1)
])


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


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


# Test sequence
test_sequence = np.array([
    [[8],
     [9],
     [10]]
], dtype=float)


# Make prediction
prediction = model.predict(test_sequence)

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

1. Import the Required Libraries

import numpy as np

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense

We are importing the tools needed to create our LSTM model.

NumPy is used to work with numerical arrays.

Sequential allows us to create layers one after another.

LSTM creates the LSTM layer.

Dense creates the final fully connected layer.

NumPy
  ↓
Handle numerical data

Sequential
  ↓
Build neural network

LSTM
  ↓
Process sequence

Dense
  ↓
Produce output

2. Create the Data

data = np.array([
    [1],
    [2],
    [3],
    [4],
    [5],
    [6],
    [7],
    [8],
    [9],
    [10]
], dtype=float)

We create a simple sequence of numbers.

1
2
3
4
5
6
7
8
9
10

The model will learn the pattern in this sequence.

We use:

dtype=float

so the values are stored as floating-point numbers.

3. Create X and y

X = []
y = []

These two variables have different jobs.

X → Input
y → Correct Answer

For example:

X = [1, 2, 3]

y = 4

The model receives the input sequence and tries to predict the target.

Input
[1, 2, 3]
    ↓
  LSTM
    ↓
Prediction

Correct answer
4

4. Set the Sequence Length

sequence_length = 3

This means we will use three previous values to predict the next value.

[1, 2, 3] → 4

[2, 3, 4] → 5

[3, 4, 5] → 6

So the model always looks at three time steps.

5. Create Training Sequences

for i in range(len(data) - sequence_length):
    X.append(data[i:i + sequence_length])
    y.append(data[i + sequence_length])

This loop converts our original sequence into training examples.

Suppose our data is:

[1, 2, 3, 4, 5]

With a sequence length of 3, the first example becomes:

X = [1, 2, 3]
y = 4

The second becomes:

X = [2, 3, 4]
y = 5

Therefore:

X                  y

[1, 2, 3]      →     4
[2, 3, 4]      →     5
[3, 4, 5]      →     6
[4, 5, 6]      →     7
...

This is the actual training data given to the LSTM.

6. Understand the Python Slicing

This line is particularly important:

X.append(data[i:i + sequence_length])

If:

i = 0
sequence_length = 3

then:

data[0:3]

gives:

[1, 2, 3]

When:

i = 1

we get:

data[1:4]

→ [2, 3, 4]

So the window moves forward one position at a time.

[1, 2, 3] → 4
    [2, 3, 4] → 5
        [3, 4, 5] → 6

7. Understand the Target

y.append(data[i + sequence_length])

This gets the value immediately after the input sequence.

For example:

data:

1  2  3  4  5
   └─────┘  ↓
    input  target

Input  = [1, 2, 3]
Target = 4

So the model learns:

Previous values
      ↓
   LSTM
      ↓
Next value

8. Convert X and y to NumPy Arrays

X = np.array(X)
y = np.array(y)

Before this, `X` and `y` are Python lists. We convert them into NumPy arrays so they can be efficiently passed to TensorFlow.

You can check their shapes:

print(X.shape)
print(y.shape)

For this example, `X` will have a shape similar to:

(7, 3, 1)

This means:

7 → training samples
3 → time steps
1 → feature

9. Build the LSTM Model

model = Sequential([
    LSTM(32, input_shape=(3, 1)),
    Dense(1)
])

The model has two layers.

Input
  ↓
LSTM(32)
  ↓
Dense(1)
  ↓
Output

LSTM(32)

LSTM(32)

`32` means the LSTM layer has 32 hidden units.

It does not mean there are 32 LSTM layers.

input_shape=(3, 1)

input_shape=(3, 1)

This tells the LSTM that each sample contains:

3 time steps
1 feature per time step

Dense(1)

Dense(1)

We want one output value, so the final Dense layer contains one unit.

[1, 2, 3]
     ↓
   LSTM
     ↓
 Dense(1)
     ↓
     4

10. Compile the Model

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

Compilation tells the model how training should happen.

Optimizer

optimizer="adam"

Adam updates the model's weights using the gradients calculated during training.

Prediction
    ↓
Calculate error
    ↓
Calculate gradients
    ↓
Adam updates weights

Loss

loss="mse"

MSE stands for Mean Squared Error. It measures how far the prediction is from the correct answer.

Example:

Actual     = 4
Prediction = 3

Error = 4 - 3
      = 1

Squared Error = 1²
              = 1

11. Train the Model

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

This starts the learning process.

`X` contains the input sequences.

`y` contains the correct answers.

`epochs=200` means the model goes through the training data 200 times.

Training data
      ↓
   LSTM
      ↓
Prediction
      ↓
Calculate loss
      ↓
Backpropagation
      ↓
Update weights
      ↓
Repeat

`verbose=0` simply hides the training progress from the console.

12. Create a Test Sequence

test_sequence = np.array([
    [[8],
     [9],
     [10]]
], dtype=float)

We give the trained model:

8
9
10

and ask it to predict what comes next.

8 → 9 → 10 → ?

The expected pattern suggests:

11

Notice that we put the sequence inside another array. This gives the model a batch dimension.

(1, 3, 1)

1 → sample
3 → time steps
1 → feature

13. Make the Prediction

prediction = model.predict(test_sequence)

The trained model processes the sequence:

[8, 9, 10]
      ↓
    LSTM
      ↓
   Dense
      ↓
 Prediction

Then:

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

This extracts the actual predicted number from the returned array.

The result may be something close to:

Predicted value: 10.9

The exact result can vary because the neural network learns an approximation rather than following a hardcoded rule.

14. Understand the Complete Flow

Original Data
[1,2,3,4,5,6,7,8,9,10]
          ↓
Create Sequences
          ↓
[1,2,3] → 4
[2,3,4] → 5
[3,4,5] → 6
          ↓
Create X and y
          ↓
LSTM(32)
          ↓
Dense(1)
          ↓
Compile
          ↓
Train
          ↓
Learn Patterns
          ↓
Give [8,9,10]
          ↓
Predict Next Value
          ↓
≈ 11

15. Simple Real-World Example

Forget the numbers for a moment. Imagine we have temperature measurements:

Monday    → 25°C
Tuesday   → 26°C
Wednesday → 27°C
Thursday  → 28°C
Friday    → 29°C

We could create:

[25, 26, 27] → 28
[26, 27, 28] → 29

The LSTM receives the previous temperatures and learns relationships in the sequence.

Then we could give:

[27, 28, 29]

and ask the model to predict the next temperature.

This is much closer to a real sequence-learning problem than simply memorizing a list of numbers.

16. One Important Thing to Understand

Do not think an LSTM is simply doing:

last_number + 1

That would just be a normal programming rule.

Instead, the neural network learns its parameters from examples.

Training Examples
       ↓
LSTM
       ↓
Learn Parameters
       ↓
New Sequence
       ↓
Prediction

This distinction is important. The model is learning a relationship from data rather than being explicitly programmed with the answer.

17. The Most Important Lines

If you are learning LSTM for the first time, focus on these lines first:

# Create sequences
X.append(data[i:i + sequence_length])
y.append(data[i + sequence_length])


# Build LSTM
model = Sequential([
    LSTM(32, input_shape=(3, 1)),
    Dense(1)
])


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


# Train
model.fit(
    X,
    y,
    epochs=200
)


# Predict
prediction = model.predict(test_sequence)

These lines represent the entire workflow:

Create Data
    ↓
Create Sequences
    ↓
Build LSTM
    ↓
Compile
    ↓
Train
    ↓
Predict

Final Summary

NumPy
→ Stores numerical data

X
→ Input sequences

y
→ Correct answers

sequence_length
→ Number of previous time steps

LSTM(32)
→ Learns patterns from sequences

Dense(1)
→ Produces one output

MSE
→ Measures prediction error

Adam
→ Updates model weights

fit()
→ Trains the model

predict()
→ Makes predictions

The complete idea is simple:

Previous Sequence
       ↓
      LSTM
       ↓
Learned Pattern
       ↓
   Prediction

Once you understand this flow, the Python code becomes much easier to read. The syntax is just implementing this learning process.

QUICK CHECK

Check Your Understanding

1. What does X contain?
The input sequences given to the LSTM.

2. What does y contain?
The correct target value for each input sequence.

3. What does LSTM(32) mean?
One LSTM layer with 32 hidden units.

4. What does input_shape=(3, 1) mean?
Three time steps and one feature at every time step.

5. What does model.fit() do?
It trains the model using the input data and targets.

6. What does model.predict() do?
It uses the trained model to generate a prediction for new input data.