{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Dog Breed Identfication\nThis notebook builds an end-to-end multi-class image classifier using TensorFlow and TensorFlow Hub.\n\n## 1. Problem\n> Identifying the breed of a dog given an image of a dog\n## 2. Data\n> As Data we are using Kaggle's Dog breed identification. You can find it here\nhttps://www.kaggle.com/competitions/dog-breed-identification\n\n## 3. Evaluation\n\n>The evaluation is a file with prediction probabilities for each dog breed of each test image\n\n## 4. Features\n> Some information about the data:\n* We are dealing with images (Unstructured Data) so it's probably best we use deep learning / transfer learning.\n* There are 120 breeds of Dogs which means it has  120 different classes.\n* There are around 10k+ test images and 10k+ train images","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2025-09-13T06:24:10.133882Z","iopub.execute_input":"2025-09-13T06:24:10.134160Z","iopub.status.idle":"2025-09-13T06:24:10.144275Z","shell.execute_reply.started":"2025-09-13T06:24:10.134132Z","shell.execute_reply":"2025-09-13T06:24:10.142733Z"}}},{"cell_type":"markdown","source":"### Get our workspace ready\n\n\n","metadata":{}},{"cell_type":"code","source":"#import necessary tools\nimport tensorflow as tf\nimport tensorflow_hub as hub\nprint(tf.__version__)\n\n#Check for GPU availability\nprint(tf.config.list_physical_devices(\"GPU\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:49:21.117385Z","iopub.execute_input":"2025-09-13T11:49:21.117656Z","iopub.status.idle":"2025-09-13T11:49:38.244534Z","shell.execute_reply.started":"2025-09-13T11:49:21.117635Z","shell.execute_reply":"2025-09-13T11:49:38.243761Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Getting our data ready (Turning into tensors)\nWith all machine learning models our data has to be in numerical format,So that's what we will be doing first. Turning our images into tensors/numerical representations:\n\nLet's start by accessing our data and checking out the labels","metadata":{}},{"cell_type":"code","source":"#checkout the labels of our data\nimport pandas as pd\n\nlabels_csv = pd.read_csv(\"/kaggle/input/dog-breed-identification/labels.csv\")\nprint(labels_csv.describe())\nlabels_csv.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:49:38.245707Z","iopub.execute_input":"2025-09-13T11:49:38.246173Z","iopub.status.idle":"2025-09-13T11:49:38.312756Z","shell.execute_reply.started":"2025-09-13T11:49:38.246155Z","shell.execute_reply":"2025-09-13T11:49:38.312211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_csv[\"breed\"].value_counts().plot.bar(figsize=(20,5))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:49:38.313456Z","iopub.execute_input":"2025-09-13T11:49:38.313702Z","iopub.status.idle":"2025-09-13T11:49:39.361405Z","shell.execute_reply.started":"2025-09-13T11:49:38.313683Z","shell.execute_reply":"2025-09-13T11:49:39.360706Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Let's view an image\nfrom IPython.display import Image\nImage(\"/kaggle/input/dog-breed-identification/train/000bec180eb18c7604dcecc8fe0dba07.jpg\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:49:39.362620Z","iopub.execute_input":"2025-09-13T11:49:39.363302Z","iopub.status.idle":"2025-09-13T11:49:39.374833Z","shell.execute_reply.started":"2025-09-13T11:49:39.363283Z","shell.execute_reply":"2025-09-13T11:49:39.374266Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Getting images and their labels\nLet's get a list of all our imagen file pathnames","metadata":{}},{"cell_type":"code","source":"# Create pathnames from image Id\nfilename = [\"/kaggle/input/dog-breed-identification/train/\" + fname + \".jpg\" for fname in labels_csv[\"id\"]]\nfilename[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:49:39.375600Z","iopub.execute_input":"2025-09-13T11:49:39.375836Z","iopub.status.idle":"2025-09-13T11:49:39.383640Z","shell.execute_reply.started":"2025-09-13T11:49:39.375811Z","shell.execute_reply":"2025-09-13T11:49:39.382885Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Lets' check whether filenames matches actual amount of files\nimport os\nif len(os.listdir(\"/kaggle/input/dog-breed-identification/train\")) == len(filename):\n  print(\"Success\")\nelse:\n  print(\"Check again\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:49:39.384283Z","iopub.execute_input":"2025-09-13T11:49:39.384460Z","iopub.status.idle":"2025-09-13T11:49:39.397675Z","shell.execute_reply.started":"2025-09-13T11:49:39.384445Z","shell.execute_reply":"2025-09-13T11:49:39.397015Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Image(filename[200])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:50:05.625593Z","iopub.execute_input":"2025-09-13T11:50:05.626416Z","iopub.status.idle":"2025-09-13T11:50:05.652829Z","shell.execute_reply.started":"2025-09-13T11:50:05.626384Z","shell.execute_reply":"2025-09-13T11:50:05.652151Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Since we have now got our training image file paths in a list, let's prepare our labels","metadata":{}},{"cell_type":"code","source":"import numpy as np\nlabels = labels_csv[\"breed\"].to_numpy()\nlen(labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:50:35.584728Z","iopub.execute_input":"2025-09-13T11:50:35.585519Z","iopub.status.idle":"2025-09-13T11:50:35.591399Z","shell.execute_reply.started":"2025-09-13T11:50:35.585498Z","shell.execute_reply":"2025-09-13T11:50:35.590418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# See if number of labels matches the number of filenames\nif len(labels) == len(filename):\n  print(\"Number of labels matches number of filenames!\")\nelse:\n  print(\"Number of labels does not match number of filenames, check data directories!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:50:46.014801Z","iopub.execute_input":"2025-09-13T11:50:46.015361Z","iopub.status.idle":"2025-09-13T11:50:46.019402Z","shell.execute_reply.started":"2025-09-13T11:50:46.015338Z","shell.execute_reply":"2025-09-13T11:50:46.018747Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Find the unique label values\nunique_breeds = np.unique(labels)\nlen(unique_breeds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:50:54.953014Z","iopub.execute_input":"2025-09-13T11:50:54.953306Z","iopub.status.idle":"2025-09-13T11:50:54.964559Z","shell.execute_reply.started":"2025-09-13T11:50:54.953286Z","shell.execute_reply":"2025-09-13T11:50:54.963889Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"unique_breeds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:51:14.670989Z","iopub.execute_input":"2025-09-13T11:51:14.671276Z","iopub.status.idle":"2025-09-13T11:51:14.676378Z","shell.execute_reply.started":"2025-09-13T11:51:14.671255Z","shell.execute_reply":"2025-09-13T11:51:14.675750Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Turn every labels into a boolean array\nboolean_labels = [labels == unique_breeds for labels in labels]\nboolean_labels[2]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:51:29.324895Z","iopub.execute_input":"2025-09-13T11:51:29.325425Z","iopub.status.idle":"2025-09-13T11:51:29.379430Z","shell.execute_reply.started":"2025-09-13T11:51:29.325403Z","shell.execute_reply":"2025-09-13T11:51:29.378894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:51:35.805927Z","iopub.execute_input":"2025-09-13T11:51:35.806562Z","iopub.status.idle":"2025-09-13T11:51:35.810708Z","shell.execute_reply.started":"2025-09-13T11:51:35.806540Z","shell.execute_reply":"2025-09-13T11:51:35.810141Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"boolean_labels = [label == unique_breeds for label in labels]\nprint(boolean_labels[0].astype(int))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:51:43.995530Z","iopub.execute_input":"2025-09-13T11:51:43.995762Z","iopub.status.idle":"2025-09-13T11:51:44.054071Z","shell.execute_reply.started":"2025-09-13T11:51:43.995747Z","shell.execute_reply":"2025-09-13T11:51:44.053504Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"boolean_labels[:2]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:51:50.663170Z","iopub.execute_input":"2025-09-13T11:51:50.663425Z","iopub.status.idle":"2025-09-13T11:51:50.668264Z","shell.execute_reply.started":"2025-09-13T11:51:50.663406Z","shell.execute_reply":"2025-09-13T11:51:50.667723Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(boolean_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:52:17.775615Z","iopub.execute_input":"2025-09-13T11:52:17.775880Z","iopub.status.idle":"2025-09-13T11:52:17.780639Z","shell.execute_reply.started":"2025-09-13T11:52:17.775862Z","shell.execute_reply":"2025-09-13T11:52:17.779885Z"}},"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 a 1 where the sample label occurs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:52:35.419571Z","iopub.execute_input":"2025-09-13T11:52:35.420121Z","iopub.status.idle":"2025-09-13T11:52:35.425936Z","shell.execute_reply.started":"2025-09-13T11:52:35.420096Z","shell.execute_reply":"2025-09-13T11:52:35.424971Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(labels[2])\nprint(boolean_labels[2].astype(int))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:52:44.771138Z","iopub.execute_input":"2025-09-13T11:52:44.771613Z","iopub.status.idle":"2025-09-13T11:52:44.775739Z","shell.execute_reply.started":"2025-09-13T11:52:44.771593Z","shell.execute_reply":"2025-09-13T11:52:44.775078Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"boolean_labels[:3]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:52:51.478656Z","iopub.execute_input":"2025-09-13T11:52:51.479236Z","iopub.status.idle":"2025-09-13T11:52:51.484268Z","shell.execute_reply.started":"2025-09-13T11:52:51.479213Z","shell.execute_reply":"2025-09-13T11:52:51.483488Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"filename[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:52:57.735350Z","iopub.execute_input":"2025-09-13T11:52:57.736049Z","iopub.status.idle":"2025-09-13T11:52:57.740701Z","shell.execute_reply.started":"2025-09-13T11:52:57.736006Z","shell.execute_reply":"2025-09-13T11:52:57.740051Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Setting our very own validation set\nAs kaggle dataset doesn't provide us with any validation set, we are going to create our own\n\n---\n\n","metadata":{}},{"cell_type":"code","source":"#Setup X & y variables\nX = filename\ny = boolean_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:53:19.677010Z","iopub.execute_input":"2025-09-13T11:53:19.677304Z","iopub.status.idle":"2025-09-13T11:53:19.680760Z","shell.execute_reply.started":"2025-09-13T11:53:19.677282Z","shell.execute_reply":"2025-09-13T11:53:19.680059Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(filename)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:53:31.640251Z","iopub.execute_input":"2025-09-13T11:53:31.640514Z","iopub.status.idle":"2025-09-13T11:53:31.645233Z","shell.execute_reply.started":"2025-09-13T11:53:31.640495Z","shell.execute_reply":"2025-09-13T11:53:31.644567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set number of images to use for experimenting\nNUM_IMAGES = 1000 #@param {type:\"slider\", min:1000, max:10000}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:53:38.504494Z","iopub.execute_input":"2025-09-13T11:53:38.505021Z","iopub.status.idle":"2025-09-13T11:53:38.508364Z","shell.execute_reply.started":"2025-09-13T11:53:38.504999Z","shell.execute_reply":"2025-09-13T11:53:38.507666Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Let's split the data into train and validation\nfrom sklearn.model_selection import train_test_split\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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:53:45.007494Z","iopub.execute_input":"2025-09-13T11:53:45.007744Z","iopub.status.idle":"2025-09-13T11:53:45.168321Z","shell.execute_reply.started":"2025-09-13T11:53:45.007725Z","shell.execute_reply":"2025-09-13T11:53:45.167782Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(X_train), len(y_train), len(X_val), len(y_val)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:53:51.715797Z","iopub.execute_input":"2025-09-13T11:53:51.716102Z","iopub.status.idle":"2025-09-13T11:53:51.721321Z","shell.execute_reply.started":"2025-09-13T11:53:51.716079Z","shell.execute_reply":"2025-09-13T11:53:51.720589Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Define Image size\nIMG_SIZE = 224\n\n#Creating a functon to preprocess the images\ndef process_image(image_path):\n  image = tf.io.read_file(image_path)\n  image = tf.image.decode_jpeg(image, channels=3)\n  image = tf.image.convert_image_dtype(image, tf.float32)\n  image = tf.image.resize(image, size=[IMG_SIZE, IMG_SIZE])\n\n  return image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:53:59.431255Z","iopub.execute_input":"2025-09-13T11:53:59.431510Z","iopub.status.idle":"2025-09-13T11:53:59.435622Z","shell.execute_reply.started":"2025-09-13T11:53:59.431492Z","shell.execute_reply":"2025-09-13T11:53:59.435073Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Turning our data into batches","metadata":{"execution":{"iopub.status.busy":"2025-09-13T11:54:05.037917Z","iopub.execute_input":"2025-09-13T11:54:05.038673Z","iopub.status.idle":"2025-09-13T11:54:05.041952Z","shell.execute_reply.started":"2025-09-13T11:54:05.038647Z","shell.execute_reply":"2025-09-13T11:54:05.041197Z"}}},{"cell_type":"code","source":"#Create a function to return a tuple (image, label)\ndef get_image_label(image_path, label):\n  image = process_image(image_path)\n  return image, label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:54:18.144133Z","iopub.execute_input":"2025-09-13T11:54:18.144393Z","iopub.status.idle":"2025-09-13T11:54:18.148176Z","shell.execute_reply.started":"2025-09-13T11:54:18.144375Z","shell.execute_reply":"2025-09-13T11:54:18.147540Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define the batch size, 32 is a good default\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 doesn't shuffle it 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\n    data_batch = data.map(process_image).batch(BATCH_SIZE)\n    return data_batch\n\n  # If the data if 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    # If the data is a training dataset, we shuffle it\n    print(\"Creating training data batches...\")\n    # Turn filepaths and labels into Tensors\n    data = tf.data.Dataset.from_tensor_slices((tf.constant(x), # filepaths\n                                              tf.constant(y))) # labels\n\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    data = data.map(get_image_label)\n\n    # Turn the data into batches\n    data_batch = data.batch(BATCH_SIZE)\n  return data_batch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:54:25.483899Z","iopub.execute_input":"2025-09-13T11:54:25.484460Z","iopub.status.idle":"2025-09-13T11:54:25.490850Z","shell.execute_reply.started":"2025-09-13T11:54:25.484437Z","shell.execute_reply":"2025-09-13T11:54:25.490214Z"}},"outputs":[],"execution_count":null},{"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":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:54:31.880257Z","iopub.execute_input":"2025-09-13T11:54:31.880741Z","iopub.status.idle":"2025-09-13T11:54:32.269642Z","shell.execute_reply.started":"2025-09-13T11:54:31.880720Z","shell.execute_reply":"2025-09-13T11:54:32.268887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data.element_spec, val_data.element_spec","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:54:42.791536Z","iopub.execute_input":"2025-09-13T11:54:42.792170Z","iopub.status.idle":"2025-09-13T11:54:42.796795Z","shell.execute_reply.started":"2025-09-13T11:54:42.792149Z","shell.execute_reply":"2025-09-13T11:54:42.796077Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualizing Data Batches\nOur data is now in batches, these can be hard to understand, So we will try to visualize them","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef show_25_images(images, labels):\n  plt.figure(figsize=(10,10))\n  for i in range (25):\n    ax = plt.subplot(5, 5, i+1)\n    plt.imshow(images[i])\n    plt.title(unique_breeds[labels[i]])\n    plt.axis(\"off\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:54:58.366656Z","iopub.execute_input":"2025-09-13T11:54:58.366903Z","iopub.status.idle":"2025-09-13T11:54:58.371376Z","shell.execute_reply.started":"2025-09-13T11:54:58.366885Z","shell.execute_reply":"2025-09-13T11:54:58.370632Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_images, train_lables = next(train_data.as_numpy_iterator())\ntrain_images, train_lables","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:55:03.448484Z","iopub.execute_input":"2025-09-13T11:55:03.449162Z","iopub.status.idle":"2025-09-13T11:55:03.681647Z","shell.execute_reply.started":"2025-09-13T11:55:03.449138Z","shell.execute_reply":"2025-09-13T11:55:03.681038Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Let's visualize the data\nshow_25_images(train_images, train_lables)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:55:10.869142Z","iopub.execute_input":"2025-09-13T11:55:10.869377Z","iopub.status.idle":"2025-09-13T11:55:12.375337Z","shell.execute_reply.started":"2025-09-13T11:55:10.869362Z","shell.execute_reply":"2025-09-13T11:55:12.374521Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_images, val_lables = next(val_data.as_numpy_iterator())\nval_images, val_lables","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:55:23.957320Z","iopub.execute_input":"2025-09-13T11:55:23.957597Z","iopub.status.idle":"2025-09-13T11:55:24.126708Z","shell.execute_reply.started":"2025-09-13T11:55:23.957568Z","shell.execute_reply":"2025-09-13T11:55:24.125922Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"show_25_images(val_images, val_lables)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:55:31.356506Z","iopub.execute_input":"2025-09-13T11:55:31.356780Z","iopub.status.idle":"2025-09-13T11:55:33.123242Z","shell.execute_reply.started":"2025-09-13T11:55:31.356759Z","shell.execute_reply":"2025-09-13T11:55:33.122509Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Building a model\n\n","metadata":{}},{"cell_type":"code","source":"import tf_keras as keras                # <-- use tf-keras API\nfrom tensorflow_hub import KerasLayer\n\nINPUT_SHAPE = (IMG_SIZE, IMG_SIZE, 3)\nOUTPUT_SHAPE = len(unique_breeds)\nMODEL_URL = \"https://tfhub.dev/google/imagenet/mobilenet_v2_100_224/feature_vector/5\"  # use feature_vector model that accepts 224x224 input\n\ndef create_model(input_shape=INPUT_SHAPE, output_shape=OUTPUT_SHAPE, model_url=MODEL_URL):\n    print(\"Building with:\", model_url)\n    model = keras.Sequential([\n        KerasLayer(model_url, input_shape=input_shape, trainable=False),  # freeze base\n        keras.layers.Dense(output_shape, activation=\"softmax\")\n    ])\n    model.compile(\n        loss=keras.losses.CategoricalCrossentropy(),\n        optimizer=keras.optimizers.Adam(),\n        metrics=[\"accuracy\"]\n    )\n    return model\n\nmodel = create_model()\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T11:56:13.184572Z","iopub.execute_input":"2025-09-13T11:56:13.184842Z","iopub.status.idle":"2025-09-13T11:56:18.025880Z","shell.execute_reply.started":"2025-09-13T11:56:13.184814Z","shell.execute_reply":"2025-09-13T11:56:18.025074Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Creating Callbacks\n\nCallbacks helps us as a function for our model that can be used during training for things such as save progress, check its progress\n\n### Tensoboard Callback","metadata":{}},{"cell_type":"code","source":"import datetime\ndef create_tensorboard_callback():\n  logdir = os.path.join(\"/content/drive/MyDrive/Dog Breed Identificattion/logs\", datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\"))\n\n  return tf.keras.callbacks.TensorBoard(logdir)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:09:09.583270Z","iopub.execute_input":"2025-09-13T12:09:09.583852Z","iopub.status.idle":"2025-09-13T12:09:09.587731Z","shell.execute_reply.started":"2025-09-13T12:09:09.583829Z","shell.execute_reply":"2025-09-13T12:09:09.586916Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Early stopping callback\nEarly stopping helps stop our model from overfitting by stopping training if a certain evaluation metrics stops improving","metadata":{}},{"cell_type":"code","source":"#creating early stopping callback\nearly_stopping = tf.keras.callbacks.EarlyStopping(monitor = \"val_accuracy\", patience=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:09:12.768335Z","iopub.execute_input":"2025-09-13T12:09:12.768972Z","iopub.status.idle":"2025-09-13T12:09:12.772484Z","shell.execute_reply.started":"2025-09-13T12:09:12.768949Z","shell.execute_reply":"2025-09-13T12:09:12.771708Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training a model (On subset of data)","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-09-13T12:09:15.436584Z","iopub.execute_input":"2025-09-13T12:09:15.437163Z","iopub.status.idle":"2025-09-13T12:09:15.440316Z","shell.execute_reply.started":"2025-09-13T12:09:15.437140Z","shell.execute_reply":"2025-09-13T12:09:15.439570Z"}},"outputs":[],"execution_count":null},{"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  from tf_keras.callbacks import EarlyStopping, TensorBoard\n\n# recreate BOTH callbacks from tf_keras\n  early_stopping = EarlyStopping(monitor=\"val_accuracy\", patience=3, restore_best_weights=True)\n  tensorboard = TensorBoard(log_dir=\"/content/drive/MyDrive/Dog Breed Identificattion/logs/run\") # Update log_dir\n\n  model.fit(train_data, epochs=NUM_EPOCHS, validation_data=val_data,\n          callbacks=[tensorboard, early_stopping])\n\n\n  # Return the fitted model\n  return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:09:16.383583Z","iopub.execute_input":"2025-09-13T12:09:16.383860Z","iopub.status.idle":"2025-09-13T12:09:16.388665Z","shell.execute_reply.started":"2025-09-13T12:09:16.383831Z","shell.execute_reply":"2025-09-13T12:09:16.387933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = train_model()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:09:19.513271Z","iopub.execute_input":"2025-09-13T12:09:19.513912Z","iopub.status.idle":"2025-09-13T12:09:51.864548Z","shell.execute_reply.started":"2025-09-13T12:09:19.513891Z","shell.execute_reply":"2025-09-13T12:09:51.863971Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Making and evaluating predictions using a trained model","metadata":{}},{"cell_type":"code","source":"predictions = model.predict(val_data, verbose=1)\npredictions","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:05.478535Z","iopub.execute_input":"2025-09-13T12:10:05.478805Z","iopub.status.idle":"2025-09-13T12:10:06.363736Z","shell.execute_reply.started":"2025-09-13T12:10:05.478785Z","shell.execute_reply":"2025-09-13T12:10:06.363159Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Let's create a function to turn this huge data into human readable data","metadata":{}},{"cell_type":"code","source":"# Turn prediction probabilities into label\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\npred_label = get_pred_label(predictions[81])\npred_label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:10.582211Z","iopub.execute_input":"2025-09-13T12:10:10.582466Z","iopub.status.idle":"2025-09-13T12:10:10.588004Z","shell.execute_reply.started":"2025-09-13T12:10:10.582448Z","shell.execute_reply":"2025-09-13T12:10:10.587280Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create a function to unbatch a dataset\ndef unbatchify(data):\n  \"\"\"\n  Takes a batched dataset of (image, label) Tensors and returns separate arrays\n  of images and labels\"\"\"\n  images = []\n  labels = []\n  for image, label in data.unbatch():\n    images.append(image.numpy())\n    labels.append(unique_breeds[label.numpy().argmax()])\n  return images, labels\n\nval_images, val_labels = unbatchify(val_data)\nval_images[0], val_labels[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:14.200396Z","iopub.execute_input":"2025-09-13T12:10:14.200870Z","iopub.status.idle":"2025-09-13T12:10:14.473553Z","shell.execute_reply.started":"2025-09-13T12:10:14.200847Z","shell.execute_reply":"2025-09-13T12:10:14.472775Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_pred(prediction_probabilities, labels, images, n=1):\n  \"\"\"\n  View the prediction\"\"\"\n  pred_prob, true_label, image = prediction_probabilities[n], labels[n], images[n]\n  pred_label = get_pred_label(pred_prob)\n\n  plt.imshow(image)\n  plt.xticks([])\n  plt.yticks([])\n\n  if pred_label == true_label:\n    color = \"green\"\n  else:\n    color = \"red\"\n\n  plt.title(f\"Prediction: {pred_label}, {np.max(pred_prob)*100:.1f}% | GT: {true_label}\", color=color)\n  plt.axis(False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:18.039910Z","iopub.execute_input":"2025-09-13T12:10:18.040184Z","iopub.status.idle":"2025-09-13T12:10:18.045946Z","shell.execute_reply.started":"2025-09-13T12:10:18.040163Z","shell.execute_reply":"2025-09-13T12:10:18.045221Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_pred_conf(prediction_probabilities, labels, n=1):\n  pred_prob, true_label = prediction_probabilities[n], labels[n]\n  pred_label = get_pred_label(pred_prob)\n  top_10_pred_indexes = pred_prob.argsort()[-10:][::-1]\n  top_10_pred_values = pred_prob[top_10_pred_indexes]\n  top_10_pred_labels = unique_breeds[top_10_pred_indexes]\n\n  # Create a list of colors for the bars\n  colors = [\"blue\"] * 10  # Start with all blue bars\n  if true_label in top_10_pred_labels:\n    # Find the index of the true label in the top 10 predictions\n    true_label_index = np.where(top_10_pred_labels == true_label)[0][0]\n    colors[true_label_index] = \"green\" # Set the color of the true label bar to green\n\n\n  plt.bar(range(10), top_10_pred_values, tick_label=top_10_pred_labels, color=colors)\n  plt.xticks(rotation=\"vertical\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:20.049511Z","iopub.execute_input":"2025-09-13T12:10:20.050195Z","iopub.status.idle":"2025-09-13T12:10:20.055065Z","shell.execute_reply.started":"2025-09-13T12:10:20.050171Z","shell.execute_reply":"2025-09-13T12:10:20.054203Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_pred_conf(predictions, val_labels, n=60)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:22.343985Z","iopub.execute_input":"2025-09-13T12:10:22.344566Z","iopub.status.idle":"2025-09-13T12:10:22.500269Z","shell.execute_reply.started":"2025-09-13T12:10:22.344544Z","shell.execute_reply":"2025-09-13T12:10:22.499507Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Training a dog model on full data","metadata":{}},{"cell_type":"code","source":"full_data = create_data_batches(X, y)\nfull_data","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:10:27.347400Z","iopub.execute_input":"2025-09-13T12:10:27.347987Z","iopub.status.idle":"2025-09-13T12:10:27.421173Z","shell.execute_reply.started":"2025-09-13T12:10:27.347965Z","shell.execute_reply":"2025-09-13T12:10:27.420383Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_model = create_model()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:11:43.767594Z","iopub.execute_input":"2025-09-13T12:11:43.768317Z","iopub.status.idle":"2025-09-13T12:11:48.447984Z","shell.execute_reply.started":"2025-09-13T12:11:43.768293Z","shell.execute_reply":"2025-09-13T12:11:48.447532Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tf_keras.callbacks import EarlyStopping, TensorBoard\nfull_model_tensorboard = TensorBoard(log_dir=\"/content/drive/MyDrive/Dog Breed Identificattion/logs/full_model_run\")\nfull_model_early_stopping = EarlyStopping(monitor=\"val_accuracy\", patience=3, restore_best_weights=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:12:08.847129Z","iopub.execute_input":"2025-09-13T12:12:08.847684Z","iopub.status.idle":"2025-09-13T12:12:08.851458Z","shell.execute_reply.started":"2025-09-13T12:12:08.847662Z","shell.execute_reply":"2025-09-13T12:12:08.850698Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"full_model.fit(full_data, epochs=NUM_EPOCHS, callbacks=[full_model_tensorboard])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:12:16.875860Z","iopub.execute_input":"2025-09-13T12:12:16.876562Z","iopub.status.idle":"2025-09-13T12:31:54.247798Z","shell.execute_reply.started":"2025-09-13T12:12:16.876537Z","shell.execute_reply":"2025-09-13T12:31:54.247233Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Making predictions on test dataset","metadata":{}},{"cell_type":"code","source":"# Load test image file names\ntest_path = \"/kaggle/input/dog-breed-identification/test\"\ntest_filenames = [test_path + \"/\" + fname for fname in os.listdir(test_path)]\ntest_filenames[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:32:01.959355Z","iopub.execute_input":"2025-09-13T12:32:01.959962Z","iopub.status.idle":"2025-09-13T12:32:02.559472Z","shell.execute_reply.started":"2025-09-13T12:32:01.959941Z","shell.execute_reply":"2025-09-13T12:32:02.558867Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_data = create_data_batches(test_filenames, test_data=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:32:06.177496Z","iopub.execute_input":"2025-09-13T12:32:06.177728Z","iopub.status.idle":"2025-09-13T12:32:06.202579Z","shell.execute_reply.started":"2025-09-13T12:32:06.177713Z","shell.execute_reply":"2025-09-13T12:32:06.201779Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_predictions = model.predict(test_data, verbose=1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:32:10.383255Z","iopub.execute_input":"2025-09-13T12:32:10.383529Z","iopub.status.idle":"2025-09-13T12:32:39.898226Z","shell.execute_reply.started":"2025-09-13T12:32:10.383509Z","shell.execute_reply":"2025-09-13T12:32:39.897607Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Create pandas dataframe\npreds_df = pd.DataFrame(columns=[\"id\"] + list(unique_breeds))\npreds_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:32:57.093141Z","iopub.execute_input":"2025-09-13T12:32:57.093390Z","iopub.status.idle":"2025-09-13T12:32:57.107362Z","shell.execute_reply.started":"2025-09-13T12:32:57.093374Z","shell.execute_reply":"2025-09-13T12:32:57.106592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_ids = [os.path.splitext(path)[0] for path in os.listdir(test_path)]\npreds_df[\"id\"] = test_ids\npreds_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:32:58.516509Z","iopub.execute_input":"2025-09-13T12:32:58.516779Z","iopub.status.idle":"2025-09-13T12:32:58.552814Z","shell.execute_reply.started":"2025-09-13T12:32:58.516758Z","shell.execute_reply":"2025-09-13T12:32:58.551945Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds_df[list(unique_breeds)] = test_predictions\npreds_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:33:02.621704Z","iopub.execute_input":"2025-09-13T12:33:02.621946Z","iopub.status.idle":"2025-09-13T12:33:02.657848Z","shell.execute_reply.started":"2025-09-13T12:33:02.621929Z","shell.execute_reply":"2025-09-13T12:33:02.657100Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds_df.to_csv(\"submission.csv\", index=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-13T12:33:05.784094Z","iopub.execute_input":"2025-09-13T12:33:05.784347Z","iopub.status.idle":"2025-09-13T12:33:07.145843Z","shell.execute_reply.started":"2025-09-13T12:33:05.784328Z","shell.execute_reply":"2025-09-13T12:33:07.145136Z"}},"outputs":[],"execution_count":null}]}