{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Dog Breed Identification System Using Deep Learning 🐕\n\n## Introduction\n\nIn this project we shall use Deep Learning to classify images according to dog breed. This is a multi-class classification problem with 120 classes. Each class has a limited number of images. We are provided with a training and test set of images of dogs. Each image has a filename that is its unique id. The dataset comprises 120 breeds of dogs. The goal of the project is to create a classifier capable of determining a dog's breed from a photo.\n\n### Dataset\n\nThe dataset for this project is available on Kaggle. <br>\n\n**Link** : https://www.kaggle.com/c/dog-breed-identification/data\n\n### Evaluation\n\nWe shall use <code>Accuracy</code>, <code>Precision</code>, <code>Recall</code> and <code>F1 score</code> to evaluate the performance of our models.<br>\n\nKaggle submissions are evaluated on <code>Multi Class Log Loss</code> between the predicted probability and the observed target.\n\n## Table of Contents\n\n1. Environment Setup\n2. Dataset Gathering\n3. Exploratory Data Analysis\n4. Dataset Preprocessing\n5. Model Experimentation\n6. Model Evaluation","metadata":{}},{"cell_type":"markdown","source":"## Environment Setup","metadata":{}},{"cell_type":"code","source":"# Suppressing Jupyter Notebook Warnings\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport os\nimport random\n\nimport tqdm\n\n# Data manipulation libraries\nimport numpy as np\nimport pandas as pd\n\n# Data visualization libraries\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n%matplotlib inline\n\n# scikit-learn packages\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, classification_report, accuracy_score, precision_score, recall_score, f1_score\n\n# Deep Learning libraries\nimport tensorflow as tf\nimport tensorflow_hub as hub\n\nimport cv2\n\n# Image display\nfrom IPython.display import display, Image","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:18.259095Z","iopub.execute_input":"2022-02-10T23:08:18.259521Z","iopub.status.idle":"2022-02-10T23:08:24.563390Z","shell.execute_reply.started":"2022-02-10T23:08:18.259433Z","shell.execute_reply":"2022-02-10T23:08:24.562674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset Gathering","metadata":{}},{"cell_type":"code","source":"# Importing the labels dataset\nlabels_csv = pd.read_csv('../input/dog-breed-identification/labels.csv')\n\n# Viewing the head of the dataset\nlabels_csv.head()","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:24.565022Z","iopub.execute_input":"2022-02-10T23:08:24.565276Z","iopub.status.idle":"2022-02-10T23:08:24.607026Z","shell.execute_reply.started":"2022-02-10T23:08:24.565240Z","shell.execute_reply":"2022-02-10T23:08:24.606222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Saving the training dataset path to a variable\ntrain_path = \"../input/dog-breed-identification/train/\"\n\n# Creating image paths from the name\nfilenames = [train_path + fname + \".jpg\" for fname in labels_csv['id']]\n\n# Viewing the first 10 filenames\nfilenames[:10]","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:24.608456Z","iopub.execute_input":"2022-02-10T23:08:24.608710Z","iopub.status.idle":"2022-02-10T23:08:24.621202Z","shell.execute_reply.started":"2022-02-10T23:08:24.608676Z","shell.execute_reply":"2022-02-10T23:08:24.620341Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Checking whether the number of filenames in the directory matches to that of ours\nif len(os.listdir(train_path)) == len(filenames):\n    print('Matched !')\nelse:\n    print('Not matched !')","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:24.623827Z","iopub.execute_input":"2022-02-10T23:08:24.624174Z","iopub.status.idle":"2022-02-10T23:08:25.044457Z","shell.execute_reply.started":"2022-02-10T23:08:24.624113Z","shell.execute_reply":"2022-02-10T23:08:25.043704Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Exploratory Data Analysis","metadata":{}},{"cell_type":"code","source":"# Viewing an image using filename\nImage(\"../input/dog-breed-identification/train/000bec180eb18c7604dcecc8fe0dba07.jpg\")","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:25.045708Z","iopub.execute_input":"2022-02-10T23:08:25.046114Z","iopub.status.idle":"2022-02-10T23:08:25.064489Z","shell.execute_reply.started":"2022-02-10T23:08:25.046077Z","shell.execute_reply":"2022-02-10T23:08:25.063819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Viewing an image using our filenames variable\nImage(filenames[10])","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:25.065648Z","iopub.execute_input":"2022-02-10T23:08:25.066291Z","iopub.status.idle":"2022-02-10T23:08:25.078984Z","shell.execute_reply.started":"2022-02-10T23:08:25.066261Z","shell.execute_reply":"2022-02-10T23:08:25.078202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Visualizing the distribution of images accoding to class\nlabels_csv[\"breed\"].value_counts().plot.bar(figsize=(20, 10));","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:25.080176Z","iopub.execute_input":"2022-02-10T23:08:25.080479Z","iopub.status.idle":"2022-02-10T23:08:27.023778Z","shell.execute_reply.started":"2022-02-10T23:08:25.080446Z","shell.execute_reply":"2022-02-10T23:08:27.023135Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset Preprocessing","metadata":{}},{"cell_type":"code","source":"# Converting the label columns to Numpy array\nlabels = labels_csv['breed'].to_numpy()\n\n# Viewing the first 10 labels\nlabels[:10]","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:27.024986Z","iopub.execute_input":"2022-02-10T23:08:27.025338Z","iopub.status.idle":"2022-02-10T23:08:27.032633Z","shell.execute_reply.started":"2022-02-10T23:08:27.025296Z","shell.execute_reply":"2022-02-10T23:08:27.031913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Saving the count of total number of unique breeds to a variabkle\nunique_breeds = np.unique(labels)\n\nprint(\"Total number of unique breeds : \", len(unique_breeds))","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:27.034203Z","iopub.execute_input":"2022-02-10T23:08:27.035148Z","iopub.status.idle":"2022-02-10T23:08:27.052121Z","shell.execute_reply.started":"2022-02-10T23:08:27.035108Z","shell.execute_reply":"2022-02-10T23:08:27.051398Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Converting the labels to a boolean array\nboolean_labels = [label == np.array(unique_breeds) for label in labels]\n\n# Viewing how it looks like\nboolean_labels[0]","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:27.055609Z","iopub.execute_input":"2022-02-10T23:08:27.056163Z","iopub.status.idle":"2022-02-10T23:08:27.142401Z","shell.execute_reply.started":"2022-02-10T23:08:27.056133Z","shell.execute_reply":"2022-02-10T23:08:27.141729Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Creating training and validation sets\n\n# Separating the features and labels\nX = filenames\ny = boolean_labels\n\nprint(f\"Number of training images: {len(X)}\")\nprint(f\"Number of labels: {len(y)}\")\n\nX_train, X_val, y_train, y_val = train_test_split(X,\n                                                  y, \n                                                  test_size=0.2,\n                                                  random_state=42)\n\nprint(f\"Number of training images : {len(X_train)}\")\nprint(f\"Number of validation images : {len(X_val)}\")","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:27.143423Z","iopub.execute_input":"2022-02-10T23:08:27.143659Z","iopub.status.idle":"2022-02-10T23:08:27.158930Z","shell.execute_reply.started":"2022-02-10T23:08:27.143625Z","shell.execute_reply":"2022-02-10T23:08:27.158288Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Image Preprocessing","metadata":{}},{"cell_type":"code","source":"# Reading an image in and checking shape\nimage = plt.imread(filenames[42])\nprint(f\"Image Shape : {image.shape}\")\n\n# Converting the image to a Tensorflow Tensor\ntf.constant(image)","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:27.159946Z","iopub.execute_input":"2022-02-10T23:08:27.160242Z","iopub.status.idle":"2022-02-10T23:08:29.502903Z","shell.execute_reply.started":"2022-02-10T23:08:27.160206Z","shell.execute_reply":"2022-02-10T23:08:29.502178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Setting the Image Size\nIMAGE_SIZE = 224\n\n# Creating a function to preprocess the images\ndef process_image(image_path):\n    '''\n    This function shall preprocess the image\n    1. Read in the image file\n    2. Turn the image into numerical tensor\n    3. Convert the color channel values to 0-1\n    4. Resize the image\n    '''\n    \n    # 1. Read in the image\n    image = tf.io.read_file(image_path)\n    \n    # 2. Turn the image into numerical tensors\n    image = tf.image.decode_jpeg(image, channels=3)\n    \n    # 3. Convert the color channel values from 0-225 to 0-1\n    image = tf.image.convert_image_dtype(image, tf.float32)\n    \n    # 4. Resize the image\n    image = tf.image.resize(image, size=[IMAGE_SIZE, IMAGE_SIZE])\n    \n    return image","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.504043Z","iopub.execute_input":"2022-02-10T23:08:29.504721Z","iopub.status.idle":"2022-02-10T23:08:29.511419Z","shell.execute_reply.started":"2022-02-10T23:08:29.504683Z","shell.execute_reply":"2022-02-10T23:08:29.510610Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Batching The Data","metadata":{}},{"cell_type":"code","source":"# Creating a function to return a tuple (image, label)\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    image = process_image(image_path)\n    return image, label","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.513647Z","iopub.execute_input":"2022-02-10T23:08:29.514322Z","iopub.status.idle":"2022-02-10T23:08:29.522720Z","shell.execute_reply.started":"2022-02-10T23:08:29.514279Z","shell.execute_reply":"2022-02-10T23:08:29.522061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Setting the batch size at 32 \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    Function to batch the data\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":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.524198Z","iopub.execute_input":"2022-02-10T23:08:29.524722Z","iopub.status.idle":"2022-02-10T23:08:29.534426Z","shell.execute_reply.started":"2022-02-10T23:08:29.524685Z","shell.execute_reply":"2022-02-10T23:08:29.533679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Creating 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":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.535379Z","iopub.execute_input":"2022-02-10T23:08:29.536969Z","iopub.status.idle":"2022-02-10T23:08:29.785369Z","shell.execute_reply.started":"2022-02-10T23:08:29.536933Z","shell.execute_reply":"2022-02-10T23:08:29.784684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Checking the different attributes of our data batches\ntrain_data.element_spec, val_data.element_spec","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.786418Z","iopub.execute_input":"2022-02-10T23:08:29.786817Z","iopub.status.idle":"2022-02-10T23:08:29.793767Z","shell.execute_reply.started":"2022-02-10T23:08:29.786780Z","shell.execute_reply":"2022-02-10T23:08:29.792887Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model Experimentation","metadata":{}},{"cell_type":"markdown","source":"### MobileNetV2","metadata":{}},{"cell_type":"code","source":"# Setup input shape to the model\nINPUT_SHAPE = [None, IMAGE_SIZE, IMAGE_SIZE, 3] # batch, height, width, colour channels\n\n# Setup output shape of the model\nOUTPUT_SHAPE = len(unique_breeds)\n\n# Model URL for MobileNetV2\nMODEL_URL1 = 'https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/5'\n\n# Creating Tensorflow EarlyStopping\nearly_stopping = tf.keras.callbacks.EarlyStopping(monitor='val_accuracy',\n                                                  patience=5)","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.795500Z","iopub.execute_input":"2022-02-10T23:08:29.795870Z","iopub.status.idle":"2022-02-10T23:08:29.803243Z","shell.execute_reply.started":"2022-02-10T23:08:29.795823Z","shell.execute_reply":"2022-02-10T23:08:29.802573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Creating the MobileResNetV2 model\nmodel1 = tf.keras.Sequential([\n    # Layer 1 : Input Layer\n    hub.KerasLayer(MODEL_URL1),\n    \n    # Layer 2 : Output Layer\n    tf.keras.layers.Dense(units=OUTPUT_SHAPE,\n                          activation='softmax')\n])\n\n# Compiling the model\nmodel1.compile(loss=tf.keras.losses.CategoricalCrossentropy(),\n               optimizer=tf.keras.optimizers.Adam(),\n               metrics=['accuracy'])\n\n# Building the model\nmodel1.build(INPUT_SHAPE)\n\n# Summary of the model\nmodel1.summary()","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:29.805586Z","iopub.execute_input":"2022-02-10T23:08:29.806280Z","iopub.status.idle":"2022-02-10T23:08:34.134983Z","shell.execute_reply.started":"2022-02-10T23:08:29.806241Z","shell.execute_reply":"2022-02-10T23:08:34.134205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fitting the model\nhistory1 = model1.fit(train_data,\n                      epochs=100,\n                      validation_data=val_data,\n                      callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:08:34.136106Z","iopub.execute_input":"2022-02-10T23:08:34.138595Z","iopub.status.idle":"2022-02-10T23:18:43.387201Z","shell.execute_reply.started":"2022-02-10T23:08:34.138565Z","shell.execute_reply":"2022-02-10T23:18:43.386465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### EfficientNetV2","metadata":{}},{"cell_type":"code","source":"# Model URL for EfficientNetV2\nMODEL_URL2 = 'https://tfhub.dev/google/imagenet/efficientnet_v2_imagenet1k_b0/classification/2'\n\n# Creating model for EfficientNetV2\nmodel2 = tf.keras.Sequential([\n    # Layer 1 : Input Layer\n    hub.KerasLayer(MODEL_URL2),\n    \n    # Layer 2 : Output Layer\n    tf.keras.layers.Dense(units=OUTPUT_SHAPE,\n                          activation='softmax')\n])\n\n# Compiling the model\nmodel2.compile(loss=tf.keras.losses.CategoricalCrossentropy(),\n               optimizer=tf.keras.optimizers.Adam(),\n               metrics=['accuracy'])\n\n# Building the model\nmodel2.build(INPUT_SHAPE)\n\n# Summary of the model\nmodel2.summary()","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:18:43.388746Z","iopub.execute_input":"2022-02-10T23:18:43.389026Z","iopub.status.idle":"2022-02-10T23:18:50.246340Z","shell.execute_reply.started":"2022-02-10T23:18:43.388990Z","shell.execute_reply":"2022-02-10T23:18:50.245549Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fitting the model\nhistory2 = model2.fit(train_data,\n                      epochs=100,\n                      validation_data=val_data,\n                      callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:18:50.247511Z","iopub.execute_input":"2022-02-10T23:18:50.247738Z","iopub.status.idle":"2022-02-10T23:23:53.794685Z","shell.execute_reply.started":"2022-02-10T23:18:50.247706Z","shell.execute_reply":"2022-02-10T23:23:53.793899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### ResNet50V1","metadata":{}},{"cell_type":"code","source":"# Model URL for ResNet50V2\nMODEL_URL3 = \"https://tfhub.dev/tensorflow/resnet_50/classification/1\"\n\n# Creating the model for ResNet50V2\nmodel3 = tf.keras.Sequential([\n    # Layer 1 : Input Layer\n    hub.KerasLayer(MODEL_URL3),\n    \n    # Layer 2 : Output Layer\n    tf.keras.layers.Dense(120, activation='softmax')\n])\n\n# Compiling the model\nmodel3.compile(loss=tf.keras.losses.CategoricalCrossentropy(),\n               optimizer=tf.keras.optimizers.Adam(),\n               metrics=['accuracy'])\n\n# Building the model\nmodel3.build(INPUT_SHAPE)\n\n# Summary of the model\nmodel3.summary()","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:23:53.796221Z","iopub.execute_input":"2022-02-10T23:23:53.797668Z","iopub.status.idle":"2022-02-10T23:24:03.456040Z","shell.execute_reply.started":"2022-02-10T23:23:53.797634Z","shell.execute_reply":"2022-02-10T23:24:03.455234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fitting the model\nhistory3 = model3.fit(train_data,\n                      epochs=100,\n                      validation_data=val_data,\n                      callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:24:03.457535Z","iopub.execute_input":"2022-02-10T23:24:03.457805Z","iopub.status.idle":"2022-02-10T23:45:44.658254Z","shell.execute_reply.started":"2022-02-10T23:24:03.457767Z","shell.execute_reply":"2022-02-10T23:45:44.657475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### InceptionV3","metadata":{}},{"cell_type":"code","source":"# Model URL for InceptionV3\nMODEL_URL4 = 'https://tfhub.dev/google/imagenet/inception_v3/feature_vector/5'\n\n# Creating model for InceptionV3\nmodel4 = tf.keras.Sequential([\n    # Layer 1 : Input Layer\n    hub.KerasLayer(MODEL_URL4),\n    \n    # Layer 2 : Output Layer\n    tf.keras.layers.Dense(120, activation='softmax')\n])\n\n# Compiling the model\nmodel4.compile(loss=tf.keras.losses.CategoricalCrossentropy(),\n               optimizer=tf.keras.optimizers.Adam(),\n               metrics=['accuracy'])\n\n# Building the model\nmodel4.build(INPUT_SHAPE)\n\n# Summary of the model\nmodel4.summary()","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:45:44.661205Z","iopub.execute_input":"2022-02-10T23:45:44.661409Z","iopub.status.idle":"2022-02-10T23:45:50.023717Z","shell.execute_reply.started":"2022-02-10T23:45:44.661383Z","shell.execute_reply":"2022-02-10T23:45:50.023034Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fitting the model\nhistory4 = model4.fit(train_data,\n                      epochs=100,\n                      validation_data=val_data,\n                      callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:45:50.025702Z","iopub.execute_input":"2022-02-10T23:45:50.026248Z","iopub.status.idle":"2022-02-10T23:54:14.690251Z","shell.execute_reply.started":"2022-02-10T23:45:50.026205Z","shell.execute_reply":"2022-02-10T23:54:14.689429Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model Evaluation","metadata":{}},{"cell_type":"code","source":"# Creating graphs to visualize the accuracy and loss for the models\nfig, axes = plt.subplots(nrows=4, \n                         ncols=2, \n                         figsize=(15, 25))\n\nfig.tight_layout(pad=5)\n\nplt.style.use('fivethirtyeight')\n\n# - *********************** - #\n# Graph for MobileNetV2 Training Accuracy vs Validation Accuracy\naxes[0][0].plot(history1.history['accuracy'])\naxes[0][0].plot(history1.history['val_accuracy'])\naxes[0][0].set_ylabel(\"Accuracy\")\naxes[0][0].set_xlabel(\"Epochs\")\naxes[0][0].set_title('Model 1: MobileNetV2 Train Acc vs Val Acc')\naxes[0][0].legend(['Train', 'Test'], loc='upper left')\n\n# Graph for MobileNetV2 Training Loss vs Validation Loss\naxes[0][1].plot(history1.history['loss'])\naxes[0][1].plot(history1.history['val_loss'])\naxes[0][1].set_ylabel(\"Loss\")\naxes[0][1].set_xlabel(\"Epochs\")\naxes[0][1].set_title('Model 1: MobileNetV2 Train Loss vs Val Loss')\naxes[0][1].legend(['Train', 'Test'], loc='upper left')\n# - *********************** - #\n\n# - *********************** - #\n# Graph for EfficientNetV2 Training Accuracy vs Validation Accuracy\naxes[1][0].plot(history2.history['accuracy'])\naxes[1][0].plot(history2.history['val_accuracy'])\naxes[1][0].set_ylabel(\"Accuracy\")\naxes[1][0].set_xlabel(\"Epochs\")\naxes[1][0].set_title('Model 2: EfficientNet50V2 Train Acc vs Val Acc')\naxes[1][0].legend(['Train', 'Test'], loc='upper left')\n\n# Graph for EfficientNetV2 Training Loss vs Validation Loss\naxes[1][1].plot(history2.history['loss'])\naxes[1][1].plot(history2.history['val_loss'])\naxes[1][1].set_ylabel(\"Loss\")\naxes[1][1].set_xlabel(\"Epochs\")\naxes[1][1].set_title('Model 2: EfficientNet50V2 Train Loss vs Val Loss')\naxes[1][1].legend(['Train', 'Test'], loc='upper left')\n# - *********************** - #\n\n# - *********************** - #\n# Graph for ResNet50V2 Training Accuracy vs Validation Accuracy\naxes[2][0].plot(history3.history['accuracy'])\naxes[2][0].plot(history3.history['val_accuracy'])\naxes[2][0].set_ylabel(\"Accuracy\")\naxes[2][0].set_xlabel(\"Epochs\")\naxes[2][0].set_title('Model 3: ResNet50V2 Train Acc vs Val Acc')\naxes[2][0].legend(['Train', 'Test'], loc='upper left')\n\n# Graph for EfficientNetV2 Training Loss vs Validation Loss\naxes[2][1].plot(history3.history['loss'])\naxes[2][1].plot(history3.history['val_loss'])\naxes[2][1].set_ylabel(\"Loss\")\naxes[2][1].set_xlabel(\"Epochs\")\naxes[2][1].set_title('Model 3: ResNet50V2 Train Loss vs Val Loss')\naxes[2][1].legend(['Train', 'Test'], loc='upper left')\n# - *********************** - #\n\n# - *********************** - #\n# Graph for InceptionV3 Training Accuracy vs Validation Accuracy\naxes[3][0].plot(history4.history['accuracy'])\naxes[3][0].plot(history4.history['val_accuracy'])\naxes[3][0].set_ylabel(\"Accuracy\")\naxes[3][0].set_xlabel(\"Epochs\")\naxes[3][0].set_title('Model 4: InceptionV3 Train Acc vs Val Acc')\naxes[3][0].legend(['Train', 'Test'], loc='upper left')\n\n# Graph for InceptionV3 Training Loss vs Validation Loss\naxes[3][1].plot(history3.history['loss'])\naxes[3][1].plot(history3.history['val_loss'])\naxes[3][1].set_ylabel(\"Loss\")\naxes[3][1].set_xlabel(\"Epochs\")\naxes[3][1].set_title('Model 4: InceptionV3 Train Loss vs Val Loss')\naxes[3][1].legend(['Train', 'Test'], loc='upper left')\n# - *********************** - #","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:54:14.696143Z","iopub.execute_input":"2022-02-10T23:54:14.697655Z","iopub.status.idle":"2022-02-10T23:54:32.691265Z","shell.execute_reply.started":"2022-02-10T23:54:14.697581Z","shell.execute_reply":"2022-02-10T23:54:32.689753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Champion Model","metadata":{}},{"cell_type":"code","source":"# ResNet50V2 turns out to be the champion model\nfinal_model = tf.keras.Sequential([\n    # Layer 1 : Input Layer\n    hub.KerasLayer(MODEL_URL3),\n    \n    # Layer 2 : Output Layer\n    tf.keras.layers.Dense(120, activation='softmax')\n])\n\n# Compiling the model\nfinal_model.compile(loss=tf.keras.losses.CategoricalCrossentropy(),\n                    metrics=['accuracy'],\n                    optimizer=tf.keras.optimizers.Adam())\n\n# Building the model\nfinal_model.build(INPUT_SHAPE)\n\n# Model Summary\nfinal_model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:54:32.695072Z","iopub.execute_input":"2022-02-10T23:54:32.695790Z","iopub.status.idle":"2022-02-10T23:54:40.964226Z","shell.execute_reply.started":"2022-02-10T23:54:32.695752Z","shell.execute_reply":"2022-02-10T23:54:40.963510Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fitting the model\nfinal_history = final_model.fit(train_data,\n                                epochs=38)","metadata":{"execution":{"iopub.status.busy":"2022-02-10T23:54:40.965457Z","iopub.execute_input":"2022-02-10T23:54:40.965697Z","iopub.status.idle":"2022-02-11T00:07:19.447872Z","shell.execute_reply.started":"2022-02-10T23:54:40.965663Z","shell.execute_reply":"2022-02-11T00:07:19.447165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Making predictions\npredictions = final_model.predict(val_data,\n                                  verbose=2)\n\n# Viewing the predictions\npredictions[0]","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:07:19.449481Z","iopub.execute_input":"2022-02-11T00:07:19.449733Z","iopub.status.idle":"2022-02-11T00:07:25.187402Z","shell.execute_reply.started":"2022-02-11T00:07:19.449698Z","shell.execute_reply":"2022-02-11T00:07:25.186691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Checking the shape of the prediction\nprint(\"Viewing the Shape : \", predictions.shape)\n\n# Checking the maximum probability\nprint(f\"Maximum value (probability of prediction) : {np.max(predictions[0])}\")\n\n# Maximum index\nprint(f\"Maximum index : {np.argmax(predictions[0])}\")\n\n# Predicted label\nprint(f\"Predicted Label : {unique_breeds[np.argmax(predictions[0])]}\")","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:07:25.188817Z","iopub.execute_input":"2022-02-11T00:07:25.189289Z","iopub.status.idle":"2022-02-11T00:07:25.196259Z","shell.execute_reply.started":"2022-02-11T00:07:25.189250Z","shell.execute_reply":"2022-02-11T00:07:25.195350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Creating a function to unbatch the data\ndef unbatching(data):\n    '''\n    This fuction is used to unbatch the data\n    '''\n    # Creating variables to save the images and labels\n    images = []\n    labels = []\n    \n    # Looping through the unbatched data\n    for image, label in data.unbatch().as_numpy_iterator():\n        images.append(image)\n        labels.append(unique_breeds[np.argmax(label)])\n    return images, labels\n\n# Unbatching the validation data\nval_images, val_labels = unbatching(val_data)\nval_images[0], val_labels[0]","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:07:25.197947Z","iopub.execute_input":"2022-02-11T00:07:25.198582Z","iopub.status.idle":"2022-02-11T00:07:30.301490Z","shell.execute_reply.started":"2022-02-11T00:07:25.198543Z","shell.execute_reply":"2022-02-11T00:07:30.300788Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Getting the predicted labels\npredicted_labels = [unique_breeds[np.argmax(predictions[i])] for i in range(len(predictions))]\n\n# Checking to see if the length of the predicted labels is equal to the toal number of data points in the validation dataset\nif len(predicted_labels) == len(val_labels):\n    print('Matched !')\nelse:\n    print('Not Matched !')","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:07:30.302830Z","iopub.execute_input":"2022-02-11T00:07:30.303101Z","iopub.status.idle":"2022-02-11T00:07:30.323207Z","shell.execute_reply.started":"2022-02-11T00:07:30.303067Z","shell.execute_reply":"2022-02-11T00:07:30.322521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(classification_report(val_labels, predicted_labels))","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:07:30.324248Z","iopub.execute_input":"2022-02-11T00:07:30.324891Z","iopub.status.idle":"2022-02-11T00:07:30.370163Z","shell.execute_reply.started":"2022-02-11T00:07:30.324831Z","shell.execute_reply":"2022-02-11T00:07:30.369517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Getting the perfromance metrics of our champion model\nprint(\"#******** ResNet50V2 Performance Metrics ********#\")\nprint(\" \")\nprint(f\"Accuracy Score  = {accuracy_score(val_labels, predicted_labels) * 100}\")\nprint(f\"Precision Score = {precision_score(val_labels, predicted_labels, average='macro') * 100}\")\nprint(f\"Recall Score    = {recall_score(val_labels, predicted_labels, average='macro') * 100}\")\nprint(f\"F1 Score        = {f1_score(val_labels, predicted_labels, average='macro') * 100}\")","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:07:30.371134Z","iopub.execute_input":"2022-02-11T00:07:30.371355Z","iopub.status.idle":"2022-02-11T00:07:30.426362Z","shell.execute_reply.started":"2022-02-11T00:07:30.371322Z","shell.execute_reply":"2022-02-11T00:07:30.425713Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n","metadata":{},"execution_count":null,"outputs":[]}]}