In [1]:
    
# Importing VGG16
from keras.applications import VGG16
    
    
In [2]:
    
network = VGG16(weights = 'imagenet', 
                include_top = False,
                input_shape = (150, 150, 3))
    
In [3]:
    
network.summary()
    
    
In [4]:
    
import os
import numpy as np
from keras.preprocessing.image import ImageDataGenerator
    
In [5]:
    
base_dir = 'E:/1_GitHub/arcyfelix/Courses/In Progress-Deep Learning With Python by François Chollet/data/Chapter 5.2 - Using convets with small datasets'
    
In [6]:
    
train_dir = os.path.join(base_dir, 'train')
validation_dir = os.path.join(base_dir, 'validation')
test_dir = os.path.join(base_dir, 'test')
    
In [7]:
    
datagen = ImageDataGenerator(rescale = 1. / 255)
batch_size = 20
    
In [8]:
    
def extract_features(directory, sample_count):
    # Initializing empty matrixes of a given shape
    features = np.zeros(shape = (sample_count, 4, 4, 512))
    labels = np.zeros(shape = (sample_count))
    
    # Generator
    generator = datagen.flow_from_directory(
        directory,
        target_size = (150, 150),
        batch_size = batch_size,
        class_mode = 'binary')
    # Initializing index
    i = 0
    for inputs_batch, labels_batch in generator:
        features_batch = network.predict(inputs_batch)
        features[i * batch_size : (i + 1) * batch_size] = features_batch
        labels[i * batch_size : (i + 1) * batch_size] = labels_batch
        i += 1
        if i * batch_size >= sample_count:
            # Note that since generators yield data indefinitely in a loop,
            # we must `break` after every image has been seen once.
            break
    return features, labels
    
In [9]:
    
train_features, train_labels = extract_features(train_dir, 2000)
validation_features, validation_labels = extract_features(validation_dir, 1000)
test_features, test_labels = extract_features(test_dir, 1000)
    
    
In [10]:
    
train_features.shape
    
    Out[10]:
In [11]:
    
train_labels.shape
    
    Out[11]:
In [12]:
    
# Flattening the features in order to feed them to a densely-connected classifier
train_features = np.reshape(train_features, (2000, 4 * 4 * 512))
validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512))
test_features = np.reshape(test_features, (1000, 4 * 4 * 512))
    
In [13]:
    
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
    
In [14]:
    
model = Sequential()
model.add(Dense(units = 256, 
                activation = 'relu', 
                input_dim = 4 * 4 * 512))
model.add(Dropout(rate = 0.5))
model.add(Dense(units = 1, 
                activation = 'sigmoid'))
model.compile(optimizer = RMSprop(lr = 2e-5),
              loss = 'binary_crossentropy',
              metrics = ['acc'])
    
In [15]:
    
history = model.fit(train_features, 
                    train_labels,
                    epochs = 30,
                    batch_size = 20,
                    validation_data = (validation_features, validation_labels))
    
    
In [16]:
    
import matplotlib.pyplot as plt
    
In [17]:
    
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
    
In [18]:
    
epochs = range(len(acc))
    
In [19]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs, 
         acc, 
         'bo', 
         label = 'Training acc')
plt.plot(epochs, 
         val_acc, 
         'b', 
         label = 'Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()
    
    
In [20]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs, 
         loss, 
         'bo', 
         label = 'Training loss')
plt.plot(epochs, 
         val_loss, 
         'b', 
         label = 'Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
    
    
In [21]:
    
from keras.layers import Flatten
    
In [22]:
    
end_to_end_model = Sequential()
end_to_end_model.add(network)
end_to_end_model.add(Flatten())
end_to_end_model.add(Dense(units = 256, 
                           activation = 'relu'))
end_to_end_model.add(Dense(units = 1, 
                           activation = 'sigmoid'))
    
In [23]:
    
end_to_end_model.summary()
    
    
In [24]:
    
print('Trainable weights before freezing the VGG base:', len(end_to_end_model.trainable_weights))
    
    
In [25]:
    
# Freezing VGG part of the network
network.trainable = False
    
In [26]:
    
print('Trainable weights after freezing the VGG base:', len(end_to_end_model.trainable_weights))
    
    
In [27]:
    
# Compiling the network
end_to_end_model.compile(loss = 'binary_crossentropy',
                         optimizer = RMSprop(lr = 2e-5),
                         metrics = ['acc'])
    
In [28]:
    
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')
# The validation data should not be augmented!
test_datagen = ImageDataGenerator(rescale = 1./255)
    
In [29]:
    
train_generator = train_datagen.flow_from_directory(
        # This is the target directory
        train_dir,
        # All images will be resized to 150x150
        target_size = (150, 150),
        batch_size = 20,
        # Since we use binary_crossentropy loss, we need binary labels
        class_mode = 'binary')
    
    
In [30]:
    
validation_generator = test_datagen.flow_from_directory(validation_dir,
                                                        target_size = (150, 150),
                                                        batch_size = 20,
                                                        class_mode = 'binary')
    
    
In [31]:
    
history = end_to_end_model.fit_generator(train_generator,
                              steps_per_epoch = 100,
                              epochs = 30,
                              validation_data = validation_generator,
                              validation_steps = 50, 
                              verbose = 2)
    
    
In [32]:
    
model.save('.\saved_checkpoints\Chapter 5.3 - Using a pre-trained convnet\cats_and_dogs_small_3.h5')
    
In [33]:
    
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
    
In [34]:
    
epochs = range(len(acc))
    
In [35]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs, 
         acc, 
         'bo', 
         label = 'Training acc')
plt.plot(epochs, 
         val_acc, 
         'b', 
         label = 'Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()
    
    
In [36]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs, 
         loss, 
         'bo', 
         label = 'Training loss')
plt.plot(epochs, 
         val_loss, 
         'b', 
         label = 'Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
    
    
In [37]:
    
network.summary()
    
    
In [38]:
    
# Fine-tuning only block5_conv1, block5_conv2 and block5_conv3
network.trainable = True
set_trainable = False
for layer in network.layers:
    if layer.name == 'block5_conv1':
        set_trainable = True
    if set_trainable:
        layer.trainable = True
    else:
        layer.trainable = False
    
In [39]:
    
# Compiling the network
end_to_end_model.compile(loss = 'binary_crossentropy',
                         optimizer = RMSprop(lr = 1e-5),
                         metrics = ['acc'])
    
In [40]:
    
history = end_to_end_model.fit_generator(train_generator,
                                         steps_per_epoch = 100,
                                         epochs = 100,
                                         validation_data = validation_generator,
                                         validation_steps = 50)
    
    
In [41]:
    
model.save('.\saved_checkpoints\Chapter 5.3 - Using a pre-trained convnet\cats_and_dogs_small_4.h5')
    
In [42]:
    
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']
    
In [43]:
    
epochs = range(len(acc))
    
In [44]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs, 
         acc, 
         'bo', 
         label = 'Training acc')
plt.plot(epochs, 
         val_acc, 
         'b', 
         label = 'Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()
    
    
In [45]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs, 
         loss, 
         'bo', 
         label = 'Training loss')
plt.plot(epochs, 
         val_loss, 
         'b', 
         label = 'Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
    
    
In [46]:
    
def smooth_curve(points, factor = 0.8):
    smoothed_points = []
    for point in points:
        if smoothed_points:
            previous = smoothed_points[-1]
            smoothed_points.append(previous * factor + point * (1 - factor))
        else:
            smoothed_points.append(point)
    return smoothed_points
    
In [47]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs,
         smooth_curve(acc), 
         'bo', 
         label = 'Smoothed training acc')
plt.plot(epochs,
         smooth_curve(val_acc), 
         'b', 
         label = 'Smoothed validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.show()
    
    
In [48]:
    
plt.figure(figsize = (10, 6))
plt.plot(epochs,
         smooth_curve(loss), 
         'bo', 
         label = 'Smoothed training loss')
plt.plot(epochs,
         smooth_curve(val_loss), 
         'b', 
         label = 'Smoothed validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()
    
    
In [49]:
    
test_generator = test_datagen.flow_from_directory(test_dir,
                                                  target_size = (150, 150),
                                                  batch_size = 20,
                                                  class_mode = 'binary')
test_loss, test_acc = end_to_end_model.evaluate_generator(test_generator, 
                                                          steps = 50)
print('Test acc:', test_acc)