TensorFlow
Task 1.2 Train a neural network with Callbacks in TensorFlow using the MNIST Dataset to reach 99% accuracy.
A Flatten layer that receives inputs with the same shape as the images
A Dense layer with 512 units and ReLU activation function
A Dense layer with 10 units and softmax activation function
Results
Epoch 1/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.2020 - accuracy: 0.9410
Epoch 2/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0811 - accuracy: 0.9756
Epoch 3/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0517 - accuracy: 0.9844
Epoch 4/10
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0371 - accuracy: 0.9885
Epoch 5/10
1873/1875 [============================>.] - ETA: 0s - loss: 0.0282 - accuracy: 0.9908
Reached 99% accuracy so cancelling training!
1875/1875 [==============================] - 8s 4ms/step - loss: 0.0282 - accuracy: 0.9908
Code
import os
import tensorflow as tf
from tensorflow import keras
# Load and inspect 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
# Defining the callback
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
def train_mnist(x_train, y_train):
# 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])
return history
hist = train_mnist(x_train, y_train)
Task 1.3 Train a convolutional neural network with callback using the MNIST Dataset to reach 99.5% accuracy.
Epoch 1/10
1875/1875 [==============================] - 35s 19ms/step - loss: 0.1488 - accuracy: 0.9569
Epoch 2/10
1875/1875 [==============================] - 35s 19ms/step - loss: 0.0514 - accuracy: 0.9841
Epoch 3/10
1875/1875 [==============================] - 35s 18ms/step - loss: 0.0335 - accuracy: 0.9899
Epoch 4/10
1875/1875 [==============================] - 35s 18ms/step - loss: 0.0223 - accuracy: 0.9932
Epoch 5/10
1875/1875 [==============================] - 35s 19ms/step - loss: 0.0153 - accuracy: 0.9950
Epoch 6/10
1875/1875 [==============================] - ETA: 0s - loss: 0.0112 - accuracy: 0.9963
Reached 99.5% accuracy so cancelling training!
1875/1875 [==============================] - 35s 19ms/step - loss: 0.0112 - accuracy: 0.9963
import os
import numpy as np
import tensorflow as tf
from tensorflow import keras
# 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")
# Get only training set
(training_images, training_labels), _ = tf.keras.datasets.mnist.load_data(path=data_path)
def reshape_and_normalize(images):
### START CODE HERE
# Reshape the images to add an extra dimension
s0, s1, s2 = images.shape;
images = images.reshape(s0, s1, s2, 1)
# Normalize pixel values
images = images / 255.0
### END CODE HERE
return images
# Reload the images in case you run this cell multiple times
(training_images, _), _ = tf.keras.datasets.mnist.load_data(path=data_path)
# Apply your function
training_images = reshape_and_normalize(training_images)
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}")
# 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
def convolutional_model():
# Define the model
model = tf.keras.models.Sequential([
# Add convolutions and max pooling
tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D(2, 2),
# Add the same layers as before
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'])
return model
# Save your untrained model
model = convolutional_model()
# Get number of weights
model_params = model.count_params()
# Unit test to limit the size of the model
assert model_params < 1000000, (
f'Your model has {model_params:,} params. For successful grading, please keep it '
f'under 1,000,000 by reducing the number of units in your Conv2D and/or Dense layers.'
)
# 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])
print(f"Your model was trained for {len(history.epoch)} epochs")
Task 1.4 Use the ImageDataGenerator to prepare the Horses or Humans dataset and train a convolutional neural network to classify human and horses.
Model Summary
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 298, 298, 16) 448
max_pooling2d (MaxPooling2 (None, 149, 149, 16) 0
D)
conv2d_1 (Conv2D) (None, 147, 147, 32) 4640
max_pooling2d_1 (MaxPoolin (None, 73, 73, 32) 0
g2D)
conv2d_2 (Conv2D) (None, 71, 71, 64) 18496
max_pooling2d_2 (MaxPoolin (None, 35, 35, 64) 0
g2D)
conv2d_3 (Conv2D) (None, 33, 33, 64) 36928
max_pooling2d_3 (MaxPoolin (None, 16, 16, 64) 0
g2D)
conv2d_4 (Conv2D) (None, 14, 14, 64) 36928
max_pooling2d_4 (MaxPoolin (None, 7, 7, 64) 0
g2D)
flatten (Flatten) (None, 3136) 0
dense (Dense) (None, 512) 1606144
dense_1 (Dense) (None, 1) 513
=================================================================
Total params: 1704097 (6.50 MB)
Trainable params: 1704097 (6.50 MB)
Non-trainable params: 0 (0.00 Byte)
_________________________________________________________________
Training Output
Epoch 1/15
8/8 [==============================] - 21s 728ms/step - loss: 0.6818 - accuracy: 0.5261
Epoch 2/15
8/8 [==============================] - 8s 1s/step - loss: 0.6593 - accuracy: 0.6338
Epoch 3/15
8/8 [==============================] - 7s 782ms/step - loss: 0.5629 - accuracy: 0.7052
Epoch 4/15
8/8 [==============================] - 7s 863ms/step - loss: 0.3728 - accuracy: 0.8543
Epoch 5/15
8/8 [==============================] - 6s 771ms/step - loss: 0.3862 - accuracy: 0.8498
Epoch 6/15
8/8 [==============================] - 7s 772ms/step - loss: 0.2239 - accuracy: 0.9255
Epoch 7/15
8/8 [==============================] - 7s 852ms/step - loss: 0.3520 - accuracy: 0.8498
Epoch 8/15
8/8 [==============================] - 7s 827ms/step - loss: 0.1984 - accuracy: 0.9277
Epoch 9/15
8/8 [==============================] - 7s 784ms/step - loss: 0.0905 - accuracy: 0.9689
Epoch 10/15
8/8 [==============================] - 7s 842ms/step - loss: 0.2262 - accuracy: 0.9199
Epoch 11/15
8/8 [==============================] - 8s 972ms/step - loss: 0.0907 - accuracy: 0.9658
Epoch 12/15
8/8 [==============================] - 6s 759ms/step - loss: 0.5115 - accuracy: 0.8443
Epoch 13/15
8/8 [==============================] - 6s 767ms/step - loss: 0.0827 - accuracy: 0.9722
Epoch 14/15
8/8 [==============================] - 7s 859ms/step - loss: 0.0452 - accuracy: 0.9844
Epoch 15/15
8/8 [==============================] - 7s 803ms/step - loss: 0.6421 - accuracy: 0.8966
Visualizing Intermediate Representations
Code [Dataset to download]
import zipfile
# Unzip the dataset
local_zip = './horse-or-human.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('./horse-or-human')
zip_ref.close()
import os
# Directory with our training horse pictures
train_horse_dir = os.path.join('./horse-or-human/horses')
# Directory with our training human pictures
train_human_dir = os.path.join('./horse-or-human/humans')
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# Parameters for our graph; we'll output images in a 4x4 configuration
nrows = 4
ncols = 4
# Index for iterating over images
pic_index = 0
# Set up matplotlib fig, and size it to fit 4x4 pics
fig = plt.gcf()
fig.set_size_inches(ncols * 4, nrows * 4)
pic_index += 8
next_horse_pix = [os.path.join(train_horse_dir, fname)
for fname in train_horse_names[pic_index-8:pic_index]]
next_human_pix = [os.path.join(train_human_dir, fname)
for fname in train_human_names[pic_index-8:pic_index]]
for i, img_path in enumerate(next_horse_pix+next_human_pix):
# Set up subplot; subplot indices start at 1
sp = plt.subplot(nrows, ncols, i + 1)
sp.axis('Off') # Don't show axes (or gridlines)
img = mpimg.imread(img_path)
plt.imshow(img)
plt.show()
import tensorflow as tf
model = tf.keras.models.Sequential([
# Note the input shape is the desired size of the image 300x300 with 3 bytes color
# This is the first convolution
tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(300, 300, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
# The second convolution
tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The third convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fourth convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# The fifth convolution
tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
tf.keras.layers.MaxPooling2D(2,2),
# Flatten the results to feed into a DNN
tf.keras.layers.Flatten(),
# 512 neuron hidden layer
tf.keras.layers.Dense(512, activation='relu'),
# Only 1 output neuron. It will contain a value from 0-1 where 0 for 1 class ('horses') and 1 for the other ('humans')
tf.keras.layers.Dense(1, activation='sigmoid')
])
from tensorflow.keras.optimizers import RMSprop
model.compile(loss='binary_crossentropy',
optimizer=RMSprop(learning_rate=0.001),
metrics=['accuracy'])
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# All images will be rescaled by 1./255
train_datagen = ImageDataGenerator(rescale=1/255)
# Flow training images in batches of 128 using train_datagen generator
train_generator = train_datagen.flow_from_directory(
'./horse-or-human/', # This is the source directory for training images
target_size=(300, 300), # All images will be resized to 300x300
batch_size=128,
# Since we use binary_crossentropy loss, we need binary labels
class_mode='binary')
history = model.fit(
train_generator,
steps_per_epoch=8,
epochs=15,
verbose=1)
import numpy as np
import random
from tensorflow.keras.utils import img_to_array, load_img
# Define a new Model that will take an image as input, and will output
# intermediate representations for all layers in the previous model after
# the first.
successive_outputs = [layer.output for layer in model.layers[1:]]
visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs)
# Prepare a random input image from the training set.
horse_img_files = [os.path.join(train_horse_dir, f) for f in train_horse_names]
human_img_files = [os.path.join(train_human_dir, f) for f in train_human_names]
img_path = random.choice(horse_img_files + human_img_files)
img = load_img(img_path, target_size=(300, 300)) # this is a PIL image
x = img_to_array(img) # Numpy array with shape (300, 300, 3)
x = x.reshape((1,) + x.shape) # Numpy array with shape (1, 300, 300, 3)
# Scale by 1/255
x /= 255
# Run the image through the network, thus obtaining all
# intermediate representations for this image.
successive_feature_maps = visualization_model.predict(x)
# These are the names of the layers, so you can have them as part of the plot
layer_names = [layer.name for layer in model.layers[1:]]
# Display the representations
for layer_name, feature_map in zip(layer_names, successive_feature_maps):
if len(feature_map.shape) == 4:
# Just do this for the conv / maxpool layers, not the fully-connected layers
n_features = feature_map.shape[-1] # number of features in feature map
# The feature map has shape (1, size, size, n_features)
size = feature_map.shape[1]
# Tile the images in this matrix
display_grid = np.zeros((size, size * n_features))
for i in range(n_features):
x = feature_map[0, :, :, i]
x -= x.mean()
x /= x.std()
x *= 64
x += 128
x = np.clip(x, 0, 255).astype('uint8')
# Tile each filter into this big horizontal grid
display_grid[:, i * size : (i + 1) * size] = x
# Display the grid
scale = 20. / n_features
plt.figure(figsize=(scale * n_features, scale))
plt.title(layer_name)
plt.grid(False)
plt.imshow(display_grid, aspect='auto', cmap='viridis')
Task 2.1 Train a model with 3 convolutional layers with the Cats vs Dogs Dataset to achieve 95% training accuracy.
Model Summary
Model: "sequential_3"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d_9 (Conv2D) (None, 148, 148, 16) 448
max_pooling2d_9 (MaxPoolin (None, 74, 74, 16) 0
g2D)
conv2d_10 (Conv2D) (None, 72, 72, 32) 4640
max_pooling2d_10 (MaxPooli (None, 36, 36, 32) 0
ng2D)
conv2d_11 (Conv2D) (None, 34, 34, 64) 18496
max_pooling2d_11 (MaxPooli (None, 17, 17, 64) 0
ng2D)
flatten_3 (Flatten) (None, 18496) 0
dense_6 (Dense) (None, 512) 9470464
dense_7 (Dense) (None, 1) 513
=================================================================
Total params: 9494561 (36.22 MB)
Trainable params: 9494561 (36.22 MB)
Non-trainable params: 0 (0.00 Byte)
_______________________________________
Output
Epoch 1/15
225/225 [==============================] - 47s 200ms/step - loss: 0.6330 - accuracy: 0.6367 - val_loss: 0.5838 - val_accuracy: 0.6716
Epoch 2/15
225/225 [==============================] - 46s 205ms/step - loss: 0.5155 - accuracy: 0.7412 - val_loss: 0.5457 - val_accuracy: 0.7104
Epoch 3/15
225/225 [==============================] - 46s 203ms/step - loss: 0.4556 - accuracy: 0.7829 - val_loss: 0.4743 - val_accuracy: 0.7688
Epoch 4/15
225/225 [==============================] - 45s 200ms/step - loss: 0.4132 - accuracy: 0.8068 - val_loss: 0.4202 - val_accuracy: 0.8080
Epoch 5/15
225/225 [==============================] - 45s 200ms/step - loss: 0.3682 - accuracy: 0.8336 - val_loss: 0.4300 - val_accuracy: 0.8092
Epoch 6/15
225/225 [==============================] - 46s 204ms/step - loss: 0.3266 - accuracy: 0.8543 - val_loss: 0.4840 - val_accuracy: 0.7924
Epoch 7/15
225/225 [==============================] - 44s 194ms/step - loss: 0.2701 - accuracy: 0.8828 - val_loss: 0.4036 - val_accuracy: 0.8216
Epoch 8/15
225/225 [==============================] - 45s 201ms/step - loss: 0.1987 - accuracy: 0.9200 - val_loss: 0.4421 - val_accuracy: 0.8164
Epoch 9/15
225/225 [==============================] - 43s 192ms/step - loss: 0.1304 - accuracy: 0.9528 - val_loss: 0.5991 - val_accuracy: 0.8088
Epoch 10/15
225/225 [==============================] - 45s 200ms/step - loss: 0.0953 - accuracy: 0.9696 - val_loss: 0.6830 - val_accuracy: 0.8108
Epoch 11/15
225/225 [==============================] - 45s 198ms/step - loss: 0.0730 - accuracy: 0.9787 - val_loss: 0.6458 - val_accuracy: 0.8124
Epoch 12/15
225/225 [==============================] - 44s 194ms/step - loss: 0.0347 - accuracy: 0.9904 - val_loss: 0.9065 - val_accuracy: 0.8184
Epoch 13/15
225/225 [==============================] - 43s 191ms/step - loss: 0.0468 - accuracy: 0.9868 - val_loss: 0.8835 - val_accuracy: 0.8156
Epoch 14/15
225/225 [==============================] - 47s 207ms/step - loss: 0.0194 - accuracy: 0.9943 - val_loss: 1.3348 - val_accuracy: 0.7876
Epoch 15/15
225/225 [==============================] - 44s 197ms/step - loss: 0.0111 - accuracy: 0.9968 - val_loss: 1.1017 - val_accuracy: 0.8192
Code[dataset]
import os
import zipfile
import random
import shutil
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from shutil import copyfile
import matplotlib.pyplot as plt
!wget --no-check-certificate \
"https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_5340.zip" \
-O "/tmp/cats-and-dogs.zip"
local_zip = '/tmp/cats-and-dogs.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp')
zip_ref.close()
source_path = '/tmp/PetImages'
source_path_dogs = os.path.join(source_path, 'Dog')
source_path_cats = os.path.join(source_path, 'Cat')
# Deletes all non-image files (there are two .db files bundled into the dataset)
!find /tmp/PetImages/ -type f ! -name "*.jpg" -exec rm {} +
# os.listdir returns a list containing all files under the given path
print(f"There are {len(os.listdir(source_path_dogs))} images of dogs.")
print(f"There are {len(os.listdir(source_path_cats))} images of cats.")
# Define root directory
root_dir = '/tmp/cats-v-dogs'
# Empty directory to prevent FileExistsError is the function is run several times
if os.path.exists(root_dir):
shutil.rmtree(root_dir)
# GRADED FUNCTION: create_train_val_dirs
def create_train_val_dirs(root_path):
"""
Creates directories for the train and test sets
Args:
root_path (string) - the base directory path to create subdirectories from
Returns:
None
"""
### START CODE HERE
# HINT:
# Use os.makedirs to create your directories with intermediate subdirectories
# Don't hardcode the paths. Use os.path.join to append the new directories to the root_path parameter
train_dir = 'training'
val_dir = 'validation'
train_path = os.path.join(root_path, train_dir)
val_path = os.path.join(root_path, val_dir)
train_path_cat = os.path.join(train_path, 'cats')
val_path_cat = os.path.join(val_path, 'cats')
train_path_dog = os.path.join(train_path, 'dogs')
val_path_dog = os.path.join(val_path, 'dogs')
os.makedirs(train_path)
os.makedirs(val_path)
os.makedirs(train_path_cat)
os.makedirs(val_path_cat)
os.makedirs(train_path_dog)
os.makedirs(val_path_dog)
### END CODE HERE
try:
create_train_val_dirs(root_path=root_dir)
except FileExistsError:
print("You should not be seeing this since the upper directory is removed beforehand")
def split_data(SOURCE_DIR, TRAINING_DIR, VALIDATION_DIR, SPLIT_SIZE):
"""
Splits the data into train and test sets
Args:
SOURCE_DIR (string): directory path containing the images
TRAINING_DIR (string): directory path to be used for training
VALIDATION_DIR (string): directory path to be used for validation
SPLIT_SIZE (float): proportion of the dataset to be used for training
Returns:
None
"""
### START CODE HERE
files = []
for filename in os.listdir(SOURCE_DIR):
file = SOURCE_DIR + filename
if os.path.getsize(file) > 0:
files.append(filename)
else:
print(filename + " is zero length, so ignoring.")
training_length = int(len(files) * SPLIT_SIZE)
testing_length = int(len(files) - training_length)
shuffled_set = random.sample(files, len(files))
training_set = shuffled_set[0:training_length]
testing_set = shuffled_set[-testing_length:]
for filename in training_set:
this_file = SOURCE_DIR + filename
destination = TRAINING_DIR + filename
copyfile(this_file, destination)
for filename in testing_set:
this_file = SOURCE_DIR + filename
destination = VALIDATION_DIR + filename
copyfile(this_file, destination)
# Define paths
CAT_SOURCE_DIR = "/tmp/PetImages/Cat/"
DOG_SOURCE_DIR = "/tmp/PetImages/Dog/"
TRAINING_DIR = "/tmp/cats-v-dogs/training/"
VALIDATION_DIR = "/tmp/cats-v-dogs/validation/"
TRAINING_CATS_DIR = os.path.join(TRAINING_DIR, "cats/")
VALIDATION_CATS_DIR = os.path.join(VALIDATION_DIR, "cats/")
TRAINING_DOGS_DIR = os.path.join(TRAINING_DIR, "dogs/")
VALIDATION_DOGS_DIR = os.path.join(VALIDATION_DIR, "dogs/")
# Empty directories in case you run this cell multiple times
if len(os.listdir(TRAINING_CATS_DIR)) > 0:
for file in os.scandir(TRAINING_CATS_DIR):
os.remove(file.path)
if len(os.listdir(TRAINING_DOGS_DIR)) > 0:
for file in os.scandir(TRAINING_DOGS_DIR):
os.remove(file.path)
if len(os.listdir(VALIDATION_CATS_DIR)) > 0:
for file in os.scandir(VALIDATION_CATS_DIR):
os.remove(file.path)
if len(os.listdir(VALIDATION_DOGS_DIR)) > 0:
for file in os.scandir(VALIDATION_DOGS_DIR):
os.remove(file.path)
# Define proportion of images used for training
split_size = .9
# Run the function
# NOTE: Messages about zero length images should be printed out
split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, VALIDATION_CATS_DIR, split_size)
split_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, VALIDATION_DOGS_DIR, split_size)
# Check that the number of images matches the expected output
# Your function should perform copies rather than moving images so original directories should contain unchanged images
print(f"\n\nOriginal cat's directory has {len(os.listdir(CAT_SOURCE_DIR))} images")
print(f"Original dog's directory has {len(os.listdir(DOG_SOURCE_DIR))} images\n")
# Training and validation splits
print(f"There are {len(os.listdir(TRAINING_CATS_DIR))} images of cats for training")
print(f"There are {len(os.listdir(TRAINING_DOGS_DIR))} images of dogs for training")
print(f"There are {len(os.listdir(VALIDATION_CATS_DIR))} images of cats for validation")
print(f"There are {len(os.listdir(VALIDATION_DOGS_DIR))} images of dogs for validation")
def train_val_generators(TRAINING_DIR, VALIDATION_DIR):
"""
Creates the training and validation data generators
Args:
TRAINING_DIR (string): directory path containing the training images
VALIDATION_DIR (string): directory path containing the testing/validation images
Returns:
train_generator, validation_generator - tuple containing the generators
"""
### START CODE HERE
# Instantiate the ImageDataGenerator class (don't forget to set the rescale argument)
train_datagen = ImageDataGenerator(rescale=1.0/255.)
# Pass in the appropriate arguments to the flow_from_directory method
train_generator = train_datagen.flow_from_directory(directory=TRAINING_DIR,
batch_size=100,
class_mode='binary',
target_size=(150, 150))
# Instantiate the ImageDataGenerator class (don't forget to set the rescale argument)
validation_datagen = ImageDataGenerator(rescale=1.0/255.)
# Pass in the appropriate arguments to the flow_from_directory method
validation_generator = validation_datagen.flow_from_directory(directory=VALIDATION_DIR,
batch_size=100,
class_mode='binary',
target_size=(150, 150))
### END CODE HERE
return train_generator, validation_generator
train_generator, validation_generator = train_val_generators(TRAINING_DIR, VALIDATION_DIR)
def create_model():
# DEFINE A KERAS MODEL TO CLASSIFY CATS V DOGS
# USE AT LEAST 3 CONVOLUTION LAYERS
### START CODE HERE
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3, 3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
from tensorflow.keras.optimizers import RMSprop
model.compile(optimizer=RMSprop(learning_rate=0.001),
loss='binary_crossentropy',
metrics=['accuracy'])
### END CODE HERE
return model
model = create_model()
# Train the model
# Note that this may take some time.
history = model.fit(train_generator,
epochs=15,
verbose=1,
validation_data=validation_generator)
model.summary()
#-----------------------------------------------------------
# Retrieve a list of list results on training and test data
# sets for each training epoch
#-----------------------------------------------------------
acc=history.history['accuracy']
val_acc=history.history['val_accuracy']
loss=history.history['loss']
val_loss=history.history['val_loss']
epochs=range(len(acc)) # Get number of epochs
#------------------------------------------------
# Plot training and validation accuracy per epoch
#------------------------------------------------
plt.plot(epochs, acc, 'r', "Training Accuracy")
plt.plot(epochs, val_acc, 'b', "Validation Accuracy")
plt.title('Training and validation accuracy')
plt.show()
print("")
#------------------------------------------------
# Plot training and validation loss per epoch
#------------------------------------------------
plt.plot(epochs, loss, 'r', "Training Loss")
plt.plot(epochs, val_loss, 'b', "Validation Loss")
plt.show()
Task 2.2 Use Data Augmentation to Tackle Overfitting with the Cats vs Dogs Dataset
Output
225/225 [==============================] - 171s 751ms/step - loss: 0.6720 - accuracy: 0.5859 - val_loss: 0.6093 - val_accuracy: 0.6732
Epoch 2/17
225/225 [==============================] - 168s 747ms/step - loss: 0.6139 - accuracy: 0.6606 - val_loss: 0.5860 - val_accuracy: 0.6764
Epoch 3/17
225/225 [==============================] - 169s 751ms/step - loss: 0.5853 - accuracy: 0.6869 - val_loss: 0.5545 - val_accuracy: 0.7116
Epoch 4/17
225/225 [==============================] - 169s 753ms/step - loss: 0.5649 - accuracy: 0.7020 - val_loss: 0.5405 - val_accuracy: 0.7264
Epoch 5/17
225/225 [==============================] - 171s 759ms/step - loss: 0.5497 - accuracy: 0.7157 - val_loss: 0.5489 - val_accuracy: 0.7112
Epoch 6/17
225/225 [==============================] - 171s 759ms/step - loss: 0.5315 - accuracy: 0.7294 - val_loss: 0.5158 - val_accuracy: 0.7420
Epoch 7/17
225/225 [==============================] - 169s 753ms/step - loss: 0.5171 - accuracy: 0.7417 - val_loss: 0.6065 - val_accuracy: 0.7056
Epoch 8/17
225/225 [==============================] - 171s 760ms/step - loss: 0.5098 - accuracy: 0.7474 - val_loss: 0.4979 - val_accuracy: 0.7580
Epoch 9/17
225/225 [==============================] - 171s 760ms/step - loss: 0.5004 - accuracy: 0.7518 - val_loss: 0.4746 - val_accuracy: 0.7648
Epoch 10/17
225/225 [==============================] - 171s 759ms/step - loss: 0.4854 - accuracy: 0.7638 - val_loss: 0.4926 - val_accuracy: 0.7500
Epoch 11/17
225/225 [==============================] - 173s 767ms/step - loss: 0.4785 - accuracy: 0.7718 - val_loss: 0.5478 - val_accuracy: 0.7248
Epoch 12/17
225/225 [==============================] - 170s 757ms/step - loss: 0.4647 - accuracy: 0.7801 - val_loss: 0.4546 - val_accuracy: 0.7768
Epoch 13/17
225/225 [==============================] - 174s 776ms/step - loss: 0.4538 - accuracy: 0.7859 - val_loss: 0.4261 - val_accuracy: 0.8028
Epoch 14/17
225/225 [==============================] - 172s 763ms/step - loss: 0.4427 - accuracy: 0.7915 - val_loss: 0.4144 - val_accuracy: 0.8060
Epoch 15/17
225/225 [==============================] - 171s 758ms/step - loss: 0.4350 - accuracy: 0.7982 - val_loss: 0.4347 - val_accuracy: 0.7940
Epoch 16/17
225/225 [==============================] - 176s 783ms/step - loss: 0.4223 - accuracy: 0.8012 - val_loss: 0.4066 - val_accuracy: 0.8136
Epoch 17/17
225/225 [==============================] - 170s 757ms/step - loss: 0.4136 - accuracy: 0.8111 - val_loss: 0.4589 - val_accuracy: 0.7828
Code
import os
import zipfile
import random
import shutil
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from shutil import copyfile
import matplotlib.pyplot as plt
!wget --no-check-certificate \
"https://download.microsoft.com/download/3/E/1/3E1C3F21-ECDB-4869-8368-6DEBA77B919F/kagglecatsanddogs_5340.zip" \
-O "/tmp/cats-and-dogs.zip"
local_zip = '/tmp/cats-and-dogs.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp')
zip_ref.close()
source_path = '/tmp/PetImages'
source_path_dogs = os.path.join(source_path, 'Dog')
source_path_cats = os.path.join(source_path, 'Cat')
# Deletes all non-image files (there are two .db files bundled into the dataset)
!find /tmp/PetImages/ -type f ! -name "*.jpg" -exec rm {} +
# os.listdir returns a list containing all files under the given path
print(f"There are {len(os.listdir(source_path_dogs))} images of dogs.")
print(f"There are {len(os.listdir(source_path_cats))} images of cats.")
# Define root directory
root_dir = '/tmp/cats-v-dogs'
# Empty directory to prevent FileExistsError is the function is run several times
if os.path.exists(root_dir):
shutil.rmtree(root_dir)
# GRADED FUNCTION: create_train_val_dirs
def create_train_val_dirs(root_path):
"""
Creates directories for the train and test sets
Args:
root_path (string) - the base directory path to create subdirectories from
Returns:
None
"""
### START CODE HERE
# HINT:
# Use os.makedirs to create your directories with intermediate subdirectories
# Don't hardcode the paths. Use os.path.join to append the new directories to the root_path parameter
os.mkdir('/tmp/cats-v-dogs')
os.mkdir('/tmp/cats-v-dogs/training')
os.mkdir('/tmp/cats-v-dogs/validation')
os.mkdir('/tmp/cats-v-dogs/training/cats')
os.mkdir('/tmp/cats-v-dogs/training/dogs')
os.mkdir('/tmp/cats-v-dogs/validation/cats')
os.mkdir('/tmp/cats-v-dogs/validation/dogs')
### END CODE HERE
try:
create_train_val_dirs(root_path=root_dir)
except FileExistsError:
print("You should not be seeing this since the upper directory is removed beforehand")
def split_data(SOURCE_DIR, TRAINING_DIR, VALIDATION_DIR, SPLIT_SIZE):
"""
Splits the data into train and test sets
Args:
SOURCE_DIR (string): directory path containing the images
TRAINING_DIR (string): directory path to be used for training
VALIDATION_DIR (string): directory path to be used for validation
SPLIT_SIZE (float): proportion of the dataset to be used for training
Returns:
None
"""
### START CODE HERE
files = []
for filename in os.listdir(SOURCE_DIR):
file = SOURCE_DIR + filename
if os.path.getsize(file) > 0:
files.append(filename)
else:
print(filename + " is zero length, so ignoring.")
training_length = int(len(files) * SPLIT_SIZE)
testing_length = int(len(files) - training_length)
shuffled_set = random.sample(files, len(files))
training_set = shuffled_set[0:training_length]
testing_set = shuffled_set[:testing_length]
for filename in training_set:
this_file = SOURCE_DIR + filename
destination = TRAINING_DIR + filename
copyfile(this_file, destination)
for filename in testing_set:
this_file = SOURCE_DIR + filename
destination = VALIDATION_DIR + filename
copyfile(this_file, destination)
### END CODE HERE
AT_SOURCE_DIR = "/tmp/PetImages/Cat/"
DOG_SOURCE_DIR = "/tmp/PetImages/Dog/"
TRAINING_DIR = "/tmp/cats-v-dogs/training/"
VALIDATION_DIR = "/tmp/cats-v-dogs/validation/"
TRAINING_CATS_DIR = os.path.join(TRAINING_DIR, "cats/")
VALIDATION_CATS_DIR = os.path.join(VALIDATION_DIR, "cats/")
TRAINING_DOGS_DIR = os.path.join(TRAINING_DIR, "dogs/")
VALIDATION_DOGS_DIR = os.path.join(VALIDATION_DIR, "dogs/")
# Empty directories in case you run this cell multiple times
if len(os.listdir(TRAINING_CATS_DIR)) > 0:
for file in os.scandir(TRAINING_CATS_DIR):
os.remove(file.path)
if len(os.listdir(TRAINING_DOGS_DIR)) > 0:
for file in os.scandir(TRAINING_DOGS_DIR):
os.remove(file.path)
if len(os.listdir(VALIDATION_CATS_DIR)) > 0:
for file in os.scandir(VALIDATION_CATS_DIR):
os.remove(file.path)
if len(os.listdir(VALIDATION_DOGS_DIR)) > 0:
for file in os.scandir(VALIDATION_DOGS_DIR):
os.remove(file.path)
# Define proportion of images used for training
split_size = .9
# Run the function
# NOTE: Messages about zero length images should be printed out
split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, VALIDATION_CATS_DIR, split_size)
split_data(DOG_SOURCE_DIR, TRAINING_DOGS_DIR, VALIDATION_DOGS_DIR, split_size)
# Your function should perform copies rather than moving images so original directories should contain unchanged images
print(f"\n\nOriginal cat's directory has {len(os.listdir(CAT_SOURCE_DIR))} images")
print(f"Original dog's directory has {len(os.listdir(DOG_SOURCE_DIR))} images\n")
# Training and validation splits. Check that the number of images matches the expected output.
print(f"There are {len(os.listdir(TRAINING_CATS_DIR))} images of cats for training")
print(f"There are {len(os.listdir(TRAINING_DOGS_DIR))} images of dogs for training")
print(f"There are {len(os.listdir(VALIDATION_CATS_DIR))} images of cats for validation")
print(f"There are {len(os.listdir(VALIDATION_DOGS_DIR))} images of dogs for validation")
def train_val_generators(TRAINING_DIR, VALIDATION_DIR):
"""
Creates the training and validation data generators
Args:
TRAINING_DIR (string): directory path containing the training images
VALIDATION_DIR (string): directory path containing the testing/validation images
Returns:
train_generator, validation_generator - tuple containing the generators
"""
### START CODE HERE
TRAINING_DIR = "/tmp/cats-v-dogs/training/"
# Instantiate the ImageDataGenerator class (don't forget to set the arguments to augment the images)
train_datagen = ImageDataGenerator(rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
# Pass in the appropriate arguments to the flow_from_directory method
train_generator = train_datagen.flow_from_directory(directory=TRAINING_DIR,
batch_size=100,
class_mode='binary',
target_size=(150, 150))
VALIDATION_DIR = "/tmp/cats-v-dogs/validation/"
# Instantiate the ImageDataGenerator class (don't forget to set the rescale argument)
validation_datagen = ImageDataGenerator(rescale=1./255,
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
# Pass in the appropriate arguments to the flow_from_directory method
validation_generator = validation_datagen.flow_from_directory(directory=VALIDATION_DIR,
batch_size=100,
class_mode='binary',
target_size=(150, 150))
### END CODE HERE
return train_generator, validation_generator
def create_model():
# DEFINE A KERAS MODEL TO CLASSIFY CATS V DOGS
# USE AT LEAST 3 CONVOLUTION LAYERS
### START CODE HERE
model = tf.keras.models.Sequential([
tf.keras.layers.Conv2D(16, (3, 3), activation='relu', input_shape=(150, 150, 3)),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(32, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D(2, 2),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(512, activation='relu'),
tf.keras.layers.Dense(1, activation='sigmoid')
])
from tensorflow.keras.optimizers import RMSprop
model.compile(optimizer=RMSprop(learning_rate=0.001),
loss='binary_crossentropy',
metrics=['accuracy'])
### END CODE HERE
return model
model = create_model()
# Train the model
# Note that this may take some time.
history = model.fit(train_generator,
epochs=17,
verbose=1,
validation_data=validation_generator)
#-----------------------------------------------------------
# Retrieve a list of list results on training and test data
# sets for each training epoch
#-----------------------------------------------------------
acc=history.history['accuracy']
val_acc=history.history['val_accuracy']
loss=history.history['loss']
val_loss=history.history['val_loss']
epochs=range(len(acc)) # Get number of epochs
#------------------------------------------------
# Plot training and validation accuracy per epoch
#------------------------------------------------
plt.plot(epochs, acc, 'r', "Training Accuracy")
plt.plot(epochs, val_acc, 'b', "Validation Accuracy")
plt.title('Training and validation accuracy')
plt.show()
print("")
#------------------------------------------------
# Plot training and validation loss per epoch
#------------------------------------------------
plt.plot(epochs, loss, 'r', "Training Loss")
plt.plot(epochs, val_loss, 'b', "Validation Loss")
plt.show()
APIs
Module | Link | Category | Usage |
---|---|---|---|
ImageDataGenerator | Preprocessing | Generate batches of tensor image data with real-time data augmentation. | |
RMSprop | Optimizers | Optimizer that implements the RMSprop algorithm. | |
Image Augmentation Layers | Preprocessing | amends images on-the-fly while training using transforms like rotation |
Last updated