MNIST Dataset - 3 Layers NN

Preparing the enviroment

In [1]:
import os
import tensorflow as tf
from tensorflow import keras

Load and inspect the data

By default the load_data from Keras accepts a path relative to ~/.keras/datasets, but in this case it is stored somewhere else, as a result of this, you need to specify the full path.

In [2]:
# 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")

# Also we'll discard the test set
(x_train, y_train), _ = tf.keras.datasets.mnist.load_data(path=data_path)
        
# Normalize pixel values
x_train = x_train / 255.0

Now take a look at the shape of the training data:

In [3]:
data_shape = x_train.shape

print(f"There are {data_shape[0]} examples with shape ({data_shape[1]}, {data_shape[2]})")
There are 60000 examples with shape (28, 28)

Defining a callback

We'll define a callback if our model's accuracy reached 99%

In [4]:
class myCallback(tf.keras.callbacks.Callback):
        # Define the correct function signature for on_epoch_end
        def on_epoch_end(self, epoch, logs={}):
            if logs.get('accuracy') is not None and logs.get('accuracy') > 0.99:
                print("\nReached 99% accuracy so cancelling training!") 
                
                # Stop training once the above condition is met
                self.model.stop_training = True

Create and train your model

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

# Define the model
model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(128, activation=tf.nn.relu),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
    ])

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

# Fit the model for 10 epochs adding the callbacks
# and save the training history
history = model.fit(x_train, y_train, epochs=10, callbacks=[callbacks])
Epoch 1/10
1875/1875 [==============================] - 7s 3ms/step - loss: 0.2640 - accuracy: 0.9244
Epoch 2/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.1166 - accuracy: 0.9652
Epoch 3/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0799 - accuracy: 0.9758
Epoch 4/10
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0615 - accuracy: 0.9810
Epoch 5/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0459 - accuracy: 0.9858
Epoch 6/10
1875/1875 [==============================] - 6s 3ms/step - loss: 0.0362 - accuracy: 0.9888
Epoch 7/10
1867/1875 [============================>.] - ETA: 0s - loss: 0.0292 - accuracy: 0.9913
Reached 99% accuracy so cancelling training!
1875/1875 [==============================] - 5s 3ms/step - loss: 0.0292 - accuracy: 0.9913

Let's check the model summary

In [11]:
model.summary()
Model: "sequential_3"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_3 (Flatten)         (32, 784)                 0         
                                                                 
 dense_4 (Dense)             (32, 128)                 100480    
                                                                 
 dense_5 (Dense)             (32, 10)                  1290      
                                                                 
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
_________________________________________________________________

Note: You see the meassage "Reached 99% accuracy so cancelling training!" due to the callback function