This is a companion notebook for the book Deep Learning with Python, Second Edition.
For
readability, it only contains runnable code blocks and section titles, and omits everything
else in the book: text paragraphs, figures, and pseudocode.
If you want to be able to follow what's going on, I recommend reading the notebook
side by side with your copy of the book.
This notebook was generated for TensorFlow 2.6.
Introduction to deep learning for computer vision
Introduction to convnets
Instantiating a small convnet
from tensorflow import keras
from [Link] import layers
inputs = [Link](shape=(28, 28, 1))
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = [Link]()(x)
outputs = [Link](10, activation="softmax")(x)
model = [Link](inputs=inputs, outputs=outputs)
Displaying the model's summary
[Link]()
Model: "model"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 28, 28, 1)] 0
conv2d (Conv2D) (None, 26, 26, 32) 320
max_pooling2d (MaxPooling2D (None, 13, 13, 32) 0
)
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
max_pooling2d_1 (MaxPooling (None, 5, 5, 64) 0
2D)
conv2d_2 (Conv2D) (None, 3, 3, 128) 73856
flatten (Flatten) (None, 1152) 0
dense (Dense) (None, 10) 11530
=================================================================
Total params: 104,202
Trainable params: 104,202
Non-trainable params: 0
_________________________________________________________________
Training the convnet on MNIST images
from [Link] import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype("float32") / 255
test_images = test_images.reshape((10000, 28, 28, 1))
test_images = test_images.astype("float32") / 255
[Link](optimizer="rmsprop",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"])
[Link](train_images, train_labels, epochs=5, batch_size=64)
Evaluating the convnet
test_loss, test_acc = [Link](test_images, test_labels)
print(f"Test accuracy: {test_acc:.3f}")
The convolution operation
Understanding border effects and padding
Understanding convolution strides
The max-pooling operation
An incorrectly structured convnet missing its max-pooling layers
inputs = [Link](shape=(28, 28, 1))
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(inputs)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = [Link]()(x)
outputs = [Link](10, activation="softmax")(x)
model_no_max_pool = [Link](inputs=inputs, outputs=outputs)
model_no_max_pool.summary()
Training a convnet from scratch on a small dataset
The relevance of deep learning for small-data problems
Downloading the data
from [Link] import files
[Link]()
!mkdir ~/.kaggle
!cp [Link] ~/.kaggle/
!chmod 600 ~/.kaggle/[Link]
!kaggle competitions download -c dogs-vs-cats
!unzip -qq [Link]
Copying images to training, validation, and test directories
import os, shutil, pathlib
original_dir = [Link]("train")
new_base_dir = [Link]("cats_vs_dogs_small")
def make_subset(subset_name, start_index, end_index):
for category in ("cat", "dog"):
dir = new_base_dir / subset_name / category
[Link](dir)
fnames = [f"{category}.{i}.jpg" for i in range(start_index,
end_index)]
for fname in fnames:
[Link](src=original_dir / fname,
dst=dir / fname)
make_subset("train", start_index=0, end_index=1000)
make_subset("validation", start_index=1000, end_index=1500)
make_subset("test", start_index=1500, end_index=2500)
Building the model
Instantiating a small convnet for dogs vs. cats classification
from tensorflow import keras
from [Link] import layers
inputs = [Link](shape=(180, 180, 3))
x = [Link](1./255)(inputs)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = [Link]()(x)
outputs = [Link](1, activation="sigmoid")(x)
model = [Link](inputs=inputs, outputs=outputs)
[Link]()
Configuring the model for training
[Link](loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
Data preprocessing
Using image_dataset_from_directory to read images
from [Link] import image_dataset_from_directory
train_dataset = image_dataset_from_directory(
new_base_dir / "train",
image_size=(180, 180),
batch_size=32)
validation_dataset = image_dataset_from_directory(
new_base_dir / "validation",
image_size=(180, 180),
batch_size=32)
test_dataset = image_dataset_from_directory(
new_base_dir / "test",
image_size=(180, 180),
batch_size=32)
import numpy as np
import tensorflow as tf
random_numbers = [Link](size=(1000, 16))
dataset = [Link].from_tensor_slices(random_numbers)
for i, element in enumerate(dataset):
print([Link])
if i >= 2:
break
batched_dataset = [Link](32)
for i, element in enumerate(batched_dataset):
print([Link])
if i >= 2:
break
reshaped_dataset = [Link](lambda x: [Link](x, (4, 4)))
for i, element in enumerate(reshaped_dataset):
print([Link])
if i >= 2:
break
Displaying the shapes of the data and labels yielded by the Dataset
for data_batch, labels_batch in train_dataset:
print("data batch shape:", data_batch.shape)
print("labels batch shape:", labels_batch.shape)
break
Fitting the model using a Dataset
callbacks = [
[Link](
filepath="convnet_from_scratch.keras",
save_best_only=True,
monitor="val_loss")
]
history = [Link](
train_dataset,
epochs=30,
validation_data=validation_dataset,
callbacks=callbacks)
Displaying curves of loss and accuracy during training
import [Link] as plt
accuracy = [Link]["accuracy"]
val_accuracy = [Link]["val_accuracy"]
loss = [Link]["loss"]
val_loss = [Link]["val_loss"]
epochs = range(1, len(accuracy) + 1)
[Link](epochs, accuracy, "bo", label="Training accuracy")
[Link](epochs, val_accuracy, "b", label="Validation accuracy")
[Link]("Training and validation accuracy")
[Link]()
[Link]()
[Link](epochs, loss, "bo", label="Training loss")
[Link](epochs, val_loss, "b", label="Validation loss")
[Link]("Training and validation loss")
[Link]()
[Link]()
Evaluating the model on the test set
test_model = [Link].load_model("convnet_from_scratch.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
Using data augmentation
Define a data augmentation stage to add to an image model
data_augmentation = [Link](
[
[Link]("horizontal"),
[Link](0.1),
[Link](0.2),
]
)
Displaying some randomly augmented training images
[Link](figsize=(10, 10))
for images, _ in train_dataset.take(1):
for i in range(9):
augmented_images = data_augmentation(images)
ax = [Link](3, 3, i + 1)
[Link](augmented_images[0].numpy().astype("uint8"))
[Link]("off")
Defining a new convnet that includes image augmentation and dropout
inputs = [Link](shape=(180, 180, 3))
x = data_augmentation(inputs)
x = [Link](1./255)(x)
x = layers.Conv2D(filters=32, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=64, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=128, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = layers.MaxPooling2D(pool_size=2)(x)
x = layers.Conv2D(filters=256, kernel_size=3, activation="relu")(x)
x = [Link]()(x)
x = [Link](0.5)(x)
outputs = [Link](1, activation="sigmoid")(x)
model = [Link](inputs=inputs, outputs=outputs)
[Link](loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
Training the regularized convnet
callbacks = [
[Link](
filepath="convnet_from_scratch_with_augmentation.keras",
save_best_only=True,
monitor="val_loss")
]
history = [Link](
train_dataset,
epochs=100,
validation_data=validation_dataset,
callbacks=callbacks)
Evaluating the model on the test set
test_model = [Link].load_model(
"convnet_from_scratch_with_augmentation.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
Leveraging a pretrained model
Feature extraction with a pretrained model
Instantiating the VGG16 convolutional base
conv_base = [Link].vgg16.VGG16(
weights="imagenet",
include_top=False,
input_shape=(180, 180, 3))
conv_base.summary()
Fast feature extraction without data augmentation
Extracting the VGG16 features and corresponding labels
import numpy as np
def get_features_and_labels(dataset):
all_features = []
all_labels = []
for images, labels in dataset:
preprocessed_images =
[Link].vgg16.preprocess_input(images)
features = conv_base.predict(preprocessed_images)
all_features.append(features)
all_labels.append(labels)
return [Link](all_features), [Link](all_labels)
train_features, train_labels = get_features_and_labels(train_dataset)
val_features, val_labels = get_features_and_labels(validation_dataset)
test_features, test_labels = get_features_and_labels(test_dataset)
train_features.shape
Defining and training the densely connected classifier
inputs = [Link](shape=(5, 5, 512))
x = [Link]()(inputs)
x = [Link](256)(x)
x = [Link](0.5)(x)
outputs = [Link](1, activation="sigmoid")(x)
model = [Link](inputs, outputs)
[Link](loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
callbacks = [
[Link](
filepath="feature_extraction.keras",
save_best_only=True,
monitor="val_loss")
]
history = [Link](
train_features, train_labels,
epochs=20,
validation_data=(val_features, val_labels),
callbacks=callbacks)
Plotting the results
import [Link] as plt
acc = [Link]["accuracy"]
val_acc = [Link]["val_accuracy"]
loss = [Link]["loss"]
val_loss = [Link]["val_loss"]
epochs = range(1, len(acc) + 1)
[Link](epochs, acc, "bo", label="Training accuracy")
[Link](epochs, val_acc, "b", label="Validation accuracy")
[Link]("Training and validation accuracy")
[Link]()
[Link]()
[Link](epochs, loss, "bo", label="Training loss")
[Link](epochs, val_loss, "b", label="Validation loss")
[Link]("Training and validation loss")
[Link]()
[Link]()
Feature extraction together with data augmentation
Instantiating and freezing the VGG16 convolutional base
conv_base = [Link].vgg16.VGG16(
weights="imagenet",
include_top=False)
conv_base.trainable = False
Printing the list of trainable weights before and after freezing
conv_base.trainable = True
print("This is the number of trainable weights "
"before freezing the conv base:", len(conv_base.trainable_weights))
conv_base.trainable = False
print("This is the number of trainable weights "
"after freezing the conv base:", len(conv_base.trainable_weights))
Adding a data augmentation stage and a classifier to the convolutional base
data_augmentation = [Link](
[
[Link]("horizontal"),
[Link](0.1),
[Link](0.2),
]
)
inputs = [Link](shape=(180, 180, 3))
x = data_augmentation(inputs)
x = [Link].vgg16.preprocess_input(x)
x = conv_base(x)
x = [Link]()(x)
x = [Link](256)(x)
x = [Link](0.5)(x)
outputs = [Link](1, activation="sigmoid")(x)
model = [Link](inputs, outputs)
[Link](loss="binary_crossentropy",
optimizer="rmsprop",
metrics=["accuracy"])
callbacks = [
[Link](
filepath="feature_extraction_with_data_augmentation.keras",
save_best_only=True,
monitor="val_loss")
]
history = [Link](
train_dataset,
epochs=50,
validation_data=validation_dataset,
callbacks=callbacks)
Evaluating the model on the test set
test_model = [Link].load_model(
"feature_extraction_with_data_augmentation.keras")
test_loss, test_acc = test_model.evaluate(test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
Fine-tuning a pretrained model
conv_base.summary()
Freezing all layers until the fourth from the last
conv_base.trainable = True
for layer in conv_base.layers[:-4]:
[Link] = False
Fine-tuning the model
[Link](loss="binary_crossentropy",
optimizer=[Link](learning_rate=1e-5),
metrics=["accuracy"])
callbacks = [
[Link](
filepath="fine_tuning.keras",
save_best_only=True,
monitor="val_loss")
]
history = [Link](
train_dataset,
epochs=30,
validation_data=validation_dataset,
callbacks=callbacks)
model = [Link].load_model("fine_tuning.keras")
test_loss, test_acc = [Link](test_dataset)
print(f"Test accuracy: {test_acc:.3f}")
Summary