Note for course TF 2: CNN in TF

Anh-Thi Dinh

Larger dataset

  • Crop an image make the predict better!
  • Make a larger dataset by rotating, scaling, cropping,...

Extract zip file + view image

1# extract zip file
2import zipfile
3
4local_zip = 'file.zip'
5zip_ref = zipfile.ZipFile(local_zip, 'r')
6zip_ref.extractall('/tmp')
7zip_ref.close()
1# show image
2import matplotlib.image as mpimg
3import matplotlib.pyplot as plt
4
5img = mpimg.imread(img_path)
6plt.imshow(img)
7plt.show()

image to np array

1from keras.preprocessing import image
2
3path = './image.png'
4img = image.load_img(path, target_size=(150, 150))
5x = image.img_to_array(img)
6x = np.expand_dims(x, axis=0)
7images = np.vstack([x])
8
9classes = model.predict(images, batch_size=10)

Plot loss and acc

1history = model.fit(...)
2acc      = history.history[     'accuracy' ]
3val_acc  = history.history[ 'val_accuracy' ]
4loss     = history.history[    'loss' ]
5val_loss = history.history['val_loss' ]
1# plot accuracy
2plt.plot  ( epochs,     acc )
3plt.plot  ( epochs, val_acc )
4plt.title ('Training and validation acc')
5plt.figure()
1# plot loss function
2plt.plot  ( epochs,     loss )
3plt.plot  ( epochs, val_loss )
4plt.title ('Training and validation loss')

Cats vs dogs

📙 Notebook: Cat vs Dog simple DNN.

os

1base_dir = '/tmp/cats-v-dogs'
2os.mkdir(base_dir)
3
4train_dir = os.path.join(base_dir, 'training')
5validation_dir = os.path.join(base_dir, 'testing')
6os.mkdir(train_dir)
7os.mkdir(validation_dir)
1os.listdir(DIRECTORY) # gives you a listing of the contents of that directory
2os.path.getsize(PATH) # gives you the size of the file
3copyfile(source, destination) # copies a file from source to destination
4random.sample(list, len(list)) # shuffles a list

Split data

Shuffle images and split/copy images to training/testing folder for each cat and dog.
1import os
2import random
3from shutil import copyfile
4def split_data(SOURCE, TRAINING, TESTING, SPLIT_SIZE):
5    lst_cat_imgs = os.listdir(SOURCE)
6    lst_cat_imgs = random.sample(lst_cat_imgs, len(lst_cat_imgs))
7    for file in lst_cat_imgs[:int(SPLIT_SIZE*len(lst_cat_imgs))]:
8        source_file = os.path.join(SOURCE, file)
9        destination_file = os.path.join(TRAINING, file)
10        if os.path.getsize(source_file) > 0:
11            copyfile(source_file, destination_file)
12    for file in lst_cat_imgs[int(SPLIT_SIZE*len(lst_cat_imgs)):]:
13        source_file = os.path.join(SOURCE, file)
14        destination_file = os.path.join(TESTING, file)
15        if os.path.getsize(source_file) > 0:
16            copyfile(source_file, destination_file)
1CAT_SOURCE_DIR = "/tmp/PetImages/Cat/"
2TRAINING_CATS_DIR = "/tmp/cats-v-dogs/training/cats/"
3TESTING_CATS_DIR = "/tmp/cats-v-dogs/testing/cats/"
4split_size = .9
5split_data(CAT_SOURCE_DIR, TRAINING_CATS_DIR, TESTING_CATS_DIR, split_size)

Define model

1model = tf.keras.models.Sequential([
2    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(150, 150, 3)),
3    tf.keras.layers.MaxPooling2D(2,2),
4    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
5    tf.keras.layers.MaxPooling2D(2,2),
6    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
7    tf.keras.layers.MaxPooling2D(2,2),
8    tf.keras.layers.Flatten(),
9    tf.keras.layers.Dense(512, activation='relu'),
10    tf.keras.layers.Dense(1, activation='sigmoid')
11])
12
13model.compile(optimizer=RMSprop(lr=0.001), loss='binary_crossentropy', metrics=['acc'])

Generate data

1TRAINING_DIR = "/tmp/cats-v-dogs/training/"
2train_datagen = ImageDataGenerator( rescale = 1.0/255. )
3
4train_generator = train_datagen.flow_from_directory(TRAINING_DIR,
5                                                    batch_size=10,
6                                                    class_mode='binary',
7                                                    target_size=(150, 150))
8
9# the same for validation
10# output:
11# Found 2700 images belonging to 2 classes (training).
12# Found 500 images beloging to 2 classes (validation).

Train

1history = model.fit(train_generator,
2					epochs=2,
3					steps_per_epoch=27, # 2700 / 10 (batch_size)
4					verbose=1,
5					validation_steps=50, # 500 / 10 (batch_size)
6					validation_data=validation_generator)

Image Augmentation

📙 Notebook: Cats v Dogs using augmentation & the final exercise (more data).
📙 Notebook:
Human vs Horse using augmentation.
  • Create multiple "other" images from original images without saving them to the memory + quickly.
  • Image augmentation helps you avoid overfitting.
  • Broad set of images for BOTH training and testing sets!
1# The different from the code in the previous section!
2
3train_datagen = ImageDataGenerator(
4    rescale=1./255,             # rescale
5    rotation_range=40,          # rotate randomly between 0 & 40 degrees (max 180)
6    width_shift_range=0.2,      # offset horizontally 20%
7    height_shift_range=0.2,     # offset vertically 20%
8    shear_range=0.2,
9    zoom_range=0.2,
10    horizontal_flip=True,
11    fill_mode='nearest'         # fill any pixel may be lost by the "nearest" ones
12)
13
14validation_datagen = ImageDataGenerator(rescale=1/255)
An illustration of image augmentation from apple.

Transfer learning

📙 Notebook: Coding transfer learning from the inception mode. → Video explains this notebook.
📙 Notebook:
Horses v Humans using callBack, Augmentation, transfer learning (final exercise).
  • Transfer learning = Taking existing model that's trained on far more data + use the features that model learned.
  • Inception/GoogLeNet network: Inception Modules are used in CNN to allow for more efficient computation and deeper Networks through a dimensionality reduction with stacked 1x1 convolutions. The modules were designed to solve the problem of computational expense, as well as overfitting, among other issues. The solution, in short, is to take multiple kernel filter sizes within the CNN, and rather than stacking them sequentially, ordering them to operate on the same level. (ref) Check more in Refereces 1, 2, 3.
  • Dropout: remove a random number of neurons in your NN. It works well because:
    • neighboring neurons often end up with similar weights, which can lead to overfitting.
    • a neuron can over-weigh the input from a neuron in the previous layer
1from tensorflow.keras import layers
2from tensorflow.keras import Model
3
4# download snapshot of weights
5
6from tensorflow.keras.applications.inception_v3 import InceptionV3
7local_weights_file = '/tmp/inception_v3_weights_notop.h5'
8
9pre_trained_model = InceptionV3(
10    input_shape = (150, 150, 3),
11    include_top = False, # Inception v3 has a fully-connected
12                         # layer at the top -> False to ignore
13                         # it and get straight to the convolution.
14    weights = None # don't wana use built-in weights
15)
16
17pre_trained_model.load_weights(local_weights_file) # but use the snapshot downloaded
18
19for layer in pre_trained_model.layers:
20    layer.trainable = False # lock pretrained layers
21                            # they're not going to be trained
22                            # with this code
23
24# pre_trained_model.summary()   # DON'T DO THAT, IT'S HUGE!!!
1# By default, the output of the last layer will be 3x3 but we wanna
2# get more info, so we move up over the model and grap layer "mixed7" from
3# inception and take its output mixed7: output of a lot of conv that are 7x7
4last_layer = pre_trained_model.get_layer('mixed7')
5last_output = last_layer.output
1from tensorflow.keras.optimizers import RMSprop
2
3# Define a new model
4
5x = layers.Flatten()(last_output) # Take the output (mixed7) from inception model
6                                  # last_output: look like dense model
7                                  #     -> input of the new model
8                                  # Starting by flatting the input
9x = layers.Dense(1024, activation='relu')(x)
10x = layers.Dropout(0.2)(x)  # randomly remove 20% of neurons (avoid overfitting)
11x = layers.Dense  (1, activation='sigmoid')(x)
12
13model = Model(pre_trained_model.input, x)
14model.compile(optimizer = RMSprop(lr=0.0001),
15              loss = 'binary_crossentropy',
16              metrics = ['accuracy'])

Multi-class classification

📙 Notebook: Rock Paper Scissors.
📙 Notebook:
MNIST Final Question.
👉 Rock-Paper-Scissors dataset (generated using CGI techniques)
The codes are quite the same as in the case of binary classification, the differences are
1train_generator = train_datagen.flow_from_directory(
2    ...
3    class_mode='categorical' # 'binary' for binary
4)
1model = tf.keras.models.Sequential([
2    ...
3    tf.keras.layers.Dense(3, activation='softmax') # 'sigmoid' for binary
4])
1model.compile(
2    loss='categorical_crossentropy' # 'binary_lossentropy' for binary
3)

More

  • Applying Convolutions on top of our Deep neural network will make training ➪ It depends on many factors. It might make your training faster or slower, and a poorly designed Convolutional layer may even be less efficient than a plain DNN!

References

  1. Inception Network - Implementation Of GoogleNet In Keras
  1. ResNet, AlexNet, VGGNet, Inception: Understanding various architectures of Convolutional Networks – CV-Tricks.com
  1. Review: GoogLeNet (Inception v1)— Winner of ILSVRC 2014 (Image Classification)
  1. Transfer learning and fine-tuning - TensorFlow Core