{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":7327,"databundleVersionId":861871,"sourceType":"competition"}],"dockerImageVersionId":30839,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n# for dirname, _, filenames in os.walk('/kaggle/input'):\n    # for filename in filenames:\n        # print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:13.867086Z","iopub.execute_input":"2025-02-15T08:25:13.867404Z","iopub.status.idle":"2025-02-15T08:25:14.209010Z","shell.execute_reply.started":"2025-02-15T08:25:13.867373Z","shell.execute_reply":"2025-02-15T08:25:14.208212Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nprint(tf.config.list_physical_devices('GPU'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:14.210082Z","iopub.execute_input":"2025-02-15T08:25:14.210417Z","iopub.status.idle":"2025-02-15T08:25:26.137962Z","shell.execute_reply.started":"2025-02-15T08:25:14.210394Z","shell.execute_reply":"2025-02-15T08:25:26.137162Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# End-to-end Multi-class Dog Breed Classification\n\nThis notebook builds an end-to-end multi-class image classifier using TensorFlow\n2.0 and TensorFlow Hub.\n\n## 1. Problem\n\nIdentifying the breed of a dog given an image of a dog.\n\nWhen I'm sitting at the cafe and I take a photo of a dog, I want to know \nwhat breed of dog it is.\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\n\nThe evaluation is a file with prediction probabilities for each dog breed of each test image\ncontained in the test.zip\n\n## 4. Features\n\nSome information  about the data:\n* We're dealing with images (unstruted 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":{}},{"cell_type":"markdown","source":"## Get our Workspace ready\n\n* Import TensorFlow\n* Import TensorFlow Hub\n* Make sure we're using GPU\n\n","metadata":{}},{"cell_type":"code","source":"# Import neccessary tools\n\nimport tensorflow as tf\nimport tensorflow_hub as hub\nprint(tf.__version__)\nprint(hub.__version__)\n\n# Check for GPU availability\nprint(\"GPU\", \"available\" if tf.config.list_physical_devices(\"GPU\") else \"not available\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:26.139329Z","iopub.execute_input":"2025-02-15T08:25:26.139767Z","iopub.status.idle":"2025-02-15T08:25:27.572741Z","shell.execute_reply.started":"2025-02-15T08:25:26.139745Z","shell.execute_reply":"2025-02-15T08:25:27.572011Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\n# Define dataset directory\ndataset_dir = \"/kaggle/input/dog-breed-identification\"\n\n# List all files and folders inside the dataset directory\nfiles = os.listdir(dataset_dir)\nprint(files)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:27.573874Z","iopub.execute_input":"2025-02-15T08:25:27.574346Z","iopub.status.idle":"2025-02-15T08:25:27.579155Z","shell.execute_reply.started":"2025-02-15T08:25:27.574322Z","shell.execute_reply":"2025-02-15T08:25:27.578237Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# check out the labels of our data\nimport pandas as pd\n\n# Load labels.csv (contains image filenames and their corresponding breeds)\nlabels_df = pd.read_csv(\"/kaggle/input/dog-breed-identification/labels.csv\")\n\n# Display first few rows\nprint(labels_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:27.580285Z","iopub.execute_input":"2025-02-15T08:25:27.580591Z","iopub.status.idle":"2025-02-15T08:25:27.630333Z","shell.execute_reply.started":"2025-02-15T08:25:27.580560Z","shell.execute_reply":"2025-02-15T08:25:27.629710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_df[\"breed\"].value_counts().plot.bar(figsize=(20, 10))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:27.630988Z","iopub.execute_input":"2025-02-15T08:25:27.631175Z","iopub.status.idle":"2025-02-15T08:25:28.857242Z","shell.execute_reply.started":"2025-02-15T08:25:27.631158Z","shell.execute_reply":"2025-02-15T08:25:28.856335Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Getting images and their labels\n\nLet's get a list of all the image file pathnames.","metadata":{}},{"cell_type":"code","source":"# create pathnames from image's ID's\nfilenames = [\"/kaggle/input/dog-breed-identification/train/\" + fname + \".jpg\" for fname in labels_df[\"id\"]]\nfilenames[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:28.858168Z","iopub.execute_input":"2025-02-15T08:25:28.858451Z","iopub.status.idle":"2025-02-15T08:25:28.867729Z","shell.execute_reply.started":"2025-02-15T08:25:28.858426Z","shell.execute_reply":"2025-02-15T08:25:28.866919Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# check whether number of filenames matches number of actual image files\n\nimport os\nif len(os.listdir(\"/kaggle/input/dog-breed-identification/train/\")) == len(filenames):\n  print(\"Filenames match actual amount of files\")\nelse:\n  print(\"Filenames do not match actual amount of files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:28.868452Z","iopub.execute_input":"2025-02-15T08:25:28.868723Z","iopub.status.idle":"2025-02-15T08:25:29.944844Z","shell.execute_reply.started":"2025-02-15T08:25:28.868692Z","shell.execute_reply":"2025-02-15T08:25:29.943936Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_df[\"breed\"][9000]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:29.947888Z","iopub.execute_input":"2025-02-15T08:25:29.948139Z","iopub.status.idle":"2025-02-15T08:25:29.952772Z","shell.execute_reply.started":"2025-02-15T08:25:29.948118Z","shell.execute_reply":"2025-02-15T08:25:29.952170Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Since we have the training image as filepaths, lets prepare our labels.","metadata":{}},{"cell_type":"code","source":"import numpy as np\nlabels = labels_df[\"breed\"].to_numpy()\nlabels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:29.954291Z","iopub.execute_input":"2025-02-15T08:25:29.954498Z","iopub.status.idle":"2025-02-15T08:25:29.966684Z","shell.execute_reply.started":"2025-02-15T08:25:29.954479Z","shell.execute_reply":"2025-02-15T08:25:29.965994Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:29.967493Z","iopub.execute_input":"2025-02-15T08:25:29.967717Z","iopub.status.idle":"2025-02-15T08:25:29.978281Z","shell.execute_reply.started":"2025-02-15T08:25:29.967686Z","shell.execute_reply":"2025-02-15T08:25:29.977622Z"}},"outputs":[],"execution_count":null},{"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 does not match number of filenames\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:29.978955Z","iopub.execute_input":"2025-02-15T08:25:29.979235Z","iopub.status.idle":"2025-02-15T08:25:29.989304Z","shell.execute_reply.started":"2025-02-15T08:25:29.979208Z","shell.execute_reply":"2025-02-15T08:25:29.988667Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Find the unique label values\nunique_breeds = np.unique(labels)\nunique_breeds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:29.990003Z","iopub.execute_input":"2025-02-15T08:25:29.990191Z","iopub.status.idle":"2025-02-15T08:25:30.007225Z","shell.execute_reply.started":"2025-02-15T08:25:29.990174Z","shell.execute_reply":"2025-02-15T08:25:30.006543Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Turn a single label into an array of booleans\nprint(labels[0])\nlabels[0] == unique_breeds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.007978Z","iopub.execute_input":"2025-02-15T08:25:30.008209Z","iopub.status.idle":"2025-02-15T08:25:30.021035Z","shell.execute_reply.started":"2025-02-15T08:25:30.008187Z","shell.execute_reply":"2025-02-15T08:25:30.020389Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Turn every label into a boolean array\nboolean_labels = [label == unique_breeds for label in labels]\nboolean_labels[:2]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.021694Z","iopub.execute_input":"2025-02-15T08:25:30.021953Z","iopub.status.idle":"2025-02-15T08:25:30.083199Z","shell.execute_reply.started":"2025-02-15T08:25:30.021933Z","shell.execute_reply":"2025-02-15T08:25:30.082417Z"}},"outputs":[],"execution_count":null},{"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 1 in the index where the label occurs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.084029Z","iopub.execute_input":"2025-02-15T08:25:30.084255Z","iopub.status.idle":"2025-02-15T08:25:30.089785Z","shell.execute_reply.started":"2025-02-15T08:25:30.084236Z","shell.execute_reply":"2025-02-15T08:25:30.088879Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Creating my own validation set\n\nSince the dataset from kaggle does not come with a validation set, I am going to create one.","metadata":{}},{"cell_type":"code","source":"X = filenames\ny = boolean_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.090842Z","iopub.execute_input":"2025-02-15T08:25:30.091144Z","iopub.status.idle":"2025-02-15T08:25:30.100375Z","shell.execute_reply.started":"2025-02-15T08:25:30.091124Z","shell.execute_reply":"2025-02-15T08:25:30.099649Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Now, I am going to start off experimenting with ~1000 images and increase as needed","metadata":{}},{"cell_type":"code","source":"# Set number of images to use for experimentation\nNUM_IMAGES = 1000 #@param (type:\"slider\", min:1000, max:1000, step:1000)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.101078Z","iopub.execute_input":"2025-02-15T08:25:30.101273Z","iopub.status.idle":"2025-02-15T08:25:30.112407Z","shell.execute_reply.started":"2025-02-15T08:25:30.101255Z","shell.execute_reply":"2025-02-15T08:25:30.111693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# split into train and validation set\nfrom sklearn.model_selection import train_test_split\n\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)\nlen(X_train), len(y_train)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.113077Z","iopub.execute_input":"2025-02-15T08:25:30.113281Z","iopub.status.idle":"2025-02-15T08:25:30.490321Z","shell.execute_reply.started":"2025-02-15T08:25:30.113263Z","shell.execute_reply":"2025-02-15T08:25:30.489591Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Preprocessing Images (turning images into Tensors)\nTo preprocess our images into Tensors, we're going to write a function which does a few things:\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-225 to 0-1)\n5. Resize the image to be a shape of (224, 224)\n6. Return the modified image\n   \nLet's first see what importing an image looks like.\n","metadata":{}},{"cell_type":"code","source":"# convert image to numpy\nfrom matplotlib.pyplot import imread\nimage = imread(filenames[42])\nimage.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.491098Z","iopub.execute_input":"2025-02-15T08:25:30.491729Z","iopub.status.idle":"2025-02-15T08:25:30.505302Z","shell.execute_reply.started":"2025-02-15T08:25:30.491695Z","shell.execute_reply":"2025-02-15T08:25:30.504568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tf.constant(image)[:2]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.506167Z","iopub.execute_input":"2025-02-15T08:25:30.506485Z","iopub.status.idle":"2025-02-15T08:25:30.795233Z","shell.execute_reply.started":"2025-02-15T08:25:30.506443Z","shell.execute_reply":"2025-02-15T08:25:30.794528Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define image size\nIMG_SIZE = 224\n\n# Create a functon for preprocessing images\ndef process_image(image_path, img_size=IMG_SIZE):\n    \"\"\"\n    Takes an image file path and turns the image into a Tensor\n    \"\"\"\n    # Read in an image file\n    image = tf.io.read_file(image_path)\n    # Turn the jpeg into numerical Tensor with 3 color channels (Red, Green, Blue)\n    image = tf.image.decode_jpeg(image, channels=3)\n    # convert the color channel values from 0-225 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":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.796017Z","iopub.execute_input":"2025-02-15T08:25:30.796260Z","iopub.status.idle":"2025-02-15T08:25:30.801399Z","shell.execute_reply.started":"2025-02-15T08:25:30.796223Z","shell.execute_reply":"2025-02-15T08:25:30.800645Z"}},"outputs":[],"execution_count":null},{"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 (batch size) at a time which can be manually adjusted.\n\nTo effectively use TensorFlow, data needs to be in the form of Tensor tuples like this: (`image, label`).","metadata":{}},{"cell_type":"code","source":"# Create a simple function to return a tuple (image, label)\n\ndef get_image_label(image_path, label):\n    \"\"\"\n    Takes an image file path name and the associated label,\n    processes the image and returns a tuple of (image, label.\n    \"\"\"\n\n    image = process_image(image_path)\n    return image, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.802211Z","iopub.execute_input":"2025-02-15T08:25:30.802480Z","iopub.status.idle":"2025-02-15T08:25:30.815735Z","shell.execute_reply.started":"2025-02-15T08:25:30.802460Z","shell.execute_reply":"2025-02-15T08:25:30.815054Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# demo of the above\n(process_image(X[42]), y[42])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.816738Z","iopub.execute_input":"2025-02-15T08:25:30.817024Z","iopub.status.idle":"2025-02-15T08:25:30.858748Z","shell.execute_reply.started":"2025-02-15T08:25:30.816992Z","shell.execute_reply":"2025-02-15T08:25:30.858150Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Next thing to do is to make a function that turns the data(X & y) we have into batches!","metadata":{}},{"cell_type":"code","source":"# Define the batch size, 32 is a good start\nBATCH_SIZE = 32\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    Creates batches of data out of image (X) and label (y) pairs.\n    Shuffles the data if it's training data but does not 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 image path into a preprocessed image)\n            \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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.859453Z","iopub.execute_input":"2025-02-15T08:25:30.859698Z","iopub.status.idle":"2025-02-15T08:25:30.866089Z","shell.execute_reply.started":"2025-02-15T08:25:30.859678Z","shell.execute_reply":"2025-02-15T08:25:30.865357Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create training and validating data batches\ntrain_data = create_data_batches(X_train, y_train)\nval_data = create_data_batches(X_val, y_val, valid_data=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.866895Z","iopub.execute_input":"2025-02-15T08:25:30.867152Z","iopub.status.idle":"2025-02-15T08:25:30.987602Z","shell.execute_reply.started":"2025-02-15T08:25:30.867125Z","shell.execute_reply":"2025-02-15T08:25:30.986919Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Check out the differernt attributes of our data batches\n\ntrain_data.element_spec, val_data.element_spec","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.992157Z","iopub.execute_input":"2025-02-15T08:25:30.992365Z","iopub.status.idle":"2025-02-15T08:25:30.997046Z","shell.execute_reply.started":"2025-02-15T08:25:30.992347Z","shell.execute_reply":"2025-02-15T08:25:30.996234Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualizing Data Batches\n\nOur data is now in batches, however these can be a little hard to understand/comprehend, so let's visualize them","metadata":{}},{"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\n    a data batch\n    \"\"\"\n    # setup the figure\n    plt.figure(figsize=(10, 10))\n    # loop through 25 (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        # Displays 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":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:30.999594Z","iopub.execute_input":"2025-02-15T08:25:30.999901Z","iopub.status.idle":"2025-02-15T08:25:31.013611Z","shell.execute_reply.started":"2025-02-15T08:25:30.999840Z","shell.execute_reply":"2025-02-15T08:25:31.012916Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_images, train_labels = next(train_data.as_numpy_iterator())\ntrain_images, train_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:31.014248Z","iopub.execute_input":"2025-02-15T08:25:31.014440Z","iopub.status.idle":"2025-02-15T08:25:31.230127Z","shell.execute_reply.started":"2025-02-15T08:25:31.014414Z","shell.execute_reply":"2025-02-15T08:25:31.229337Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Now let's visualize the data in a training batch\nshow_25_images(train_images, train_labels)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:31.230956Z","iopub.execute_input":"2025-02-15T08:25:31.231258Z","iopub.status.idle":"2025-02-15T08:25:33.084555Z","shell.execute_reply.started":"2025-02-15T08:25:31.231226Z","shell.execute_reply":"2025-02-15T08:25:33.083363Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_images, val_labels = next(val_data.as_numpy_iterator())\nshow_25_images(val_images, val_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:33.085348Z","iopub.execute_input":"2025-02-15T08:25:33.085569Z","iopub.status.idle":"2025-02-15T08:25:34.891090Z","shell.execute_reply.started":"2025-02-15T08:25:33.085551Z","shell.execute_reply":"2025-02-15T08:25:34.889910Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Building our 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.","metadata":{}},{"cell_type":"code","source":"# # Setup input shape to the model\n# INPUT_SHAPE = [IMG_SIZE, IMG_SIZE, 3] #batch, height, width, color channels\n\n# # setup output shape of our model\n# OUTPUT_SHAPE = len(unique_breeds)\n\n# # setup model URL from TensorFlow Hub\n# MODEL_URL = \"https://tfhub.dev/google/tf2-preview/mobilenet_v2/feature_vector/4\"\n# # MODEL_URL = \"https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/4\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:34.892199Z","iopub.execute_input":"2025-02-15T08:25:34.892575Z","iopub.status.idle":"2025-02-15T08:25:34.896452Z","shell.execute_reply.started":"2025-02-15T08:25:34.892539Z","shell.execute_reply":"2025-02-15T08:25:34.895371Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Now we've got out inputs, outputs and  models ready to go.\nLet's put them together into a Keras deep learning model!\n\nLet's create a function which:\n\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 (aka do this first, then this, then that).\n* Compiles the model (says how 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 can be found here: https://www.tensorflow.org/guide/keras/overview","metadata":{}},{"cell_type":"code","source":"import tf_keras as keras","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:34.897290Z","iopub.execute_input":"2025-02-15T08:25:34.897551Z","iopub.status.idle":"2025-02-15T08:25:34.910267Z","shell.execute_reply.started":"2025-02-15T08:25:34.897530Z","shell.execute_reply":"2025-02-15T08:25:34.909255Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# # Create a function which builds a Keras model\n# def create_model(input_shape=INPUT_SHAPE, output_shape=OUTPUT_SHAPE, model_url=MODEL_URL):\n#     print(\"Building model with:\", model_url)\n\n#     # Setup the model layers\n#     model = keras.Sequential([\n#         hub.KerasLayer(model_url, input_shape=input_shape, trainable=False),  # Feature extractor layer\n#         keras.layers.Dense(units=output_shape, activation=\"softmax\")  # Output layer\n#     ])\n\n#     # Compile the model\n#     model.compile(\n#         loss=keras.losses.CategoricalCrossentropy(),\n#         optimizer=keras.optimizers.Adam(),\n#         metrics=[\"accuracy\"]\n#     )\n\n#     return model\n\n# # Build and summarize the model\n# model = create_model()\n# model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:34.911075Z","iopub.execute_input":"2025-02-15T08:25:34.911312Z","iopub.status.idle":"2025-02-15T08:25:34.922311Z","shell.execute_reply.started":"2025-02-15T08:25:34.911292Z","shell.execute_reply":"2025-02-15T08:25:34.921535Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"I want to try a new model URL because the above function returned a different figure to the dense layer in the function","metadata":{}},{"cell_type":"code","source":"# Setup input shape to the model\nINPUT_SHAPE = [None, IMG_SIZE, IMG_SIZE, 3] #batch, height, width, color 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_130_224/classification/4\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:34.923032Z","iopub.execute_input":"2025-02-15T08:25:34.923271Z","iopub.status.idle":"2025-02-15T08:25:34.938018Z","shell.execute_reply.started":"2025-02-15T08:25:34.923243Z","shell.execute_reply":"2025-02-15T08:25:34.937360Z"}},"outputs":[],"execution_count":null},{"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  # Setup the model layers\n  model = keras.Sequential([\n    hub.KerasLayer(MODEL_URL), # Layer 1 (input layer)\n    keras.layers.Dense(units=OUTPUT_SHAPE, \n                          activation=\"softmax\") # Layer 2 (output layer)\n  ])\n\n  # Compile the model\n  model.compile(\n      loss=keras.losses.CategoricalCrossentropy(), # Our model wants to reduce this (how wrong its guesses are)\n      optimizer=keras.optimizers.Adam(), # A friend telling our model how to improve its guesses\n      metrics=[\"accuracy\"] # We'd like this to go up\n  )\n\n  # Build the model\n  model.build(INPUT_SHAPE) # Let the model know what kind of inputs it'll be getting\n  \n  return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:34.938894Z","iopub.execute_input":"2025-02-15T08:25:34.939167Z","iopub.status.idle":"2025-02-15T08:25:34.951353Z","shell.execute_reply.started":"2025-02-15T08:25:34.939138Z","shell.execute_reply":"2025-02-15T08:25:34.950608Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a model and check its details\nmodel = create_model()\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:34.952132Z","iopub.execute_input":"2025-02-15T08:25:34.952402Z","iopub.status.idle":"2025-02-15T08:25:37.572458Z","shell.execute_reply.started":"2025-02-15T08:25:34.952374Z","shell.execute_reply":"2025-02-15T08:25:37.571793Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Okay, this second function is a better one to use as it returns same value with dense layers passed into the function and will allow for uniformity in future","metadata":{}},{"cell_type":"markdown","source":"## Creating callbacks\n\ncallbacks are helpful functions a model can use during training to do such thimgs such 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 whic helps tracks our model's progress and one 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.\n\n* Load the TensorBoard notebook extension\n* Create a TensorBoard callback which is able to save logs.\n* Create a TensorBoard callback which is able to save logs to a directory and pass it to our model's `fit()` function.\n* Visualoze our model's training logs with the `tensorboard` magic function(which is done after model training)","metadata":{}},{"cell_type":"code","source":"# Load TensorBoard notebook extension\nimport os\nos.makedirs(\"/kaggle/working/logs\", exist_ok=True)  # Create a log directory\n%load_ext tensorboard","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:37.573242Z","iopub.execute_input":"2025-02-15T08:25:37.573487Z","iopub.status.idle":"2025-02-15T08:25:37.594588Z","shell.execute_reply.started":"2025-02-15T08:25:37.573465Z","shell.execute_reply":"2025-02-15T08:25:37.593886Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls /kaggle/working/logs\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:37.595706Z","iopub.execute_input":"2025-02-15T08:25:37.596005Z","iopub.status.idle":"2025-02-15T08:25:37.742330Z","shell.execute_reply.started":"2025-02-15T08:25:37.595976Z","shell.execute_reply":"2025-02-15T08:25:37.741151Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"I am thinking it's best for this to be in a function that creates a new file with current date and time anytime it runs","metadata":{}},{"cell_type":"code","source":"import os\nimport datetime\nfrom tf_keras.callbacks import TensorBoard\n\ndef create_tensorboard_callback():\n    # Create a new log directory with a timestamp\n    logdir = os.path.join(\"/kaggle/working/logs\", \n                          datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\"))\n    \n    # Return a TensorBoard callback that saves logs to this directory\n    return TensorBoard(log_dir=logdir)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:37.743580Z","iopub.execute_input":"2025-02-15T08:25:37.743833Z","iopub.status.idle":"2025-02-15T08:25:37.748197Z","shell.execute_reply.started":"2025-02-15T08:25:37.743806Z","shell.execute_reply":"2025-02-15T08:25:37.747368Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Early Stopping Callback\n\nEarly stopping helps stop the model from overfitting by stopping training if a certain evaluation metric stops improving.","metadata":{}},{"cell_type":"code","source":"# Create early stopping call back\n\nearly_stopping = keras.callbacks.EarlyStopping(monitor=\"val_accuracy\",\n                                              patience=2,\n                                               min_delta=0.01,\n                                              restore_best_weights=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:37.749115Z","iopub.execute_input":"2025-02-15T08:25:37.749409Z","iopub.status.idle":"2025-02-15T08:25:37.759831Z","shell.execute_reply.started":"2025-02-15T08:25:37.749380Z","shell.execute_reply":"2025-02-15T08:25:37.759204Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training a model (on subset of data)\n\nThe first model is only going to train on 1000 images to make sure that everything is working.","metadata":{}},{"cell_type":"code","source":"NUM_EPOCHS = 100 #@param {type:\"slider\", min:10, max:100, step:10}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:37.760610Z","iopub.execute_input":"2025-02-15T08:25:37.760809Z","iopub.status.idle":"2025-02-15T08:25:37.771167Z","shell.execute_reply.started":"2025-02-15T08:25:37.760792Z","shell.execute_reply":"2025-02-15T08:25:37.770447Z"}},"outputs":[],"execution_count":null},{"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 the model passing it the training data, validation data, number of epochs to train for (`NUM_EPOCHS`) and the callbacks which are helper functions.\n* Return the model.","metadata":{}},{"cell_type":"code","source":"# Build a function to train and return a trained model\n\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 in 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 fitted model\n    return model\n\n# Fit the model to the data\nmodel = train_model()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:25:37.772181Z","iopub.execute_input":"2025-02-15T08:25:37.772459Z","iopub.status.idle":"2025-02-15T08:26:02.357836Z","shell.execute_reply.started":"2025-02-15T08:25:37.772432Z","shell.execute_reply":"2025-02-15T08:26:02.357075Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Question:** it looks like the model is overfitting because it is performing far better on the training dataset than the validation set, how can this be prevented in deep learning neural networks? \n\n**Note:** overfitting to begin with is a good thing! it means our model is learning!!","metadata":{}},{"cell_type":"markdown","source":"### Checking the TensorBoard Logs\n\nThe TensorBoard magic function (`%tensorboard`) will access the logs directory created earlier and visualize its content","metadata":{}},{"cell_type":"code","source":"!ls -lh /kaggle/working/logs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:02.358685Z","iopub.execute_input":"2025-02-15T08:26:02.358995Z","iopub.status.idle":"2025-02-15T08:26:02.531845Z","shell.execute_reply.started":"2025-02-15T08:26:02.358972Z","shell.execute_reply":"2025-02-15T08:26:02.531009Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%reload_ext tensorboard\n%tensorboard --logdir /kaggle/working/logs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:02.532922Z","iopub.execute_input":"2025-02-15T08:26:02.533194Z","iopub.status.idle":"2025-02-15T08:26:08.071304Z","shell.execute_reply.started":"2025-02-15T08:26:02.533153Z","shell.execute_reply":"2025-02-15T08:26:08.070568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!tensorboard dev upload --logdir /kaggle/working/logs \\\n    --name \"My Kaggle Experiment\" \\\n    --description \"Training logs for my model\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:08.072142Z","iopub.execute_input":"2025-02-15T08:26:08.072457Z","iopub.status.idle":"2025-02-15T08:26:12.426590Z","shell.execute_reply.started":"2025-02-15T08:26:08.072418Z","shell.execute_reply":"2025-02-15T08:26:12.425709Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Unfortunately, cannot figure out how to load Tensorboard in Kaggle. ","metadata":{}},{"cell_type":"markdown","source":"## Making and evaluating predictions using a trained model","metadata":{}},{"cell_type":"code","source":"# Make predictions on the validation data (not used to train on)\npredictions = model.predict(val_data, verbose=1)\npredictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:12.427628Z","iopub.execute_input":"2025-02-15T08:26:12.427878Z","iopub.status.idle":"2025-02-15T08:26:13.298270Z","shell.execute_reply.started":"2025-02-15T08:26:12.427840Z","shell.execute_reply":"2025-02-15T08:26:13.297541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.299182Z","iopub.execute_input":"2025-02-15T08:26:13.299505Z","iopub.status.idle":"2025-02-15T08:26:13.304100Z","shell.execute_reply.started":"2025-02-15T08:26:13.299473Z","shell.execute_reply":"2025-02-15T08:26:13.303417Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# First prediction\nindex = 0\nprint(predictions[index])\nprint(f\"Max value(probability of predictions): {np.max(predictions[index])}\")\nprint(f\"Sum: {np.sum(predictions[index])}\")\nprint(f\"Max index: {np.argmax(predictions[index])}\")\nprint(f\"Predicted label: {unique_breeds[np.argmax(predictions[index])]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.305059Z","iopub.execute_input":"2025-02-15T08:26:13.305346Z","iopub.status.idle":"2025-02-15T08:26:13.321260Z","shell.execute_reply.started":"2025-02-15T08:26:13.305317Z","shell.execute_reply":"2025-02-15T08:26:13.320320Z"}},"outputs":[],"execution_count":null},{"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 probability into their respective label(easier to understand)\n\ndef 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\n# Get a predicted label based on an array of prediction probabilities\npred_label = get_pred_label(predictions[11])\npred_label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.322246Z","iopub.execute_input":"2025-02-15T08:26:13.322533Z","iopub.status.idle":"2025-02-15T08:26:13.333699Z","shell.execute_reply.started":"2025-02-15T08:26:13.322503Z","shell.execute_reply":"2025-02-15T08:26:13.332905Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.334571Z","iopub.execute_input":"2025-02-15T08:26:13.334909Z","iopub.status.idle":"2025-02-15T08:26:13.344871Z","shell.execute_reply.started":"2025-02-15T08:26:13.334878Z","shell.execute_reply":"2025-02-15T08:26:13.344029Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Now since our validation data is in a batch dataset, we need to get them out of the batch and make predictions on the validation images and then compare those predictions to the validation labels (truth labels)","metadata":{}},{"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\n    returns separate arrays of image 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\n    return images, labels\n# Unbathify the validation data\nval_images, val_labels = unbatchify(val_data)\nval_images[0], val_labels[0]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.345673Z","iopub.execute_input":"2025-02-15T08:26:13.345911Z","iopub.status.idle":"2025-02-15T08:26:13.656839Z","shell.execute_reply.started":"2025-02-15T08:26:13.345889Z","shell.execute_reply":"2025-02-15T08:26:13.656139Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Now we've got ways to get:\n* Prediction labels\n* Validation labels\n* Validation images\n\nLet's make some function to make these all a bit  more visual.\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 integers.\n* Convert the preeiction probabilities to a predicted Label.\n* Plot the predicted label, it's predicted probability, thr 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 color 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, probablity 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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.657674Z","iopub.execute_input":"2025-02-15T08:26:13.657945Z","iopub.status.idle":"2025-02-15T08:26:13.662753Z","shell.execute_reply.started":"2025-02-15T08:26:13.657924Z","shell.execute_reply":"2025-02-15T08:26:13.661973Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_pred(prediction_probabilities=predictions,\n         labels=val_labels,\n         images=val_images,\n         n=100)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.663784Z","iopub.execute_input":"2025-02-15T08:26:13.664107Z","iopub.status.idle":"2025-02-15T08:26:13.847727Z","shell.execute_reply.started":"2025-02-15T08:26:13.664078Z","shell.execute_reply":"2025-02-15T08:26:13.846790Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Another function to view the model's top 10 predictions.\n\nThis function will:\n* Take an input of prediction probabilities array and a ground truth and an integer\n* Find the prediction using `get_pred_label()`\n* Find the top 10:\n  * Prediction probabilities indexes\n  * Prediction probabilites 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  Plots the top 10 highest prediction confidences along with\n  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  # Setup plot\n  top_plot = plt.bar(np.arange(len(top_10_pred_labels)), \n                     top_10_pred_values, \n                     color=\"grey\")\n  plt.xticks(np.arange(len(top_10_pred_labels)),\n             labels=top_10_pred_labels,\n             rotation=\"vertical\")\n\n  # Change 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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.848753Z","iopub.execute_input":"2025-02-15T08:26:13.849076Z","iopub.status.idle":"2025-02-15T08:26:13.855299Z","shell.execute_reply.started":"2025-02-15T08:26:13.849048Z","shell.execute_reply":"2025-02-15T08:26:13.854547Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_pred_conf(prediction_probabilities=predictions,\n               labels=val_labels,\n               n=9)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:13.856164Z","iopub.execute_input":"2025-02-15T08:26:13.856363Z","iopub.status.idle":"2025-02-15T08:26:14.037514Z","shell.execute_reply.started":"2025-02-15T08:26:13.856343Z","shell.execute_reply":"2025-02-15T08:26:14.036826Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Now that there are functions to help visualize the predictions and evaluate the model, let's check out few predictions.","metadata":{}},{"cell_type":"code","source":"# Let's check a few predictions and their different values\ni_multiplier = 0\nnum_rows = 3\nnum_cols = 2\nnum_images = num_rows*num_cols\nplt.figure(figsize=(5*2*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":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:26:14.038278Z","iopub.execute_input":"2025-02-15T08:26:14.038501Z","iopub.status.idle":"2025-02-15T08:26:15.492792Z","shell.execute_reply.started":"2025-02-15T08:26:14.038471Z","shell.execute_reply":"2025-02-15T08:26:15.491883Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Saving and Reloading a trained model","metadata":{}},{"cell_type":"code","source":"# # Create a function to save a trained model\n# def save_model(model, suffix=None):\n#     \"\"\"\n#     Saves a given model in a model's directory and appends a suffix (string).\n#     \"\"\"\n#     # crate a model directory pathname with current time\n#     modeldir = os.path.join(\"/kaggle/working/models\",\n#                            datetime.datetime.now().strftime(\"%Y%m%d-%H%M%s\"))\n#     model_path = modeldir + \"-\" + suffix + \".keras\" # Save format of model\n#     print(f\"Saving model to: {model_path}...\")\n#     model.save(model_path)\n#     return model_path\n\n\n# Create a function to save a trained model\ndef save_model(model, suffix=None):\n    \"\"\"\n    Saves a given model in a model's directory and appends a suffix (string).\n    \"\"\"\n    # Define the model directory\n    modeldir = os.path.join(\"/kaggle/working/models\")\n    \n    # Check if the directory exists, if not, create it\n    if not os.path.exists(modeldir):\n        os.makedirs(modeldir)\n\n    # Create a unique model file path with timestamp and suffix\n    model_path = os.path.join(modeldir, datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\") + \"-\" + suffix + \".keras\")\n    \n    print(f\"Saving model to: {model_path}...\")\n    model.save(model_path)\n\n    return model_path\n\n# Save the model trained on 1000 images\nsave_model(model, suffix=\"1000-images-mobilenetv2-Adam\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:31:49.162156Z","iopub.execute_input":"2025-02-15T08:31:49.162533Z","iopub.status.idle":"2025-02-15T08:31:49.398177Z","shell.execute_reply.started":"2025-02-15T08:31:49.162503Z","shell.execute_reply":"2025-02-15T08:31:49.397418Z"}},"outputs":[],"execution_count":null},{"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 = keras.models.load_model(model_path,\n                                   custom_objects={\"KerasLayer\":hub.KerasLayer})\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:32:06.489959Z","iopub.execute_input":"2025-02-15T08:32:06.490304Z","iopub.status.idle":"2025-02-15T08:32:06.494630Z","shell.execute_reply.started":"2025-02-15T08:32:06.490273Z","shell.execute_reply":"2025-02-15T08:32:06.493801Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load trained model\nload_image_model = load_model(\"/kaggle/working/models/20250215-083149-1000-images-mobilenetv2-Adam.keras\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:32:46.298222Z","iopub.execute_input":"2025-02-15T08:32:46.298542Z","iopub.status.idle":"2025-02-15T08:32:49.392422Z","shell.execute_reply.started":"2025-02-15T08:32:46.298520Z","shell.execute_reply":"2025-02-15T08:32:49.391483Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Evaluate a pre-saved model\nmodel.evaluate(val_data)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:33:46.476199Z","iopub.execute_input":"2025-02-15T08:33:46.476504Z","iopub.status.idle":"2025-02-15T08:33:46.886669Z","shell.execute_reply.started":"2025-02-15T08:33:46.476481Z","shell.execute_reply":"2025-02-15T08:33:46.886020Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training a big dog model (on the full data)","metadata":{}},{"cell_type":"code","source":"len(X), len(y)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:00.776846Z","iopub.execute_input":"2025-02-15T08:34:00.777196Z","iopub.status.idle":"2025-02-15T08:34:00.783053Z","shell.execute_reply.started":"2025-02-15T08:34:00.777168Z","shell.execute_reply":"2025-02-15T08:34:00.782056Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:03.284526Z","iopub.execute_input":"2025-02-15T08:34:03.284967Z","iopub.status.idle":"2025-02-15T08:34:03.291210Z","shell.execute_reply.started":"2025-02-15T08:34:03.284927Z","shell.execute_reply":"2025-02-15T08:34:03.289920Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a data batch with the full dataset\nfull_data = create_data_batches(X, y)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:07.145414Z","iopub.execute_input":"2025-02-15T08:34:07.145701Z","iopub.status.idle":"2025-02-15T08:34:07.218331Z","shell.execute_reply.started":"2025-02-15T08:34:07.145679Z","shell.execute_reply":"2025-02-15T08:34:07.217621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:15.351294Z","iopub.execute_input":"2025-02-15T08:34:15.351589Z","iopub.status.idle":"2025-02-15T08:34:15.356991Z","shell.execute_reply.started":"2025-02-15T08:34:15.351565Z","shell.execute_reply":"2025-02-15T08:34:15.356124Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a model for full_model\nfull_model = create_model()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:19.817778Z","iopub.execute_input":"2025-02-15T08:34:19.818102Z","iopub.status.idle":"2025-02-15T08:34:21.574819Z","shell.execute_reply.started":"2025-02-15T08:34:19.818078Z","shell.execute_reply":"2025-02-15T08:34:21.574145Z"}},"outputs":[],"execution_count":null},{"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 = keras.callbacks.EarlyStopping(monitor=\"accuracy\",\n                                                         patience=2,\n                                                         min_delta=0.01,\n                                                         restore_best_weights=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:25.956817Z","iopub.execute_input":"2025-02-15T08:34:25.957195Z","iopub.status.idle":"2025-02-15T08:34:25.961408Z","shell.execute_reply.started":"2025-02-15T08:34:25.957163Z","shell.execute_reply":"2025-02-15T08:34:25.960512Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Note:** Running the cell below will take a little while because the GPU has to load all 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":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:34:41.417236Z","iopub.execute_input":"2025-02-15T08:34:41.417644Z","iopub.status.idle":"2025-02-15T08:37:17.555364Z","shell.execute_reply.started":"2025-02-15T08:34:41.417607Z","shell.execute_reply":"2025-02-15T08:37:17.554560Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"save_model(full_model, suffix=\"full-image-set-mobilenetv2-Adam\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:38:20.407923Z","iopub.execute_input":"2025-02-15T08:38:20.408246Z","iopub.status.idle":"2025-02-15T08:38:20.604588Z","shell.execute_reply.started":"2025-02-15T08:38:20.408223Z","shell.execute_reply":"2025-02-15T08:38:20.603917Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load in the full model\nloaded_full_model = load_model(\"/kaggle/working/models/20250215-083820-full-image-set-mobilenetv2-Adam.keras\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:38:39.087317Z","iopub.execute_input":"2025-02-15T08:38:39.087632Z","iopub.status.idle":"2025-02-15T08:38:41.583819Z","shell.execute_reply.started":"2025-02-15T08:38:39.087608Z","shell.execute_reply":"2025-02-15T08:38:41.583047Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Making predictions on the test dataset\n\nSince the  model was 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\nLuckily, we created `create_data_batches()` which can take a list of filenames as input and convert them into Tensor batches.\n\nTo make predictions on the test data, we'll:\n* Get the test image filenames\n* Convert the filenames into 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":{"execution":{"iopub.status.busy":"2025-02-14T09:29:51.182928Z","iopub.execute_input":"2025-02-14T09:29:51.183325Z","iopub.status.idle":"2025-02-14T09:29:51.188970Z","shell.execute_reply.started":"2025-02-14T09:29:51.183298Z","shell.execute_reply":"2025-02-14T09:29:51.188193Z"}}},{"cell_type":"code","source":"# Load test image filenames\ntest_path = \"/kaggle/input/dog-breed-identification/test/\"\ntest_filename = [test_path + fname for fname in os.listdir(test_path)]\ntest_filename[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:38:48.215745Z","iopub.execute_input":"2025-02-15T08:38:48.216086Z","iopub.status.idle":"2025-02-15T08:38:49.129771Z","shell.execute_reply.started":"2025-02-15T08:38:48.216058Z","shell.execute_reply":"2025-02-15T08:38:49.129051Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(test_filename)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:38:52.412789Z","iopub.execute_input":"2025-02-15T08:38:52.413145Z","iopub.status.idle":"2025-02-15T08:38:52.418150Z","shell.execute_reply.started":"2025-02-15T08:38:52.413111Z","shell.execute_reply":"2025-02-15T08:38:52.417378Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create test data batch\ntest_data = create_data_batches(test_filename,test_data=True )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:38:55.626991Z","iopub.execute_input":"2025-02-15T08:38:55.627396Z","iopub.status.idle":"2025-02-15T08:38:55.654533Z","shell.execute_reply.started":"2025-02-15T08:38:55.627363Z","shell.execute_reply":"2025-02-15T08:38:55.653659Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:38:58.656678Z","iopub.execute_input":"2025-02-15T08:38:58.657019Z","iopub.status.idle":"2025-02-15T08:38:58.662004Z","shell.execute_reply.started":"2025-02-15T08:38:58.656988Z","shell.execute_reply":"2025-02-15T08:38:58.661177Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Note:** Calling `predict()` on the full model and passing it the test data batch will take a long time to run. ","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":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:02.176815Z","iopub.execute_input":"2025-02-15T08:39:02.177170Z","iopub.status.idle":"2025-02-15T08:39:30.596374Z","shell.execute_reply.started":"2025-02-15T08:39:02.177142Z","shell.execute_reply":"2025-02-15T08:39:30.595647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save predictions (Numpy Array) to csv file (for access later)\nnp.savetxt(\"/kaggle/working/preds_array.csv\", test_predictions, delimiter=\",\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:39.146991Z","iopub.execute_input":"2025-02-15T08:39:39.147299Z","iopub.status.idle":"2025-02-15T08:39:40.201570Z","shell.execute_reply.started":"2025-02-15T08:39:39.147275Z","shell.execute_reply":"2025-02-15T08:39:40.200589Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load predictions (Numpy array) from csv file\ntest_predictions = np.loadtxt(\"/kaggle/working/preds_array.csv\", delimiter=\",\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:43.846925Z","iopub.execute_input":"2025-02-15T08:39:43.847240Z","iopub.status.idle":"2025-02-15T08:39:44.359255Z","shell.execute_reply.started":"2025-02-15T08:39:43.847217Z","shell.execute_reply":"2025-02-15T08:39:44.358208Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_predictions[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:47.497149Z","iopub.execute_input":"2025-02-15T08:39:47.497435Z","iopub.status.idle":"2025-02-15T08:39:47.503596Z","shell.execute_reply.started":"2025-02-15T08:39:47.497410Z","shell.execute_reply":"2025-02-15T08:39:47.502885Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_predictions.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:51.532228Z","iopub.execute_input":"2025-02-15T08:39:51.532516Z","iopub.status.idle":"2025-02-15T08:39:51.538352Z","shell.execute_reply.started":"2025-02-15T08:39:51.532493Z","shell.execute_reply":"2025-02-15T08:39:51.537455Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Preparing kaggle test dataset predictions\n\n* Create a pandas DataFrame with an ID column as well as column for each dog breed.\n* Add data to tge ID column by etracting the test image ID's from their filepaths.\n* Add data (the prediction probabilities) to each of the dog breed columnms.\n* Export the DataFrame as a CSV ","metadata":{}},{"cell_type":"code","source":"[\"id\"] + list(unique_breeds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:54.967700Z","iopub.execute_input":"2025-02-15T08:39:54.968056Z","iopub.status.idle":"2025-02-15T08:39:54.974288Z","shell.execute_reply.started":"2025-02-15T08:39:54.968025Z","shell.execute_reply":"2025-02-15T08:39:54.973541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a pandas DataFrame with empty columns\npreds_df = pd.DataFrame(columns=[\"id\"] + list(unique_breeds))\npreds_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:39:58.277155Z","iopub.execute_input":"2025-02-15T08:39:58.277604Z","iopub.status.idle":"2025-02-15T08:39:58.303879Z","shell.execute_reply.started":"2025-02-15T08:39:58.277558Z","shell.execute_reply":"2025-02-15T08:39:58.303025Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:40:01.575705Z","iopub.execute_input":"2025-02-15T08:40:01.576052Z","iopub.status.idle":"2025-02-15T08:40:01.603263Z","shell.execute_reply.started":"2025-02-15T08:40:01.576014Z","shell.execute_reply":"2025-02-15T08:40:01.602559Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:40:05.469816Z","iopub.execute_input":"2025-02-15T08:40:05.470181Z","iopub.status.idle":"2025-02-15T08:40:05.487248Z","shell.execute_reply.started":"2025-02-15T08:40:05.470155Z","shell.execute_reply":"2025-02-15T08:40:05.486343Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Add the prediction probabilities to each dog breed column\npreds_df[list(unique_breeds)] = test_predictions\npreds_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-15T08:40:08.584716Z","iopub.execute_input":"2025-02-15T08:40:08.585080Z","iopub.status.idle":"2025-02-15T08:40:08.635862Z","shell.execute_reply.started":"2025-02-15T08:40:08.585048Z","shell.execute_reply":"2025-02-15T08:40:08.635148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}