1225 lines
29 KiB
Plaintext
1225 lines
29 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"This is a companion notebook for the book [Deep Learning with Python, Second Edition](https://www.manning.com/books/deep-learning-with-python-second-edition?a_aid=keras&a_bid=76564dff). For readability, it only contains runnable code blocks and section titles, and omits everything else in the book: text paragraphs, figures, and pseudocode.\n\n**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.**\n\nThis notebook was generated for TensorFlow 2.6."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"# Introduction to deep learning for computer vision"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"## Introduction to convnets"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Instantiating a small convnet**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow import keras\n",
|
|
"from tensorflow.keras import layers\n",
|
|
"inputs = keras.Input(shape=(28, 28, 1))\n",
|
|
"x = layers.Conv2D(filters=32, kernel_size=3, activation=\"relu\")(inputs)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=64, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=128, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.Flatten()(x)\n",
|
|
"outputs = layers.Dense(10, activation=\"softmax\")(x)\n",
|
|
"model = keras.Model(inputs=inputs, outputs=outputs)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Displaying the model's summary**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Training the convnet on MNIST images**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow.keras.datasets import mnist\n",
|
|
"\n",
|
|
"(train_images, train_labels), (test_images, test_labels) = mnist.load_data()\n",
|
|
"train_images = train_images.reshape((60000, 28, 28, 1))\n",
|
|
"train_images = train_images.astype(\"float32\") / 255\n",
|
|
"test_images = test_images.reshape((10000, 28, 28, 1))\n",
|
|
"test_images = test_images.astype(\"float32\") / 255\n",
|
|
"model.compile(optimizer=\"rmsprop\",\n",
|
|
" loss=\"sparse_categorical_crossentropy\",\n",
|
|
" metrics=[\"accuracy\"])\n",
|
|
"model.fit(train_images, train_labels, epochs=5, batch_size=64)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Evaluating the convnet**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"test_loss, test_acc = model.evaluate(test_images, test_labels)\n",
|
|
"print(f\"Test accuracy: {test_acc:.3f}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### The convolution operation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Understanding border effects and padding"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Understanding convolution strides"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### The max-pooling operation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**An incorrectly structured convnet missing its max-pooling layers**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"inputs = keras.Input(shape=(28, 28, 1))\n",
|
|
"x = layers.Conv2D(filters=32, kernel_size=3, activation=\"relu\")(inputs)\n",
|
|
"x = layers.Conv2D(filters=64, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.Conv2D(filters=128, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.Flatten()(x)\n",
|
|
"outputs = layers.Dense(10, activation=\"softmax\")(x)\n",
|
|
"model_no_max_pool = keras.Model(inputs=inputs, outputs=outputs)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model_no_max_pool.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"## Training a convnet from scratch on a small dataset"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### The relevance of deep learning for small-data problems"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Downloading the data"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from google.colab import files\n",
|
|
"files.upload()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"!mkdir ~/.kaggle\n",
|
|
"!cp kaggle.json ~/.kaggle/\n",
|
|
"!chmod 600 ~/.kaggle/kaggle.json"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"!kaggle competitions download -c dogs-vs-cats"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"!unzip -qq dogs-vs-cats.zip"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"!unzip -qq train.zip"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Copying images to training, validation, and test directories**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import os, shutil, pathlib\n",
|
|
"\n",
|
|
"original_dir = pathlib.Path(\"train\")\n",
|
|
"new_base_dir = pathlib.Path(\"cats_vs_dogs_small\")\n",
|
|
"\n",
|
|
"def make_subset(subset_name, start_index, end_index):\n",
|
|
" for category in (\"cat\", \"dog\"):\n",
|
|
" dir = new_base_dir / subset_name / category\n",
|
|
" os.makedirs(dir)\n",
|
|
" fnames = [f\"{category}.{i}.jpg\" for i in range(start_index, end_index)]\n",
|
|
" for fname in fnames:\n",
|
|
" shutil.copyfile(src=original_dir / fname,\n",
|
|
" dst=dir / fname)\n",
|
|
"\n",
|
|
"make_subset(\"train\", start_index=0, end_index=1000)\n",
|
|
"make_subset(\"validation\", start_index=1000, end_index=1500)\n",
|
|
"make_subset(\"test\", start_index=1500, end_index=2500)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Building the model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Instantiating a small convnet for dogs vs. cats classification**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow import keras\n",
|
|
"from tensorflow.keras import layers\n",
|
|
"\n",
|
|
"inputs = keras.Input(shape=(180, 180, 3))\n",
|
|
"x = layers.Rescaling(1./255)(inputs)\n",
|
|
"x = layers.Conv2D(filters=32, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=64, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=128, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=256, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=256, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.Flatten()(x)\n",
|
|
"outputs = layers.Dense(1, activation=\"sigmoid\")(x)\n",
|
|
"model = keras.Model(inputs=inputs, outputs=outputs)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Configuring the model for training**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model.compile(loss=\"binary_crossentropy\",\n",
|
|
" optimizer=\"rmsprop\",\n",
|
|
" metrics=[\"accuracy\"])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Data preprocessing"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Using `image_dataset_from_directory` to read images**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from tensorflow.keras.utils import image_dataset_from_directory\n",
|
|
"\n",
|
|
"train_dataset = image_dataset_from_directory(\n",
|
|
" new_base_dir / \"train\",\n",
|
|
" image_size=(180, 180),\n",
|
|
" batch_size=32)\n",
|
|
"validation_dataset = image_dataset_from_directory(\n",
|
|
" new_base_dir / \"validation\",\n",
|
|
" image_size=(180, 180),\n",
|
|
" batch_size=32)\n",
|
|
"test_dataset = image_dataset_from_directory(\n",
|
|
" new_base_dir / \"test\",\n",
|
|
" image_size=(180, 180),\n",
|
|
" batch_size=32)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import numpy as np\n",
|
|
"import tensorflow as tf\n",
|
|
"random_numbers = np.random.normal(size=(1000, 16))\n",
|
|
"dataset = tf.data.Dataset.from_tensor_slices(random_numbers)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"for i, element in enumerate(dataset):\n",
|
|
" print(element.shape)\n",
|
|
" if i >= 2:\n",
|
|
" break"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"batched_dataset = dataset.batch(32)\n",
|
|
"for i, element in enumerate(batched_dataset):\n",
|
|
" print(element.shape)\n",
|
|
" if i >= 2:\n",
|
|
" break"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"reshaped_dataset = dataset.map(lambda x: tf.reshape(x, (4, 4)))\n",
|
|
"for i, element in enumerate(reshaped_dataset):\n",
|
|
" print(element.shape)\n",
|
|
" if i >= 2:\n",
|
|
" break"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Displaying the shapes of the data and labels yielded by the `Dataset`**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"for data_batch, labels_batch in train_dataset:\n",
|
|
" print(\"data batch shape:\", data_batch.shape)\n",
|
|
" print(\"labels batch shape:\", labels_batch.shape)\n",
|
|
" break"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Fitting the model using a `Dataset`**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"callbacks = [\n",
|
|
" keras.callbacks.ModelCheckpoint(\n",
|
|
" filepath=\"convnet_from_scratch.keras\",\n",
|
|
" save_best_only=True,\n",
|
|
" monitor=\"val_loss\")\n",
|
|
"]\n",
|
|
"history = model.fit(\n",
|
|
" train_dataset,\n",
|
|
" epochs=30,\n",
|
|
" validation_data=validation_dataset,\n",
|
|
" callbacks=callbacks)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Displaying curves of loss and accuracy during training**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"accuracy = history.history[\"accuracy\"]\n",
|
|
"val_accuracy = history.history[\"val_accuracy\"]\n",
|
|
"loss = history.history[\"loss\"]\n",
|
|
"val_loss = history.history[\"val_loss\"]\n",
|
|
"epochs = range(1, len(accuracy) + 1)\n",
|
|
"plt.plot(epochs, accuracy, \"bo\", label=\"Training accuracy\")\n",
|
|
"plt.plot(epochs, val_accuracy, \"b\", label=\"Validation accuracy\")\n",
|
|
"plt.title(\"Training and validation accuracy\")\n",
|
|
"plt.legend()\n",
|
|
"plt.figure()\n",
|
|
"plt.plot(epochs, loss, \"bo\", label=\"Training loss\")\n",
|
|
"plt.plot(epochs, val_loss, \"b\", label=\"Validation loss\")\n",
|
|
"plt.title(\"Training and validation loss\")\n",
|
|
"plt.legend()\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Evaluating the model on the test set**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"test_model = keras.models.load_model(\"convnet_from_scratch.keras\")\n",
|
|
"test_loss, test_acc = test_model.evaluate(test_dataset)\n",
|
|
"print(f\"Test accuracy: {test_acc:.3f}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Using data augmentation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Define a data augmentation stage to add to an image model**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"data_augmentation = keras.Sequential(\n",
|
|
" [\n",
|
|
" layers.RandomFlip(\"horizontal\"),\n",
|
|
" layers.RandomRotation(0.1),\n",
|
|
" layers.RandomZoom(0.2),\n",
|
|
" ]\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Displaying some randomly augmented training images**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"plt.figure(figsize=(10, 10))\n",
|
|
"for images, _ in train_dataset.take(1):\n",
|
|
" for i in range(9):\n",
|
|
" augmented_images = data_augmentation(images)\n",
|
|
" ax = plt.subplot(3, 3, i + 1)\n",
|
|
" plt.imshow(augmented_images[0].numpy().astype(\"uint8\"))\n",
|
|
" plt.axis(\"off\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Defining a new convnet that includes image augmentation and dropout**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"inputs = keras.Input(shape=(180, 180, 3))\n",
|
|
"x = data_augmentation(inputs)\n",
|
|
"x = layers.Rescaling(1./255)(x)\n",
|
|
"x = layers.Conv2D(filters=32, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=64, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=128, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=256, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.MaxPooling2D(pool_size=2)(x)\n",
|
|
"x = layers.Conv2D(filters=256, kernel_size=3, activation=\"relu\")(x)\n",
|
|
"x = layers.Flatten()(x)\n",
|
|
"x = layers.Dropout(0.5)(x)\n",
|
|
"outputs = layers.Dense(1, activation=\"sigmoid\")(x)\n",
|
|
"model = keras.Model(inputs=inputs, outputs=outputs)\n",
|
|
"\n",
|
|
"model.compile(loss=\"binary_crossentropy\",\n",
|
|
" optimizer=\"rmsprop\",\n",
|
|
" metrics=[\"accuracy\"])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Training the regularized convnet**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"callbacks = [\n",
|
|
" keras.callbacks.ModelCheckpoint(\n",
|
|
" filepath=\"convnet_from_scratch_with_augmentation.keras\",\n",
|
|
" save_best_only=True,\n",
|
|
" monitor=\"val_loss\")\n",
|
|
"]\n",
|
|
"history = model.fit(\n",
|
|
" train_dataset,\n",
|
|
" epochs=100,\n",
|
|
" validation_data=validation_dataset,\n",
|
|
" callbacks=callbacks)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Evaluating the model on the test set**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"test_model = keras.models.load_model(\n",
|
|
" \"convnet_from_scratch_with_augmentation.keras\")\n",
|
|
"test_loss, test_acc = test_model.evaluate(test_dataset)\n",
|
|
"print(f\"Test accuracy: {test_acc:.3f}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"## Leveraging a pretrained model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Feature extraction with a pretrained model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Instantiating the VGG16 convolutional base**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base = keras.applications.vgg16.VGG16(\n",
|
|
" weights=\"imagenet\",\n",
|
|
" include_top=False,\n",
|
|
" input_shape=(180, 180, 3))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Fast feature extraction without data augmentation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Extracting the VGG16 features and corresponding labels**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"def get_features_and_labels(dataset):\n",
|
|
" all_features = []\n",
|
|
" all_labels = []\n",
|
|
" for images, labels in dataset:\n",
|
|
" preprocessed_images = keras.applications.vgg16.preprocess_input(images)\n",
|
|
" features = conv_base.predict(preprocessed_images)\n",
|
|
" all_features.append(features)\n",
|
|
" all_labels.append(labels)\n",
|
|
" return np.concatenate(all_features), np.concatenate(all_labels)\n",
|
|
"\n",
|
|
"train_features, train_labels = get_features_and_labels(train_dataset)\n",
|
|
"val_features, val_labels = get_features_and_labels(validation_dataset)\n",
|
|
"test_features, test_labels = get_features_and_labels(test_dataset)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"train_features.shape"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Defining and training the densely connected classifier**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"inputs = keras.Input(shape=(5, 5, 512))\n",
|
|
"x = layers.Flatten()(inputs)\n",
|
|
"x = layers.Dense(256)(x)\n",
|
|
"x = layers.Dropout(0.5)(x)\n",
|
|
"outputs = layers.Dense(1, activation=\"sigmoid\")(x)\n",
|
|
"model = keras.Model(inputs, outputs)\n",
|
|
"model.compile(loss=\"binary_crossentropy\",\n",
|
|
" optimizer=\"rmsprop\",\n",
|
|
" metrics=[\"accuracy\"])\n",
|
|
"\n",
|
|
"callbacks = [\n",
|
|
" keras.callbacks.ModelCheckpoint(\n",
|
|
" filepath=\"feature_extraction.keras\",\n",
|
|
" save_best_only=True,\n",
|
|
" monitor=\"val_loss\")\n",
|
|
"]\n",
|
|
"history = model.fit(\n",
|
|
" train_features, train_labels,\n",
|
|
" epochs=20,\n",
|
|
" validation_data=(val_features, val_labels),\n",
|
|
" callbacks=callbacks)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Plotting the results**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"acc = history.history[\"accuracy\"]\n",
|
|
"val_acc = history.history[\"val_accuracy\"]\n",
|
|
"loss = history.history[\"loss\"]\n",
|
|
"val_loss = history.history[\"val_loss\"]\n",
|
|
"epochs = range(1, len(acc) + 1)\n",
|
|
"plt.plot(epochs, acc, \"bo\", label=\"Training accuracy\")\n",
|
|
"plt.plot(epochs, val_acc, \"b\", label=\"Validation accuracy\")\n",
|
|
"plt.title(\"Training and validation accuracy\")\n",
|
|
"plt.legend()\n",
|
|
"plt.figure()\n",
|
|
"plt.plot(epochs, loss, \"bo\", label=\"Training loss\")\n",
|
|
"plt.plot(epochs, val_loss, \"b\", label=\"Validation loss\")\n",
|
|
"plt.title(\"Training and validation loss\")\n",
|
|
"plt.legend()\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Feature extraction together with data augmentation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Instantiating and freezing the VGG16 convolutional base**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base = keras.applications.vgg16.VGG16(\n",
|
|
" weights=\"imagenet\",\n",
|
|
" include_top=False)\n",
|
|
"conv_base.trainable = False"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Printing the list of trainable weights before and after freezing**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base.trainable = True\n",
|
|
"print(\"This is the number of trainable weights \"\n",
|
|
" \"before freezing the conv base:\", len(conv_base.trainable_weights))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base.trainable = False\n",
|
|
"print(\"This is the number of trainable weights \"\n",
|
|
" \"after freezing the conv base:\", len(conv_base.trainable_weights))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Adding a data augmentation stage and a classifier to the convolutional base**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"data_augmentation = keras.Sequential(\n",
|
|
" [\n",
|
|
" layers.RandomFlip(\"horizontal\"),\n",
|
|
" layers.RandomRotation(0.1),\n",
|
|
" layers.RandomZoom(0.2),\n",
|
|
" ]\n",
|
|
")\n",
|
|
"\n",
|
|
"inputs = keras.Input(shape=(180, 180, 3))\n",
|
|
"x = data_augmentation(inputs)\n",
|
|
"x = keras.applications.vgg16.preprocess_input(x)\n",
|
|
"x = conv_base(x)\n",
|
|
"x = layers.Flatten()(x)\n",
|
|
"x = layers.Dense(256)(x)\n",
|
|
"x = layers.Dropout(0.5)(x)\n",
|
|
"outputs = layers.Dense(1, activation=\"sigmoid\")(x)\n",
|
|
"model = keras.Model(inputs, outputs)\n",
|
|
"model.compile(loss=\"binary_crossentropy\",\n",
|
|
" optimizer=\"rmsprop\",\n",
|
|
" metrics=[\"accuracy\"])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"callbacks = [\n",
|
|
" keras.callbacks.ModelCheckpoint(\n",
|
|
" filepath=\"feature_extraction_with_data_augmentation.keras\",\n",
|
|
" save_best_only=True,\n",
|
|
" monitor=\"val_loss\")\n",
|
|
"]\n",
|
|
"history = model.fit(\n",
|
|
" train_dataset,\n",
|
|
" epochs=50,\n",
|
|
" validation_data=validation_dataset,\n",
|
|
" callbacks=callbacks)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Evaluating the model on the test set**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"test_model = keras.models.load_model(\n",
|
|
" \"feature_extraction_with_data_augmentation.keras\")\n",
|
|
"test_loss, test_acc = test_model.evaluate(test_dataset)\n",
|
|
"print(f\"Test accuracy: {test_acc:.3f}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Fine-tuning a pretrained model"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base.summary()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Freezing all layers until the fourth from the last**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"conv_base.trainable = True\n",
|
|
"for layer in conv_base.layers[:-4]:\n",
|
|
" layer.trainable = False"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"**Fine-tuning the model**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model.compile(loss=\"binary_crossentropy\",\n",
|
|
" optimizer=keras.optimizers.RMSprop(learning_rate=1e-5),\n",
|
|
" metrics=[\"accuracy\"])\n",
|
|
"\n",
|
|
"callbacks = [\n",
|
|
" keras.callbacks.ModelCheckpoint(\n",
|
|
" filepath=\"fine_tuning.keras\",\n",
|
|
" save_best_only=True,\n",
|
|
" monitor=\"val_loss\")\n",
|
|
"]\n",
|
|
"history = model.fit(\n",
|
|
" train_dataset,\n",
|
|
" epochs=30,\n",
|
|
" validation_data=validation_dataset,\n",
|
|
" callbacks=callbacks)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model = keras.models.load_model(\"fine_tuning.keras\")\n",
|
|
"test_loss, test_acc = model.evaluate(test_dataset)\n",
|
|
"print(f\"Test accuracy: {test_acc:.3f}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"## Summary"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"colab": {
|
|
"collapsed_sections": [],
|
|
"name": "chapter08_intro-to-dl-for-computer-vision.i",
|
|
"private_outputs": false,
|
|
"provenance": [],
|
|
"toc_visible": true
|
|
},
|
|
"kernelspec": {
|
|
"display_name": "Python 3",
|
|
"language": "python",
|
|
"name": "python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.7.0"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 0
|
|
}
|