{ "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 }