DEEP LEARNING • LESSON 15

Prepare the Data

Before a neural network can learn from images, we need to prepare those images correctly. In this lesson, we will clean and transform the MNIST data into a format the model can work with efficiently.

SIMPLE IDEA

Good data preparation makes training easier.

Our images already contain the information we need, but their pixel values are not yet in the most useful format for our neural network. We will normalize the pixels and make sure the input data has the correct shape.

01

Load the MNIST Dataset

First, we load the dataset using TensorFlow.

import tensorflow as tf

(x_train, y_train), (x_test, y_test) = \
    tf.keras.datasets.mnist.load_data()

We now have four important variables.

x_train → training images
y_train → training labels

x_test  → test images
y_test  → test labels
02

Understand x_train

x_train contains the images used to train the neural network.

print(x_train.shape)

The shape will look like this:

(60000, 28, 28)

This means there are 60,000 training images and every image has 28 rows and 28 columns of pixels.

60000
  ↓
Number of images

28
  ↓
Image height

28
  ↓
Image width
03

Understand y_train

y_train contains the correct answer for each training image.

print(y_train.shape)

The result is:

(60000,)

There is one label for each image.

x_train[0] → Image
y_train[0] → Correct digit

x_train[1] → Image
y_train[1] → Correct digit
04

Understand Pixel Values

MNIST images use grayscale pixel values between 0 and 255.

0   → Black
255 → White

Example:

0     0     0
0   255   255
0   255     0

A neural network can work with these numbers, but using values between 0 and 1 is generally more convenient for training.

05

Normalize the Images

We divide every pixel value by 255.

x_train = x_train / 255.0
x_test = x_test / 255.0

This changes the range from:

0 → 255

to:

0 → 1

For example:

Original pixel:

255

After normalization:

255 / 255 = 1.0


Original pixel:

128

After normalization:

128 / 255 = 0.502
06

Why Normalize?

Neural networks generally train more smoothly when their input values are kept within a small numerical range.

Before:

0 ─────────────── 255


After:

0 ─────────────── 1

We are not changing what the image represents. We are simply changing the numerical scale used to represent the pixels.

07

Do We Normalize the Labels?

No. We do not divide the digit labels by 255.

Image:

x_train
↓
Normalize
↓
0 to 1


Label:

y_train
↓
Keep as
0 to 9

The label is already a class identifier. For example, the label 7 simply means the image represents the digit 7.

08

Check the Data After Normalization

print(x_train.min())
print(x_train.max())

We should now see values close to:

0.0
1.0

This confirms that the image pixels have been normalized.

09

Do We Need to Reshape MNIST?

That depends on the neural network architecture we build next.

If we use a simple Dense network, we need to flatten each 28 × 28 image into a single vector.

28 × 28 image
      ↓
784 values

28 × 28 = 784

However, if we build a CNN, we would normally preserve the spatial image structure instead of flattening it immediately.

10

Flattening the Image

Suppose we have:

28 × 28

Flattening converts it into:

784 values

[0.0, 0.0, 0.2, 0.8, ...]

In Keras, a Dense neural network can perform this using a Flatten layer.

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(
        input_shape=(28, 28)
    ),
    ...
])

The Flatten layer does not learn anything. Its job is simply to rearrange the image data into a one-dimensional vector.

11

Keep Training and Test Data Separate

We normalize both datasets, but we must not mix their images together.

x_train → Model Training
y_train → Correct Training Answers


x_test → Final Evaluation
y_test → Correct Test Answers

The test set should remain unseen during model training. Otherwise, the final accuracy can give us a misleading picture of the model's performance.

12

Complete Data Preparation Code

import tensorflow as tf

# Load dataset
(x_train, y_train), (x_test, y_test) = \
    tf.keras.datasets.mnist.load_data()

# Normalize pixel values
x_train = x_train / 255.0
x_test = x_test / 255.0

# Check shapes
print("Training images:", x_train.shape)
print("Training labels:", y_train.shape)

print("Test images:", x_test.shape)
print("Test labels:", y_test.shape)

# Check pixel range
print("Minimum pixel:", x_train.min())
print("Maximum pixel:", x_train.max())
13

What Happens to One Image?

Original Image

28 × 28 pixels
Pixel range: 0 - 255

        ↓

Normalize

28 × 28 pixels
Pixel range: 0 - 1

        ↓

Flatten if using Dense network

28 × 28
   ↓
784 values

        ↓

Neural Network

Notice that the actual digit has not changed. Only its numerical representation has been prepared for the model.

14

The Important Difference With CNNs

There is one important detail you should not overlook. Flattening is useful for a basic Dense network, but it throws away the explicit 2D structure of the image.

Dense Network

28 × 28
   ↓
Flatten
   ↓
784
   ↓
Dense Layers


CNN

28 × 28
   ↓
Convolution
   ↓
Feature Maps
   ↓
Pooling
   ↓
Classifier

This is one reason CNNs are better suited to image problems: they can learn spatial patterns such as edges, shapes, and textures before classification.

KEY TAKEAWAY

Prepare the data before asking the model to learn.

For our MNIST project, we load the images, inspect their shapes, normalize pixel values from 0–255 to 0–1, keep labels unchanged, and preserve the test data separately. If we use a Dense network, the 28 × 28 image can then be flattened into 784 values.

Quick Check

Why do we divide image pixels by 255?

To normalize pixel values from the range 0–255 to the range 0–1.

Should we divide the labels by 255?

No. The labels represent class numbers from 0 to 9 and should remain class identifiers.

Why do we keep test data separate?

Because we need genuinely unseen data to evaluate how well the trained model generalizes.