{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "_os2SNaj1njY" }, "source": [ "# Image classification from scratch\n", "\n", "**Author:** [fchollet](https://twitter.com/fchollet)
\n", "**Date created:** 2020/04/27
\n", "**Last modified:** 2020/04/28
\n", "**Description:** Training an image classifier from scratch on the Kaggle Cats vs Dogs dataset." ] }, { "cell_type": "markdown", "metadata": { "id": "hEPiUEtj1njZ" }, "source": [ "## Introduction\n", "\n", "This example shows how to do image classification from scratch, starting from JPEG\n", "image files on disk, without leveraging pre-trained weights or a pre-made Keras\n", "Application model. We demonstrate the workflow on the Kaggle Cats vs Dogs binary\n", " classification dataset.\n", "\n", "We use the `image_dataset_from_directory` utility to generate the datasets, and\n", "we use Keras image preprocessing layers for image standardization and data augmentation.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "vFcWzzPQ1nja" }, "source": [ "## Setup\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "u_z-j-fY1njb" }, "outputs": [], "source": [ "import tensorflow as tf\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "import pydot\n", "import os\n", "from PIL import Image\n", "import matplotlib.pyplot as plt\n", "from keras.utils.vis_utils import plot_model" ] }, { "cell_type": "markdown", "metadata": { "id": "iusfbMxZ1njc" }, "source": [ "## Load the data: the Cats vs Dogs dataset\n", "\n", "### Raw data download\n", "\n", "First, let's download the 786M ZIP archive of the raw data:\n" ] }, { "cell_type": "markdown", "metadata": { "id": "5lujeYX81njd" }, "source": [ "Now we have a `PetImages` folder which contain two subfolders, `Cat` and `Dog`. Each\n", " subfolder contains image files for each category.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "jED1LIFr1njd", "outputId": "bfed1264-9e8d-42d3-be60-3bde47503bf0" }, "outputs": [], "source": [ "!ls PetImages\n" ] }, { "cell_type": "markdown", "metadata": { "id": "iz07gyGU1nje" }, "source": [ "### Filter out corrupted images\n", "\n", "When working with lots of real-world image data, corrupted images are a common\n", "occurence. Let's filter out badly-encoded images that do not feature the string \"JFIF\"\n", " in their header.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 244 }, "id": "nsPyGIsQ1nje", "outputId": "1eeee067-5d8c-44ed-d2eb-5831ad806f47" }, "outputs": [], "source": [ "num_skipped = 0\n", "print(\"here!\")\n", "for folder_name in (\"Cat\", \"Dog\"):\n", " folder_path = os.path.join(\"PetImages\", folder_name)\n", " for fname in os.listdir(folder_path):\n", " if fname[-1].lower() == 'g':\n", " fpath = os.path.join(folder_path, fname)\n", " #Image.open(fpath).convert('L').save(fpath)\n", " try:\n", " fobj = open(fpath, \"rb\")\n", " is_jfif = tf.compat.as_bytes(\"JFIF\") in fobj.peek(10)\n", " finally:\n", " fobj.close()\n", "\n", " if not is_jfif:\n", " num_skipped += 1\n", " # Delete corrupted image\n", " os.remove(fpath)\n", "\n", "print(\"Deleted %d images\" % num_skipped)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "n82W39da1njf" }, "source": [ "## Generate a `Dataset`\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "m-KkH4-D1njf", "outputId": "fdad103a-674e-4be3-b10d-c43fdbe25a11" }, "outputs": [], "source": [ "image_size = (180, 180)\n", "batch_size = 32\n", "\n", "train_ds = tf.keras.preprocessing.image_dataset_from_directory(\n", " \"PetImages\",\n", " color_mode='grayscale',\n", " validation_split=0.2,\n", " subset=\"training\",\n", " seed=1337,\n", " image_size=image_size,\n", " batch_size=batch_size,\n", ")\n", "val_ds = tf.keras.preprocessing.image_dataset_from_directory(\n", " \"PetImages\",\n", " color_mode='grayscale',\n", " validation_split=0.2,\n", " subset=\"validation\",\n", " seed=1337,\n", " image_size=image_size,\n", " batch_size=batch_size,\n", ")\n" ] }, { "cell_type": "markdown", "metadata": { "id": "SWzlW2H-1njf" }, "source": [ "## Visualize the data\n", "\n", "Here are the first 9 images in the training dataset. As you can see, label 1 is \"dog\"\n", " and label 0 is \"cat\".\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 591 }, "id": "St7lj7zC1njg", "outputId": "9a20d448-26a8-4e0b-9373-dd3b7051334b" }, "outputs": [], "source": [ "plt.figure(figsize=(10, 10))\n", "for images, labels in train_ds.take(1):\n", " for i in range(9):\n", " ax = plt.subplot(3, 3, i + 1)\n", " img = images[i].numpy().astype(\"uint8\").squeeze()\n", " plt.imshow(img,cmap='gray', vmin=0, vmax=255)\n", " plt.title(int(labels[i]))\n", " plt.axis(\"off\")\n" ] }, { "cell_type": "markdown", "metadata": { "id": "03HkTWlO1njg" }, "source": [ "## Using image data augmentation\n", "\n", "When you don't have a large image dataset, it's a good practice to artificially\n", "introduce sample diversity by applying random yet realistic transformations to the\n", "training images, such as random horizontal flipping or small random rotations. This\n", "helps expose the model to different aspects of the training data while slowing down\n", " overfitting.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "LM39ZkDl1njg" }, "outputs": [], "source": [ "data_augmentation = keras.Sequential(\n", " [\n", " layers.RandomFlip(\"horizontal\"),\n", " layers.RandomRotation(0.1),\n", " ]\n", ")\n" ] }, { "cell_type": "markdown", "metadata": { "id": "G7dmLVej1njh" }, "source": [ "Let's visualize what the augmented samples look like, by applying `data_augmentation`\n", " repeatedly to the first image in the dataset:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 575 }, "id": "pI6hq_U01njh", "outputId": "8d19c4ae-cce0-4143-fa3a-b4866eb1ad49" }, "outputs": [], "source": [ "plt.figure(figsize=(10, 10))\n", "for images, _ in train_ds.take(1):\n", " for i in range(9):\n", " augmented_images = data_augmentation(images)\n", " ax = plt.subplot(3, 3, i + 1)\n", " img = augmented_images[0].numpy().astype(\"uint8\").squeeze()\n", " plt.imshow(img,cmap='gray', vmin=0, vmax=255)\n", " plt.axis(\"off\")\n" ] }, { "cell_type": "markdown", "metadata": { "id": "CElkI2-r1njh" }, "source": [ "## Standardizing the data\n", "\n", "Our image are already in a standard size (180x180), as they are being yielded as\n", "contiguous `float32` batches by our dataset. However, their RGB channel values are in\n", " the `[0, 255]` range. This is not ideal for a neural network;\n", "in general you should seek to make your input values small. Here, we will\n", "standardize values to be in the `[0, 1]` by using a `Rescaling` layer at the start of\n", " our model.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "ETAHN-xe1njh" }, "source": [ "## Two options to preprocess the data\n", "\n", "There are two ways you could be using the `data_augmentation` preprocessor:\n", "\n", "**Option 1: Make it part of the model**, like this:\n", "\n", "```python\n", "inputs = keras.Input(shape=input_shape)\n", "x = data_augmentation(inputs)\n", "x = layers.Rescaling(1./255)(x)\n", "... # Rest of the model\n", "```\n", "\n", "With this option, your data augmentation will happen *on device*, synchronously\n", "with the rest of the model execution, meaning that it will benefit from GPU\n", " acceleration.\n", "\n", "**Option 2: apply it to the dataset**, so as to obtain a dataset that yields batches of\n", " augmented images, like this:\n", "\n", "```python\n", "augmented_train_ds = train_ds.map(\n", " lambda x, y: (data_augmentation(x, training=True), y))\n", "```\n", "\n", "We'll go with the first option.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "h_6iyi4P1njh" }, "source": [ "## Configure the dataset for performance\n", "\n", "Let's make sure to use buffered prefetching so we can yield data from disk without\n", " having I/O becoming blocking:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ofmdIqoK1njh" }, "outputs": [], "source": [ "train_ds = train_ds.prefetch(buffer_size=32)\n", "val_ds = val_ds.prefetch(buffer_size=32)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "dVPOJ-x91nji" }, "source": [ "## Build a model\n", "\n", "We'll build a small version of the Xception network. We haven't particularly tried to\n", "optimize the architecture; if you want to do a systematic search for the best model\n", " configuration, consider using\n", "[KerasTuner](https://github.com/keras-team/keras-tuner).\n", "\n", "Note that:\n", "\n", "- We start the model with the `data_augmentation` preprocessor, followed by a\n", " `Rescaling` layer.\n", "- We include a `Dropout` layer before the final classification layer.\n" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 312 }, "id": "DENybniZ1nji", "outputId": "05bdae59-7d62-4401-f6a1-1ef4102acd32" }, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def make_model(input_shape, num_classes):\n", " inputs = keras.Input(shape=input_shape)\n", " x = layers.Flatten()(inputs)\n", " layer1 = layers.Dense(500,activation=\"relu\")(x)\n", " if num_classes == 2:\n", " activation = \"sigmoid\"\n", " units = 1\n", " else:\n", " activation = \"softmax\"\n", " units = num_classes\n", " outputs = layers.Dense(units, activation=activation)(layer1)\n", " return keras.Model(inputs, outputs)\n", "\n", "\n", "model = make_model(input_shape=image_size, num_classes=2)\n", "keras.utils.plot_model(model, show_shapes=True)\n" ] }, { "cell_type": "markdown", "metadata": { "id": "ixwtcs_s1nji" }, "source": [ "## Train the model\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 636 }, "id": "mzaGa4mz1njj", "outputId": "898a58c3-0a05-472f-8281-0bc779376278" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/50\n", "586/586 [==============================] - 83s 139ms/step - loss: 195.7281 - accuracy: 0.5196 - val_loss: 71.4404 - val_accuracy: 0.5041\n", "Epoch 2/50\n", "586/586 [==============================] - 86s 146ms/step - loss: 35.0901 - accuracy: 0.5271 - val_loss: 9.5992 - val_accuracy: 0.5572\n", "Epoch 3/50\n", "586/586 [==============================] - 84s 144ms/step - loss: 16.7845 - accuracy: 0.5332 - val_loss: 5.5357 - val_accuracy: 0.5649\n", "Epoch 4/50\n", "193/586 [========>.....................] - ETA: 1:01 - loss: 11.0913 - accuracy: 0.5376" ] }, { "ename": "KeyboardInterrupt", "evalue": "", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0mmetrics\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m\"accuracy\"\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m )\n\u001b[0;32m---> 11\u001b[0;31m model.fit(\n\u001b[0m\u001b[1;32m 12\u001b[0m \u001b[0mtrain_ds\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mepochs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mepochs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcallbacks\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mcallbacks\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mvalidation_data\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mval_ds\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m )\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/keras/utils/traceback_utils.py\u001b[0m in \u001b[0;36merror_handler\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 62\u001b[0m \u001b[0mfiltered_tb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 63\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 64\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 65\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;31m# pylint: disable=broad-except\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 66\u001b[0m \u001b[0mfiltered_tb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_process_traceback_frames\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/keras/engine/training.py\u001b[0m in \u001b[0;36mfit\u001b[0;34m(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)\u001b[0m\n\u001b[1;32m 1214\u001b[0m _r=1):\n\u001b[1;32m 1215\u001b[0m \u001b[0mcallbacks\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mon_train_batch_begin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstep\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1216\u001b[0;31m \u001b[0mtmp_logs\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtrain_function\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0miterator\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 1217\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mdata_handler\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mshould_sync\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 1218\u001b[0m \u001b[0mcontext\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0masync_wait\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/util/traceback_utils.py\u001b[0m in \u001b[0;36merror_handler\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 148\u001b[0m \u001b[0mfiltered_tb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 149\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 150\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mfn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 151\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 152\u001b[0m \u001b[0mfiltered_tb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0m_process_traceback_frames\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0me\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__traceback__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwds)\u001b[0m\n\u001b[1;32m 908\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 909\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mOptionalXlaContext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_jit_compile\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 910\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_call\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 911\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 912\u001b[0m \u001b[0mnew_tracing_count\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mexperimental_get_tracing_count\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/eager/def_function.py\u001b[0m in \u001b[0;36m_call\u001b[0;34m(self, *args, **kwds)\u001b[0m\n\u001b[1;32m 940\u001b[0m \u001b[0;31m# In this case we have created variables on the first call, so we run the\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 941\u001b[0m \u001b[0;31m# defunned version which is guaranteed to never create variables.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 942\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stateless_fn\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwds\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# pylint: disable=not-callable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 943\u001b[0m \u001b[0;32melif\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_stateful_fn\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 944\u001b[0m \u001b[0;31m# Release the lock early so that multiple threads can perform the call\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/eager/function.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 3128\u001b[0m (graph_function,\n\u001b[1;32m 3129\u001b[0m filtered_flat_args) = self._maybe_define_function(args, kwargs)\n\u001b[0;32m-> 3130\u001b[0;31m return graph_function._call_flat(\n\u001b[0m\u001b[1;32m 3131\u001b[0m filtered_flat_args, captured_inputs=graph_function.captured_inputs) # pylint: disable=protected-access\n\u001b[1;32m 3132\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/eager/function.py\u001b[0m in \u001b[0;36m_call_flat\u001b[0;34m(self, args, captured_inputs, cancellation_manager)\u001b[0m\n\u001b[1;32m 1957\u001b[0m and executing_eagerly):\n\u001b[1;32m 1958\u001b[0m \u001b[0;31m# No tape is watching; skip to running the function.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1959\u001b[0;31m return self._build_call_outputs(self._inference_function.call(\n\u001b[0m\u001b[1;32m 1960\u001b[0m ctx, args, cancellation_manager=cancellation_manager))\n\u001b[1;32m 1961\u001b[0m forward_backward = self._select_forward_and_backward_functions(\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/eager/function.py\u001b[0m in \u001b[0;36mcall\u001b[0;34m(self, ctx, args, cancellation_manager)\u001b[0m\n\u001b[1;32m 596\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0m_InterpolateFunctionError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 597\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mcancellation_manager\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 598\u001b[0;31m outputs = execute.execute(\n\u001b[0m\u001b[1;32m 599\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msignature\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 600\u001b[0m \u001b[0mnum_outputs\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_num_outputs\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;32m/opt/miniconda3/lib/python3.8/site-packages/tensorflow/python/eager/execute.py\u001b[0m in \u001b[0;36mquick_execute\u001b[0;34m(op_name, num_outputs, inputs, attrs, ctx, name)\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;32mtry\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0mctx\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mensure_initialized\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,\n\u001b[0m\u001b[1;32m 59\u001b[0m inputs, attrs, num_outputs)\n\u001b[1;32m 60\u001b[0m \u001b[0;32mexcept\u001b[0m \u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_NotOkStatusException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mKeyboardInterrupt\u001b[0m: " ] } ], "source": [ "epochs = 25\n", "\n", "callbacks = [\n", " keras.callbacks.ModelCheckpoint(\"save_at_{epoch}.h5\"),\n", "]\n", "model.compile(\n", " optimizer=keras.optimizers.Adam(1e-3),\n", " loss=\"binary_crossentropy\",\n", " metrics=[\"accuracy\"],\n", ")\n", "model.fit(\n", " train_ds, epochs=epochs, callbacks=callbacks, validation_data=val_ds,\n", ")\n" ] }, { "cell_type": "markdown", "metadata": { "id": "smjeG0W21njj" }, "source": [ "After 50 epochs, we're up to 64% accuracy on the test set, but still close to chance on the validation set.\n" ] }, { "cell_type": "markdown", "metadata": { "id": "TO_jOMfA1njj" }, "source": [ "## Run inference on new data\n", "\n", "Note that data augmentation and dropout are inactive at inference time.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "-0DzdyI_1njj" }, "outputs": [], "source": [ "img = keras.preprocessing.image.load_img(\n", " \"calvin.jpg\", target_size=image_size, color_mode=\"grayscale\"\n", ")\n", "img_array = keras.preprocessing.image.img_to_array(img)\n", "print(img_array.shape)\n", "img_array = tf.expand_dims(img_array, 0) # Create batch axis\n", "\n", "predictions = model.predict(img_array)\n", "score = predictions[0]\n", "print(\n", " \"This image is %.2f percent cat and %.2f percent dog.\"\n", " % (100 * (1 - score), 100 * score)\n", ")\n", "#\"PetImages/Cat/6779.jpg\"" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "accelerator": "GPU", "colab": { "collapsed_sections": [], "name": "cat_regression", "provenance": [] }, "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.8.5" } }, "nbformat": 4, "nbformat_minor": 1 }