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

ModuleLinkCategory 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