827 lines
21 KiB
Plaintext
827 lines
21 KiB
Plaintext
{
|
|
"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": [
|
|
"## Interpreting what ConvNets learn"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Visualizing intermediate activations"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from google.colab import files\n",
|
|
"\n",
|
|
"# You can use this to load the file\n",
|
|
"# \"convnet_from_scratch_with_augmentation.keras\"\n",
|
|
"# you obtained in the last chapter.\n",
|
|
"files.upload()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import keras\n",
|
|
"model = keras.models.load_model(\n",
|
|
" \"convnet_from_scratch_with_augmentation.keras\"\n",
|
|
")\n",
|
|
"model.summary(line_length=80)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import keras\n",
|
|
"import numpy as np\n",
|
|
"\n",
|
|
"img_path = keras.utils.get_file(\n",
|
|
" fname=\"cat.jpg\", origin=\"https://img-datasets.s3.amazonaws.com/cat.jpg\"\n",
|
|
")\n",
|
|
"\n",
|
|
"def get_img_array(img_path, target_size):\n",
|
|
" img = keras.utils.load_img(img_path, target_size=target_size)\n",
|
|
" array = keras.utils.img_to_array(img)\n",
|
|
" array = np.expand_dims(array, axis=0)\n",
|
|
" return array\n",
|
|
"\n",
|
|
"img_tensor = get_img_array(img_path, target_size=(180, 180))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"\n",
|
|
"plt.axis(\"off\")\n",
|
|
"plt.imshow(img_tensor[0].astype(\"uint8\"))\n",
|
|
"plt.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from keras import layers\n",
|
|
"\n",
|
|
"layer_outputs = []\n",
|
|
"layer_names = []\n",
|
|
"for layer in model.layers:\n",
|
|
" if isinstance(layer, (layers.Conv2D, layers.MaxPooling2D)):\n",
|
|
" layer_outputs.append(layer.output)\n",
|
|
" layer_names.append(layer.name)\n",
|
|
"activation_model = keras.Model(inputs=model.input, outputs=layer_outputs)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"activations = activation_model.predict(img_tensor)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"first_layer_activation = activations[0]\n",
|
|
"print(first_layer_activation.shape)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import matplotlib.pyplot as plt\n",
|
|
"\n",
|
|
"plt.matshow(first_layer_activation[0, :, :, 5], cmap=\"viridis\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"images_per_row = 16\n",
|
|
"for layer_name, layer_activation in zip(layer_names, activations):\n",
|
|
" n_features = layer_activation.shape[-1]\n",
|
|
" size = layer_activation.shape[1]\n",
|
|
" n_cols = n_features // images_per_row\n",
|
|
" display_grid = np.zeros(\n",
|
|
" ((size + 1) * n_cols - 1, images_per_row * (size + 1) - 1)\n",
|
|
" )\n",
|
|
" for col in range(n_cols):\n",
|
|
" for row in range(images_per_row):\n",
|
|
" channel_index = col * images_per_row + row\n",
|
|
" channel_image = layer_activation[0, :, :, channel_index].copy()\n",
|
|
" if channel_image.sum() != 0:\n",
|
|
" channel_image -= channel_image.mean()\n",
|
|
" channel_image /= channel_image.std()\n",
|
|
" channel_image *= 64\n",
|
|
" channel_image += 128\n",
|
|
" channel_image = np.clip(channel_image, 0, 255).astype(\"uint8\")\n",
|
|
" display_grid[\n",
|
|
" col * (size + 1) : (col + 1) * size + col,\n",
|
|
" row * (size + 1) : (row + 1) * size + row,\n",
|
|
" ] = channel_image\n",
|
|
" scale = 1.0 / size\n",
|
|
" plt.figure(\n",
|
|
" figsize=(scale * display_grid.shape[1], scale * display_grid.shape[0])\n",
|
|
" )\n",
|
|
" plt.title(layer_name)\n",
|
|
" plt.grid(False)\n",
|
|
" plt.axis(\"off\")\n",
|
|
" plt.imshow(display_grid, aspect=\"auto\", cmap=\"viridis\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Visualizing ConvNet filters"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import keras_hub\n",
|
|
"\n",
|
|
"model = keras_hub.models.Backbone.from_preset(\n",
|
|
" \"xception_41_imagenet\",\n",
|
|
")\n",
|
|
"preprocessor = keras_hub.layers.ImageConverter.from_preset(\n",
|
|
" \"xception_41_imagenet\",\n",
|
|
" image_size=(180, 180),\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"for layer in model.layers:\n",
|
|
" if isinstance(layer, (keras.layers.Conv2D, keras.layers.SeparableConv2D)):\n",
|
|
" print(layer.name)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"layer_name = \"block3_sepconv1\"\n",
|
|
"layer = model.get_layer(name=layer_name)\n",
|
|
"feature_extractor = keras.Model(inputs=model.input, outputs=layer.output)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"activation = feature_extractor(preprocessor(img_tensor))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"from keras import ops\n",
|
|
"\n",
|
|
"def compute_loss(image, filter_index):\n",
|
|
" activation = feature_extractor(image)\n",
|
|
" filter_activation = activation[:, 2:-2, 2:-2, filter_index]\n",
|
|
" return ops.mean(filter_activation)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Gradient ascent in TensorFlow"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%backend tensorflow\n",
|
|
"import tensorflow as tf\n",
|
|
"\n",
|
|
"@tf.function\n",
|
|
"def gradient_ascent_step(image, filter_index, learning_rate):\n",
|
|
" with tf.GradientTape() as tape:\n",
|
|
" tape.watch(image)\n",
|
|
" loss = compute_loss(image, filter_index)\n",
|
|
" grads = tape.gradient(loss, image)\n",
|
|
" grads = ops.normalize(grads)\n",
|
|
" image += learning_rate * grads\n",
|
|
" return image"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Gradient ascent in PyTorch"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%backend torch\n",
|
|
"import torch\n",
|
|
"\n",
|
|
"def gradient_ascent_step(image, filter_index, learning_rate):\n",
|
|
" image = image.clone().detach().requires_grad_(True)\n",
|
|
" loss = compute_loss(image, filter_index)\n",
|
|
" loss.backward()\n",
|
|
" grads = image.grad\n",
|
|
" grads = ops.normalize(grads)\n",
|
|
" image = image + learning_rate * grads\n",
|
|
" return image"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Gradient ascent in JAX"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%backend jax\n",
|
|
"import jax\n",
|
|
"\n",
|
|
"grad_fn = jax.grad(compute_loss)\n",
|
|
"\n",
|
|
"@jax.jit\n",
|
|
"def gradient_ascent_step(image, filter_index, learning_rate):\n",
|
|
" grads = grad_fn(image, filter_index)\n",
|
|
" grads = ops.normalize(grads)\n",
|
|
" image += learning_rate * grads\n",
|
|
" return image"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### The filter visualization loop"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"img_width = 200\n",
|
|
"img_height = 200\n",
|
|
"\n",
|
|
"def generate_filter_pattern(filter_index):\n",
|
|
" iterations = 30\n",
|
|
" learning_rate = 10.0\n",
|
|
" image = keras.random.uniform(\n",
|
|
" minval=0.4, maxval=0.6, shape=(1, img_width, img_height, 3)\n",
|
|
" )\n",
|
|
" for i in range(iterations):\n",
|
|
" image = gradient_ascent_step(image, filter_index, learning_rate)\n",
|
|
" return image[0]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"def deprocess_image(image):\n",
|
|
" image -= ops.mean(image)\n",
|
|
" image /= ops.std(image)\n",
|
|
" image *= 64\n",
|
|
" image += 128\n",
|
|
" image = ops.clip(image, 0, 255)\n",
|
|
" image = image[25:-25, 25:-25, :]\n",
|
|
" image = ops.cast(image, dtype=\"uint8\")\n",
|
|
" return ops.convert_to_numpy(image)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"plt.axis(\"off\")\n",
|
|
"plt.imshow(deprocess_image(generate_filter_pattern(filter_index=2)))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"all_images = []\n",
|
|
"for filter_index in range(64):\n",
|
|
" print(f\"Processing filter {filter_index}\")\n",
|
|
" image = deprocess_image(generate_filter_pattern(filter_index))\n",
|
|
" all_images.append(image)\n",
|
|
"\n",
|
|
"margin = 5\n",
|
|
"n = 8\n",
|
|
"box_width = img_width - 25 * 2\n",
|
|
"box_height = img_height - 25 * 2\n",
|
|
"full_width = n * box_width + (n - 1) * margin\n",
|
|
"full_height = n * box_height + (n - 1) * margin\n",
|
|
"stitched_filters = np.zeros((full_width, full_height, 3))\n",
|
|
"\n",
|
|
"for i in range(n):\n",
|
|
" for j in range(n):\n",
|
|
" image = all_images[i * n + j]\n",
|
|
" stitched_filters[\n",
|
|
" (box_width + margin) * i : (box_width + margin) * i + box_width,\n",
|
|
" (box_height + margin) * j : (box_height + margin) * j + box_height,\n",
|
|
" :,\n",
|
|
" ] = image\n",
|
|
"\n",
|
|
"keras.utils.save_img(f\"filters_for_layer_{layer_name}.png\", stitched_filters)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Visualizing heatmaps of class activation"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"img_path = keras.utils.get_file(\n",
|
|
" fname=\"elephant.jpg\",\n",
|
|
" origin=\"https://img-datasets.s3.amazonaws.com/elephant.jpg\",\n",
|
|
")\n",
|
|
"img = keras.utils.load_img(img_path)\n",
|
|
"img_array = np.expand_dims(img, axis=0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model = keras_hub.models.ImageClassifier.from_preset(\n",
|
|
" \"xception_41_imagenet\",\n",
|
|
" activation=\"softmax\",\n",
|
|
")\n",
|
|
"preds = model.predict(img_array)\n",
|
|
"preds.shape"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"keras_hub.utils.decode_imagenet_predictions(preds)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"np.argmax(preds[0])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"img_array = model.preprocessor(img_array)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"last_conv_layer_name = \"block14_sepconv2_act\"\n",
|
|
"last_conv_layer = model.backbone.get_layer(last_conv_layer_name)\n",
|
|
"last_conv_layer_model = keras.Model(model.inputs, last_conv_layer.output)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"classifier_input = last_conv_layer.output\n",
|
|
"x = classifier_input\n",
|
|
"for layer_name in [\"pooler\", \"predictions\"]:\n",
|
|
" x = model.get_layer(layer_name)(x)\n",
|
|
"classifier_model = keras.Model(classifier_input, x)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Getting the gradient of the top class: TensorFlow version"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%backend tensorflow\n",
|
|
"import tensorflow as tf\n",
|
|
"\n",
|
|
"def get_top_class_gradients(img_array):\n",
|
|
" last_conv_layer_output = last_conv_layer_model(img_array)\n",
|
|
" with tf.GradientTape() as tape:\n",
|
|
" tape.watch(last_conv_layer_output)\n",
|
|
" preds = classifier_model(last_conv_layer_output)\n",
|
|
" top_pred_index = ops.argmax(preds[0])\n",
|
|
" top_class_channel = preds[:, top_pred_index]\n",
|
|
"\n",
|
|
" grads = tape.gradient(top_class_channel, last_conv_layer_output)\n",
|
|
" return grads, last_conv_layer_output\n",
|
|
"\n",
|
|
"grads, last_conv_layer_output = get_top_class_gradients(img_array)\n",
|
|
"grads = ops.convert_to_numpy(grads)\n",
|
|
"last_conv_layer_output = ops.convert_to_numpy(last_conv_layer_output)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Getting the gradient of the top class: PyTorch version"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%backend torch\n",
|
|
"def get_top_class_gradients(img_array):\n",
|
|
" last_conv_layer_output = last_conv_layer_model(img_array)\n",
|
|
" last_conv_layer_output = (\n",
|
|
" last_conv_layer_output.clone().detach().requires_grad_(True)\n",
|
|
" )\n",
|
|
" preds = classifier_model(last_conv_layer_output)\n",
|
|
" top_pred_index = ops.argmax(preds[0])\n",
|
|
" top_class_channel = preds[:, top_pred_index]\n",
|
|
" top_class_channel.backward()\n",
|
|
" grads = last_conv_layer_output.grad\n",
|
|
" return grads, last_conv_layer_output\n",
|
|
"\n",
|
|
"grads, last_conv_layer_output = get_top_class_gradients(img_array)\n",
|
|
"grads = ops.convert_to_numpy(grads)\n",
|
|
"last_conv_layer_output = ops.convert_to_numpy(last_conv_layer_output)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Getting the gradient of the top class: JAX version"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"%%backend jax\n",
|
|
"import jax\n",
|
|
"\n",
|
|
"def loss_fn(last_conv_layer_output):\n",
|
|
" preds = classifier_model(last_conv_layer_output)\n",
|
|
" top_pred_index = ops.argmax(preds[0])\n",
|
|
" top_class_channel = preds[:, top_pred_index]\n",
|
|
" return top_class_channel[0]\n",
|
|
"\n",
|
|
"grad_fn = jax.grad(loss_fn)\n",
|
|
"\n",
|
|
"def get_top_class_gradients(img_array):\n",
|
|
" last_conv_layer_output = last_conv_layer_model(img_array)\n",
|
|
" grads = grad_fn(last_conv_layer_output)\n",
|
|
" return grads, last_conv_layer_output\n",
|
|
"\n",
|
|
"grads, last_conv_layer_output = get_top_class_gradients(img_array)\n",
|
|
"grads = ops.convert_to_numpy(grads)\n",
|
|
"last_conv_layer_output = ops.convert_to_numpy(last_conv_layer_output)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"#### Displaying the class activation heatmap"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"pooled_grads = np.mean(grads, axis=(0, 1, 2))\n",
|
|
"last_conv_layer_output = last_conv_layer_output[0].copy()\n",
|
|
"for i in range(pooled_grads.shape[-1]):\n",
|
|
" last_conv_layer_output[:, :, i] *= pooled_grads[i]\n",
|
|
"heatmap = np.mean(last_conv_layer_output, axis=-1)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"heatmap = np.maximum(heatmap, 0)\n",
|
|
"heatmap /= np.max(heatmap)\n",
|
|
"plt.matshow(heatmap)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": 0,
|
|
"metadata": {
|
|
"colab_type": "code"
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"import matplotlib.cm as cm\n",
|
|
"\n",
|
|
"img = keras.utils.load_img(img_path)\n",
|
|
"img = keras.utils.img_to_array(img)\n",
|
|
"\n",
|
|
"heatmap = np.uint8(255 * heatmap)\n",
|
|
"\n",
|
|
"jet = cm.get_cmap(\"jet\")\n",
|
|
"jet_colors = jet(np.arange(256))[:, :3]\n",
|
|
"jet_heatmap = jet_colors[heatmap]\n",
|
|
"\n",
|
|
"jet_heatmap = keras.utils.array_to_img(jet_heatmap)\n",
|
|
"jet_heatmap = jet_heatmap.resize((img.shape[1], img.shape[0]))\n",
|
|
"jet_heatmap = keras.utils.img_to_array(jet_heatmap)\n",
|
|
"\n",
|
|
"superimposed_img = jet_heatmap * 0.4 + img\n",
|
|
"superimposed_img = keras.utils.array_to_img(superimposed_img)\n",
|
|
"\n",
|
|
"plt.imshow(superimposed_img)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"colab_type": "text"
|
|
},
|
|
"source": [
|
|
"### Visualizing the latent space of a ConvNet"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"accelerator": "GPU",
|
|
"colab": {
|
|
"collapsed_sections": [],
|
|
"name": "chapter10_interpreting-what-convnets-learn",
|
|
"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
|
|
} |