Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
fchollet
GitHub Repository: fchollet/deep-learning-with-python-notebooks
Path: blob/master/chapter09_convnet-architecture-patterns.ipynb
709 views
Kernel: Python 3

This is a companion notebook for the book 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.

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.

The book's contents are available online at deeplearningwithpython.io.

!pip install keras keras-hub --upgrade -q
import os os.environ["KERAS_BACKEND"] = "jax"
# @title import os from IPython.core.magic import register_cell_magic @register_cell_magic def backend(line, cell): current, required = os.environ.get("KERAS_BACKEND", ""), line.split()[-1] if current == required: get_ipython().run_cell(cell) else: print( f"This cell requires the {required} backend. To run it, change KERAS_BACKEND to " f"\"{required}\" at the top of the notebook, restart the runtime, and rerun the notebook." )

Convnet architecture patterns

Modularity, hierarchy, and reuse

Residual connections

import keras from keras import layers inputs = keras.Input(shape=(32, 32, 3)) x = layers.Conv2D(32, 3, activation="relu")(inputs) residual = x x = layers.Conv2D(64, 3, activation="relu", padding="same")(x) residual = layers.Conv2D(64, 1)(residual) x = layers.add([x, residual])
inputs = keras.Input(shape=(32, 32, 3)) x = layers.Conv2D(32, 3, activation="relu")(inputs) residual = x x = layers.Conv2D(64, 3, activation="relu", padding="same")(x) x = layers.MaxPooling2D(2, padding="same")(x) residual = layers.Conv2D(64, 1, strides=2)(residual) x = layers.add([x, residual])
inputs = keras.Input(shape=(32, 32, 3)) x = layers.Rescaling(1.0 / 255)(inputs) def residual_block(x, filters, pooling=False): residual = x x = layers.Conv2D(filters, 3, activation="relu", padding="same")(x) x = layers.Conv2D(filters, 3, activation="relu", padding="same")(x) if pooling: x = layers.MaxPooling2D(2, padding="same")(x) residual = layers.Conv2D(filters, 1, strides=2)(residual) elif filters != residual.shape[-1]: residual = layers.Conv2D(filters, 1)(residual) x = layers.add([x, residual]) return x x = residual_block(x, filters=32, pooling=True) x = residual_block(x, filters=64, pooling=True) x = residual_block(x, filters=128, pooling=False) x = layers.GlobalAveragePooling2D()(x) outputs = layers.Dense(1, activation="sigmoid")(x) model = keras.Model(inputs=inputs, outputs=outputs)

Batch normalization

Depthwise separable convolutions

Putting it together: A mini Xception-like model

import kagglehub kagglehub.login()
import zipfile download_path = kagglehub.competition_download("dogs-vs-cats") with zipfile.ZipFile(download_path + "/train.zip", "r") as zip_ref: zip_ref.extractall(".")
import os, shutil, pathlib from keras.utils import image_dataset_from_directory original_dir = pathlib.Path("train") new_base_dir = pathlib.Path("dogs_vs_cats_small") def make_subset(subset_name, start_index, end_index): for category in ("cat", "dog"): dir = new_base_dir / subset_name / category os.makedirs(dir) fnames = [f"{category}.{i}.jpg" for i in range(start_index, end_index)] for fname in fnames: shutil.copyfile(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) batch_size = 64 image_size = (180, 180) train_dataset = image_dataset_from_directory( new_base_dir / "train", image_size=image_size, batch_size=batch_size, ) validation_dataset = image_dataset_from_directory( new_base_dir / "validation", image_size=image_size, batch_size=batch_size, ) test_dataset = image_dataset_from_directory( new_base_dir / "test", image_size=image_size, batch_size=batch_size, )
import tensorflow as tf from keras import layers data_augmentation_layers = [ layers.RandomFlip("horizontal"), layers.RandomRotation(0.1), layers.RandomZoom(0.2), ] def data_augmentation(images, targets): for layer in data_augmentation_layers: images = layer(images) return images, targets augmented_train_dataset = train_dataset.map( data_augmentation, num_parallel_calls=8 ) augmented_train_dataset = augmented_train_dataset.prefetch(tf.data.AUTOTUNE)
import keras inputs = keras.Input(shape=(180, 180, 3)) x = layers.Rescaling(1.0 / 255)(inputs) x = layers.Conv2D(filters=32, kernel_size=5, use_bias=False)(x) for size in [32, 64, 128, 256, 512]: residual = x x = layers.BatchNormalization()(x) x = layers.Activation("relu")(x) x = layers.SeparableConv2D(size, 3, padding="same", use_bias=False)(x) x = layers.BatchNormalization()(x) x = layers.Activation("relu")(x) x = layers.SeparableConv2D(size, 3, padding="same", use_bias=False)(x) x = layers.MaxPooling2D(3, strides=2, padding="same")(x) residual = layers.Conv2D( size, 1, strides=2, padding="same", use_bias=False )(residual) x = layers.add([x, residual]) x = layers.GlobalAveragePooling2D()(x) x = layers.Dropout(0.5)(x) outputs = layers.Dense(1, activation="sigmoid")(x) model = keras.Model(inputs=inputs, outputs=outputs)
model.compile( loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"], ) history = model.fit( augmented_train_dataset, epochs=100, validation_data=validation_dataset, )

Beyond convolution: Vision Transformers