{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🐕Multi-class Dog Breed Classification\n\n> using `Tensorflow 2.0` and `Tensorflow Hub`\n\n## 1. Problem\nIdentifying the breed of a dog given an image of a dog.\n\n## 2. Data\nThe data we're using is from Kaggle's dog breed identification competition.\n\nhttps://www.kaggle.com/c/dog-breed-identification/data\n\n## 3. Evaluation\nThe evaluation is a file with prediction probabilities for each dog breed of each test image.\n\nhttps://www.kaggle.com/c/dog-breed-identification/overview/evaluation\n\n## 4. Features\nSome information about the data:\n\n* We're dealing with images (unstructured data) so it's probably best we use deep learning/transfer learning.\n* There are 120 breeds of dogs (this means there are 120 different classes).\n* There are around 10,000+ images in the training set (these images have labels).\n* There are around 10,000+ images in the test set (these images have no labels, because we'll want to predict them).","metadata":{"id":"AKF70O5RZsoG"}},{"cell_type":"code","source":"#!unzip \"drive/MyDrive/Colab Notebooks/Dog Breed Identification/dog-breed-identification.zip\" -d \"drive/MyDrive/Colab Notebooks/Dog Breed Identification/data\"","metadata":{"id":"PJugkGKYUTvA"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Workspace setup","metadata":{"id":"yQLrkIYYb6b3"}},{"cell_type":"code","source":"import tensorflow as tf\nimport tensorflow_hub as hub\n\nprint(\"TF version:\", tf.__version__)\nprint(\"TF hub version:\", hub.__version__)\n\n# Check for GPU availability\nprint(\"GPU\", \"available (YESSSS!!!!!)\" if tf.config.list_physical_devices(\"GPU\") else \"not available :(\")","metadata":{"id":"YkM9lCqfbtWB","outputId":"ea7a932a-121e-4fa2-f551-63d1d55a45e3"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Getting data ready (turning into Tensors)","metadata":{"id":"MGEAxsBlcSHi"}},{"cell_type":"code","source":"import pandas as pd\nlabels_csv = pd.read_csv(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/data/labels.csv\")\n","metadata":{"id":"JSrS70sUe6st"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv.describe()","metadata":{"id":"tzHgit1be39c","outputId":"aeaff548-a2ff-4f80-f14a-732d8f203b8a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv.head()","metadata":{"id":"3fmUalyJfd3P","outputId":"dc2214d9-c302-4fef-f621-40f345e654b9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv[\"breed\"].value_counts().plot.bar(figsize=(20, 10));","metadata":{"id":"EB4YpqfTffG5","outputId":"3ec98a50-f0aa-457e-d552-7474bcd9a025"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv[\"breed\"].value_counts().median()","metadata":{"id":"LTZla4Ayf4mn","outputId":"4cf7e30a-09b7-47c0-a1a6-fd8c8bdbdd84"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from IPython.display import Image\nImage(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/data/train/0021f9ceb3235effd7fcde7f7538ed62.jpg\")","metadata":{"id":"GyL5YmI9gKes","outputId":"b3ea4499-3e73-4c77-8bc0-0035142ef4d7"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting images and their labels","metadata":{"id":"sVVOVxYuwO5o"}},{"cell_type":"code","source":"labels_csv.head()","metadata":{"id":"UnTT3zVHwl3W","outputId":"b098f723-37e2-478d-8ad9-48bee566d27f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filenames = [f'drive/MyDrive/Colab Notebooks/Dog Breed Identification/data/train/{fname}.jpg' for fname in labels_csv[\"id\"]]\n\nfilenames[:10]","metadata":{"id":"J2T1wupfwoAH","outputId":"35e06cfe-cd56-4e56-924b-653c5224e756"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nif len(os.listdir(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/data/train\")) == len(filenames):\n  print(\"Filenames match actual amount of files!!! Proceed.\")\nelse:\n  print(\"Filenames do not match actual amount of files, check the target directory.\")","metadata":{"id":"sjhRZnhFw4yp","outputId":"32bd9220-719a-4c79-f983-c5cd964a5d92"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"Image(filenames[9000])","metadata":{"id":"KiqNEqW5xnx5","outputId":"750cc798-7ad5-419f-d699-da42c38a6bd7"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels = labels_csv[\"breed\"].to_numpy()\nlabels[:10]","metadata":{"id":"4uXNvpoo02Ix","outputId":"6278e5f3-224f-489a-a705-115ad56816b3"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(labels) == len(filenames)","metadata":{"id":"k029FZEP1YGZ","outputId":"ac9e9ebb-5fa1-4af2-9575-1cdca7a5a288"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\n\nunique_breeds = np.unique(labels)\nunique_breeds","metadata":{"id":"xNRGj6r51bc7","outputId":"2c65ad1d-d689-46eb-b32b-c6a622f40d7b"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(unique_breeds)","metadata":{"id":"dnl3gKGc1wCo","outputId":"341ef3c2-fdc8-4122-8f75-4d39c9aa086b"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn single label into an array of booleans\nprint(labels[0])\n\nlabels[0] == unique_breeds","metadata":{"id":"iiPYE8Vl1zyb","outputId":"e072cdde-6282-4269-ab3c-4ea7d3a10d0a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn every label into a boolean array\n\nboolean_labels = [label == unique_breeds for label in labels]\nboolean_labels[:2]","metadata":{"id":"NYj-LwcV2jMj","outputId":"8def7b93-5544-4ea4-84f4-77efac69e3b9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(boolean_labels)","metadata":{"id":"YJpQsO-J27JW","outputId":"9b94f3c5-20b7-4935-e04d-994a906ef33e"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create validation set","metadata":{"id":"oXWoIRZ-29q8"}},{"cell_type":"code","source":"X = filenames\ny = boolean_labels","metadata":{"id":"i4nYNWz23r4s"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(filenames)","metadata":{"id":"61USYfYE3x0y","outputId":"367f30c7-598b-453c-c893-865812011134"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"NUM_IMAGES = 1000 #@param {type:\"slider\", min:1000, max:10000, step:1000}","metadata":{"id":"PesCdof-3ywU"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_val, y_train, y_val = train_test_split(X[:NUM_IMAGES], y[:NUM_IMAGES], test_size=0.2, random_state=42)\n\nlen(X_train), len(y_train), len(X_val), len(y_val)","metadata":{"id":"4JlyqVCd4hfz","outputId":"5613aea1-97f0-4a3b-f97c-bb3f116eb9e7"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train[:5], y_train[:2]","metadata":{"id":"lv8R5LHa42mq","outputId":"fa553385-1dcf-481f-e479-35f1fc3357ec"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocessing Images (turning images into Tensors)","metadata":{"id":"N4M4aXWf5HWi"}},{"cell_type":"code","source":"from matplotlib.pyplot import imread\n\nimage = imread(filenames[42])\nimage.shape","metadata":{"id":"bsLrA71H5Yir","outputId":"8fefadc4-339a-45fa-c11e-bffa8deca3bd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image[:2]","metadata":{"id":"9xwG2use6EHQ","outputId":"8c5055ea-6ec5-48f7-cb7c-8a543a9d8fc4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.constant(image)[:2]","metadata":{"id":"hTs3hwTB6K4T","outputId":"2bfc1914-29b2-4fe4-b2c8-823c1fb45cc2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMG_SIZE = 224","metadata":{"id":"UD6SDF3H6aRJ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"@tf.autograph.experimental.do_not_convert\ndef process_image(image_path: str):\n  \"\"\"\n  Take an image file path and turns the image into a Tensor\n  \"\"\"\n  image = tf.io.read_file(image_path)\n  # 3 channels (Red, Green, Blue)\n  image = tf.image.decode_jpeg(image, channels=3)\n  # Convert the colour channel values from 0-255, to 0-1 values\n  image = tf.image.convert_image_dtype(image, tf.float32)\n  # Resize image to IMG_SIZE\n  image = tf.image.resize(image, size=[IMG_SIZE, IMG_SIZE])\n  return image","metadata":{"id":"b_88-zzO_Nev"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Turning data into batches\n","metadata":{"id":"sFwnNREw_XCN"}},{"cell_type":"code","source":"@tf.autograph.experimental.do_not_convert\ndef get_image_label(image_path: str, label):\n  \"\"\"\n  Takes an image file path name and the associated label,\n  processes the image and returns a tuple (image, label)\n  \"\"\"\n  image = process_image(image_path)\n  return image, label","metadata":{"id":"xdmSBFU6CHlq"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCH_SIZE = 32","metadata":{"id":"17eLARJ4Cu6A"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_data_batches(X, y=None, batch_size=BATCH_SIZE, valid_data=False, test_data=False):\n  \"\"\"\n  Creates batches of data out of image (X) and label (y) pairs.\n  Shuffles the data if it's training data but doesn't shuffle if it's validation data.\n  Also accepts test data as input (no labels).\n  \"\"\"\n  # If the data is a test dataset, we probably don't have have labels\n  if test_data:\n    print(\"Creating test data batches...\")\n    data = tf.data.Dataset.from_tensor_slices((tf.constant(X))) # only filepaths (no labels)\n    data_batch = data.map(process_image).batch(BATCH_SIZE)\n    return data_batch\n\n  # If the data is a valid dataset, we don't need to shuffle it\n  if valid_data:\n    print(\"Creating validation data batches...\")\n    data = tf.data.Dataset.from_tensor_slices((\n                                              tf.constant(X), # filepaths\n                                              tf.constant(y)  # labels\n                                              ))\n    data_batch = data.map(get_image_label).batch(BATCH_SIZE)\n    return data_batch\n\n  print(\"Creating training data batches...\")\n  data = tf.data.Dataset.from_tensor_slices((\n                                             tf.constant(X),\n                                             tf.constant(y)\n                                            ))\n  data_batch = data.shuffle(buffer_size=len(X)) \\\n                   .map(get_image_label) \\\n                   .batch(BATCH_SIZE)\n  return data_batch","metadata":{"id":"USunVqKcDOPo"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = create_data_batches(X_train, y_train)\nval_data = create_data_batches(X_val, y_val, valid_data=True)","metadata":{"id":"8vbqXLobFnAB","outputId":"190fa2d6-38ae-4132-dbf2-53b6afe642e9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.element_spec, val_data.element_spec","metadata":{"id":"GClYoSYZF0r8","outputId":"b6119f1f-bc22-4c29-a672-ba6f1522520e"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualizing Data Batches","metadata":{"id":"BDVYFKCnGUr7"}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\ndef show_25_images(images, labels):\n  \"\"\"\n  Displays a plot of 25 images and their labels from a data batch.\n  \"\"\"\n  plt.figure(figsize=(10, 10))\n  for i in range(25):\n    # 5 rows, 5 columns\n    ax = plt.subplot(5, 5, i+1)\n    plt.imshow(images[i])\n    plt.title(unique_breeds[labels[i].argmax()])\n    # Turn the grid lines off\n    plt.axis(\"off\")","metadata":{"id":"wZYkNKxfG-de"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data","metadata":{"id":"896nX_TKH91c","outputId":"66129ef1-ac67-449d-9624-5b90516cc541"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_images, train_labels = next(train_data.as_numpy_iterator())\nshow_25_images(train_images, train_labels)","metadata":{"id":"asFiG-6FINfy","outputId":"1d5ed096-0bc2-4cd8-a9b6-68cbe7577ed2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_images, val_labels = next(val_data.as_numpy_iterator())\nshow_25_images(val_images, val_labels)","metadata":{"id":"LWXwK_Q1IiR9","outputId":"326603dc-b76c-4e11-fa88-e806a7149d20"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Building a model","metadata":{"id":"zgT-XaYFJBWl"}},{"cell_type":"code","source":"# Input shape to the model\nINPUT_SHAPE = [None, IMG_SIZE, IMG_SIZE, 3] # batch, height, width, colour channels\n\n# Output shape of the model\nOUTPUT_SHAPE = len(unique_breeds)\n\nMODEL_URL = \"https://tfhub.dev/google/imagenet/mobilenet_v3_large_100_224/classification/5\"","metadata":{"id":"asUgSYXLJcFG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_model(input_shape=INPUT_SHAPE, output_shape=OUTPUT_SHAPE, model_url=MODEL_URL):\n  print(\"Build a model with:\", model_url)\n\n  model = tf.keras.Sequential([\n      hub.KerasLayer(model_url),\n      tf.keras.layers.Dense(units=output_shape, activation=\"softmax\")\n  ])\n\n  model.compile(\n      loss=tf.keras.losses.CategoricalCrossentropy(),\n      optimizer=tf.keras.optimizers.Adam(),\n      metrics=[\"accuracy\"]\n  )\n\n  model.build(input_shape)\n\n  return model","metadata":{"id":"AJRzwJH4qk2-"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model()\nmodel.summary()","metadata":{"id":"2J0UPkybsLlc","outputId":"4d4ac15a-9452-4e5e-8959-a611e11da7d1"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Creating callbacks\n\nCallbacks are helper functions a model can use during training to do such things as save its progress, check its progress or stop training early if a model stops improving.","metadata":{"id":"0H__XEeusPd_"}},{"cell_type":"markdown","source":"### TensorBoard callback\n\nhttps://www.tensorflow.org/api_docs/python/tf/keras/callbacks/TensorBoard\n","metadata":{"id":"ZvxQefa2zoik"}},{"cell_type":"code","source":"%load_ext tensorboard","metadata":{"id":"KAFJpVNyxfdG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import datetime as dt\n\ndef create_tensorboard_callback():\n  logdir = os.path.join(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/logs\", dt.datetime.now().strftime(\"%Y%m%d-%H%M%S\"))\n  return tf.keras.callbacks.TensorBoard(logdir)","metadata":{"id":"9QWT72mMyGsN"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Early Stopping Callback\n\nhttps://www.tensorflow.org/api_docs/python/tf/keras/callbacks/EarlyStopping\n","metadata":{"id":"b-APnJMczvuz"}},{"cell_type":"code","source":"early_stopping = tf.keras.callbacks.EarlyStopping(\"val_accuracy\", patience=3)","metadata":{"id":"UjiSMDTyzQlD"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training a model","metadata":{"id":"td3tBPtMQLNX"}},{"cell_type":"code","source":"NUM_EPOCHS = 100 #@param {type: \"slider\", min: 10, max: 100, step: 10}","metadata":{"id":"1-wYYeWE0O24"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tf.config.list_physical_devices(\"GPU\")","metadata":{"id":"9wJSWRQ3QqCc","outputId":"86ca540c-8560-424d-fda6-121200867461"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model():\n  \"\"\"\n  Trains a given model and returns the trained version.\n  \"\"\"\n  model = create_model()\n\n  tensorboard = create_tensorboard_callback()\n\n  model.fit(x=train_data,epochs=NUM_EPOCHS,validation_data=val_data,validation_freq=1,callbacks=[tensorboard, early_stopping])\n\n  return model\n","metadata":{"id":"BOaimnj8Ri0j"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model()","metadata":{"id":"ACBlyZopShKQ","outputId":"f0b8e311-7bbe-4637-eac9-5b6a4a5d7934"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Checking the TensorBoard logs","metadata":{"id":"CtP_skUYVBXV"}},{"cell_type":"code","source":"%tensorboard --logdir drive/MyDrive/Colab\\ Notebooks/Dog\\ Breed\\ Identification/logs","metadata":{"id":"pQ7NtslBSj2c","outputId":"76b93f17-6a4a-4e26-cb1b-c2c0d2098487"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Making and evaluating predictions using a trained model","metadata":{"id":"RNy5lY_JWNL1"}},{"cell_type":"code","source":"predictions = model.predict(val_data, verbose=1)","metadata":{"id":"aNedt8iBVWAl","outputId":"7c0f4e43-0d12-4e6d-f49a-cf40b855085f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions","metadata":{"id":"dw3VQN5XWeRs","outputId":"bda70a5a-8386-4d4b-b142-2dcceb882b83"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.sum(predictions[0])","metadata":{"id":"pHilmUeZWgFY","outputId":"6e5ccff2-397c-4052-acf8-04c0d6b2d212"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# First prediction\nindex = 0\nprint(f\"Max value (probability of prediction): {np.max(predictions[index])}\")\nprint(\"Sum:\", np.sum(predictions[index]))\nprint(\"Max index:\", np.argmax(predictions[index]))\nprint(\"Predicted label:\", unique_breeds[np.argmax(predictions[index])])\nprint(\"Actual label:\", unique_breeds[np.argmax(y_val[index])])","metadata":{"id":"lxcRvtbBW4kY","outputId":"723a8bc8-0be1-4cb2-cfb4-ebe3b7a63a1c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_pred_label(prediction_probabilities):\n  \"\"\"\n  Turns an array of prediction probabilities into a label.\n  \"\"\"\n  return unique_breeds[np.argmax(prediction_probabilities)]\n\npred_label = get_pred_label(predictions[7])\npred_label","metadata":{"id":"Cxbb0N6TX_EE","outputId":"7203d1f8-ebc4-4ec7-e605-6b70802e4634"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_data","metadata":{"id":"V2e1WslneqGk","outputId":"73c977e1-7c15-4ee5-ef2f-6a5a45bfc8fe"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a function to unbatch a batch dataset\ndef unbatchify(data):\n  \"\"\"\n  Takes a batched dataset of (image, label) Tensors and reutrns separate arrays\n  of images and labels.\n  \"\"\"\n  images = []\n  labels = []\n  # Loop through unbatched data\n  for image, label in data.unbatch().as_numpy_iterator():\n    images.append(image)\n    labels.append(unique_breeds[np.argmax(label)])\n  return images, labels\n\n# Unbatchify the validation data\nval_images, val_labels = unbatchify(val_data)\nval_images[0], val_labels[0]","metadata":{"id":"NArjf8mWe0ig","outputId":"e4c1b7f6-582c-4cc7-b36f-a5b2e4b93c8a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_pred(prediction_probabilities, labels, images, n=1):\n  \"\"\"\n  View the prediction, ground truth and image for sample n\n  \"\"\"\n  pred_prob, true_label, image = prediction_probabilities[n], labels[n], images[n]\n\n  pred_label = get_pred_label(pred_prob)\n\n  plt.imshow(image)\n  plt.xticks([])\n  plt.yticks([])\n\n  if pred_label == true_label:\n    color = \"green\"\n  else:\n    color = \"red\"\n\n  plt.title(\"{} {:2.0f}% {}\".format(pred_label, np.max(pred_prob) * 100, true_label), color=color)","metadata":{"id":"4994m87CfKtE"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_pred(prediction_probabilities=predictions,\n          labels=val_labels,\n          images=val_images,\n          n=10)","metadata":{"id":"6qvoyhTOhljt","outputId":"9c7024b7-e823-42d8-a58a-f3e2d31024ba"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"😆","metadata":{"id":"JfPJsNsMjPwG"}},{"cell_type":"code","source":"def plot_pred_conf(prediction_probabilities, labels, n=1):\n  \"\"\"\n  Plus the top 10 highest prediction confidences along with the truth label for sample n.\n  \"\"\"\n  pred_prob, true_label = prediction_probabilities[n], labels[n]\n\n  # Get the predicted label\n  pred_label = get_pred_label(pred_prob)\n\n  # Find the top 10 prediction confidence indexes\n  top_10_pred_indexes = pred_prob.argsort()[-10:][::-1]\n  # Find the top 10 prediction confidence values\n  top_10_pred_values = pred_prob[top_10_pred_indexes]\n  # Find the top 10 prediction labels\n  top_10_pred_labels = unique_breeds[top_10_pred_indexes]\n\n  top_10_plot = plt.bar(np.arange(len(top_10_pred_labels)), top_10_pred_values, color=\"grey\")\n\n  plt.xticks(np.arange(len(top_10_pred_labels)), labels=top_10_pred_labels, rotation=\"vertical\")\n\n  if np.isin(true_label, top_10_pred_labels):\n    top_10_plot[np.argmax(top_10_pred_labels == true_label)].set_color(\"green\")\n","metadata":{"id":"EFi8zw1Dhs3v"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_pred_conf(prediction_probabilities=predictions,\n               labels=val_labels,\n               n=42)","metadata":{"id":"Se8_Rs6lkOor","outputId":"176b6fe7-a4d2-4272-da4a-adce9f1d4e51"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"i_multiplier = 30\nnum_rows = 3\nnum_cols = 2\nnum_images = num_rows*num_cols\nplt.figure(figsize=(10*num_cols, 5*num_rows))\nfor i in range(num_images):\n  plt.subplot(num_rows, 2*num_cols, 2*i+1)\n  plot_pred(prediction_probabilities=predictions,\n            labels=val_labels,\n            images=val_images,\n            n=i+i_multiplier)\n  plt.subplot(num_rows, 2*num_cols, 2*i+2)\n  plot_pred_conf(prediction_probabilities=predictions,\n                 labels=val_labels,\n                 n=i+i_multiplier)\nplt.tight_layout(h_pad=1.0)\nplt.show()","metadata":{"id":"S3X2QfZzkO-j","outputId":"24a076b1-a04b-4442-9782-7c1b102ec114"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from sklearn.metrics import confusion_matrix\nfrom seaborn import heatmap","metadata":{"id":"tv_8GqqHiEr4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cf_matrix = confusion_matrix(val_labels, [get_pred_label(pred) for pred in predictions], labels=unique_breeds)","metadata":{"id":"ea72AhPtiuGR"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20,15))\nax = heatmap(cf_matrix, cmap=\"Blues\", linewidths=1)\nax.set_xlabel('Actual')\nax.set_ylabel('Predicted')\nax.xaxis.tick_top()\nplt.xticks(rotation=45)\nplt.show()","metadata":{"id":"ISYnG_4vaZCz","outputId":"dfc70e5b-00bd-4958-9935-33eb941afd10"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Saving and reloading a trained model","metadata":{"id":"gXTRjCVcoZ4W"}},{"cell_type":"code","source":"import datetime\ndef save_model(model, suffix=None):\n  \"\"\"\n  Saves a given model in a models directory and appends a suffix (string).\n  \"\"\"\n  # Create a model directory pathname with current time\n  modeldir = os.path.join(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/models\",\n                          datetime.datetime.now().strftime(\"%Y%m%d-%H%M%s\"))\n  model_path = modeldir + \"-\" + suffix + \".h5\" # save format of model\n  print(f\"Saving model to: {model_path}...\")\n  model.save(model_path)\n  return model_path","metadata":{"id":"cqyGODJomMOJ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_model(model_path):\n  \"\"\"\n  Loads a saved model from a specified path.\n  \"\"\"\n  print(f\"Loading saved model from: {model_path}\")\n  model = tf.keras.models.load_model(model_path,\n                                     custom_objects={\"KerasLayer\":hub.KerasLayer})\n  return model","metadata":{"id":"o0CgxAO9oj0g"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_model(model, suffix=\"1000-images-mobilenetv3-Adam\")","metadata":{"id":"CydmDL8po4M1","outputId":"22d0e632-0e5d-4812-cbf9-3085ec9b1155"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loaded_1000_image_model = load_model('drive/MyDrive/Colab Notebooks/Dog Breed Identification/models/20230119-15281674142106-1000-images-mobilenetv3-Adam.h5')","metadata":{"id":"3pKqHBmno41L","outputId":"b4f29496-51c9-46d3-de51-9a621c425f30"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.evaluate(val_data)","metadata":{"id":"eVVJfP6UpeFY","outputId":"4c8d67b8-a4ed-4f0b-d03c-6e5ca410450f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loaded_1000_image_model.evaluate(val_data)","metadata":{"id":"t0wU149Gpu9h","outputId":"0e35c7d3-bc67-44aa-951f-b0d7df807163"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training a big model 🐕 (full data)","metadata":{"id":"H-tIoZLoqDio"}},{"cell_type":"code","source":"full_data = create_data_batches(X, y)\nfull_data","metadata":{"id":"_YzQ2P6WpwYx","outputId":"cf6d2002-bc8c-4885-c43e-6b6cec164de1"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"full_model = create_model()","metadata":{"id":"6mRaQ0OoqdCt","outputId":"4c3e92f0-ece1-4075-e15f-691e251bbdf9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"full_model_tensorboard = create_tensorboard_callback()\nfull_model_early_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"accuracy\", patience=3)","metadata":{"id":"OVaNSafMqqEQ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"full_model.fit(x=full_data, epochs=NUM_EPOCHS, callbacks=[full_model_tensorboard, full_model_early_stopping])","metadata":{"id":"CGdvmBIlrBqb","outputId":"4c2b30fc-e968-49c3-9fa8-eeb2df3a3b2d"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_model(model, suffix=\"full-images-mobilenetv3-Adam\")","metadata":{"id":"IDXZiuN7rgIm","outputId":"1ada3b83-ee48-4be4-ee20-7dfcdf740cf4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loaded_full_model = load_model('drive/MyDrive/Colab Notebooks/Dog Breed Identification/models/20230119-16451674146707-full-images-mobilenetv3-Adam.h5')","metadata":{"id":"m9uMJlb16hAa","outputId":"295bd8f8-0654-43dd-dfda-31be5258f610"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Making predictions on the test dataset","metadata":{"id":"053f7cWt7OYy"}},{"cell_type":"code","source":"test_path = \"drive/MyDrive/Colab Notebooks/Dog Breed Identification/data/test/\"\ntest_filenames = [test_path + fname for fname in os.listdir(test_path)]\ntest_filenames[:10]","metadata":{"id":"U46ZyAdw6--x","outputId":"f0347434-6565-4aa4-c4fa-9013a2460c7d"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(test_filenames)","metadata":{"id":"cA-uW4L_72cq","outputId":"442bd4d4-db8a-4ae8-8c0d-8c1029062b2c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data = create_data_batches(test_filenames, test_data=True)\ntest_data","metadata":{"id":"EFHZOg9G75uv","outputId":"c642eaca-eeb7-4241-dc5c-4031ec5a267c"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions = loaded_full_model.predict(test_data, verbose=1)","metadata":{"id":"OaClR_ai8CBR","outputId":"236e1787-9811-4646-c24b-fe6e7dc63e72"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# np.savetxt(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/preds_array.csv\", test_predictions, delimiter=\",\")","metadata":{"id":"ioDIVwPg8lii"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions = np.loadtxt(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/preds_array.csv\", delimiter=\",\")","metadata":{"id":"c4GfbQgCIvsM"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions[:10]","metadata":{"id":"0Z75wbf2I6cI","outputId":"6a739236-80d4-43eb-efd1-d94a34b84663"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preparing test dataset predictions for Kaggle\n\nhttps://www.kaggle.com/c/dog-breed-identification/overview/evaluation","metadata":{"id":"2FGZfFzwJsfv"}},{"cell_type":"code","source":"preds_df = pd.DataFrame(columns=[\"id\"]+list(unique_breeds))\npreds_df.head()","metadata":{"id":"mQzWpGtiJGdy","outputId":"730f0afb-b31d-4e1b-8691-0d6f99b26364"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ids = [os.path.splitext(path)[0] for path in os.listdir(test_path)]\n\npreds_df[\"id\"] = test_ids","metadata":{"id":"guolzHZrKRLl"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds_df[list(unique_breeds)] = test_predictions\npreds_df[:10]","metadata":{"id":"ouhvUghEKsAz","outputId":"5f16ba63-452d-4650-a3eb-f6541659194a"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds_df.to_csv(\"drive/MyDrive/Colab Notebooks/Dog Breed Identification/full_model_predictions_submission_1_mobilenetV3.csv\",\n                index=False)","metadata":{"id":"dqNjI6nELadD"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prediction for custom images","metadata":{"id":"sxzD1puoO2-h"}},{"cell_type":"code","source":"cust_imgs_path = \"drive/MyDrive/Colab Notebooks/Dog Breed Identification/custom images/\"\ncust_imgs_filenames = [cust_imgs_path + fname for fname in os.listdir(cust_imgs_path)]\ncust_imgs_filenames","metadata":{"id":"vv0yQSpoLqoq","outputId":"4d70c256-9113-41dd-99e1-cc0080f6c84e"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cust_data = create_data_batches(cust_imgs_filenames, test_data=True)\ncust_data","metadata":{"id":"53vqRdlSPjBh","outputId":"9dee8fff-85eb-4a6f-e757-34fae5d2c2b5"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_preds = loaded_full_model.predict(cust_data)","metadata":{"id":"HZKqcQsgPyL5","outputId":"b2cdcc20-962c-4fb9-e721-277eb58572d6"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_preds.shape","metadata":{"id":"0u9c1vDqP9Lj","outputId":"6d9b13d3-a3fe-4793-d5d8-7e77d35ddc2f"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_pred_labels = [get_pred_label(pred) for pred in custom_preds]\ncustom_pred_labels","metadata":{"id":"1gN4VI7iQGvH","outputId":"8518ec1e-b1bc-473f-ce37-9babf4d8a633"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"custom_imgs = [img for img in cust_data.unbatch().as_numpy_iterator()]\nlen(custom_imgs)","metadata":{"id":"bocDdTM2QVB2","outputId":"30824a46-f06b-48eb-b74f-ad5f5664a13e"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 10))\nfor i, image in enumerate(custom_imgs):\n  plt.subplot(1, 4, i+1)\n  plt.xticks([])\n  plt.yticks([])\n  plt.title(custom_pred_labels[i])\n  plt.imshow(image)","metadata":{"id":"tLA4nm1tRAkQ","outputId":"75276b4c-693d-4b84-ef9b-7fb74b42160d"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"id":"0_wCk-J5RVUU"},"execution_count":null,"outputs":[]}]}