{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The CIFAR10 Dataset\n",
    "\n",
    "[Keras CIFAR10 info page](https://keras.io/api/datasets/cifar10)\n",
    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\n",
    "[CIFAR10 home page](https://www.cs.toronto.edu/~kriz/cifar.html)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Preliminaries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "plt.rcParams[\"figure.figsize\"] = (2,2)  # default figure size: 2x2 inches"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "kKKAa30Y8NvM",
    "jupyter": {
     "source_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "# generalized version of plot_history that plots validation data if available\n",
    "\n",
    "def plot_history(history):\n",
    "    loss_values = history.history['loss']\n",
    "    accuracy_values = history.history['accuracy']\n",
    "    validation = 'val_loss' in history.history\n",
    "    if validation:\n",
    "        val_loss_values = history.history['val_loss']\n",
    "        val_accuracy_values = history.history['val_accuracy']\n",
    "    epoch_nums = range(1, len(loss_values)+1)\n",
    "    plt.figure(figsize=(12,4)) # width, height in inches\n",
    "    plt.subplot(1, 2, 1)\n",
    "    if validation:\n",
    "        plt.plot(epoch_nums, loss_values, 'r', label=\"Training loss\")\n",
    "        plt.plot(epoch_nums, val_loss_values, 'r--', label=\"Validation loss\")\n",
    "        plt.title(\"Training/validation loss\")\n",
    "        plt.legend()\n",
    "    else:\n",
    "        plt.plot(epoch_nums, loss_values, 'r', label=\"Training loss\")\n",
    "        plt.title(\"Training loss\")\n",
    "    plt.xlabel(\"Epochs\")\n",
    "    plt.ylabel(\"Loss\")\n",
    "    plt.subplot(1, 2, 2)\n",
    "    if validation:\n",
    "        plt.plot(epoch_nums, accuracy_values, 'b', label='Training accuracy')\n",
    "        plt.plot(epoch_nums, val_accuracy_values, 'b--', label='Validation accuracy')\n",
    "        plt.title(\"Training/validation accuracy\")\n",
    "        plt.legend()\n",
    "    else:\n",
    "        plt.plot(epoch_nums, accuracy_values, 'b', label='Training accuracy')\n",
    "        plt.title(\"Training accuracy\")\n",
    "    plt.xlabel(\"Epochs\")\n",
    "    plt.ylabel(\"Accuracy\")\n",
    "    plt.ylim(0, 1)\n",
    "    plt.show()\n",
    "    \n",
    "from tensorflow.keras.models import Model\n",
    "\n",
    "# this version of show_channels does not call preprocess_image\n",
    "\n",
    "def show_channels(network, image, layer_name, channels=range(20), cmap='gray', cols=5):\n",
    "    # channels can be a number like 0 or a sequence like [0, 2, 4] or range(10)\n",
    "    layer_names = [layer.name for layer in network.layers]\n",
    "    if layer_name not in layer_names:\n",
    "        print(f'No such layer: {layer_name}')\n",
    "        return\n",
    "    # generate activation maps for layer_name\n",
    "    input_tensor = network.layers[0].input\n",
    "    output_tensor = network.get_layer(layer_name).output\n",
    "    activation_model = Model(inputs=input_tensor, outputs=output_tensor)\n",
    "    batch = np.array([image])\n",
    "    #output = activation_model.predict(batch)[0] # using predict causes a weird warning message\n",
    "    output = activation_model(batch)[0].numpy()\n",
    "    h, w, d = output.shape\n",
    "    # display activation maps\n",
    "    if type(channels) is int:\n",
    "        channels  = [channels]\n",
    "    rows = len(channels) // cols\n",
    "    if len(channels) > rows*cols:\n",
    "        rows += 1\n",
    "    plt.figure(figsize=(3*cols,3*rows))  # (width, height) in inches\n",
    "    k = 0\n",
    "    for channel in channels:\n",
    "        if 0 <= channel < d:\n",
    "            k += 1\n",
    "            plt.subplot(rows, cols, k)\n",
    "            plt.imshow(output[:,:,channel], cmap=cmap)\n",
    "            plt.title(f'channel {channel}')\n",
    "            plt.axis('off')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### CIFAR10 categories\n",
    "\n",
    "*   0 = airplane\n",
    "*   1 = car\n",
    "*   2 = bird\n",
    "*   3 = cat\n",
    "*   4 = deer\n",
    "*   5 = dog\n",
    "*   6 = frog\n",
    "*   7 = horse\n",
    "*   8 = ship\n",
    "*   9 = truck"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Load and examine the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.datasets import cifar10"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(train_images,train_labels), (test_images,test_labels) = cifar10.load_data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_images.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "print(train_images.dtype, train_images.min(), train_images.max())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_images[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(train_images[0]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_labels.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(train_labels[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "train_labels[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(train_labels[0][0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_labels = train_labels.reshape(50000)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_labels.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "print(train_labels[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_labels[:10]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_labels = test_labels.reshape(len(test_labels))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_labels.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "names = 'airplane car bird cat deer dog frog horse ship truck'.split()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "names[6]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "def show_random_image():\n",
    "    n = random.randrange(len(train_images))\n",
    "    category_num = train_labels[n]\n",
    "    category_name = names[category_num]\n",
    "    print(f\"train_images[{n}]: {category_name}\")\n",
    "    plt.imshow(train_images[n])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show_random_image()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "8fVjEm9F8NvR",
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# show_random_selection() shows training images from all categories\n",
    "# show_random_selection(n) shows training images from category n\n",
    "\n",
    "def show_random_selection(category_num=None):\n",
    "    if category_num == None:\n",
    "        which = range(len(train_images))\n",
    "    elif 0 <= category_num < len(names):\n",
    "        which = [i for i in range(len(train_images)) if train_labels[i] == category_num]\n",
    "    else:\n",
    "        print(\"category out of range\")\n",
    "        return\n",
    "    plt.figure(figsize=(15,15))  # (width, height) in inches\n",
    "    rows, columns = 5, 6\n",
    "    for k in range(1, columns*rows+1):\n",
    "        i = random.choice(which)\n",
    "        plt.subplot(rows, columns, k)\n",
    "        category_num = train_labels[i]\n",
    "        plt.title(names[category_num])\n",
    "        plt.axis('off')\n",
    "        plt.imshow(train_images[i])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show_random_selection(6)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from keras.utils import to_categorical"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# create the one-hot target vectors\n",
    "train_targets = to_categorical(train_labels, num_classes=10)\n",
    "test_targets = to_categorical(test_labels, num_classes=10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_targets[99]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(test_labels[99])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "names[7]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "plt.imshow(test_images[99]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "jp-MarkdownHeadingCollapsed": true,
    "tags": []
   },
   "source": [
    "### Optional: Convert images to grayscale"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "frog = train_images[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "frog.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(frog);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "frog"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's start with just the top row of pixels in the image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "top_row = frog[0]  # top row of pixels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "top_row"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "len(top_row)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can average together the three RGB values for each pixel like this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "np.dot(top_row, [1/3, 1/3, 1/3])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "len(np.dot(top_row, [1/3, 1/3, 1/3]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "np.round(np.dot(top_row, [1/3, 1/3, 1/3]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "np.round(np.dot(top_row, [1/3, 1/3, 1/3])).astype('uint8')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can also apply the operation to the whole image:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "np.round(np.dot(frog, [1/3, 1/3, 1/3])).astype('uint8')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# convert a color image to grayscale\n",
    "\n",
    "def color2gray(image):\n",
    "    assert image.dtype == 'uint8', \"image must be of type uint8\"\n",
    "    rgb_weights = [1/3, 1/3, 1/3]\n",
    "    gray = np.round(np.dot(image, rgb_weights)).astype('uint8')\n",
    "    return gray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "frog_gray = color2gray(frog)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "frog_gray.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(frog_gray);  # default colormap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(frog_gray, cmap='gray');  # grayscale colormap"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "# version 2:\n",
    "# - corrects for perceptual effects\n",
    "# - returns shape (height, width, 1)\n",
    "\n",
    "def color2gray(image):\n",
    "    assert image.dtype == 'uint8', \"image must be of type uint8\"\n",
    "    rgb_weights = [0.299, 0.587, 0.114]  # corrects for perceptual effects\n",
    "    gray = np.round(np.dot(image, rgb_weights)).astype('uint8')\n",
    "    gray = gray.reshape(gray.shape + (1,))  # reshape as (height, width, 1)\n",
    "    return gray"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "color2gray(frog).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(color2gray(frog), cmap='gray');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "color2gray(train_images[0]).shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can convert all training images at once to grayscale:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "color2gray(train_images).shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_images_gray = color2gray(train_images)\n",
    "test_images_gray = color2gray(test_images)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_images_gray.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_images_gray.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(test_images_gray[99], cmap='gray');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Prepare the training data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "(train_images,train_labels), (test_images,test_labels) = cifar10.load_data()\n",
    "# simplify the labels\n",
    "train_labels = train_labels.reshape(len(train_labels))\n",
    "test_labels = test_labels.reshape(len(test_labels))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(train_images.dtype, train_images.min(), train_images.max())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_images.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "test_images.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def normalize(image):\n",
    "    assert image.dtype == 'uint8', \"image must be of type uint8\"\n",
    "    return (image / 255).astype('float32')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "normalize(train_images[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_images = normalize(train_images)\n",
    "test_images = normalize(test_images)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "print(train_images.dtype, train_images.min(), train_images.max())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(train_images[0]);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "oNye2dTw8NvS"
   },
   "source": [
    "### Build a convolutional neural network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "1Y6w5f5a8NvS"
   },
   "outputs": [],
   "source": [
    "from keras.models import Sequential\n",
    "from keras.layers import Input, Dense, Flatten\n",
    "from keras.layers import Conv2D, MaxPooling2D"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "r3V1roX-8NvT",
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "def build_convnet():\n",
    "    convnet = Sequential()\n",
    "    convnet.add(Input(shape=(32,32,3)))\n",
    "    convnet.add(Conv2D(64, (3,3), activation='relu', name='conv1'))\n",
    "    convnet.add(MaxPooling2D((2,2), name='pool1'))\n",
    "    convnet.add(Conv2D(64, (3,3), activation='relu', name='conv2'))\n",
    "    convnet.add(MaxPooling2D((2,2), name='pool2'))\n",
    "    convnet.add(Conv2D(64, (3,3), activation='relu', name='conv3'))\n",
    "    convnet.add(Flatten())\n",
    "    convnet.add(Dense(64, activation='relu', name='hidden'))\n",
    "    convnet.add(Dense(10, activation='softmax', name='output'))\n",
    "    \n",
    "    convnet.compile(loss='categorical_crossentropy',\n",
    "                    optimizer='rmsprop',\n",
    "                    metrics=['accuracy'])\n",
    "    return convnet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "tZ4j2kQk8NvT"
   },
   "outputs": [],
   "source": [
    "convnet = build_convnet()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "YI0bkp688NvT",
    "outputId": "df12f7f5-0e6c-49c9-ada3-d8a76371b70d"
   },
   "outputs": [],
   "source": [
    "convnet.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "QgPX6uDi8NvT",
    "outputId": "70203e3c-bf78-4e7f-d8d5-5bec9aee6a74",
    "tags": []
   },
   "outputs": [],
   "source": [
    "history = convnet.fit(train_images, train_targets, epochs=10, batch_size=64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Ekhhebp28NvU",
    "outputId": "94648dc7-7515-4dde-d9fe-56b9729b5e33"
   },
   "outputs": [],
   "source": [
    "convnet.evaluate(train_images, train_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "RENYg4MF8NvU",
    "outputId": "91c0895c-b9d1-4a55-ec5a-33a726542d8e"
   },
   "outputs": [],
   "source": [
    "convnet.evaluate(test_images, test_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 295
    },
    "id": "SQ-Rp79h8NvU",
    "outputId": "9dffca8d-fa9d-4241-ff7a-0bc59030aeeb"
   },
   "outputs": [],
   "source": [
    "plot_history(history)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "rIyT6ZhB8NvU"
   },
   "outputs": [],
   "source": [
    "outputs = convnet.predict(test_images)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "sNcqZR6p8NvU",
    "outputId": "6761222c-21f2-4114-ef73-3057f6e75275"
   },
   "outputs": [],
   "source": [
    "outputs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "bMY5RDU28NvV"
   },
   "outputs": [],
   "source": [
    "predictions = [np.argmax(output) for output in outputs]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "A6jEHSHR8NvV"
   },
   "outputs": [],
   "source": [
    "wrong = [i for i in range(len(predictions)) if predictions[i] != test_labels[i]]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "Q3qYaTre8NvV",
    "outputId": "b7978012-2a4d-459c-91c4-1cee3fa0c87f"
   },
   "outputs": [],
   "source": [
    "print(f\"Misclassified {len(wrong)} test images out of {len(test_images)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "source_hidden": true
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "def show_wrong_images(network):\n",
    "    outputs = network.predict(test_images)\n",
    "    predictions = [np.argmax(output) for output in outputs]\n",
    "    wrong = [i for i in range(len(predictions)) if predictions[i] != test_labels[i]]\n",
    "    print(f\"Misclassified {len(wrong)} test images out of {len(test_images)}\")\n",
    "    plt.figure(figsize=(12,12))  # (width, height) in inches\n",
    "    rows, columns = 5, 6\n",
    "    for i in range(1, columns*rows+1):\n",
    "        w = random.choice(wrong)\n",
    "        img = test_images[w]\n",
    "        predicted_name = names[predictions[w]]\n",
    "        correct_name = names[test_labels[w]]\n",
    "        plt.subplot(rows, columns, i)\n",
    "        plt.title(f'\"{predicted_name}\"  ({correct_name})')\n",
    "        plt.axis('off')\n",
    "        plt.imshow(img)  #, cmap='gray')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "xWzA_SzO8NvW",
    "tags": []
   },
   "source": [
    "A random sampling of misclassified images:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 682
    },
    "id": "KcdUFpB28NvW",
    "outputId": "893a9785-78a0-4469-85be-bad65ad9d535"
   },
   "outputs": [],
   "source": [
    "show_wrong_images(convnet)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "te3iyYJJB8vG"
   },
   "source": [
    "### Use a validation set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "y-NxLKcHB_YF",
    "outputId": "e7733bbb-ec58-4897-c793-9c3e7cded645"
   },
   "outputs": [],
   "source": [
    "train_images.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "zZ8aIk0CCMzS",
    "outputId": "7f035fa9-9436-4388-f371-b4851f72b761"
   },
   "outputs": [],
   "source": [
    "train_labels.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "G1oSVXEGCCvv",
    "outputId": "1e8eff83-223f-4273-bb07-ef67bad1b345"
   },
   "outputs": [],
   "source": [
    "train_targets.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "rAPOb_rsCO4E"
   },
   "outputs": [],
   "source": [
    "# of images to use for validation set\n",
    "split = 10000\n",
    "\n",
    "val_images = train_images[:split]\n",
    "val_targets = train_targets[:split]\n",
    "val_labels = train_labels[:split]\n",
    "\n",
    "subset_images = train_images[split:]\n",
    "subset_targets = train_targets[split:]\n",
    "subset_labels = train_labels[split:]\n",
    "\n",
    "print(f\"Using {len(subset_images)} images for training, {len(val_images)} for validation\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "nFNA4PzYC4VF",
    "outputId": "61d52751-f82f-4e46-b096-0892985abd06"
   },
   "outputs": [],
   "source": [
    "subset_images.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "WIblTME6Cxif"
   },
   "outputs": [],
   "source": [
    "convnet = build_convnet()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "BEtb9bmnC63t",
    "outputId": "b030ed8e-df86-415f-b458-17180b611283",
    "tags": []
   },
   "outputs": [],
   "source": [
    "history = convnet.fit(subset_images, subset_targets,\n",
    "                      validation_data=(val_images, val_targets),\n",
    "                      epochs=10, batch_size=64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "fLPHDkw0DPeS",
    "outputId": "2aa5b1a8-8e0d-418d-bd60-7d209d7451d2"
   },
   "outputs": [],
   "source": [
    "convnet.evaluate(subset_images, subset_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "bTI-mUNrDhMb",
    "outputId": "a5d334eb-0f7b-4875-9246-459542b0de1b"
   },
   "outputs": [],
   "source": [
    "convnet.evaluate(test_images, test_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 295
    },
    "id": "FYC4SsYRDm9Q",
    "outputId": "f7b4d6c7-54ac-4955-b52a-4bf49188ba7b"
   },
   "outputs": [],
   "source": [
    "plot_history(history)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "JlrvfMqVDomg"
   },
   "outputs": [],
   "source": [
    "convnet = build_convnet()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "E-iyF6QPDuJ3",
    "outputId": "8ead8451-26c0-4973-aca9-b9b896161e29"
   },
   "outputs": [],
   "source": [
    "history = convnet.fit(train_images, train_targets, epochs=4, batch_size=64)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "OZTKNdbPEdMV",
    "outputId": "412c7169-3b35-4b73-c2d8-2134ecc23913"
   },
   "outputs": [],
   "source": [
    "convnet.evaluate(train_images, train_targets)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "u2KL4xFZD1tO",
    "outputId": "c9efebac-cf90-43ce-eb6f-33abeac0f87a"
   },
   "outputs": [],
   "source": [
    "convnet.evaluate(test_images, test_targets)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wGHDd0wND9uN",
    "tags": []
   },
   "source": [
    "### Cats vs. Dogs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# This function returns a subset of the CIFAR10 dataset\n",
    "# consisting of the specified image classes. \n",
    "\n",
    "def load_cifar10_subset(selected_classes=[]):\n",
    "    if len(selected_classes) == 0:\n",
    "        selected_classes = list(range(10))\n",
    "    for n in selected_classes:\n",
    "        assert type(n) == int and 0 <= n <= 9, \"classes must be ints in range 0-9\"\n",
    "    # load the data\n",
    "    (train_images,train_labels), (test_images,test_labels) = cifar10.load_data()\n",
    "    # simplify the labels\n",
    "    train_labels = train_labels.reshape(len(train_labels))\n",
    "    test_labels = test_labels.reshape(len(test_labels))\n",
    "    # extract the desired classes\n",
    "    indices = [i for i in range(len(train_labels)) if train_labels[i] in selected_classes]\n",
    "    selected_train_images = train_images[indices]\n",
    "    selected_train_labels = train_labels[indices]\n",
    "    indices = [i for i in range(len(test_labels)) if test_labels[i] in selected_classes]\n",
    "    selected_test_images = test_images[indices]\n",
    "    selected_test_labels = test_labels[indices]\n",
    "    new_train_labels = np.array([selected_classes.index(i) for i in selected_train_labels])\n",
    "    new_test_labels = np.array([selected_classes.index(i) for i in selected_test_labels])\n",
    "    class_names = 'airplane car bird cat deer dog frog horse ship truck'.split()\n",
    "    new_names = [class_names[n] for n in selected_classes]\n",
    "    # normalize the images\n",
    "    selected_train_images = normalize(selected_train_images)\n",
    "    selected_test_images = normalize(selected_test_images)\n",
    "    return ((selected_train_images,new_train_labels),\n",
    "            (selected_test_images,new_test_labels),\n",
    "            new_names)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "4wfox7ck8NvN",
    "outputId": "9ce0631e-029a-4959-b210-b64c11f9079d"
   },
   "outputs": [],
   "source": [
    "(train_images,train_labels), (test_images,test_labels), names = load_cifar10_subset([3,5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_labels[:20]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(train_images[5]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "plt.imshow(train_images[4]);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "4wfox7ck8NvN",
    "outputId": "9ce0631e-029a-4959-b210-b64c11f9079d"
   },
   "outputs": [],
   "source": [
    "# create the one-hot target vectors\n",
    "train_targets = to_categorical(train_labels, num_classes=2)\n",
    "test_targets = to_categorical(test_labels, num_classes=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "train_targets[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show_random_selection(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "show_random_selection(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### How well can you train the network to distinguish cats from dogs?\n",
    "\n",
    "Try it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wGHDd0wND9uN",
    "tags": []
   },
   "source": [
    "### Dogs vs. Airplanes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "4wfox7ck8NvN",
    "outputId": "9ce0631e-029a-4959-b210-b64c11f9079d",
    "tags": []
   },
   "outputs": [],
   "source": [
    "(train_images,train_labels), (test_images,test_labels), names = load_cifar10_subset([5,0])\n",
    "\n",
    "# create the one-hot target vectors\n",
    "train_targets = to_categorical(train_labels, num_classes=2)\n",
    "test_targets = to_categorical(test_labels, num_classes=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "names"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "show_random_selection()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### How well can you train the network to distinguish dogs from airplanes?\n",
    "\n",
    "Try it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cars vs. Trucks vs. Ships vs. Airplanes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "4wfox7ck8NvN",
    "outputId": "9ce0631e-029a-4959-b210-b64c11f9079d",
    "tags": []
   },
   "outputs": [],
   "source": [
    "(train_images,train_labels), (test_images,test_labels), names = load_cifar10_subset([1,9,8,0])\n",
    "\n",
    "# create the one-hot target vectors\n",
    "train_targets = to_categorical(train_labels, num_classes=4)\n",
    "test_targets = to_categorical(test_labels, num_classes=4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "show_random_selection()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Try it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Or some other combination of categories..."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.12.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
