Welcome to the first assignment of week 2. In this assignment, you will:
input_shape
import numpy as np
from keras import layers
from keras.layers import Input, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D
from keras.layers import AveragePooling2D, MaxPooling2D, Dropout, GlobalMaxPooling2D, GlobalAveragePooling2D
from keras.models import Model
from keras.preprocessing import image
from keras.utils import layer_utils
from keras.utils.data_utils import get_file
from keras.applications.imagenet_utils import preprocess_input
import pydot
from IPython.display import SVG
from keras.utils.vis_utils import model_to_dot
from keras.utils import plot_model
from kt_utils import *
import keras.backend as K
K.set_image_data_format('channels_last')
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
%matplotlib inline
Using TensorFlow backend.
Note: As you can see, we've imported a lot of functions from Keras. You can use them by calling them directly in your code. Ex: X = Input(...)
or X = ZeroPadding2D(...)
.
In other words, unlike TensorFlow, you don't have to create the graph and then make a separate sess.run()
call to evaluate those variables.
To build and train this model, you have gathered pictures of some volunteers in a nearby neighborhood. The dataset is labeled.
Run the following code to normalize the dataset and learn about its shapes.
X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()
# Normalize image vectors
X_train = X_train_orig/255.
X_test = X_test_orig/255.
# Reshape
Y_train = Y_train_orig.T
Y_test = Y_test_orig.T
print ("number of training examples = " + str(X_train.shape[0]))
print ("number of test examples = " + str(X_test.shape[0]))
print ("X_train shape: " + str(X_train.shape))
print ("Y_train shape: " + str(Y_train.shape))
print ("X_test shape: " + str(X_test.shape))
print ("Y_test shape: " + str(Y_test.shape))
number of training examples = 600 number of test examples = 150 X_train shape: (600, 64, 64, 3) Y_train shape: (600, 1) X_test shape: (150, 64, 64, 3) Y_test shape: (150, 1)
Details of the "Face" dataset:
Keras is very good for rapid prototyping. In just a short time you will be able to build a model that achieves outstanding results.
Here is an example of a model in Keras:
def model(input_shape):
"""
input_shape: The height, width and channels as a tuple.
Note that this does not include the 'batch' as a dimension.
If you have a batch like 'X_train',
then you can provide the input_shape using
X_train.shape[1:]
"""
# Define the input placeholder as a tensor with shape input_shape. Think of this as your input image!
X_input = Input(input_shape)
# Zero-Padding: pads the border of X_input with zeroes
X = ZeroPadding2D((3, 3))(X_input)
# CONV -> BN -> RELU Block applied to X
X = Conv2D(32, (7, 7), strides = (1, 1), name = 'conv0')(X)
X = BatchNormalization(axis = 3, name = 'bn0')(X)
X = Activation('relu')(X)
# MAXPOOL
X = MaxPooling2D((2, 2), name='max_pool')(X)
# FLATTEN X (means convert it to a vector) + FULLYCONNECTED
X = Flatten()(X)
X = Dense(1, activation='sigmoid', name='fc')(X)
# Create model. This creates your Keras model instance, you'll use this instance to train/test the model.
model = Model(inputs = X_input, outputs = X, name='HappyModel')
return model
X = ...
Z1 = ...
A1 = ...
X = ...
X = ...
X = ...
X_input
, which we kept separate since it's needed later.X = ZeroPadding2D((3, 3))(X_input)
ZP = ZeroPadding2D((3, 3)) # ZP is an object that can be called as a function
X = ZP(X_input)
Exercise: Implement a HappyModel()
.
AveragePooling2D()
, GlobalMaxPooling2D()
, Dropout()
.Note: Be careful with your data's shapes. Use what you've learned in the videos to make sure your convolutional, pooling and fully-connected layers are adapted to the volumes you're applying it to.
# GRADED FUNCTION: HappyModel
def HappyModel(input_shape):
"""
Implementation of the HappyModel.
Arguments:
input_shape -- shape of the images of the dataset
(height, width, channels) as a tuple.
Note that this does not include the 'batch' as a dimension.
If you have a batch like 'X_train',
then you can provide the input_shape using
X_train.shape[1:]
Returns:
model -- a Model() instance in Keras
"""
### START CODE HERE ###
# Feel free to use the suggested outline in the text above to get started, and run through the whole
# exercise (including the later portions of this notebook) once. The come back also try out other
# network architectures as well.
# Define the input placeholder as a tensor with shape input_shape. Think of this as your input image!
X_input = Input(input_shape)
# Zero-Padding: pads the border of X_input with zeroes
X = ZeroPadding2D((3, 3))(X_input)
# CONV -> BN -> RELU Block applied to X
X = Conv2D(32, (7, 7), strides = (1, 1), name = 'conv0')(X)
X = BatchNormalization(axis = 3, name = 'bn0')(X)
X = Activation('relu')(X)
# MAXPOOL
X = MaxPooling2D((2, 2), name='max_pool')(X)
# FLATTEN X (means convert it to a vector) + FULLYCONNECTED
X = Flatten()(X)
X = Dense(1, activation='sigmoid', name='fc')(X)
# Create model. This creates your Keras model instance, you'll use this instance to train/test the model.
model = Model(inputs = X_input, outputs = X, name='HappyModel')
### END CODE HERE ###
return model
You have now built a function to describe your model. To train and test this model, there are four steps in Keras:
Create the model by calling the function above
Compile the model by calling model.compile(optimizer = "...", loss = "...", metrics = ["accuracy"])
Train the model on train data by calling model.fit(x = ..., y = ..., epochs = ..., batch_size = ...)
Test the model on test data by calling model.evaluate(x = ..., y = ...)
If you want to know more about model.compile()
, model.fit()
, model.evaluate()
and their arguments, refer to the official Keras documentation.
Hint:
The input_shape
parameter is a tuple (height, width, channels). It excludes the batch number.
Try X_train.shape[1:]
as the input_shape
.
### START CODE HERE ### (1 line)
happyModel = HappyModel(X_train.shape[1:])
### END CODE HERE ###
Hint:
Optimizers you can try include 'adam'
, 'sgd'
or others. See the documentation for optimizers
The "happiness detection" is a binary classification problem. The loss function that you can use is 'binary_cross_entropy'
. Note that 'categorical_cross_entropy'
won't work with your data set as its formatted, because the data is an array of 0 or 1 rather than two arrays (one for each category). Documentation for losses
### START CODE HERE ### (1 line)
happyModel.compile(optimizer="adam", loss="binary_crossentropy", metrics=["accuracy"])
### END CODE HERE ###
Hint:
Use the 'X_train'
, 'Y_train'
variables. Use integers for the epochs and batch_size
Note: If you run fit()
again, the model
will continue to train with the parameters it has already learned instead of reinitializing them.
### START CODE HERE ### (1 line)
happyModel.fit(X_train, Y_train, epochs=40, batch_size=16)
### END CODE HERE ###
Epoch 1/40 600/600 [==============================] - 13s - loss: 1.0135 - acc: 0.7167 Epoch 2/40 600/600 [==============================] - 14s - loss: 0.2618 - acc: 0.8933 Epoch 3/40 600/600 [==============================] - 15s - loss: 0.1645 - acc: 0.9267 Epoch 4/40 600/600 [==============================] - 15s - loss: 0.2936 - acc: 0.8900 Epoch 5/40 600/600 [==============================] - 15s - loss: 0.1807 - acc: 0.9400 Epoch 6/40 600/600 [==============================] - 12s - loss: 0.0837 - acc: 0.9733 Epoch 7/40 600/600 [==============================] - 12s - loss: 0.1091 - acc: 0.9600 Epoch 8/40 600/600 [==============================] - 12s - loss: 0.0626 - acc: 0.9800 Epoch 9/40 600/600 [==============================] - 12s - loss: 0.0862 - acc: 0.9733 Epoch 10/40 600/600 [==============================] - 12s - loss: 0.0622 - acc: 0.9833 Epoch 11/40 600/600 [==============================] - 12s - loss: 0.1605 - acc: 0.9467 Epoch 12/40 600/600 [==============================] - 12s - loss: 0.0742 - acc: 0.9700 Epoch 13/40 600/600 [==============================] - 12s - loss: 0.1780 - acc: 0.9333 Epoch 14/40 600/600 [==============================] - 12s - loss: 0.1964 - acc: 0.9417 Epoch 15/40 600/600 [==============================] - 12s - loss: 0.1130 - acc: 0.9600 Epoch 16/40 600/600 [==============================] - 12s - loss: 0.1369 - acc: 0.9517 Epoch 17/40 600/600 [==============================] - 12s - loss: 0.1024 - acc: 0.9683 Epoch 18/40 600/600 [==============================] - 12s - loss: 0.0844 - acc: 0.9700 Epoch 19/40 600/600 [==============================] - 12s - loss: 0.0534 - acc: 0.9867 Epoch 20/40 600/600 [==============================] - 12s - loss: 0.0500 - acc: 0.9817 Epoch 21/40 600/600 [==============================] - 12s - loss: 0.0974 - acc: 0.9767 Epoch 22/40 600/600 [==============================] - 12s - loss: 0.0916 - acc: 0.9667 Epoch 23/40 600/600 [==============================] - 12s - loss: 0.0773 - acc: 0.9767 Epoch 24/40 600/600 [==============================] - 12s - loss: 0.0758 - acc: 0.9767 Epoch 25/40 600/600 [==============================] - 12s - loss: 0.0370 - acc: 0.9900 Epoch 26/40 600/600 [==============================] - 12s - loss: 0.0383 - acc: 0.9833 Epoch 27/40 600/600 [==============================] - 12s - loss: 0.0366 - acc: 0.9867 Epoch 28/40 600/600 [==============================] - 12s - loss: 0.0338 - acc: 0.9900 Epoch 29/40 600/600 [==============================] - 12s - loss: 0.0330 - acc: 0.9917 Epoch 30/40 600/600 [==============================] - 12s - loss: 0.0949 - acc: 0.9683 Epoch 31/40 600/600 [==============================] - 12s - loss: 0.0303 - acc: 0.9900 Epoch 32/40 600/600 [==============================] - 12s - loss: 0.0433 - acc: 0.9883 Epoch 33/40 600/600 [==============================] - 12s - loss: 0.0421 - acc: 0.9867 Epoch 34/40 600/600 [==============================] - 12s - loss: 0.0431 - acc: 0.9850 Epoch 35/40 600/600 [==============================] - 12s - loss: 0.0555 - acc: 0.9817 Epoch 36/40 600/600 [==============================] - 12s - loss: 0.0772 - acc: 0.9800 Epoch 37/40 600/600 [==============================] - 12s - loss: 0.0163 - acc: 0.9933 Epoch 38/40 600/600 [==============================] - 12s - loss: 0.1446 - acc: 0.9633 Epoch 39/40 600/600 [==============================] - 12s - loss: 0.0614 - acc: 0.9783 Epoch 40/40 600/600 [==============================] - 12s - loss: 0.0907 - acc: 0.9783
<keras.callbacks.History at 0x7f1f417b3710>
Hint:
Use the 'X_test'
and 'Y_test'
variables to evaluate the model's performance.
### START CODE HERE ### (1 line)
preds = happyModel.evaluate(X_test, Y_test)
### END CODE HERE ###
print()
print ("Loss = " + str(preds[0]))
print ("Test Accuracy = " + str(preds[1]))
150/150 [==============================] - 1s Loss = 0.217553080916 Test Accuracy = 0.919999997616
If your happyModel()
function worked, its accuracy should be better than random guessing (50% accuracy).
To give you a point of comparison, our model gets around 95% test accuracy in 40 epochs (and 99% train accuracy) with a mini batch size of 16 and "adam" optimizer.
If you have not yet achieved a very good accuracy (>= 80%), here are some things tips:
X = Conv2D(32, (3, 3), strides = (1, 1), name = 'conv0')(X)
X = BatchNormalization(axis = 3, name = 'bn0')(X)
X = Activation('relu')(X)
until your height and width dimensions are quite low and your number of channels quite large (≈32 for example).
You can then flatten the volume and use a fully-connected layer.
Note: If you perform hyperparameter tuning on your model, the test set actually becomes a dev set, and your model might end up overfitting to the test (dev) set. Normally, you'll want separate dev and test sets. The dev set is used for parameter tuning, and the test set is used once to estimate the model's performance in production.
Congratulations, you have created a proof of concept for "happiness detection"!
Congratulations on finishing this assignment. You can now take a picture of your face and see if it can classify whether your expression is "happy" or "not happy". To do that:
The training/test sets were quite similar; for example, all the pictures were taken against the same background (since a front door camera is always mounted in the same position). This makes the problem easier, but a model trained on this data may or may not work on your own data. But feel free to give it a try!
### START CODE HERE ###
img_path = 'images/my_image.jpg'
### END CODE HERE ###
img = image.load_img(img_path, target_size=(64, 64))
imshow(img)
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
print(happyModel.predict(x))
[[ 0.]]
Two other basic features of Keras that you'll find useful are:
model.summary()
: prints the details of your layers in a table with the sizes of its inputs/outputsplot_model()
: plots your graph in a nice layout. You can even save it as ".png" using SVG() if you'd like to share it on social media ;). It is saved in "File" then "Open..." in the upper bar of the notebook.Run the following code.
happyModel.summary()
_________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) (None, 64, 64, 3) 0 _________________________________________________________________ zero_padding2d_1 (ZeroPaddin (None, 70, 70, 3) 0 _________________________________________________________________ conv0 (Conv2D) (None, 64, 64, 32) 4736 _________________________________________________________________ bn0 (BatchNormalization) (None, 64, 64, 32) 128 _________________________________________________________________ activation_1 (Activation) (None, 64, 64, 32) 0 _________________________________________________________________ max_pool (MaxPooling2D) (None, 32, 32, 32) 0 _________________________________________________________________ flatten_1 (Flatten) (None, 32768) 0 _________________________________________________________________ fc (Dense) (None, 1) 32769 ================================================================= Total params: 37,633 Trainable params: 37,569 Non-trainable params: 64 _________________________________________________________________
plot_model(happyModel, to_file='HappyModel.png')
SVG(model_to_dot(happyModel).create(prog='dot', format='svg'))