In the course you learned how to do classification using Fashion MNIST, a data set containing items of clothing. There’s another, similar dataset called MNIST which has items of handwriting – the digits 0 through 9.
Write an MNIST classifier that trains to 99% accuracy and stops once this threshold is achieved. In the lecture you saw how this was done for the loss but here you will be using accuracy instead.
Some notes:
# IMPORTANT: This will check your notebook's metadata for grading.
# Please do not continue the lab unless the output of this cell tells you to proceed.
!python add_metadata.py --filename C1W2_Assignment.ipynb
[32mGrader metadata detected! You can proceed with the lab![0m
NOTE: To prevent errors from the autograder, you are not allowed to edit or delete non-graded cells in this notebook . Please only put your solutions in between the ### START CODE HERE
and ### END CODE HERE
code comments, and also refrain from adding any new cells. Once you have passed this assignment and want to experiment with any of the non-graded code, you may follow the instructions at the bottom of this notebook.
# grader-required-cell
import os
import tensorflow as tf
from tensorflow import keras
Begin by loading the data. A couple of things to notice:
The file mnist.npz
is already included in the current workspace under the data
directory. 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.
load_data
returns the train and test sets in the form of the tuples (x_train, y_train), (x_test, y_test)
but in this exercise you will be needing only the train set so you can ignore the second tuple.
# grader-required-cell
# 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, "data/mnist.npz")
# Discard 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:
# grader-required-cell
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)
Now it is time to create your own custom callback. For this complete the myCallback
class and the on_epoch_end
method in the cell below. If you need some guidance on how to proceed, check out this link.
# grader-required-cell
# GRADED CLASS: myCallback
### START CODE HERE
# Remember to inherit from the correct class
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
### END CODE HERE
Now that you have defined your callback it is time to complete the train_mnist
function below.
You must set your model to train for 10 epochs and the callback should fire before the 9th epoch for you to pass this assignment.
Hint:
# grader-required-cell
# GRADED FUNCTION: train_mnist
def train_mnist(x_train, y_train):
### START CODE HERE
# Instantiate the callback class
callbacks = myCallback()
# Define the model
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(512, 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])
### END CODE HERE
return history
Call the train_mnist
passing in the appropiate parameters to get the training history:
# grader-required-cell
hist = train_mnist(x_train, y_train)
Epoch 1/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.2009 - accuracy: 0.9407
Epoch 2/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0824 - accuracy: 0.9744
Epoch 3/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0534 - accuracy: 0.9837
Epoch 4/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0368 - accuracy: 0.9886
Epoch 5/10
1867/1875 [============================>.] - ETA: 0s - loss: 0.0272 - accuracy: 0.9910
Reached 99% accuracy so cancelling training!
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0274 - accuracy: 0.9909
If you see the message Reached 99% accuracy so cancelling training!
printed out after less than 9 epochs it means your callback worked as expected.
Run the following cell to see an architecture that works well for the problem at hand:
# WE STRONGLY RECOMMEND YOU TO TRY YOUR OWN ARCHITECTURES FIRST
# AND ONLY RUN THIS CELL IF YOU WISH TO SEE AN ANSWER
import base64
encoded_answer = "CiAgIC0gQSBGbGF0dGVuIGxheWVyIHRoYXQgcmVjZWl2ZXMgaW5wdXRzIHdpdGggdGhlIHNhbWUgc2hhcGUgYXMgdGhlIGltYWdlcwogICAtIEEgRGVuc2UgbGF5ZXIgd2l0aCA1MTIgdW5pdHMgYW5kIFJlTFUgYWN0aXZhdGlvbiBmdW5jdGlvbgogICAtIEEgRGVuc2UgbGF5ZXIgd2l0aCAxMCB1bml0cyBhbmQgc29mdG1heCBhY3RpdmF0aW9uIGZ1bmN0aW9uCg=="
encoded_answer = encoded_answer.encode('ascii')
answer = base64.b64decode(encoded_answer)
answer = answer.decode('ascii')
print(answer)
Congratulations on finishing this week’s assignment!
You have successfully implemented a callback that gives you more control over the training loop for your model. Nice job!
Keep it up!
Important Note: Please only do this when you've already passed the assignment to avoid problems with the autograder.
Here's a short demo of how to do the steps above: