{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "This is a companion notebook for the book [Deep Learning with Python, Third Edition](https://www.manning.com/books/deep-learning-with-python-third-edition). 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\nThe book's contents are available online at [deeplearningwithpython.io](https://deeplearningwithpython.io)." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "!pip install keras keras-hub --upgrade -q" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import os\n", "os.environ[\"KERAS_BACKEND\"] = \"jax\"" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "cellView": "form", "colab_type": "code" }, "outputs": [], "source": [ "# @title\n", "import os\n", "from IPython.core.magic import register_cell_magic\n", "\n", "@register_cell_magic\n", "def backend(line, cell):\n", " current, required = os.environ.get(\"KERAS_BACKEND\", \"\"), line.split()[-1]\n", " if current == required:\n", " get_ipython().run_cell(cell)\n", " else:\n", " print(\n", " f\"This cell requires the {required} backend. To run it, change KERAS_BACKEND to \"\n", " f\"\\\"{required}\\\" at the top of the notebook, restart the runtime, and rerun the notebook.\"\n", " )" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "## ConvNet architecture patterns" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Modularity, hierarchy, and reuse" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Residual connections" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import keras\n", "from keras import layers\n", "\n", "inputs = keras.Input(shape=(32, 32, 3))\n", "x = layers.Conv2D(32, 3, activation=\"relu\")(inputs)\n", "residual = x\n", "x = layers.Conv2D(64, 3, activation=\"relu\", padding=\"same\")(x)\n", "residual = layers.Conv2D(64, 1)(residual)\n", "x = layers.add([x, residual])" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "inputs = keras.Input(shape=(32, 32, 3))\n", "x = layers.Conv2D(32, 3, activation=\"relu\")(inputs)\n", "residual = x\n", "x = layers.Conv2D(64, 3, activation=\"relu\", padding=\"same\")(x)\n", "x = layers.MaxPooling2D(2, padding=\"same\")(x)\n", "residual = layers.Conv2D(64, 1, strides=2)(residual)\n", "x = layers.add([x, residual])" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "inputs = keras.Input(shape=(32, 32, 3))\n", "x = layers.Rescaling(1.0 / 255)(inputs)\n", "\n", "def residual_block(x, filters, pooling=False):\n", " residual = x\n", " x = layers.Conv2D(filters, 3, activation=\"relu\", padding=\"same\")(x)\n", " x = layers.Conv2D(filters, 3, activation=\"relu\", padding=\"same\")(x)\n", " if pooling:\n", " x = layers.MaxPooling2D(2, padding=\"same\")(x)\n", " residual = layers.Conv2D(filters, 1, strides=2)(residual)\n", " elif filters != residual.shape[-1]:\n", " residual = layers.Conv2D(filters, 1)(residual)\n", " x = layers.add([x, residual])\n", " return x\n", "\n", "x = residual_block(x, filters=32, pooling=True)\n", "x = residual_block(x, filters=64, pooling=True)\n", "x = residual_block(x, filters=128, pooling=False)\n", "\n", "x = layers.GlobalAveragePooling2D()(x)\n", "outputs = layers.Dense(1, activation=\"sigmoid\")(x)\n", "model = keras.Model(inputs=inputs, outputs=outputs)" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Batch normalization" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Depthwise separable convolutions" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Putting it together: A mini Xception-like model" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import kagglehub\n", "\n", "kagglehub.login()" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import zipfile\n", "\n", "download_path = kagglehub.competition_download(\"dogs-vs-cats\")\n", "\n", "with zipfile.ZipFile(download_path + \"/train.zip\", \"r\") as zip_ref:\n", " zip_ref.extractall(\".\")" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import os, shutil, pathlib\n", "from keras.utils import image_dataset_from_directory\n", "\n", "original_dir = pathlib.Path(\"train\")\n", "new_base_dir = pathlib.Path(\"dogs_vs_cats_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, 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)\n", "\n", "batch_size = 64\n", "image_size = (180, 180)\n", "train_dataset = image_dataset_from_directory(\n", " new_base_dir / \"train\",\n", " image_size=image_size,\n", " batch_size=batch_size,\n", ")\n", "validation_dataset = image_dataset_from_directory(\n", " new_base_dir / \"validation\",\n", " image_size=image_size,\n", " batch_size=batch_size,\n", ")\n", "test_dataset = image_dataset_from_directory(\n", " new_base_dir / \"test\",\n", " image_size=image_size,\n", " batch_size=batch_size,\n", ")" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import tensorflow as tf\n", "from keras import layers\n", "\n", "data_augmentation_layers = [\n", " layers.RandomFlip(\"horizontal\"),\n", " layers.RandomRotation(0.1),\n", " layers.RandomZoom(0.2),\n", "]\n", "\n", "def data_augmentation(images, targets):\n", " for layer in data_augmentation_layers:\n", " images = layer(images)\n", " return images, targets\n", "\n", "augmented_train_dataset = train_dataset.map(\n", " data_augmentation, num_parallel_calls=8\n", ")\n", "augmented_train_dataset = augmented_train_dataset.prefetch(tf.data.AUTOTUNE)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import keras\n", "\n", "inputs = keras.Input(shape=(180, 180, 3))\n", "x = layers.Rescaling(1.0 / 255)(inputs)\n", "x = layers.Conv2D(filters=32, kernel_size=5, use_bias=False)(x)\n", "\n", "for size in [32, 64, 128, 256, 512]:\n", " residual = x\n", "\n", " x = layers.BatchNormalization()(x)\n", " x = layers.Activation(\"relu\")(x)\n", " x = layers.SeparableConv2D(size, 3, padding=\"same\", use_bias=False)(x)\n", "\n", " x = layers.BatchNormalization()(x)\n", " x = layers.Activation(\"relu\")(x)\n", " x = layers.SeparableConv2D(size, 3, padding=\"same\", use_bias=False)(x)\n", "\n", " x = layers.MaxPooling2D(3, strides=2, padding=\"same\")(x)\n", "\n", " residual = layers.Conv2D(\n", " size, 1, strides=2, padding=\"same\", use_bias=False\n", " )(residual)\n", " x = layers.add([x, residual])\n", "\n", "x = layers.GlobalAveragePooling2D()(x)\n", "x = layers.Dropout(0.5)(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.compile(\n", " loss=\"binary_crossentropy\",\n", " optimizer=\"adam\",\n", " metrics=[\"accuracy\"],\n", ")\n", "history = model.fit(\n", " augmented_train_dataset,\n", " epochs=100,\n", " validation_data=validation_dataset,\n", ")" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Beyond convolution: Vision Transformers" ] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "chapter09_convnet-architecture-patterns", "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.10.0" } }, "nbformat": 4, "nbformat_minor": 0 }