{"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":"# 🐶 End-to-end Multi-class Dog Breed Classification\nThis notebook builds an end-to-end multi-class image classifier using TensorFlow 2.0 and TensorFlow Hub.\n\n## 1. Problem\n\nIdentifying the breed of a dog given and image of a dog.\n\nWhen I'am sitting at cafe and I take a photo of a dog, I want to know what breed of dog it is.\n\n## 2. Data\n\nThe data w're using is from Kaggle's dog breed identification competition.\n\nhttps://www.kaggle.com/competitions/dog-breed-identification/data\n\n## 3. Evaluation\n\n\nThe evaluation is a file with prediction probabilities for each dog breed of each test image.\n\nwww.kaggle.com/competitions/dog-breed-identification/overview/evaluation\n\n\n## 4. Features\n\nSome information about the data:\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 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 non labels, because we'll we want to predict them).\n\n","metadata":{"id":"-83MaxE7y7Xe"}},{"cell_type":"code","source":"# Unzip the uploaded data into Google Drive\n# !unzip \"drive/MyDrive/Dog Vision/dog-breed-identification.zip\" -d \"drive/My Drive/Dog Vision\"","metadata":{"id":"YDPLncSE6vvZ","execution":{"iopub.status.busy":"2023-09-25T17:05:20.480129Z","iopub.execute_input":"2023-09-25T17:05:20.480588Z","iopub.status.idle":"2023-09-25T17:05:20.486524Z","shell.execute_reply.started":"2023-09-25T17:05:20.480555Z","shell.execute_reply":"2023-09-25T17:05:20.485305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Get our workspace ready\n\n* Import TensorFlow 2.X ✅\n* Import TensorFlow Hub ✅\n* Make sure we're using a GPU ✅","metadata":{"id":"LyVvet97pONI"}},{"cell_type":"code","source":"# Import necessarry tools\nimport tensorflow as tf\nimport tensorflow_hub as hub\nprint(\"TF version\", tf.__version__ )\nprint(\"TF Hub version:\", hub.__version__)\n\n\n\n# Check for GPU availability\nprint(\"GPU\", \"available\" if tf.config.list_physical_devices(\"GPU\") else \"not available\")","metadata":{"id":"ZgtcoeS1pUII","outputId":"cdbe736b-9f80-4ead-c633-88cc54254c91","execution":{"iopub.status.busy":"2023-09-25T17:05:20.562390Z","iopub.execute_input":"2023-09-25T17:05:20.563094Z","iopub.status.idle":"2023-09-25T17:05:20.570474Z","shell.execute_reply.started":"2023-09-25T17:05:20.563056Z","shell.execute_reply":"2023-09-25T17:05:20.569490Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Getting our data ready(turning into Tensors)\n\nWith all machine learning models, our data has to be in numerical format. So that's what we'll be doing first. Turning our images into Tensors (numerical representations).\n\nLet's start by accessing our data and checking out the labels.","metadata":{"id":"9FUmfLinqIKp"}},{"cell_type":"code","source":"# Checkout the labels of our data\nimport pandas as pd\nlabels_csv = pd.read_csv(\"/kaggle/input/dog-breed-identification/labels.csv\")\nprint(labels_csv.describe())\nprint(labels_csv.head())","metadata":{"id":"6d44OpV26hH5","outputId":"325e1419-c207-4d31-928c-ca595ff1b2cc","execution":{"iopub.status.busy":"2023-09-25T17:05:20.687027Z","iopub.execute_input":"2023-09-25T17:05:20.687696Z","iopub.status.idle":"2023-09-25T17:05:20.727013Z","shell.execute_reply.started":"2023-09-25T17:05:20.687655Z","shell.execute_reply":"2023-09-25T17:05:20.725843Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv.head()","metadata":{"id":"tzd7GP6F7mGL","outputId":"5403d6ec-f83f-49d0-a5de-a174edfeefca","execution":{"iopub.status.busy":"2023-09-25T17:05:20.729127Z","iopub.execute_input":"2023-09-25T17:05:20.729829Z","iopub.status.idle":"2023-09-25T17:05:20.742826Z","shell.execute_reply.started":"2023-09-25T17:05:20.729788Z","shell.execute_reply":"2023-09-25T17:05:20.741802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# How many images are there in of each model\nlabels_csv[\"breed\"].value_counts().plot.bar(figsize=(20, 10));","metadata":{"id":"WdtNoyCN8P07","outputId":"b77e28a8-9b41-44fd-c64d-51b479afd16b","execution":{"iopub.status.busy":"2023-09-25T17:05:20.744736Z","iopub.execute_input":"2023-09-25T17:05:20.745930Z","iopub.status.idle":"2023-09-25T17:05:22.193279Z","shell.execute_reply.started":"2023-09-25T17:05:20.745892Z","shell.execute_reply":"2023-09-25T17:05:22.192305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv[\"breed\"].value_counts().median()","metadata":{"id":"LCHIqaqC80V6","outputId":"b28f1f88-53b3-454d-e4cd-f8cb90caf1fb","execution":{"iopub.status.busy":"2023-09-25T17:05:22.195131Z","iopub.execute_input":"2023-09-25T17:05:22.195777Z","iopub.status.idle":"2023-09-25T17:05:22.205934Z","shell.execute_reply.started":"2023-09-25T17:05:22.195737Z","shell.execute_reply":"2023-09-25T17:05:22.204936Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Let's view an image\nfrom IPython.display import Image\nImage(\"/kaggle/input/dog-breed-identification/train/001513dfcb2ffafc82cccf4d8bbaba97.jpg\")","metadata":{"id":"IkIi0n9G9aUr","outputId":"ef3fb7b8-98d1-4395-8372-1521b6733dd3","execution":{"iopub.status.busy":"2023-09-25T17:05:22.207651Z","iopub.execute_input":"2023-09-25T17:05:22.208492Z","iopub.status.idle":"2023-09-25T17:05:22.226288Z","shell.execute_reply.started":"2023-09-25T17:05:22.208438Z","shell.execute_reply":"2023-09-25T17:05:22.225248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Getting images and their labels\n\nLet's get a list of all of our image file pathnames","metadata":{"id":"Rl-J02tGaOEU"}},{"cell_type":"code","source":"labels_csv.head()","metadata":{"id":"SpwN55WOcmeJ","outputId":"f079070e-875f-443a-e6e1-fd6a020aee4c","execution":{"iopub.status.busy":"2023-09-25T17:05:22.229900Z","iopub.execute_input":"2023-09-25T17:05:22.230810Z","iopub.status.idle":"2023-09-25T17:05:22.245046Z","shell.execute_reply.started":"2023-09-25T17:05:22.230774Z","shell.execute_reply":"2023-09-25T17:05:22.244103Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create pathnames from image ID's\nfilenames = [\"/kaggle/input/dog-breed-identification/train/\" + fname + \".jpg\" for fname in labels_csv[\"id\"]]\n\n# Check the first 10\nfilenames[:10]\n","metadata":{"id":"YVVlUPz1caPC","outputId":"8d0213dc-be7b-4825-f163-aee1551566e5","execution":{"iopub.status.busy":"2023-09-25T17:05:22.246225Z","iopub.execute_input":"2023-09-25T17:05:22.246532Z","iopub.status.idle":"2023-09-25T17:05:22.260796Z","shell.execute_reply.started":"2023-09-25T17:05:22.246499Z","shell.execute_reply":"2023-09-25T17:05:22.259598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check whether number of filenames matches number of actual image files\nimport os\nif len(os.listdir(\"/kaggle/input/dog-breed-identification/train\")) == len(filenames):\n  print(\"Filenames match actual amount of files!!! Proceed.\")\nelse:\n  print(\"Filenames do not match actual amount of file, check the target directory.\")\n","metadata":{"id":"HfIMgwUVc2Bi","outputId":"e0724cf0-6d81-4908-873f-da9e21b55442","execution":{"iopub.status.busy":"2023-09-25T17:05:22.262440Z","iopub.execute_input":"2023-09-25T17:05:22.263027Z","iopub.status.idle":"2023-09-25T17:05:22.276540Z","shell.execute_reply.started":"2023-09-25T17:05:22.262995Z","shell.execute_reply":"2023-09-25T17:05:22.275201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# One more check\nfrom IPython.display import Image\nImage(filenames[9000])","metadata":{"id":"e4TJxwCofdRz","outputId":"e5cc8f2e-f0fe-4a06-a44e-becb181f8fc4","execution":{"iopub.status.busy":"2023-09-25T17:05:22.277827Z","iopub.execute_input":"2023-09-25T17:05:22.278787Z","iopub.status.idle":"2023-09-25T17:05:22.289734Z","shell.execute_reply.started":"2023-09-25T17:05:22.278751Z","shell.execute_reply":"2023-09-25T17:05:22.288647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels_csv[\"breed\"][9000]","metadata":{"id":"ZgTjnqZokAAr","outputId":"e8211483-21aa-44ce-ca01-05bebbad0530","execution":{"iopub.status.busy":"2023-09-25T17:05:22.291220Z","iopub.execute_input":"2023-09-25T17:05:22.292634Z","iopub.status.idle":"2023-09-25T17:05:22.299512Z","shell.execute_reply.started":"2023-09-25T17:05:22.292603Z","shell.execute_reply":"2023-09-25T17:05:22.298239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since we've now got our training image filepaths in a list, let's prepare our labels.","metadata":{"id":"ZapvAnptvnpR"}},{"cell_type":"code","source":"import numpy as np\nlabels = labels_csv[\"breed\"].to_numpy()\n#labels = np.array(labels) does same thing as above\nlabels","metadata":{"id":"NK3M4Oh9vwxS","outputId":"aa07f025-d9e6-4a4f-cbfa-eea5ac782d1b","execution":{"iopub.status.busy":"2023-09-25T17:05:22.301013Z","iopub.execute_input":"2023-09-25T17:05:22.301740Z","iopub.status.idle":"2023-09-25T17:05:22.314085Z","shell.execute_reply.started":"2023-09-25T17:05:22.301705Z","shell.execute_reply":"2023-09-25T17:05:22.312966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(labels)","metadata":{"id":"f0Wx31Gdv5PB","outputId":"e129d355-32f8-4c2b-8603-ac370cef49b9","execution":{"iopub.status.busy":"2023-09-25T17:05:22.320667Z","iopub.execute_input":"2023-09-25T17:05:22.321395Z","iopub.status.idle":"2023-09-25T17:05:22.327960Z","shell.execute_reply.started":"2023-09-25T17:05:22.321360Z","shell.execute_reply":"2023-09-25T17:05:22.327008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# See if number of labels matches the number of filenames\nif len(labels) == len(filenames):\n  print(\"Number of labels matches number of filenames!\")\nelse:\n  print(\"Number of labels doesnot match number of filenames, check data directories!\")\n","metadata":{"id":"fuj_1zd2wPkB","outputId":"02881f59-fbe7-4d04-d59c-bf2cc05a8eda","execution":{"iopub.status.busy":"2023-09-25T17:05:22.329768Z","iopub.execute_input":"2023-09-25T17:05:22.330573Z","iopub.status.idle":"2023-09-25T17:05:22.338622Z","shell.execute_reply.started":"2023-09-25T17:05:22.330541Z","shell.execute_reply":"2023-09-25T17:05:22.337565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Find the unique label values\nunique_breeds = np.unique(labels)\nlen(unique_breeds)","metadata":{"id":"2U33suWaw0Ih","outputId":"866936ee-8f09-4d72-a3b5-d0e4981f860d","execution":{"iopub.status.busy":"2023-09-25T17:05:22.340363Z","iopub.execute_input":"2023-09-25T17:05:22.341182Z","iopub.status.idle":"2023-09-25T17:05:22.363012Z","shell.execute_reply.started":"2023-09-25T17:05:22.341030Z","shell.execute_reply":"2023-09-25T17:05:22.362052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn a single label into an array of booleans\nprint(labels[0])\nlabels[0] == unique_breeds","metadata":{"id":"EWSBQn5vx9qy","outputId":"9bc5713e-869b-4a35-ce50-34249251a2a0","execution":{"iopub.status.busy":"2023-09-25T17:05:22.364763Z","iopub.execute_input":"2023-09-25T17:05:22.365081Z","iopub.status.idle":"2023-09-25T17:05:22.373803Z","shell.execute_reply.started":"2023-09-25T17:05:22.365051Z","shell.execute_reply":"2023-09-25T17:05:22.372779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn every label into boolean array\nboolean_labels = [label == unique_breeds for label in labels]\nboolean_labels[:2]\n","metadata":{"id":"5oX6Dypty5hz","outputId":"d1bbe484-eccb-4073-c4a8-eef7b6424591","execution":{"iopub.status.busy":"2023-09-25T17:05:22.375394Z","iopub.execute_input":"2023-09-25T17:05:22.376234Z","iopub.status.idle":"2023-09-25T17:05:22.477359Z","shell.execute_reply.started":"2023-09-25T17:05:22.376201Z","shell.execute_reply":"2023-09-25T17:05:22.476427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(boolean_labels)","metadata":{"id":"5yZfEyYwzz1C","outputId":"b54c7dcc-05ce-417a-9449-49e0cf4cbaff","execution":{"iopub.status.busy":"2023-09-25T17:05:22.478727Z","iopub.execute_input":"2023-09-25T17:05:22.479123Z","iopub.status.idle":"2023-09-25T17:05:22.486066Z","shell.execute_reply.started":"2023-09-25T17:05:22.479091Z","shell.execute_reply":"2023-09-25T17:05:22.484516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Example: Turning boolean array into integers\nprint(labels[0]) # original label\nprint(np.where(unique_breeds == labels[0])) # index where label occurs\nprint(boolean_labels[0].argmax()) # index where label occurs in boolean array\nprint(boolean_labels[0].astype(int)) # there will be a 1 where the sample label occurs","metadata":{"id":"eFjdroqdz5Mx","outputId":"0baa179f-8b3d-4d1b-c65b-9a284b435565","execution":{"iopub.status.busy":"2023-09-25T17:05:22.487229Z","iopub.execute_input":"2023-09-25T17:05:22.487526Z","iopub.status.idle":"2023-09-25T17:05:22.500339Z","shell.execute_reply.started":"2023-09-25T17:05:22.487495Z","shell.execute_reply":"2023-09-25T17:05:22.497992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(labels[2])\nprint(boolean_labels[2].astype(int))","metadata":{"id":"fUrB5MK03evT","outputId":"665764e0-01fe-4a86-eed7-fb897fdd349a","execution":{"iopub.status.busy":"2023-09-25T17:05:22.502472Z","iopub.execute_input":"2023-09-25T17:05:22.503249Z","iopub.status.idle":"2023-09-25T17:05:22.510971Z","shell.execute_reply.started":"2023-09-25T17:05:22.503215Z","shell.execute_reply":"2023-09-25T17:05:22.509962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"boolean_labels[:2]","metadata":{"id":"tLs1OkGe79mG","outputId":"4752d107-de08-4653-e6a8-454c8bc31f28","execution":{"iopub.status.busy":"2023-09-25T17:05:22.512102Z","iopub.execute_input":"2023-09-25T17:05:22.513072Z","iopub.status.idle":"2023-09-25T17:05:22.527843Z","shell.execute_reply.started":"2023-09-25T17:05:22.513036Z","shell.execute_reply":"2023-09-25T17:05:22.526578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"filenames[:10]","metadata":{"id":"6K4rH5dr4fXj","outputId":"89f6a177-3278-42a9-beff-15870e419d7c","execution":{"iopub.status.busy":"2023-09-25T17:05:22.530106Z","iopub.execute_input":"2023-09-25T17:05:22.531119Z","iopub.status.idle":"2023-09-25T17:05:22.539337Z","shell.execute_reply.started":"2023-09-25T17:05:22.531083Z","shell.execute_reply":"2023-09-25T17:05:22.538175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Creating our own validation set\nSince the dataset from Kaggle doesn't come with a validation set, we're going to create our own.","metadata":{"id":"bHmYn3lp8XPP"}},{"cell_type":"code","source":"# Setup X & y variables\nX = filenames\ny = boolean_labels","metadata":{"id":"RvZEOLzT7UuU","execution":{"iopub.status.busy":"2023-09-25T17:05:22.541431Z","iopub.execute_input":"2023-09-25T17:05:22.542360Z","iopub.status.idle":"2023-09-25T17:05:22.550374Z","shell.execute_reply.started":"2023-09-25T17:05:22.542325Z","shell.execute_reply":"2023-09-25T17:05:22.549234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(filenames)","metadata":{"id":"mGOFcl-C9inW","outputId":"043016f7-84ef-4de2-a9ae-fa5f90fcd90d","execution":{"iopub.status.busy":"2023-09-25T17:05:22.552215Z","iopub.execute_input":"2023-09-25T17:05:22.553070Z","iopub.status.idle":"2023-09-25T17:05:22.565109Z","shell.execute_reply.started":"2023-09-25T17:05:22.553036Z","shell.execute_reply":"2023-09-25T17:05:22.564161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We're going to start off experimenting with ~1000 images and increases as needed.","metadata":{"id":"xvKQFUI2-DNP"}},{"cell_type":"code","source":"# Set number of imagess to use for experimenting\nNUM_IMAGES = 1000 #@param {type:\"slider\", min:1000, max:10000, step:1000}","metadata":{"id":"r1aYWtdm9kSV","execution":{"iopub.status.busy":"2023-09-25T17:05:22.566994Z","iopub.execute_input":"2023-09-25T17:05:22.567979Z","iopub.status.idle":"2023-09-25T17:05:22.574325Z","shell.execute_reply.started":"2023-09-25T17:05:22.567946Z","shell.execute_reply":"2023-09-25T17:05:22.573310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Let's split our data into train and validation sets\nfrom sklearn.model_selection import train_test_split\n\n# Split them into training and validation of total size NUM_IMAGES\nX_train, X_val, y_train, y_val = train_test_split(X[:NUM_IMAGES],\n                                                  y[:NUM_IMAGES],\n                                                  test_size=0.2,\n                                                  random_state=42)\n\nlen(X_train), len(y_train), len(X_val), len(y_val)","metadata":{"id":"5fW9wLap9qBl","outputId":"5709e169-c80e-4d13-b986-96d7b002c9c0","execution":{"iopub.status.busy":"2023-09-25T17:05:22.576302Z","iopub.execute_input":"2023-09-25T17:05:22.577064Z","iopub.status.idle":"2023-09-25T17:05:22.593123Z","shell.execute_reply.started":"2023-09-25T17:05:22.577032Z","shell.execute_reply":"2023-09-25T17:05:22.591912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Let's have a geez at the training data\nX_train[:5], y_train[:2]","metadata":{"id":"Ql5WMyuHAsYG","outputId":"04ec8fc2-c557-4775-fe0b-3fe63b274915","execution":{"iopub.status.busy":"2023-09-25T17:05:22.594910Z","iopub.execute_input":"2023-09-25T17:05:22.595296Z","iopub.status.idle":"2023-09-25T17:05:22.605240Z","shell.execute_reply.started":"2023-09-25T17:05:22.595259Z","shell.execute_reply":"2023-09-25T17:05:22.604232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocessing Images (turning images into Tensors)\n\nTo preprocess our images to Tensors we're going to write a function which does a few things:\n1. Take an image filepath as input\n2. Use TensorFlow to read the file and save it to a variable, `image`\n3. Turn our `image` (a jpg) into Tensors\n4. Resize the `image` to be shape of (224, 224)\n5. Return the modified `image`\n\nBefore we do, let's see what importing an image looks like.","metadata":{"id":"BrzG2l19A592"}},{"cell_type":"code","source":"# Convert image to NumPy array\nfrom matplotlib.pyplot import imread\nimage = imread(filenames[42])\nimage.shape","metadata":{"id":"f7sfUzfIZIy9","outputId":"8e80ad09-c6eb-495c-fca3-64efffd3b56a","execution":{"iopub.status.busy":"2023-09-25T17:05:22.606612Z","iopub.execute_input":"2023-09-25T17:05:22.607561Z","iopub.status.idle":"2023-09-25T17:05:22.620432Z","shell.execute_reply.started":"2023-09-25T17:05:22.607529Z","shell.execute_reply":"2023-09-25T17:05:22.619403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image.max(), image.min()","metadata":{"id":"Y3vnK67ab_Mv","outputId":"4cc34f5c-79cc-401f-a3f3-d251cdaa9525","execution":{"iopub.status.busy":"2023-09-25T17:05:22.622220Z","iopub.execute_input":"2023-09-25T17:05:22.623134Z","iopub.status.idle":"2023-09-25T17:05:22.630501Z","shell.execute_reply.started":"2023-09-25T17:05:22.623100Z","shell.execute_reply":"2023-09-25T17:05:22.629246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Turn image into a tensor\ntf.constant(image)","metadata":{"id":"kUswZkmTegdO","outputId":"e5dc8b82-5c4d-41ec-8015-93cba5a45de5","execution":{"iopub.status.busy":"2023-09-25T17:05:22.632271Z","iopub.execute_input":"2023-09-25T17:05:22.632868Z","iopub.status.idle":"2023-09-25T17:05:22.644709Z","shell.execute_reply.started":"2023-09-25T17:05:22.632833Z","shell.execute_reply":"2023-09-25T17:05:22.643387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've seen what an image looks like as a Tensor, let's make a function to preprocess them.\n\n1. Take an image filepath as input\n2. Use TensorFlow to read the file and save it to a variable, `image`\n3. Turn our `image` (a jpg) into Tensors\n4. Normalize our image (convert color channel values from 0-255 to 0-1).\n5. Resize the `image` to be shape of (224, 224)\n6. Return the modified `image`","metadata":{"id":"Ep3vZmA2e33u"}},{"cell_type":"code","source":"# Define image size\nIMG_SIZE = 224\n\n\n# Create a function for preprocessing images\ndef process_image(image_path, img_size=IMG_SIZE):\n  \"\"\"\n  Take an image file path and turns the image into Tensor.\n  \"\"\"\n  # Read in an image file\n  image = tf.io.read_file(image_path)\n    # Turn the jpeg image into numerical Tensor with 3 colour 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 the image to our desired value (224, 224)\n  image = tf.image.resize(image, size=[IMG_SIZE, IMG_SIZE])\n\n  return image","metadata":{"id":"bmKHpHWESXr8","execution":{"iopub.status.busy":"2023-09-25T17:05:22.652986Z","iopub.execute_input":"2023-09-25T17:05:22.653589Z","iopub.status.idle":"2023-09-25T17:05:22.660749Z","shell.execute_reply.started":"2023-09-25T17:05:22.653558Z","shell.execute_reply":"2023-09-25T17:05:22.659504Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Turning our data into batches\n\nWhy turn our data into batches?\n\nLet's say you're trying to process 10,000+ images in one go... they all might not fit into memory.\n\nSo that's why we do about 32 images at a time (you can manually adjust the batch size if need be).\n\nIn order to use TensorFlow effectively, we need our data in the form of Tensor tuples which look like this:\n`(image, label)`.\n","metadata":{"id":"VAGdP5P7ZYM-"}},{"cell_type":"code","source":"# Create a simple function to return a tuple (image, label)\ndef get_image_label(image_path, label):\n  \"\"\"\n  Takes an image file path name and associated label,\n  processes the image and return a tuple of (image, label).\n  \"\"\"\n  image = process_image(image_path)\n  return image, label","metadata":{"id":"KwTg7COc_gJn","execution":{"iopub.status.busy":"2023-09-25T17:05:22.662133Z","iopub.execute_input":"2023-09-25T17:05:22.664738Z","iopub.status.idle":"2023-09-25T17:05:22.673404Z","shell.execute_reply.started":"2023-09-25T17:05:22.664704Z","shell.execute_reply":"2023-09-25T17:05:22.672245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n # Demo of the above\n(process_image(X[42]), tf.constant(y[42]))","metadata":{"id":"eurPpY4-BdKY","outputId":"84594195-8d05-4a5c-c294-3e25005eebed","execution":{"iopub.status.busy":"2023-09-25T17:05:22.675601Z","iopub.execute_input":"2023-09-25T17:05:22.675982Z","iopub.status.idle":"2023-09-25T17:05:22.695155Z","shell.execute_reply.started":"2023-09-25T17:05:22.675956Z","shell.execute_reply":"2023-09-25T17:05:22.693895Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've got a way to turn our data into tuples of Tensors in the form: `(image, label)`, let's make a funtion to turn all of our data (`X` & `y`) into batches!","metadata":{"id":"gd-tNWVnDolZ"}},{"cell_type":"code","source":"# Define the batch size, 32 is a good start\nBATCH_SIZE = 32\n\n\n# Create a function to turn data into batches\ndef create_data_batches(X, y=None, batch_size=BATCH_SIZE, valid_data=False, test_data=False):\n  \"\"\"\n  Create 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 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  elif valid_data:\n    print(\"Creating validation data batches...\")\n    data = tf.data.Dataset.from_tensor_slices((tf.constant(X), # filepaths\n                                                tf.constant(y))) # labels\n    data_batch = data.map(get_image_label).batch(BATCH_SIZE)\n    return data_batch\n\n  else:\n    print(\"Creating training data batches...\")\n    # Turn filepaths and labels into Tensors\n    data  = tf.data.Dataset.from_tensor_slices((tf.constant(X),\n                                                tf.constant(y)))\n    # Shuffling pathnames and labels before mapping image processor function is faster than shuffling images\n    data = data.shuffle(buffer_size=len(X))\n\n    # Create (image, label) tuples (this also turns the images path into a preprocessed image)\n    data = data.map(get_image_label)\n\n    # Turn the training data into batches\n    data_batch = data.batch(BATCH_SIZE)\n  return data_batch\n\n\n\n","metadata":{"id":"nfU1tq8-CIAb","execution":{"iopub.status.busy":"2023-09-25T17:05:22.696911Z","iopub.execute_input":"2023-09-25T17:05:22.697254Z","iopub.status.idle":"2023-09-25T17:05:22.708070Z","shell.execute_reply.started":"2023-09-25T17:05:22.697222Z","shell.execute_reply":"2023-09-25T17:05:22.706579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create training and validation data batches\ntrain_data = create_data_batches(X_train, y_train)\nval_data = create_data_batches(X_val, y_val, valid_data=True)","metadata":{"id":"SbpP2ppOpvyf","outputId":"2b1ca903-4280-42c7-c5e7-eff9b867c563","execution":{"iopub.status.busy":"2023-09-25T17:05:22.709752Z","iopub.execute_input":"2023-09-25T17:05:22.710572Z","iopub.status.idle":"2023-09-25T17:05:22.832590Z","shell.execute_reply.started":"2023-09-25T17:05:22.710535Z","shell.execute_reply":"2023-09-25T17:05:22.831645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check out the different attributes of our data batches\ntrain_data.element_spec, val_data.element_spec","metadata":{"id":"JmepG4HFqtN-","outputId":"1712015c-55ea-41c8-c2aa-e37c2d151cb8","execution":{"iopub.status.busy":"2023-09-25T17:05:22.834190Z","iopub.execute_input":"2023-09-25T17:05:22.834907Z","iopub.status.idle":"2023-09-25T17:05:22.842568Z","shell.execute_reply.started":"2023-09-25T17:05:22.834868Z","shell.execute_reply":"2023-09-25T17:05:22.841515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualizing Data Batches\n\nOur data is now in batches, however, these can be a little hard to understand/comprehend, let's visualize them!","metadata":{"id":"XuerYOqBrJkP"}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Create a function for viewing images in a data batch\ndef show_25_images(images, labels):\n  \"\"\"\n  Displays a plot of 25 images and their labels from a data batch.\n  \"\"\"\n  # Setup the figure\n  plt.figure(figsize=(10, 10))\n  # Loop through 26 (for displaying 25 images)\n  for i in range(25):\n    # Create subplots (5 rows, 5 columns)\n    ax = plt.subplot(5, 5, i+1)\n    # Display an image\n    plt.imshow(images[i])\n    # Add the image label as the title\n    plt.title(unique_breeds[labels[i].argmax()])\n    # Turn the grid lines off\n    plt.axis(\"off\")","metadata":{"id":"S767ThAPskpu","execution":{"iopub.status.busy":"2023-09-25T17:05:22.844224Z","iopub.execute_input":"2023-09-25T17:05:22.844900Z","iopub.status.idle":"2023-09-25T17:05:22.853052Z","shell.execute_reply.started":"2023-09-25T17:05:22.844866Z","shell.execute_reply":"2023-09-25T17:05:22.851917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data","metadata":{"id":"9nmFXVRXw-0J","outputId":"7c039566-7892-4adc-b2fd-939ded31332d","execution":{"iopub.status.busy":"2023-09-25T17:05:22.854591Z","iopub.execute_input":"2023-09-25T17:05:22.855494Z","iopub.status.idle":"2023-09-25T17:05:22.869492Z","shell.execute_reply.started":"2023-09-25T17:05:22.855435Z","shell.execute_reply":"2023-09-25T17:05:22.868307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Now let's visualize the data in a training batch\ntrain_images, train_labels = next(train_data.as_numpy_iterator())\nshow_25_images(train_images, train_labels)","metadata":{"id":"Tp3zxlZXu5zv","outputId":"1741e062-a400-490f-9ac1-438b0928787b","execution":{"iopub.status.busy":"2023-09-25T17:05:22.872734Z","iopub.execute_input":"2023-09-25T17:05:22.873020Z","iopub.status.idle":"2023-09-25T17:05:25.162376Z","shell.execute_reply.started":"2023-09-25T17:05:22.872996Z","shell.execute_reply":"2023-09-25T17:05:25.161507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Now let's visualize our validation set\nval_images, val_labels = next(val_data.as_numpy_iterator())\nshow_25_images(val_images, val_labels)","metadata":{"id":"bmrlME2g27OO","outputId":"9b381876-e468-48bb-f584-f8cf7902a50a","execution":{"iopub.status.busy":"2023-09-25T17:05:25.163860Z","iopub.execute_input":"2023-09-25T17:05:25.164468Z","iopub.status.idle":"2023-09-25T17:05:27.536902Z","shell.execute_reply.started":"2023-09-25T17:05:25.164421Z","shell.execute_reply":"2023-09-25T17:05:27.536001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Building a model\n\nBefore we build a model, there are a few things we need to define:\n* The input shape (our images shape, in the form of Tensors) to our model.\n* The output shape (image labels, in the form of Tensors) of our model.\n* The URL of the model we want to use from TensorFlow Hub -https://tfhub.dev/google/imagenet/mobilenet_v2_140_224/classification/5","metadata":{"id":"ja7BQEmq3yHw"}},{"cell_type":"code","source":"IMG_SIZE","metadata":{"id":"849gzl9HszWd","outputId":"2a6f9745-67b8-4058-a481-821ebf5d3f60","execution":{"iopub.status.busy":"2023-09-25T17:05:27.538276Z","iopub.execute_input":"2023-09-25T17:05:27.539152Z","iopub.status.idle":"2023-09-25T17:05:27.545527Z","shell.execute_reply.started":"2023-09-25T17:05:27.539115Z","shell.execute_reply":"2023-09-25T17:05:27.544599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Setup input shape to the model\nINPUT_SHAPE = [None, IMG_SIZE, IMG_SIZE, 3] # batch, height, width, colour channels\n\n# Setup output shape of our model\nOUTPUT_SHAPE = len(unique_breeds)\n\n# Setup model URL from TensorFlow Hub\nMODEL_URL = \"https://tfhub.dev/google/imagenet/mobilenet_v2_140_224/classification/5\"","metadata":{"id":"C2_UKTUwsTRi","execution":{"iopub.status.busy":"2023-09-25T17:05:27.547106Z","iopub.execute_input":"2023-09-25T17:05:27.548195Z","iopub.status.idle":"2023-09-25T17:05:27.556628Z","shell.execute_reply.started":"2023-09-25T17:05:27.548137Z","shell.execute_reply":"2023-09-25T17:05:27.555750Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've got our inputs, outputs and model ready to go.Let's put them together into a Keras deep learning model!\n\nKnowing this, let's create a function which:\n* Takes the input shape, output shape and the model we've chosen as parameters.\n* Defines the layers in a Keras model in sequential fashion (do this first, then this, then that).\n* Compiles the model (says it should be evaluated and improved).\n* Builds the model  (tells the model the input shape it'll be getting).\n* Returns the model.\n\nAll of these steps found on here:https://www.tensorflow.org/guide/keras","metadata":{"id":"sIqeeknWse8F"}},{"cell_type":"code","source":"# Create a function which builds a Keras model\ndef create_model(input_shape=INPUT_SHAPE, output_shape=OUTPUT_SHAPE, model_url=MODEL_URL):\n  print(\"Building model with:\", MODEL_URL)\n\n\n  # Setup the model layers\n  model = tf.keras.Sequential([\n    hub.KerasLayer(MODEL_URL), # Layer 1 (input layer)\n    tf.keras.layers.Dense(units=OUTPUT_SHAPE,\n                          activation=\"softmax\") # Layer 2 (output layer)\n  ])\n  # Compile the model\n  model.compile(\n      loss=tf.keras.losses.CategoricalCrossentropy(),\n      optimizer=tf.keras.optimizers.Adam(),\n      metrics=[\"accuracy\"]\n  )\n\n  # Build the model\n  model.build(INPUT_SHAPE)\n\n  return model","metadata":{"id":"7nMf1NUnYQdg","execution":{"iopub.status.busy":"2023-09-25T17:05:27.558066Z","iopub.execute_input":"2023-09-25T17:05:27.558725Z","iopub.status.idle":"2023-09-25T17:05:27.568521Z","shell.execute_reply.started":"2023-09-25T17:05:27.558694Z","shell.execute_reply":"2023-09-25T17:05:27.567595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model()\nmodel.summary()","metadata":{"id":"TQC4ZWmEZM3v","outputId":"2ab33945-22a7-48b5-9eb6-e484015e2f16","execution":{"iopub.status.busy":"2023-09-25T17:05:27.570350Z","iopub.execute_input":"2023-09-25T17:05:27.571002Z","iopub.status.idle":"2023-09-25T17:05:29.770498Z","shell.execute_reply.started":"2023-09-25T17:05:27.570971Z","shell.execute_reply":"2023-09-25T17:05:29.769520Z"},"trusted":true},"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.\n\nWe'll create two callbacks, one for TensorBoard which helps track our models progress and another for early stopping which prevents our model from training for too long.\n\n### TensorBoard Callback\n\nTo setup a TensorBoard callback we need to do 3 things:\n1. Load the TensorBoard notebook extension\n2. Create a TensorBoard callback which is able to save logs to a directory and pass it to our model's `fit()` function.\n3. Visualize our models training logs with the `%tensorboard` magic function (we'll do this after model training).","metadata":{"id":"ZZKGLjJJe0Qw"}},{"cell_type":"code","source":"# Load TensorBoard notebook extension\n%load_ext tensorboard","metadata":{"id":"3b47dgGfnu5h","outputId":"ee8cb6eb-cfb9-4e89-adb3-6d88c935c97a","execution":{"iopub.status.busy":"2023-09-25T17:05:29.772045Z","iopub.execute_input":"2023-09-25T17:05:29.772881Z","iopub.status.idle":"2023-09-25T17:05:29.778749Z","shell.execute_reply.started":"2023-09-25T17:05:29.772846Z","shell.execute_reply":"2023-09-25T17:05:29.777587Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import datetime\n\n# Create a function to build a TensorBoard callback\ndef create_tensorboard_callback():\n  # Create a log directory for storing TensorBoard logs\n  logdir = os.path.join(\"/kaggle/working/logs\",\n                        # Make it so the logs get tracked whenever we run an experiment\n                        datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\"))\n\n\n  return tf.keras.callbacks.TensorBoard(logdir)","metadata":{"id":"DUcz01D8pfHB","execution":{"iopub.status.busy":"2023-09-25T17:05:29.780344Z","iopub.execute_input":"2023-09-25T17:05:29.781350Z","iopub.status.idle":"2023-09-25T17:05:29.791177Z","shell.execute_reply.started":"2023-09-25T17:05:29.781315Z","shell.execute_reply":"2023-09-25T17:05:29.789944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Early Stopping Callback\n\nEarly stopping helps stop our model from overfitting by stopping training if a certain evaluation metric stops improving.","metadata":{"id":"01sKMgQesd7C"}},{"cell_type":"code","source":"# Create early stopping callback\nearly_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"val_accuracy\",\n                                                  patience=3)","metadata":{"id":"HOpYIND8ty4x","execution":{"iopub.status.busy":"2023-09-25T17:05:29.792880Z","iopub.execute_input":"2023-09-25T17:05:29.793239Z","iopub.status.idle":"2023-09-25T17:05:29.806761Z","shell.execute_reply.started":"2023-09-25T17:05:29.793202Z","shell.execute_reply":"2023-09-25T17:05:29.805516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training a model (on subset of data)\n\nOur first model is only going to train on 1000 images, to make sure everything is working.","metadata":{"id":"zIu3I7pHumLS"}},{"cell_type":"code","source":"NUM_EPOCHS = 100 # @param {type:\"slider\", min:10, max:100, step:10}","metadata":{"id":"gmE11diEWkrR","execution":{"iopub.status.busy":"2023-09-25T17:05:29.808599Z","iopub.execute_input":"2023-09-25T17:05:29.809039Z","iopub.status.idle":"2023-09-25T17:05:29.818504Z","shell.execute_reply.started":"2023-09-25T17:05:29.808910Z","shell.execute_reply":"2023-09-25T17:05:29.817158Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check to make sure we're still running on a GPU\nprint(\"GPU\", \"available\" if tf.config.list_physical_devices(\"GPU\") else \"not avilable\")","metadata":{"id":"NW9iQhzWXLtY","outputId":"a55ad76a-d5ee-41fc-9aae-33a971bd8392","execution":{"iopub.status.busy":"2023-09-25T17:05:29.820366Z","iopub.execute_input":"2023-09-25T17:05:29.820801Z","iopub.status.idle":"2023-09-25T17:05:29.828487Z","shell.execute_reply.started":"2023-09-25T17:05:29.820768Z","shell.execute_reply":"2023-09-25T17:05:29.827523Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's create a function which trains a model.\n\n* Create a model using `create_model()`\n* Setup a TensorBoard callback using `create_tensorboard_callback`\n* Call the `fit()` function on our model passing it the training data, validation data, number of epochs to train for (`NUM_EPOCHS`) and the callbacks we'd like to use\n* Return the model","metadata":{"id":"YHvVWt0cX6gR"}},{"cell_type":"code","source":"# Build a function to train and return a trained model\ndef train_model():\n  \"\"\"\n  Trains a given model and returns the trained version,\n  \"\"\"\n  # Create a model\n  model = create_model()\n\n  # Create new TensorBoard session everytime we train a model\n  tensorboard = create_tensorboard_callback()\n\n  # Fit the model to the data passing it the callbacks we created\n  model.fit(x=train_data,\n            epochs=NUM_EPOCHS,\n            validation_data=val_data,\n            validation_freq=1,\n            callbacks=[tensorboard, early_stopping])\n\n  # Return the fitted model\n  return model\n","metadata":{"id":"RWh4whl7YpvB","execution":{"iopub.status.busy":"2023-09-25T17:05:29.838747Z","iopub.execute_input":"2023-09-25T17:05:29.839409Z","iopub.status.idle":"2023-09-25T17:05:29.845508Z","shell.execute_reply.started":"2023-09-25T17:05:29.839377Z","shell.execute_reply":"2023-09-25T17:05:29.844485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fit the model\nmodel = train_model()","metadata":{"id":"M3cYf-2ubCrR","outputId":"19d11db9-f1ca-437f-f705-aa8f2f1a7020","execution":{"iopub.status.busy":"2023-09-25T17:05:29.847078Z","iopub.execute_input":"2023-09-25T17:05:29.847766Z","iopub.status.idle":"2023-09-25T17:06:10.551185Z","shell.execute_reply.started":"2023-09-25T17:05:29.847732Z","shell.execute_reply":"2023-09-25T17:06:10.550073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Question:** It looks like our model is overfitting because it's performing far better on the training dataset than the validation dataset, what are some ways to prevent overfitting in deeplearning neural networks?\n\n**Note:** Overfitting to begin with is a good thing! It means our model is learning!!!","metadata":{"id":"PNS3-0Wxbcag"}},{"cell_type":"markdown","source":"### Checking the TensorBoard logs\n\nThe TensorBoard magic function (`%tensorboard`) will access the log directory we created earlier and visualize its contents .  ","metadata":{"id":"CE8sHP-JePjB"}},{"cell_type":"code","source":"%tensorboard --logdir /kaggle/working/logs","metadata":{"id":"zaQW8b0skeiB","outputId":"dfe93c7a-03ac-4654-b312-644330cd6104","execution":{"iopub.status.busy":"2023-09-25T17:06:10.552885Z","iopub.execute_input":"2023-09-25T17:06:10.553621Z","iopub.status.idle":"2023-09-25T17:06:16.584182Z","shell.execute_reply.started":"2023-09-25T17:06:10.553579Z","shell.execute_reply":"2023-09-25T17:06:16.582744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##Making and evaluating predictions using a trained model","metadata":{"id":"sMFhOfQeHA4n"}},{"cell_type":"code","source":"val_data","metadata":{"id":"ZOrxVHdPHpX4","outputId":"850629d7-4d4d-4f1f-a8c0-0f1a6e85f7e6","execution":{"iopub.status.busy":"2023-09-25T17:06:16.585704Z","iopub.execute_input":"2023-09-25T17:06:16.586521Z","iopub.status.idle":"2023-09-25T17:06:16.594218Z","shell.execute_reply.started":"2023-09-25T17:06:16.586486Z","shell.execute_reply":"2023-09-25T17:06:16.593141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make prediciton on the validation data (not used to train on)\npredictions = model.predict(val_data, verbose=1)\npredictions","metadata":{"id":"RtTSMDerHOGA","execution":{"iopub.status.busy":"2023-09-25T17:06:16.595780Z","iopub.execute_input":"2023-09-25T17:06:16.596855Z","iopub.status.idle":"2023-09-25T17:06:19.388559Z","shell.execute_reply.started":"2023-09-25T17:06:16.596817Z","shell.execute_reply":"2023-09-25T17:06:19.387564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions.shape","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.392796Z","iopub.execute_input":"2023-09-25T17:06:19.393129Z","iopub.status.idle":"2023-09-25T17:06:19.400353Z","shell.execute_reply.started":"2023-09-25T17:06:19.393101Z","shell.execute_reply":"2023-09-25T17:06:19.399080Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# First prediction\nindex = 42\nprint(predictions[0])\nprint(f\"Maxvalue (probability of prediction): {np.max(predictions[index])}\")\nprint(f\"Sum: {np.sum(predictions[index])}\")\nprint(f\"Max index: {np.argmax(predictions[index])}\")\nprint(f\"Predictions label: {unique_breeds[np.argmax(predictions[index])]}\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.402171Z","iopub.execute_input":"2023-09-25T17:06:19.402856Z","iopub.status.idle":"2023-09-25T17:06:19.415836Z","shell.execute_reply.started":"2023-09-25T17:06:19.402817Z","shell.execute_reply":"2023-09-25T17:06:19.414678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Having the above functionality is great but we want to be able to do it at scale.\n\nAnd it would be even better if we could see the image the prediction is being made on!\n\n**Note:** Prediction probabilities are also known as confidence levels ","metadata":{}},{"cell_type":"code","source":"# Turn prediction probabilities into their respective label (easier to understand)\ndef get_pred_label(prediction_probabilities):\n    \"\"\"\n    Turns an array of predicitions probabilities into labels.\n    \"\"\"\n    return unique_breeds[np.argmax(prediction_probabilities)]\n\n# Get a predicted label based on an array of prediction probabilities\npred_label= get_pred_label(predictions[81])\npred_label","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.417411Z","iopub.execute_input":"2023-09-25T17:06:19.418115Z","iopub.status.idle":"2023-09-25T17:06:19.429308Z","shell.execute_reply.started":"2023-09-25T17:06:19.418078Z","shell.execute_reply":"2023-09-25T17:06:19.428236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now since our validation data is still in a batch dataset,\nwe'll have unbatchify it to make predictions on the validation images and compare those predictions to the validation labels(truth labels).","metadata":{}},{"cell_type":"code","source":"val_data","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.430960Z","iopub.execute_input":"2023-09-25T17:06:19.431780Z","iopub.status.idle":"2023-09-25T17:06:19.442905Z","shell.execute_reply.started":"2023-09-25T17:06:19.431743Z","shell.execute_reply":"2023-09-25T17:06:19.441870Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a function to unbatch a batch dataset\ndef unbatchify(batch_data):\n    \"\"\"\n    Takes a batched dataset of (image, label) Tensors and returns seperate arrays of images and labels. \n    \"\"\"\n    images = []\n    labels = []\n    # Loop through unbatched data\n    for image, label in batch_data.unbatch().as_numpy_iterator():\n        images.append(image)\n        labels.append(unique_breeds[np.argmax(label)])\n        \n    return images, labels\n\n# Unbatchify the validation data\nval_images, val_labels = unbatchify(val_data)\nval_images[0], val_labels[0]","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.444394Z","iopub.execute_input":"2023-09-25T17:06:19.445651Z","iopub.status.idle":"2023-09-25T17:06:19.976648Z","shell.execute_reply.started":"2023-09-25T17:06:19.445608Z","shell.execute_reply":"2023-09-25T17:06:19.975505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've got ways to get:\n* Prediction labels\n* Validation labels(truth labels)\n* Validation images\n\nLet's make some function to make these all a bit more visualize.\n\nWe'll create a function which:\n* Takes an array of prediction probabilities, an array of truth labels and an array of images and an integers.\n* Convert the prediction probabilities to a predicted label.\n* Plot the predicted label, its predicted probability, the truth label and the target image on a single plot.","metadata":{}},{"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    # Get the pred label\n    pred_label = get_pred_label(pred_prob)\n    \n    # Plot image & remove ticks\n    plt.imshow(image)\n    plt.xticks([])\n    plt.yticks([])\n    \n    # Change the colour of the title depending on if the prediction is right or wrong\n    if pred_label == true_label:\n        color = \"green\"\n    else:\n        color = \"red\"\n    \n    # Change plot title to be predicted, probability of prediction and truth label\n    plt.title(\"{} {:2.0f}% {}\".format(pred_label,\n                                     np.max(pred_prob)*100,\n                                     true_label),\n                                     color=color)\n    ","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.978189Z","iopub.execute_input":"2023-09-25T17:06:19.979315Z","iopub.status.idle":"2023-09-25T17:06:19.988343Z","shell.execute_reply.started":"2023-09-25T17:06:19.979270Z","shell.execute_reply":"2023-09-25T17:06:19.987265Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_pred(prediction_probabilities=predictions,\n         labels=val_labels,\n         images=val_images,\n         n=84)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:19.989973Z","iopub.execute_input":"2023-09-25T17:06:19.991056Z","iopub.status.idle":"2023-09-25T17:06:20.255641Z","shell.execute_reply.started":"2023-09-25T17:06:19.991004Z","shell.execute_reply":"2023-09-25T17:06:20.254415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've got one function to visualize our models top predictions, let's make another to view our models top 10 predictions.\n\nThis function will:\n* Take an input of prediction probabilities array and a ground truth array and an integer\n* Find the prediction using `get_pred_label()`\n* Find the top 10:\n   * Prediction probabilities indexes\n   * Prediction probabilities values\n   * Prediction labels\n* Plot the top 10 prediction probability values and labels, coloring the true label green.","metadata":{}},{"cell_type":"code","source":"def plot_pred_conf(prediction_probabilities, labels, n=1):\n    \"\"\"\n    Plus the top 10 highest prediction confidences along with truth labels 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 prediciton confidence values\n    top_10_pred_values = pred_prob[top_10_pred_indexes]\n    # Find the top 10 prediciton labels\n    top_10_pred_labels = unique_breeds[top_10_pred_indexes]\n    \n    # Setup plot\n    top_plot = plt.bar(np.arange(len(top_10_pred_labels)),\n                      top_10_pred_values,\n                      color=\"grey\")\n    \n    plt.xticks(np.arange(len(top_10_pred_labels)),\n              labels=top_10_pred_labels,\n               rotation=\"vertical\")\n               \n    # Change the color of true label\n    if np.isin(true_label, top_10_pred_labels):\n               top_plot[np.argmax(top_10_pred_labels == true_label)].set_color(\"green\")\n    else:\n               pass\n    ","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:20.257427Z","iopub.execute_input":"2023-09-25T17:06:20.258596Z","iopub.status.idle":"2023-09-25T17:06:20.272190Z","shell.execute_reply.started":"2023-09-25T17:06:20.258556Z","shell.execute_reply":"2023-09-25T17:06:20.270273Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_pred_conf(predictions, val_labels, n=9)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:20.278704Z","iopub.execute_input":"2023-09-25T17:06:20.279594Z","iopub.status.idle":"2023-09-25T17:06:20.711985Z","shell.execute_reply.started":"2023-09-25T17:06:20.279555Z","shell.execute_reply":"2023-09-25T17:06:20.710918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've got some function to help us visualize our prediction and evaluate our models,let's check out a few. ","metadata":{"execution":{"iopub.status.busy":"2023-09-25T10:36:18.023403Z","iopub.execute_input":"2023-09-25T10:36:18.023772Z","iopub.status.idle":"2023-09-25T10:36:18.030784Z","shell.execute_reply.started":"2023-09-25T10:36:18.023741Z","shell.execute_reply":"2023-09-25T10:36:18.029307Z"}}},{"cell_type":"code","source":"# Lets check out a few predictions and their different values\ni_multiplier = 20\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)\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:20.713803Z","iopub.execute_input":"2023-09-25T17:06:20.714426Z","iopub.status.idle":"2023-09-25T17:06:22.965603Z","shell.execute_reply.started":"2023-09-25T17:06:20.714390Z","shell.execute_reply":"2023-09-25T17:06:22.964668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Saving and reloading a trained model","metadata":{"execution":{"iopub.status.busy":"2023-09-25T10:59:43.737782Z","iopub.execute_input":"2023-09-25T10:59:43.738183Z","iopub.status.idle":"2023-09-25T10:59:43.742742Z","shell.execute_reply.started":"2023-09-25T10:59:43.738145Z","shell.execute_reply":"2023-09-25T10:59:43.741837Z"}}},{"cell_type":"code","source":"# Create a function to save a model\ndef save_model(model, suffix=None):\n    \"\"\"\n    Saves a given model in a models directory and appends a suffix (string).\n    \"\"\"\n    modeldir = os.path.join(\"/kaggle/working/\",\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":{"execution":{"iopub.status.busy":"2023-09-25T17:06:22.966887Z","iopub.execute_input":"2023-09-25T17:06:22.967524Z","iopub.status.idle":"2023-09-25T17:06:22.974152Z","shell.execute_reply.started":"2023-09-25T17:06:22.967488Z","shell.execute_reply":"2023-09-25T17:06:22.973343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a function to load a trained model\ndef 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    \n    return model","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:22.976106Z","iopub.execute_input":"2023-09-25T17:06:22.976868Z","iopub.status.idle":"2023-09-25T17:06:22.989697Z","shell.execute_reply.started":"2023-09-25T17:06:22.976833Z","shell.execute_reply":"2023-09-25T17:06:22.988594Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we've got functions to save and load a trained model, let's make sure they work!","metadata":{}},{"cell_type":"code","source":"# Save our model trained on 1000 images\nsave_model(model, suffix=\"1000-images-mobilenetv2-Adam\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:06:22.991270Z","iopub.execute_input":"2023-09-25T17:06:22.991944Z","iopub.status.idle":"2023-09-25T17:06:23.295472Z","shell.execute_reply.started":"2023-09-25T17:06:22.991913Z","shell.execute_reply":"2023-09-25T17:06:23.294280Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load a trained model\nloaded_1000_image_model = load_model(\"/kaggle/input/dogvision/20230925-17061695661582-1000-images-mobilenetv2-Adam.h5\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:01.887499Z","iopub.execute_input":"2023-09-25T17:07:01.887892Z","iopub.status.idle":"2023-09-25T17:07:03.983835Z","shell.execute_reply.started":"2023-09-25T17:07:01.887862Z","shell.execute_reply":"2023-09-25T17:07:03.982838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Evaluate the pre-saved model\nmodel.evaluate(val_data)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:20.573514Z","iopub.execute_input":"2023-09-25T17:07:20.573879Z","iopub.status.idle":"2023-09-25T17:07:21.167289Z","shell.execute_reply.started":"2023-09-25T17:07:20.573849Z","shell.execute_reply":"2023-09-25T17:07:21.166278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Evaluate the loaded model\nloaded_1000_image_model.evaluate(val_data)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:21.420208Z","iopub.execute_input":"2023-09-25T17:07:21.420554Z","iopub.status.idle":"2023-09-25T17:07:22.514540Z","shell.execute_reply.started":"2023-09-25T17:07:21.420526Z","shell.execute_reply":"2023-09-25T17:07:22.513506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training a big dog model (on the full data)","metadata":{}},{"cell_type":"code","source":"len(X), len(y)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:22.517106Z","iopub.execute_input":"2023-09-25T17:07:22.517791Z","iopub.status.idle":"2023-09-25T17:07:22.525363Z","shell.execute_reply.started":"2023-09-25T17:07:22.517749Z","shell.execute_reply":"2023-09-25T17:07:22.524178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a data batch with the full data set\nfull_data = create_data_batches(X, y)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:22.526942Z","iopub.execute_input":"2023-09-25T17:07:22.528054Z","iopub.status.idle":"2023-09-25T17:07:22.671274Z","shell.execute_reply.started":"2023-09-25T17:07:22.528016Z","shell.execute_reply":"2023-09-25T17:07:22.670385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"full_data","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:22.674164Z","iopub.execute_input":"2023-09-25T17:07:22.675013Z","iopub.status.idle":"2023-09-25T17:07:22.681539Z","shell.execute_reply.started":"2023-09-25T17:07:22.674980Z","shell.execute_reply":"2023-09-25T17:07:22.680511Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a model for full model\nfull_model = create_model()","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:22.683055Z","iopub.execute_input":"2023-09-25T17:07:22.683987Z","iopub.status.idle":"2023-09-25T17:07:25.002643Z","shell.execute_reply.started":"2023-09-25T17:07:22.683953Z","shell.execute_reply":"2023-09-25T17:07:25.001631Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create full model callbacks\nfull_model_tensorboard = create_tensorboard_callback()\n# No validation set when training on all the data, so we can't monitor validation accuracy\nfull_model_early_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"accuracy\",\n                                                            patience=3)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:25.003936Z","iopub.execute_input":"2023-09-25T17:07:25.004284Z","iopub.status.idle":"2023-09-25T17:07:25.012309Z","shell.execute_reply.started":"2023-09-25T17:07:25.004251Z","shell.execute_reply":"2023-09-25T17:07:25.011256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Note:** Running the cell below will take a little while (maybe up to 30 minutes for the first epoch) because the GPU we're using in the runtime has to load all of the images into memory.","metadata":{}},{"cell_type":"code","source":"# Fit the full model to the full data\nfull_model.fit(x=full_data,\n              epochs=NUM_EPOCHS,\n              callbacks=[full_model_tensorboard, full_model_early_stopping])","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:07:25.015289Z","iopub.execute_input":"2023-09-25T17:07:25.015985Z","iopub.status.idle":"2023-09-25T17:16:57.154286Z","shell.execute_reply.started":"2023-09-25T17:07:25.015951Z","shell.execute_reply":"2023-09-25T17:16:57.153027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"save_model(full_model, suffix=\"full-image-set-mobilenetv2-Adam\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:16:57.156185Z","iopub.execute_input":"2023-09-25T17:16:57.156612Z","iopub.status.idle":"2023-09-25T17:16:57.409393Z","shell.execute_reply.started":"2023-09-25T17:16:57.156573Z","shell.execute_reply":"2023-09-25T17:16:57.408387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load in full model\nloaded_full_model = load_model(\"/kaggle/input/dogvision/20230925-17161695662217-full-image-set-mobilenetv2-Adam.h5\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:19:51.833639Z","iopub.execute_input":"2023-09-25T17:19:51.834195Z","iopub.status.idle":"2023-09-25T17:19:53.900372Z","shell.execute_reply.started":"2023-09-25T17:19:51.834158Z","shell.execute_reply":"2023-09-25T17:19:53.899206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Making predictions on the test dataset\n\nSince our model has been trained on images in the form of Tensor batches, to make predictions on the test data, we'll have to get it into the same format.\n\nWe created `create_data_batches()` earlier which can take a list of filenames as input and convert them into Tensor batches.","metadata":{}},{"cell_type":"markdown","source":"To make predictions on the test data, we'll:\n* Get the test image filenames \n* Convert the filename into the test data batches using `create_data_batches()` and setting the `test_data` parameter to `True` (since the test data doesn't have labels.\n* Make a predictions array by passing the test batches to the `predict()` method called on our model.","metadata":{}},{"cell_type":"code","source":"# Load test images filenames\ntest_path = \"/kaggle/input/dog-breed-identification/test/\"\ntest_filenames = [test_path + fname for fname in os.listdir(test_path)]\ntest_filenames[:10]","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:19:58.597563Z","iopub.execute_input":"2023-09-25T17:19:58.598645Z","iopub.status.idle":"2023-09-25T17:19:58.920554Z","shell.execute_reply.started":"2023-09-25T17:19:58.598598Z","shell.execute_reply":"2023-09-25T17:19:58.919582Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(test_filenames)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:19:59.032648Z","iopub.execute_input":"2023-09-25T17:19:59.033284Z","iopub.status.idle":"2023-09-25T17:19:59.039858Z","shell.execute_reply.started":"2023-09-25T17:19:59.033253Z","shell.execute_reply":"2023-09-25T17:19:59.038744Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create test data batch\ntest_data = create_data_batches(test_filenames, test_data=True)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:19:59.942862Z","iopub.execute_input":"2023-09-25T17:19:59.943236Z","iopub.status.idle":"2023-09-25T17:19:59.969014Z","shell.execute_reply.started":"2023-09-25T17:19:59.943205Z","shell.execute_reply":"2023-09-25T17:19:59.968015Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:20:02.822117Z","iopub.execute_input":"2023-09-25T17:20:02.822507Z","iopub.status.idle":"2023-09-25T17:20:02.828414Z","shell.execute_reply.started":"2023-09-25T17:20:02.822468Z","shell.execute_reply":"2023-09-25T17:20:02.827519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Note:** Calling `predict()` on our full model and passing it the test data batch will take a long time to run(about an~hr)","metadata":{}},{"cell_type":"code","source":"# Make predictions on test data batch using the loaded full model\ntest_predictions = loaded_full_model.predict(test_data,\n                                           verbose=1)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:20:04.198186Z","iopub.execute_input":"2023-09-25T17:20:04.198904Z","iopub.status.idle":"2023-09-25T17:21:26.549659Z","shell.execute_reply.started":"2023-09-25T17:20:04.198861Z","shell.execute_reply":"2023-09-25T17:21:26.548526Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save predictions (NumPy array) to csv file (for access later)\n\nnp.savetxt(\"/kaggle/working/preds_array.csv\", test_predictions, delimiter=\",\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:26.552074Z","iopub.execute_input":"2023-09-25T17:21:26.552438Z","iopub.status.idle":"2023-09-25T17:21:27.859739Z","shell.execute_reply.started":"2023-09-25T17:21:26.552405Z","shell.execute_reply":"2023-09-25T17:21:27.858649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load predictions (NumPy array) from csv file\ntest_predictions = np.loadtxt(\"/kaggle/input/dogvision/preds_array.csv\", delimiter=\",\")","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:27.861340Z","iopub.execute_input":"2023-09-25T17:21:27.861731Z","iopub.status.idle":"2023-09-25T17:21:28.491954Z","shell.execute_reply.started":"2023-09-25T17:21:27.861694Z","shell.execute_reply":"2023-09-25T17:21:28.490918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions[:10]","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:28.494695Z","iopub.execute_input":"2023-09-25T17:21:28.495059Z","iopub.status.idle":"2023-09-25T17:21:28.504392Z","shell.execute_reply.started":"2023-09-25T17:21:28.495024Z","shell.execute_reply":"2023-09-25T17:21:28.503236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions.shape","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:28.505956Z","iopub.execute_input":"2023-09-25T17:21:28.506931Z","iopub.status.idle":"2023-09-25T17:21:28.513180Z","shell.execute_reply.started":"2023-09-25T17:21:28.506896Z","shell.execute_reply":"2023-09-25T17:21:28.512241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preparing test dataset for Kaggle \n\nLooking at the Kaggle sample submission, we find that it wants our models prediction probability outputs in a DataFrame with an ID and a column for each different dog breed www.kaggle.com/competitions/dog-breed-identification/overview/evaluation\n\n\nTo get the data in this format, we'll:\n* Create a pandas DataFrame with an ID column as a column for each dog breed\n* Add data to the ID column by extracting the test image ID's from their filepaths\n* Add data (the prediction probabilities) to each of the dog breed columns\n* Export the DataFrame as a CSV to submit it to Kaggle.","metadata":{}},{"cell_type":"code","source":"# Create a pandas DataFrame with empty columns\npreds_df = pd.DataFrame(columns=[\"id\"] + list(unique_breeds))\npreds_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:28.514402Z","iopub.execute_input":"2023-09-25T17:21:28.515317Z","iopub.status.idle":"2023-09-25T17:21:28.544648Z","shell.execute_reply.started":"2023-09-25T17:21:28.515282Z","shell.execute_reply":"2023-09-25T17:21:28.543639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Append test image ID's to predictions DataFrame\ntest_ids = [os.path.splitext(path)[0] for path in os.listdir(test_path)]\npreds_df[\"id\"] = test_ids","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:28.546122Z","iopub.execute_input":"2023-09-25T17:21:28.546662Z","iopub.status.idle":"2023-09-25T17:21:28.587770Z","shell.execute_reply.started":"2023-09-25T17:21:28.546630Z","shell.execute_reply":"2023-09-25T17:21:28.586839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Add the predictions probabilities to each dog breed column\npreds_df[list(unique_breeds)] = test_predictions\npreds_df","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:28.589154Z","iopub.execute_input":"2023-09-25T17:21:28.589531Z","iopub.status.idle":"2023-09-25T17:21:28.663573Z","shell.execute_reply.started":"2023-09-25T17:21:28.589493Z","shell.execute_reply":"2023-09-25T17:21:28.662387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Save our predictions dataframe to CSV for submission to kaggle\npreds_df.to_csv(\"/kaggle/working/full_model_predictions_submission_1_mobilenetV2.csv\",\n               index=False)","metadata":{"execution":{"iopub.status.busy":"2023-09-25T17:21:28.665257Z","iopub.execute_input":"2023-09-25T17:21:28.665646Z","iopub.status.idle":"2023-09-25T17:21:31.457794Z","shell.execute_reply.started":"2023-09-25T17:21:28.665611Z","shell.execute_reply":"2023-09-25T17:21:31.456793Z"},"trusted":true},"execution_count":null,"outputs":[]}]}