Week 1: Larger Datasets
-
We will first review how to build CNNs, prepare your data with
ImageDataGenerator
and examine your results. You'll follow these steps:- Explore the example data of
Dogs vs. Cats
- Build and train a neural network to classify between the two pets
- Evaluate the training and validation accuracy
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
- Explore the example data of
-
Download dataset and process it
!wget --no-check-certificate https://storage.googleapis.com/mledu-datasets/cats_and_dogs_filtered.zip import zipfile # Unzip the archive local_zip = './cats_and_dogs_filtered.zip' zip_ref = zipfile.ZipFile(local_zip, 'r') zip_ref.extractall() zip_ref.close() #printing the dataset import os base_dir = 'cats_and_dogs_filtered' print("Contents of base directory:") print(os.listdir(base_dir)) print("\nContents of train directory:") print(os.listdir(f'{base_dir}/train')) print("\nContents of validation directory:") print(os.listdir(f'{base_dir}/validation')) #paths of the data train_dir = os.path.join(base_dir, 'train') validation_dir = os.path.join(base_dir, 'validation') # Directory with training cat/dog pictures train_cats_dir = os.path.join(train_dir, 'cats') train_dogs_dir = os.path.join(train_dir, 'dogs') # Directory with validation cat/dog pictures validation_cats_dir = os.path.join(validation_dir, 'cats') validation_dogs_dir = os.path.join(validation_dir, 'dogs')
-
Make your own paths
# 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) def create_train_val_dirs(root_path): try: os.mkdir('/tmp/cats-v-dogs') os.mkdir('/tmp/cats-v-dogs/validation') os.mkdir('/tmp/cats-v-dogs/training') os.mkdir('/tmp/cats-v-dogs/training/dogs') os.mkdir('/tmp/cats-v-dogs/training/cats') os.mkdir('/tmp/cats-v-dogs/validation/cats') os.mkdir('/tmp/cats-v-dogs/validation/dogs') except OSError: pass 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") # Test your create_train_val_dirs function for rootdir, dirs, files in os.walk(root_dir): for subdir in dirs: print(os.path.join(rootdir, subdir))
-
Splitting data
def split_data(SOURCE_DIR, TRAINING_DIR, VALIDATION_DIR, SPLIT_SIZE): 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) random_set = random.sample(files,len(files)) training_set = random_set[0:training_length] testing_set = random_set[training_length:] for filename in training_set: curr_file = SOURCE_DIR + filename target_dir = TRAINING_DIR + filename copyfile(curr_file,target_dir) for filename in testing_set: curr_file = SOURCE_DIR + filename target_dir = VALIDATION_DIR + filename copyfile(curr_file,target_dir) pass
-
Testing the split
# 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")
-
Model
import tensorflow as tf model = tf.keras.models.Sequential([ # Note the input shape is the desired size of the image 150x150 with 3 bytes color 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), # 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 ('cats') and 1 for the other ('dogs') tf.keras.layers.Dense(1, activation='sigmoid') ]) model.summary() from tensorflow.keras.optimizers import RMSprop model.compile(optimizer=RMSprop(learning_rate=0.001), loss='binary_crossentropy', metrics = ['accuracy'])
-
Data pre processing using ImageDataGenerator
from tensorflow.keras.preprocessing.image import ImageDataGenerator # All images will be rescaled by 1./255. train_datagen = ImageDataGenerator( rescale = 1.0/255. ) test_datagen = ImageDataGenerator( rescale = 1.0/255. ) # -------------------- # Flow training images in batches of 20 using train_datagen generator # -------------------- train_generator = train_datagen.flow_from_directory(train_dir, batch_size=20, class_mode='binary', target_size=(150, 150)) # -------------------- # Flow validation images in batches of 20 using test_datagen generator # -------------------- validation_generator = test_datagen.flow_from_directory(validation_dir, batch_size=20, class_mode = 'binary', target_size = (150, 150))
-
Training
history = model.fit( train_generator, epochs=15, validation_data=validation_generator, verbose=2 )
-
Visualisations of convolutions
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 successive_outputs = [layer.output for layer in model.layers] visualization_model = tf.keras.models.Model(inputs = model.input, outputs = successive_outputs) # Prepare a random input image from the training set. cat_img_files = [os.path.join(train_cats_dir, f) for f in train_cat_fnames] dog_img_files = [os.path.join(train_dogs_dir, f) for f in train_dog_fnames] img_path = random.choice(cat_img_files + dog_img_files) img = load_img(img_path, target_size=(150, 150)) # this is a PIL image x = img_to_array(img) # Numpy array with shape (150, 150, 3) x = x.reshape((1,) + x.shape) # Numpy array with shape (1, 150, 150, 3) # Scale by 1/255 x /= 255.0 # 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 our plot layer_names = [layer.name for layer in model.layers] # 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 the feature map size = feature_map.shape[ 1] # feature map shape (1, size, size, n_features) # Tile the images in this matrix display_grid = np.zeros((size, size * n_features)) #------------------------------------------------- # Postprocess the feature to be visually palatable #------------------------------------------------- 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') display_grid[:, i * size : (i + 1) * size] = x # Tile each filter into a horizontal grid #----------------- # 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' )
-
Evaluating acc and loss
import matplotlib.pyplot as plt # Plot the model results acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(len(acc)) plt.plot(epochs, acc, 'r', label='Training accuracy') plt.plot(epochs, val_acc, 'b', label='Validation accuracy') plt.title('Training and validation accuracy') plt.figure() plt.plot(epochs, loss, 'r', label='Training Loss') plt.plot(epochs, val_loss, 'b', label='Validation Loss') plt.title('Training and validation loss') plt.legend() plt.show()
Week 2: Augmentation
- Augmentation - the process of generating new transformed version of images from the given dataset to increase diversity, https://keras.io/preprocessing/image/
- It does bring randomness in the test data, but if test/validation data doesn’t have the same randomness it’ll give bad validation accuracy
-
We implement this with the use of ImageDataGenerator with different arguments -
# Create new model model_for_aug = create_model() # This code has changed. Now instead of the ImageGenerator just rescaling # the image, we also rotate and do other operations 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') test_datagen = ImageDataGenerator(rescale=1./255) # Flow training images in batches of 20 using train_datagen generator train_generator = train_datagen.flow_from_directory( train_dir, # This is the source directory for training images target_size=(150, 150), # All images will be resized to 150x150 batch_size=20, # Since we use binary_crossentropy loss, we need binary labels class_mode='binary') # Flow validation images in batches of 20 using test_datagen generator validation_generator = test_datagen.flow_from_directory( validation_dir, target_size=(150, 150), batch_size=20, class_mode='binary') # Train the new model history_with_aug = model_for_aug.fit( train_generator, steps_per_epoch=100, # 2000 images = batch_size * steps epochs=EPOCHS, validation_data=validation_generator, validation_steps=50, # 1000 images = batch_size * steps verbose=2)
-
These are just a few of the options available:
-
rotation_range
is a value in degrees (0–180) within which to randomly rotate pictures. -
width_shift
andheight_shift
are ranges (as a fraction of total width or height) within which to randomly translate pictures vertically or horizontally. -
shear_range
is for randomly applying shearing transformations. -
zoom_range
is for randomly zooming inside pictures. -
horizontal_flip
is for randomly flipping half of the images horizontally. This is relevant when there are no assumptions of horizontal assymmetry (e.g. real-world pictures). -
fill_mode
is the strategy used for filling in newly created pixels, which can appear after a rotation or a width/height shift.
-
Week 3: Transfer Learning
- We will use the convolution layers of the InceptionV3 architecture as your base model. To do that, you need to:
- Set the input shape to fit your application. In this case. set it to
150x150x3
as you've been doing in the last few labs. - Pick and freeze the convolution layers to take advantage of the features it has learned already.
- Add dense layers which you will train
- Set the input shape to fit your application. In this case. set it to
-
Download pre trained weights and loading the model
# Download the pre-trained weights. No top means it excludes the fully connected layer it uses for classification. !wget --no-check-certificate \ https://storage.googleapis.com/mledu-datasets/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5 \ -O /tmp/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5 from tensorflow.keras.applications.inception_v3 import InceptionV3 from tensorflow.keras import layers # Set the weights file you downloaded into a variable local_weights_file = '/tmp/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5' # Initialize the base model. # Set the input shape and remove the dense layers. pre_trained_model = InceptionV3(input_shape = (150, 150, 3), include_top = False, weights = None) # Load the pre-trained weights you downloaded. pre_trained_model.load_weights(local_weights_file) # Freeze the weights of the layers. for layer in pre_trained_model.layers: layer.trainable = False pre_trained_model.summary()
-
Choosing the last layer
# Choose `mixed7` as the last layer of your base model last_layer = pre_trained_model.get_layer('mixed7') print('last layer output shape: ', last_layer.output_shape) last_output = last_layer.output
-
Adding our own dense layer
from tensorflow.keras.optimizers import RMSprop from tensorflow.keras import Model # Flatten the output layer to 1 dimension x = layers.Flatten()(last_output) # Add a fully connected layer with 1,024 hidden units and ReLU activation x = layers.Dense(1024, activation='relu')(x) # Add a dropout rate of 0.2 x = layers.Dropout(0.2)(x) # Add a final sigmoid layer for classification x = layers.Dense (1, activation='sigmoid')(x) # Append the dense network to the base model model = Model(pre_trained_model.input, x) # Print the model summary. See your dense network connected at the end. model.summary() # Set the training parameters model.compile(optimizer = RMSprop(learning_rate=0.0001), loss = 'binary_crossentropy', metrics = ['accuracy'])
-
Preparing the dataset with augmentation
# Download the dataset !wget https://storage.googleapis.com/tensorflow-1-public/course2/cats_and_dogs_filtered.zip import os import zipfile from tensorflow.keras.preprocessing.image import ImageDataGenerator # Extract the archive zip_ref = zipfile.ZipFile("./cats_and_dogs_filtered.zip", 'r') zip_ref.extractall("tmp/") zip_ref.close() # Define our example directories and files base_dir = 'tmp/cats_and_dogs_filtered' train_dir = os.path.join( base_dir, 'train') validation_dir = os.path.join( base_dir, 'validation') # Directory with training cat pictures train_cats_dir = os.path.join(train_dir, 'cats') # Directory with training dog pictures train_dogs_dir = os.path.join(train_dir, 'dogs') # Directory with validation cat pictures validation_cats_dir = os.path.join(validation_dir, 'cats') # Directory with validation dog pictures validation_dogs_dir = os.path.join(validation_dir, 'dogs') # Add our data-augmentation parameters to ImageDataGenerator 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) # Note that the validation data should not be augmented! test_datagen = ImageDataGenerator( rescale = 1.0/255. ) # Flow training images in batches of 20 using train_datagen generator train_generator = train_datagen.flow_from_directory(train_dir, batch_size = 20, class_mode = 'binary', target_size = (150, 150)) # Flow validation images in batches of 20 using test_datagen generator validation_generator = test_datagen.flow_from_directory( validation_dir, batch_size = 20, class_mode = 'binary', target_size = (150, 150))
-
Training the model
# Train the model. history = model.fit( train_generator, validation_data = validation_generator, steps_per_epoch = 100, epochs = 20, validation_steps = 50, verbose = 2)
-
Evaluating the model
import matplotlib.pyplot as plt acc = history.history['accuracy'] val_acc = history.history['val_accuracy'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(len(acc)) plt.plot(epochs, acc, 'r', label='Training accuracy') plt.plot(epochs, val_acc, 'b', label='Validation accuracy') plt.title('Training and validation accuracy') plt.legend(loc=0) plt.figure() plt.show()
Week 4: Classifications (multiple instead of binary)
-
The only changes comes in the model definition
import tensorflow as tf model = tf.keras.models.Sequential([ # Note the input shape is the desired size of the image 150x150 with 3 bytes color # This is the first convolution tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(150, 150, 3)), tf.keras.layers.MaxPooling2D(2, 2), # The second convolution tf.keras.layers.Conv2D(64, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), # The third convolution tf.keras.layers.Conv2D(128, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), # The fourth convolution tf.keras.layers.Conv2D(128, (3,3), activation='relu'), tf.keras.layers.MaxPooling2D(2,2), # Flatten the results to feed into a DNN tf.keras.layers.Flatten(), tf.keras.layers.Dropout(0.5), # 512 neuron hidden layer tf.keras.layers.Dense(512, activation='relu'), tf.keras.layers.Dense(3, activation='softmax') ]) # Print the model summary model.summary() # Set the training parameters model.compile(loss = 'categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy']) #if it doesn't work use loss='sparse_categorical_crossentropy'
-
ImageDataGenerator
from tensorflow.keras.preprocessing.image import ImageDataGenerator TRAINING_DIR = "tmp/rps-train/rps" training_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') VALIDATION_DIR = "tmp/rps-test/rps-test-set" validation_datagen = ImageDataGenerator(rescale = 1./255) train_generator = training_datagen.flow_from_directory( TRAINING_DIR, target_size=(150,150), class_mode='categorical', batch_size=126 ) validation_generator = validation_datagen.flow_from_directory( VALIDATION_DIR, target_size=(150,150), class_mode='categorical', batch_size=126 ) # Train the model history = model.fit(train_generator, epochs=25, steps_per_epoch=20, validation_data = validation_generator, verbose = 1, validation_steps=3)
Top comments (0)