MNIST Dataset - 3 Layers + CNN (Using Convolutions)

In [2]:
import os
import numpy as np
import tensorflow as tf
from tensorflow import keras

Load the data

In [4]:
# Load the data

# Get current working directory
current_dir = os.getcwd() 

# Append data/mnist.npz to the previous path to get the full path
data_path = os.path.join(current_dir, "./mnist.npz") 

# Get only training set
(training_images, training_labels), _ = tf.keras.datasets.mnist.load_data(path=data_path) 

Pre-processing the data

Since we will use 3-dimensional arrays (without counting the batch dimension) to represent image data. The third dimension represents the color using RGB values. This data might be in black and white format so the third dimension doesn't really add any additional information for the classification process but it is a good practice regardless.

In [6]:
# Reload the images in case you run this cell multiple times
(training_images, _), _ = tf.keras.datasets.mnist.load_data(path=data_path)

# Reshape the images to add an extra dimension
training_images = training_images.reshape(60000, 28, 28, 1)

Normalize the pixel values so that these are values between 0 and 1. You can achieve this by dividing every value in the array by the maximum.

In [7]:
# Normalize pixel values
training_images = training_images / 255.0

Let's check what we have done:

In [8]:
print(f"Maximum pixel value after normalization: {np.max(training_images)}\n")
print(f"Shape of training set after reshaping: {training_images.shape}\n")
print(f"Shape of one image after reshaping: {training_images[0].shape}")
Maximum pixel value after normalization: 1.0

Shape of training set after reshaping: (60000, 28, 28, 1)

Shape of one image after reshaping: (28, 28, 1)

Defining our callback

In [9]:
# Remember to inherit from the correct class
class myCallback(tf.keras.callbacks.Callback):
    # Define the method that checks the accuracy at the end of each epoch
    def on_epoch_end(self, epoch, logs={}):
            if logs.get('accuracy') is not None and logs.get('accuracy') > 0.995:
                print("\nReached 99.5% accuracy so cancelling training!") 
                self.model.stop_training = True

Creating our convolutional model

In [10]:
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
]) 

# Compile the model
model.compile(optimizer='adam', 
              loss='sparse_categorical_crossentropy', 
              metrics=['accuracy']) 

Let's check the summary:

In [12]:
model.summary()
Model: "sequential"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 conv2d (Conv2D)             (None, 26, 26, 32)        320       
                                                                 
 max_pooling2d (MaxPooling2D  (None, 13, 13, 32)       0         
 )                                                               
                                                                 
 flatten (Flatten)           (None, 5408)              0         
                                                                 
 dense (Dense)               (None, 128)               692352    
                                                                 
 dense_1 (Dense)             (None, 10)                1290      
                                                                 
=================================================================
Total params: 693,962
Trainable params: 693,962
Non-trainable params: 0
_________________________________________________________________

Training our convolutional model

In [14]:
# Instantiate the callback class
callbacks = myCallback()

# Train your model (this can take up to 5 minutes)
history = model.fit(training_images, training_labels, epochs=10, callbacks=[callbacks])
Epoch 1/10
1875/1875 [==============================] - 29s 15ms/step - loss: 0.1453 - accuracy: 0.9570
Epoch 2/10
1875/1875 [==============================] - 31s 16ms/step - loss: 0.0515 - accuracy: 0.9848
Epoch 3/10
1875/1875 [==============================] - 26s 14ms/step - loss: 0.0332 - accuracy: 0.9897
Epoch 4/10
1875/1875 [==============================] - 24s 13ms/step - loss: 0.0215 - accuracy: 0.9931
Epoch 5/10
1874/1875 [============================>.] - ETA: 0s - loss: 0.0150 - accuracy: 0.9952
Reached 99.5% accuracy so cancelling training!
1875/1875 [==============================] - 25s 14ms/step - loss: 0.0150 - accuracy: 0.9952
In [16]:
print(f"Model was trained for {len(history.epoch)} epochs")
Model was trained for 5 epochs