{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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\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\nfor 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 5GB 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","execution_count":null,"outputs":[]},{"metadata":{},"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 2.0 and TensorFlow Hub\n\n## 1. Problem\nIdentifying the breed of a dog, given the image of a dog.\n\n## 2. Data\nData is available in this competition\n\n## 3. Evaluation\nThe evaluation is a file with prediction probabilities for each dog breed of each test image.\n\n## Features\nThis is unstructured data, since we're dealing with images here, so it is a deep learning problem. ","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Importing the necessary libraries","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import tensorflow as tf\nimport tensorflow_hub as hub\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom IPython.display import Image\nimport matplotlib.pyplot as plt\nprint('TensorFlow Version :', tf.__version__)\nprint('TensorFlow_Hub Version :', hub.__version__)\n\n# Check if we're using GPU\nprint('GPU','Available!!, Noice' if tf.config.list_logical_devices('GPU') else 'Not Available')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Getting our data(images) ready, by converting it into tensors.\n\nLet's take a look at our labels.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv = pd.read_csv('../input/dog-breed-identification/labels.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv[70:80]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### EDA","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Let's take a look at most common dog breed.\n* Also this helps us figure out number of images for each breed.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(labels_csv['breed'].value_counts()[:10])\nlabels_csv['breed'].value_counts()[:20].plot.bar(figsize=(20,10))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Hmmm, looks like these are the top 5 most common dog breeds in this data :\n\n\n `scottish_deerhound      126\n maltese_dog             117\n afghan_hound            116\n entlebucher             115\n bernese_mountain_dog    114`","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"* Overall frequency of `breed` column","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv['breed'].value_counts(normalize=True).plot.bar(logx=False, figsize=(20,10))\nprint(labels_csv['breed'].value_counts().median())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We should know that for model training purposes, it's recommended that we use about 100 annotations per label, with minumum of 10 annotations.\n\nWhat it means is, if we had atleast 100 values/images per each breed, our model would learn really good. \n\nBut that's not the case here. We have roughly 82 images per breed.\n\nAnyway, let's continue.\n\nLet's try and view an image.\n\nSince `scottish_deerhound` is the most common breed, let's take a look at it.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"Image('../input/dog-breed-identification/train/0042188c895a2f14ef64a918ed9c7b64.jpg')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's look at another image,","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"Image('../input/dog-breed-identification/train/01e787576c003930f96c966f9c3e1d44.jpg')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now as humans, we can identify some patterns/features of this breed. \n\nLet's look at some of the features of this breed :\n\n1. It looks like a large greyhound cloaked in a wiry coat. \n2. This breed has long, slender legs, like a greyhound.\n3. It has relatively narrow body, deep chest, tucked abdomen, arched loin      and long tail.\n4. It is Dolichocephalic (long face).\n\nNow let's see if our model can similarly figure out different features from this data.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Now let's map `images` and their `labels` ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create pathnames from image ID's\nfilenames = []","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filenames = []\nfor filename in labels_csv['id']:\n    filenames.append('../input/dog-breed-identification/train/' + filename + '.jpg')\nfilenames[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check if number of filenames are equal to number of actual image files.\nimport os\nif len(os.listdir('../input/dog-breed-identification/train/')) == len(filenames):\n    print('Yes ! they match')\nelse:\n    print('No, they don\\'t')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Awesome, number of filenames are equal to number of image files.\n\nLet's make one last check.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(labels_csv['breed'][9000])\nImage(filenames[9000])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"WOAHHH ! What a beast, looks like a lion.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Since we've a list of training image filepaths, it's time to prepare our labels.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"labels = labels_csv['breed']\nlabels = np.array(labels)\nlabels\n\n# Or we can ,\n# labels = labels_csv['breed'].to_numpy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(labels)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now in case we had structured data, in order to find the missing values, we had `df.isnull().sum()`.\n\nBut since we're dealing with unstructured data, we have to check for missing values by comparing length of `filenames` and `labels`.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check if number of labels are equal to number of filenames.\nimport os\nif len(filenames) == len(labels):\n    print('Yessssss ! no missing values ;-)')\nelse:\n    print('Nooooo ! Look\\'s like we have missing values to deal with')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Beautiful, looks like we don't have any missing data.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's find unique label values.\nunique_breeds = np.unique(labels)\nunique_breeds\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(unique_breeds)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Awesome ! Since we had 120 breed of dogs.\n\nNow let's turn labels into boolean array.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(labels[0])\nlabels[0] == unique_breeds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"boolean_labels = [label == unique_breeds for label in labels]\nboolean_labels[:2]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating a validation set","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nX = filenames\ny = boolean_labels","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's first train on 1000 images.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Splitting into train and validation set.\nX_train, X_valid, y_train, y_valid = train_test_split(X[:1000], y[:1000], test_size = 0.2, random_state = 42)\n\n# Checking the dimensions of train and validation set\nlen(X_train), len(X_valid), len(y_train), len(y_valid)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's look if everything is fine.\nX_train[:1], y_train[:1]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Preprocessing the images.\n\nIt's time to convert images into tensors :\n1. Take an image filepath as input\n2. Use tensorflow to read the file and save it to a variable, `image`.\n3. Turn `image` ('.jpg') into tensor\n4. Normalize image (convert colour channels from 0-255 to 0-1\n5. Resize `image` to a shape of (224, 224)\n6. Return the modified `image`.\n\nNow before that, let's import an image","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from matplotlib.pyplot import imread\nimage = imread(filenames[30])\nimage.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image.max(), image.min()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can almost convert anything into a tensor using `tf.constant()`","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"tf.constant(image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Define image size\n#IMG_SIZE = 224\n\n# Create a function that preprocessess images\ndef image_process(image_path):\n    '''\n    Takes an image filepath and converts image into a tensor\n    '''\n    # Read image file\n    image = tf.io.read_file(image_path)\n    \n    # Turn the jpg image into numerical tensor with 3 colour channels (red, green, blue)\n    image = tf.image.decode_jpeg(image, channels = 3)\n    \n    # Convert the colour channel values from 0-255 to 0-1 values\n    image = tf.image.convert_image_dtype(image, tf.float32)\n    \n    # Resize the image (224,224)\n    image = tf.image.resize(image, size = [224,224])\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Turning data into batches (default=32)\n\nIf you're trying to process 10222 images in one go, they won't fit into the memory.\n\nHence process 32 images at a time.\n\nIn order to use tensorflow effectively, our data has to be in the form of tensor tuples, like this :\n`(image, label)`","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating a function that return a tuple of image and tensor [(image, tensor)]\ndef get_image_label(image_path, label):\n    '''\n    Takes an image filepath name and the associated label,\n    processes the image and returns a tuple of (image, label)\n    '''\n    image = image_process(image_path)\n    return image, label","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now that we've converted our data into tuple of tensors `(image, label)`, let's turn all of our data(`X & y`) into batches.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating a function to turn data into batches.\ndef data_batcher(X, y=None, batch_size = 32, valid_data = False, test_data = False):\n    '''\n    Creates batches of data out of image (X) and label (y) pairs.\n    It shuffles if it's training data, but won't if it's validation data.\n    Also accepts test data as input (it doesn't have labels).\n    '''\n    \n    # If the data is test data, we won't have labels\n    if test_data:\n        print('Creating test data batches...')\n    \n        # Only filepaths, not labels\n        data = tf.data.Dataset.from_tensor_slices((tf.constant(X)))\n        data_batch = data.map(image_process).batch(32)\n        return data_batch\n\n    # If the data is valid dataset, we don't 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(32) \n        return data_batch\n    # If the data is training data set\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), # filepaths\n                                                   tf.constant(y))) # labels\n        \n        # Shuffle the pathnames and labels before mapping image processor function\n        # ... is faster than shuffling images\n        data = data.shuffle(buffer_size = len(X))\n        \n        # Create a image, label tuple and turns the image path into a preprocessed image\n        data = data.map(get_image_label)\n        \n        # Turning the training data into batches.\n        data_batch = data.batch(32) \n    return data_batch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create training and validation data batches.\ntrain_data = data_batcher(X_train, y_train)\nval_data = data_batcher(X_valid, y_valid, valid_data = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Check different attributes of our data batches.\ntrain_data.element_spec, val_data.element_spec","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Visualizing Data Batches\n\nAlthough our data is now in batches, it can be hard to understand.\n\nSo let's visualize it.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating a function to view images in a data batch\ndef show_lim_images(images,labels):\n    '''\n    Displays a plot of given number of images and their labels from a data batch.\n    '''\n    # Setting up the fig\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        # Display an image\n        plt.imshow(images[i])\n        # Add the image lable as title.\n        plt.title(unique_breeds[labels[i].argmax()])\n        # Turn the gridlines off\n        plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now let's visualize it.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images, train_labels = next(train_data.as_numpy_iterator()) \nshow_lim_images(train_images, train_labels)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_images, valid_labels = next(val_data.as_numpy_iterator()) \nshow_lim_images(valid_images, valid_labels)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Building the model\n\nBefore building a model, let's define a few things\n1. The input shape(our images in tensors) to our model.\n2. The output shape(image labels, in tensors) of our model.\n3. URL of the model we want to use : https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/4","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setup input shape to the model.\nINPUT_SHAPE = [None, 224, 224,3] #batch, height, width, colour channels.\n# Setup the output shape of the model.\nOUTPUT_SHAPE = len(unique_breeds)\n# Setup model URL from tensorflow hub.\nMODEL_URL = 'https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/4'","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now that we've our inputs, outputs and model all set up, let's use `Keras` api from `TensorFlow` for creating deep learning model.\n\nLet's create a function which:\n1. Takes input, output shape along with model we've chosen.\n2. Defines layers in the `Keras` model(Sequential fashion).\n3. Compiles the model.\n4. Builds the model.\n5. Returns the model.\n\nSource : https://www.tensorflow.org/guide/keras/overview","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_model(input_shape = INPUT_SHAPE, output_shape = OUTPUT_SHAPE, model_url = MODEL_URL):\n    print('Building model with : ', MODEL_URL, '...')\n    \n    #Setting up the model layers\n    model = tf.keras.Sequential([\n        hub.KerasLayer(MODEL_URL), #1st layer/input layer\n        tf.keras.layers.Dense(units = OUTPUT_SHAPE,\n                              activation='softmax')])#2nd/output layer\n    \n    # Compiling the model\n    model.compile(loss=tf.keras.losses.CategoricalCrossentropy(),\n                  optimizer=tf.keras.optimizers.Adam(),\n                  metrics=['accuracy'])\n        \n    # Building the model\n    model.build(INPUT_SHAPE)\n    \n    return model    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = create_model()\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Callbacks\n\nCallbacks are like checkpoints that we have in games, it checks progress or stop training if there's no significant improvement in model.\n\nSo now we create a callback, \n* To stop the model early, if it's training for too long, because that'll lead to overfitting.\n\n\n### Stopping Callback\n\nSometimes the model keeps on training evem though there is no improvement, which will cause overfitting. At times like that we use a callback to stop the model to train.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create early stopping \nearly_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"val_accuracy\",\n                                                  patience=3) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training\n\nNow we won't train on all of our data, just 1000 images (800-training, 200-validation), As this will save us time.\n\nThe final parameter we'll define before training is NUM_EPOCHS (also known as number of epochs).\n\nNUM_EPOCHS defines number of passes of the data we'd like our model to do.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Build a function to train and return a trained model (100 epochs)\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_tf_callback()\n\n    # Fit the model to the data passing it the callbacks we created\n    model.fit(x=train_data,\n          epochs=100,\n          validation_data=val_data,\n          validation_freq=1, # check validation metrics every epoch\n          callbacks=[early_stopping])\n  \n    # Return the fitted model.\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Fit the model to the data\nmodel = train_model()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Looking at the accuracy and difference between accuracy and val_accuracy, it seems that the model is overfitting.\n\nWhile it is doing exceptionally good on training data, it's not doing that good on validation data.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Predictions\n\nMaking predictions with our model returns an array with a different value for each label.\n\nIn this case, making predictions on the validation data (200 images) returns an array (predictions) of arrays, each containing 120 different values (one for each unique dog breed).\n\nThese different values are the probabilities or the likelihood the model has predicted a certain image being a certain breed of dog. The higher the value, the more likely the model thinks a given image is a specific breed of dog.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Make predictions on the validation data (not used to train on)\npredictions = model.predict(val_data, verbose=1)\npredictions[0] # Predictions of one image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def pred(index):\n    '''\n    Takes index value from the predictions and returns \n    highest confidence level index of the highest confidence value\n    and dog breed.\n    '''\n    max_value = np.max(predictions[index])\n    max_value_index = predictions[index].argmax()\n    breed_at_that_index = unique_breeds[max_value_index]\n    print(f\"Confidence Level for first image : {max_value}\")\n    print(f\"Index for the Max Value : {max_value_index}\")\n    print(f\"Breed at that Index :  {breed_at_that_index}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred(0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Hmmm, lets see according to the model, it's highly probable that the dog in the first image is a `cairn`, with a confidence of 45.13%.  Now this is variable, because we've shuffled the training data.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Now let's take our `val_data`(which is in batches) and get a list of it, or basically unbatch it.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Turn prediction probabilities into their respective label (easier to understand)\ndef get_pred_label(prediction_probabilities):\n  \"\"\"\n  Turns an array of 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[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a function to unbatch.\ndef unbatch(data):\n    '''\n    Takes a dataset(which is in batches), and unbatches it. \n    '''\n    images = []\n    labels = []\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","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_images, val_labels = unbatch(val_data)\nval_images[0], val_labels[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Let's visualize the predictions.\n\nNow we've got ways to get:\n1. Prediction labels\n2. Validation labels(truth labels)\n3. Validation images\n\nLets visualize it with a function.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot(pred_probs, labels, images, n=1):\n    '''\n    View prediction, actual truth, and image for sample n\n    '''\n    pred_prob, true_label, image = pred_probs[n], labels[n], images[n]\n    \n    #Getting pred \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    # Changing colour, depending upon whether the prediction is right or wrong.\n    if pred_label == true_label:\n        color='green'\n    else:\n        color='red'\n    \n    \n    # Change plot title\n    plt.title('{} - {:2.0f}%\\n{}'.format(pred_label, \n                                   np.max(pred_prob)*100,\n                                   true_label),\n                                   color=color)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot(predictions, val_labels, val_images,73)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now that we've visualized the model's predictions, let's look at the top 10 predictions.","execution_count":null},{"metadata":{"trusted":true},"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=\"black\")\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(\"red\")\n  else:\n    pass","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_pred_conf(prediction_probabilities=predictions,\n               labels=val_labels,\n               n=20)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"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_probs=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()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Saving a model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from datetime import datetime\ndef save_model(model, suffix=None):\n  \"\"\"\n  Saves a given model in a models directory and appends a suffix (str)\n  for clarity and reuse.\n  \"\"\"\n  # Create model directory with current time\n  modeldir = os.path.join(\"\",\n                          datetime.now().strftime(\"%Y%m%d-%H%M%s\"))\n  model_path = modeldir + \"-\" + suffix + \".h5\" # save format of model\n  print(f\"Saving model to: {model_path}...\")\n  model.save(model_path)\n  return model_path","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_model(model_path):\n  \"\"\"\n  Loads a saved model from a specified path.\n  \"\"\"\n  print(f\"Loading saved model from: {model_path}\")\n  model = tf.keras.models.load_model(model_path,\n                                     custom_objects={\"KerasLayer\":hub.KerasLayer})\n  return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Save our model trained on 1000 images\nsave_model(model, suffix=\"1000-images-Adam\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training a model in full dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Turn full training data in a data batch\nfull_data = data_batcher(X, y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Instantiate a new model for training on the full dataset\nfull_model = create_model()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Lets make some callbacks too.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create full model callbacks\nfull_model_early_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"accuracy\",\n                                                             patience=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Fitting the model on full data.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Fit the full model to the full training data\nfull_model.fit(x=full_data,\n               epochs=5,\n               callbacks=[full_model_early_stopping])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's save this model.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"save_model(full_model, suffix=\"all-images-Adam\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load test image filenames (since we're using os.listdir(), these already have .jpg)\ntest = \"/kaggle/input/dog-breed-identification/test/\"\ntest_filenames = [test + fname for fname in os.listdir(test_path)]\n\ntest_filenames[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create test data batch\ntest_data = data_batcher(test_filenames, test_data=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Make predictions on test data batch using the loaded full model\ntest_preds = full_model.predict(test_data,\n                                             verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating pandas DataFrame with empty columns\nsubm_df = pd.DataFrame(columns=[\"id\"] + list(unique_breeds))\n# Append test image ID's to predictions DataFrame\ntest = \"/kaggle/input/dog-breed-identification/test/\"\nsubm_df[\"id\"] = [os.path.splitext(path)[0] for path in os.listdir(test)]\n# Add the prediction probabilities to each dog breed column\nsubm_df[list(unique_breeds)] = test_predictions\nsubm_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Taking a .csv output for submission\nsubm_df.to_csv(\"Submissions.csv\",\n                 index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}