{"cells":[{"metadata":{"id":"5Lm-0oy4HQTI","outputId":"e77384f7-6b01-4c8b-ad7f-3233b96a7218","trusted":false},"cell_type":"code","source":"!pip3 uninstall -y kaggle","execution_count":null,"outputs":[]},{"metadata":{"id":"i8yUUSj8IoEC","outputId":"d87b0fd9-8d9f-4bc1-94de-fd518ca5ff01","trusted":false},"cell_type":"code","source":"!pip3 install kaggle==1.5.6","execution_count":null,"outputs":[]},{"metadata":{"id":"jOk7MoiCGilg","outputId":"0916ce9a-a6ef-4da3-fb3a-b5b2648f60c3","trusted":false},"cell_type":"code","source":"from google.colab import files\nfiles.upload()","execution_count":null,"outputs":[]},{"metadata":{"id":"KbnmVRkkHgzw","trusted":false},"cell_type":"code","source":"!mkdir .kaggle\n!cp kaggle.json .kaggle/","execution_count":null,"outputs":[]},{"metadata":{"id":"IJK6xTEJH60p","trusted":false},"cell_type":"code","source":"!mv .kaggle/ /root/","execution_count":null,"outputs":[]},{"metadata":{"id":"lxx4kEahIIu4","trusted":false},"cell_type":"code","source":"!chmod 600 /root/.kaggle/kaggle.json","execution_count":null,"outputs":[]},{"metadata":{"id":"cG88t-hTJKp5","outputId":"0e7e4997-4db5-4c1a-8b76-b571befb51b4","trusted":false},"cell_type":"code","source":"!kaggle competitions download -c \"dog-breed-identification\"","execution_count":null,"outputs":[]},{"metadata":{"id":"RlDLwtDFJiuc","outputId":"6d3087a3-1101-4c51-8095-a8e818c63ddd","trusted":false},"cell_type":"code","source":"!unzip \"/content/dog-breed-identification.zip\"","execution_count":null,"outputs":[]},{"metadata":{"id":"UAiU_DGx_zYQ"},"cell_type":"markdown","source":"## 🐶 End-to-end Multi-class Dog Breed Classification\n\nThis notebook builds a multi-class image classifier using TensorFlow 2.0 and TensorFlow Hub\n\n## Problem\n\nIdentifying the breed of the dog given the image of it.\n\n## Data\n\nThe dataset I'm using is from Kaggle's Dog breed identification competition.\n\nhttps://www.kaggle.com/c/dog-breed-identification/data\n\n## Evaluation\n\nThe  evaluation is a file with prediction probabilities for each dog breed of each test image.\n\nhttps://www.kaggle.com/c/dog-breed-identification/overview/evaluation\n\n## Features\n\n- We're dealing with images (unstructured) so we use TensorFlow/Deep learning\n- We have 120 dog breeds in our project (that means there are 120 different classes).\n\n\n\n## Getting our Workspace ready"},{"metadata":{"id":"iSxIqjGq8KDe","outputId":"5d58da60-7d9c-4efe-86b5-b3a971a195a4","trusted":false},"cell_type":"code","source":"import tensorflow as tf\nimport tensorflow_hub as hub\n\nprint(\"TF version: \", tf.__version__)\n\nprint(\"GPU\", \"available\" if tf.config.list_physical_devices(\"GPU\") else \"not available :(\")","execution_count":null,"outputs":[]},{"metadata":{"id":"8PKaFnEHN-hF"},"cell_type":"markdown","source":"## Getting our data ready\n\nWith all our mechine learning models, all our data should be in numerical format.\n\nTurning our data(images) into Tensors(numerical reprasentation)"},{"metadata":{"id":"Xhd7SSvQD35r","outputId":"eeb2d4cd-3517-4e91-c3a9-ffd8a6b8119c","trusted":false},"cell_type":"code","source":"import pandas as pd\nlabel_csv = pd.read_csv(\"/content/labels.csv\")\nprint(label_csv.describe())\nlabel_csv.head()","execution_count":null,"outputs":[]},{"metadata":{"id":"6raZfutUPKW0","outputId":"31d38c6a-c507-441f-c6fe-b3bb95dd5fbf","trusted":false},"cell_type":"code","source":"label_csv.breed.value_counts().plot.bar(figsize=(20, 10));","execution_count":null,"outputs":[]},{"metadata":{"id":"2aFtTrjiPlcC","outputId":"9abd09b5-e3f6-4955-c167-78fa56111324","trusted":false},"cell_type":"code","source":"from IPython.display import Image\nImage(\"train/0021f9ceb3235effd7fcde7f7538ed62.jpg\")","execution_count":null,"outputs":[]},{"metadata":{"id":"MROpQs_RpSWc"},"cell_type":"markdown","source":"## Getting Images & their labels\n\ngetting the image file pathnames"},{"metadata":{"id":"gTh_3EnRoAAK","outputId":"ac1691b6-1fb3-4e4f-e7b0-7162b9f312e6","trusted":false},"cell_type":"code","source":"#  Create pathnames with image ID's\n\nfilenames = [\"train/\" + fname + \".jpg\" for fname in label_csv.id]\n\nfilenames[:10]","execution_count":null,"outputs":[]},{"metadata":{"id":"zgyBVCYhp27W","outputId":"9c46ba95-5542-4067-964d-8ee966155968","trusted":false},"cell_type":"code","source":"# Checking\nimport os\nlen(os.listdir(\"train\")) == len(filenames)","execution_count":null,"outputs":[]},{"metadata":{"id":"o4JIC9GKq17z","outputId":"bdf66b1b-3dc6-4b1b-846e-9883f471a42e","trusted":false},"cell_type":"code","source":"print(label_csv.breed[9000])\nImage(filenames[9000])","execution_count":null,"outputs":[]},{"metadata":{"id":"fchevAcJsMKX","outputId":"9bc07d5d-9784-4247-a63c-038c524b63c8","trusted":false},"cell_type":"code","source":"import numpy as np\nlabels = label_csv.breed.to_numpy()\n\nlabels","execution_count":null,"outputs":[]},{"metadata":{"id":"1v-UixmEs2NZ","outputId":"413e8c67-46c5-416f-fc3c-0ad3a6b25591","trusted":false},"cell_type":"code","source":"# Find unique label values\nunique_breeds = np.unique(labels)\nlen(unique_breeds)","execution_count":null,"outputs":[]},{"metadata":{"id":"NlYRWPxztIVa","outputId":"83b53710-8500-45ad-c451-1d6723c8227f","trusted":false},"cell_type":"code","source":"# Turn single label into array of boolean label\nlabels[0]\nlabels[0] == unique_breeds","execution_count":null,"outputs":[]},{"metadata":{"id":"sjyYPF7NuTqH","outputId":"f2ece50b-78e7-473a-ab26-f067df961e83","trusted":false},"cell_type":"code","source":"# Turning every label in to boolean array\nbool_labels = [label == unique_breeds for label in labels]\nbool_labels[:2]","execution_count":null,"outputs":[]},{"metadata":{"id":"LeD6YX-0utK6","outputId":"4da8f200-2481-4f96-cb65-89a04392687e","trusted":false},"cell_type":"code","source":"# accessing labels in form of int's\nprint(labels[0])\nprint(bool_labels[0].argmax())\nprint(bool_labels[0].astype(int))","execution_count":null,"outputs":[]},{"metadata":{"id":"inYdlCBrw9gN"},"cell_type":"markdown","source":"## Creating a Validation dataset\n\nSince the dataset from kaggle doesn't come with a validation set."},{"metadata":{"id":"cSYZ4BGsva4X","trusted":false},"cell_type":"code","source":"# setup X, y labels\nX = filenames\ny = bool_labels","execution_count":null,"outputs":[]},{"metadata":{"id":"UW4APRRbyNi8"},"cell_type":"markdown","source":"We're going to start off with ~1000 images and imcrease as needed"},{"metadata":{"id":"XLQESpmjwdzY","trusted":false},"cell_type":"code","source":"# Set no.of images to use for experimenting\nNUN_IMAGES = 1000 #@param {type:\"slider\", min:1000, max:10000, step:100}","execution_count":null,"outputs":[]},{"metadata":{"id":"768bOKOwybHE","outputId":"e07c2662-3748-4688-e7b0-0d4ced02b01e","trusted":false},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_val, y_train, y_val = train_test_split(X[:NUN_IMAGES],\n                                                  y[:NUN_IMAGES],\n                                                  test_size = 0.2,\n                                                  random_state = 69)\n\nlen(X_train), len(y_train), len(X_val), len(y_val)","execution_count":null,"outputs":[]},{"metadata":{"id":"TDnvuV3s0uIA"},"cell_type":"markdown","source":"## Preprocessing Images\n\nTo preprocess our images into Tensors we're going to write a functio which does a few things.\n1. Turn a image filepath as input.\n2. Use TensorFlow to read this file and store it to a varible, `image`.\n3. Turn our `image` into a Tensor.\n4. Convert the `image` colour channel values from 0-255 to 0-1\n5. Resize the `image` to be a shape of (224, 224).\n6. Return the modified `image`"},{"metadata":{"id":"b9F_rgmvzv4U","outputId":"f316a3a5-5731-4e80-b2be-af8f1b9da458","trusted":false},"cell_type":"code","source":"# convert image ti a NumPy array\nfrom matplotlib.pyplot import imread\nimage = imread(filenames[69])\nimage.shape","execution_count":null,"outputs":[]},{"metadata":{"id":"gP_Lk3IJ3Hp2","outputId":"7c0026cd-d53d-46f3-e276-e0b4ce2fee85","trusted":false},"cell_type":"code","source":"image # \"3\" means RGB (our image is represented in RGB format)","execution_count":null,"outputs":[]},{"metadata":{"id":"UhBs1Lwo3KJY","outputId":"066c03e9-54d6-41e3-cd54-d506abbbea6d","trusted":false},"cell_type":"code","source":"# Turn image into a tensor\ntf.constant(image)","execution_count":null,"outputs":[]},{"metadata":{"id":"3jLFM7il3bC2","trusted":false},"cell_type":"code","source":"# Written from TensorFlow Load Image section in TensorFlow website (See there)\n\nIMG_SIZE = 224\n# Create a functio to resize the image\ndef process_img(image_path, image_size=IMG_SIZE):\n\n  # Read in an Image file.\n  image = tf.io.read_file(image_path)\n  # Turn jpeg into numerical Tensor with color channel 3\n  image = tf.image.decode_jpeg(image, 3)\n  # Convert the colour channel values from 0-255 to 0-1\n  image = tf.image.convert_image_dtype(image, tf.float32)\n  # Resize our image to our desired value\n  image = tf.image.resize(image, size=(IMG_SIZE, IMG_SIZE))\n\n  return image","execution_count":null,"outputs":[]},{"metadata":{"id":"JSUxhSozNcbQ"},"cell_type":"markdown","source":"## Turning our data into batches.\n\nWhy turn our data into batches?\n\nlet's say we are trying ot process 10,000+ images in one go.....they all might not fit into memory.\n\nSo that's why we do 32 (batch size) images at a time.(you can manually adjust the batch size).\n\n> In oredr to use TensorFlow effectively, we need our data in the form of Tensor tuples (looks like: `(image, label)`)."},{"metadata":{"id":"D8SiEBxy8fx7","trusted":false},"cell_type":"code","source":"# Create a simple functio to return Tensor tuple (image, label)\ndef get_image_label(image_path, label):\n  image = process_img(image_path)\n  return (image, label)","execution_count":null,"outputs":[]},{"metadata":{"id":"sgnKs-x7POI9","outputId":"49d5a751-f4c7-4889-9994-05b92223bb02","trusted":false},"cell_type":"code","source":"(process_img(X[69]), tf.constant(y[69]))","execution_count":null,"outputs":[]},{"metadata":{"id":"DmhEnyTRWcYr"},"cell_type":"markdown","source":"Now we've got a way to turn our data into tuples of Tensors in the form : `(image, label)`. let's turn all our data (`X` & `y`) into batches"},{"metadata":{"id":"FLqrck5mP6k0","trusted":false},"cell_type":"code","source":"BATCH_SIZE = 32\n\n#Create a functio to turn data into batches\ndef create_data_batches(X, y=None, batch_size=BATCH_SIZE, valid_data=None, test_data=None):\n  \"\"\"\n  Creates batches of data out of image (X) and label (y) pairs.\n  Shuffels data if it's training data but doesn't shuffle if it's validation data.\n  Also accepts test_data as input (no labels)\n  \"\"\"\n  if test_data:\n    print(\"Creating test data batches...\")\n    data = tf.data.Dataset.from_tensor_slices((tf.constant(X)))\n    data_batch = data.map(process_img).batch(BATCH_SIZE)\n    return data_batch\n\n  elif valid_data:\n    print(\"Creating validation data batches...\")\n    data = tf.data.Dataset.from_tensor_slices((tf.constant(X),\n                                               tf.constant(y)))\n    data_batch = data.map(get_image_label).batch(BATCH_SIZE)\n    return data_batch\n\n  else:\n    print(\"Creating Training data batches...\")\n    data = tf.data.Dataset.from_tensor_slices((tf.constant(X),\n                                               tf.constant(y)))\n    # Shuffeling pathnames and labels before mapping image processor function is faster than shuffeling images\n    data = data.shuffle(buffer_size = len(X))\n    data_batch = data.map(get_image_label).batch(BATCH_SIZE)\n\n  return data_batch\n","execution_count":null,"outputs":[]},{"metadata":{"id":"gDjNFg6uyNLY","outputId":"bb72a9cb-9fcb-43e0-ea92-7b00ad95c81e","trusted":false},"cell_type":"code","source":"train_data = create_data_batches(X_train, y_train)\nval_data = create_data_batches(X_val, y_val, valid_data=True)","execution_count":null,"outputs":[]},{"metadata":{"id":"1PPxYmWPzK6c","outputId":"c4a15bf8-4fbc-4e48-faa6-fffc25730572","trusted":false},"cell_type":"code","source":"train_data.element_spec, val_data.element_spec","execution_count":null,"outputs":[]},{"metadata":{"id":"aFtAo3Laup5I"},"cell_type":"markdown","source":"## Visualizing Data batches\n\nOur Data now is in batches, however these can be a little harder to understand/comprehend. Let's visualize them."},{"metadata":{"id":"ct0h7GmwWKVB","trusted":false},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n\ndef show_25_images(image, labels):\n  plt.figure(figsize=(10, 10))\n  for i in range(25):\n    ax = plt.subplot(5, 5, i+1)\n    plt.imshow(image[i])\n    plt.title(unique_breeds[labels[i].argmax()])\n    plt.axis(\"off\")","execution_count":null,"outputs":[]},{"metadata":{"id":"u-6MemaPxJUT","trusted":false},"cell_type":"code","source":"train_images, train_labels = next(train_data.as_numpy_iterator())","execution_count":null,"outputs":[]},{"metadata":{"id":"4rSGn9PuyG12","outputId":"9882e409-9678-4d4c-a471-fd9bd007d307","trusted":false},"cell_type":"code","source":"show_25_images(train_images, train_labels)","execution_count":null,"outputs":[]},{"metadata":{"id":"fGRENh3-Czl0"},"cell_type":"markdown","source":"## Building a model\n\nBefore we build our model, there are few things we need to define:\n- The input shape (our image shape, in the form of tensors) to our model.\n- The output shape (image labels, in the form of tensors) of our model.\n- The URL of the model we want to use from TensorFlow Hub - https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/4"},{"metadata":{"id":"dvka2IRPzsZX","trusted":false},"cell_type":"code","source":"INPUT_SHAPE = [None, IMG_SIZE, IMG_SIZE, 3] # batch size, height, width, colour channels.\n\nOUTPUT_SHAPE = len(unique_breeds)\n\nMODEL_URL = \"https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/4\"","execution_count":null,"outputs":[]},{"metadata":{"id":"8ygEu_MDQo9q"},"cell_type":"markdown","source":"Now we've got our inputs, outputs & model ready to go.Let's put them all together in keras deeplearning model.\n\nlet's Create a function:\n\n- Takes the input shape, output shape & model we've choosen as parameters.\n- Define the layers in keras model in sequential fashion (do this, then that, then that).\n- Compiles the model.\n- Builds the model(tells the model the input shape it'll be getting).\n- Returns the model.\n\n> All of these steps can be found here: https://www.tensorflow.org/guide/keras/sequential_model\n\n\n"},{"metadata":{"id":"Xi2nPYXCPbNN","trusted":false},"cell_type":"code","source":"# Creating a function that creates a keras model\ndef create_model(input_shape=INPUT_SHAPE, output_shape=OUTPUT_SHAPE, model_url=MODEL_URL):\n    print(\"Building model with: \", MODEL_URL)\n\n    # setup model layers\n    model = tf.keras.Sequential([\n        hub.KerasLayer(MODEL_URL), # layer 1 (INPUT LAYER)\n        tf.keras.layers.Dense(units=OUTPUT_SHAPE,\n                              activation=\"softmax\") # layer2 (OUTPUT LAYER)\n    ])\n\n    # Compile the model\n    model.compile(\n        loss = tf.keras.losses.CategoricalCrossentropy(),\n        optimizer = tf.keras.optimizers.Adam(),\n        metrics = [\"accuracy\"]\n    )\n\n    # Build a model\n    model.build(INPUT_SHAPE)\n\n    return model","execution_count":null,"outputs":[]},{"metadata":{"id":"5YFcECDSX2qx","outputId":"e3fe0401-d119-4c32-ee75-990c85a25ffb","trusted":false},"cell_type":"code","source":"model = create_model()\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"id":"VUYuMDBUeUGE"},"cell_type":"markdown","source":"## Creating Callbacks\n\nCallbacks are helper functions that a model can use during training to do such things as save it's progress, check it's progress or stop training early if model stops improving...\n\nWe'll create two callbacks, One for TensorBoard which helps track our models progress andanother for early stopping which prevents our model from training too long.\n\n### TensorBoard callback\n\nSetup:\n\n1. Load TensorBoard notebook extension. ✅\n2. Create a TensorBoard callback which is able to save logs to a directory and pass it to our models `fit` function. ✅\n3. Visualize our model training logs with the `%tensorboard` magic function (we'll do this after model training). ✅"},{"metadata":{"id":"ZN6eSbVGeRDq","trusted":false},"cell_type":"code","source":"# load TensorBoard notebook extension\n%load_ext tensorboard","execution_count":null,"outputs":[]},{"metadata":{"id":"4R7ddumvicPK","trusted":false},"cell_type":"code","source":"import datetime\n\n# TensorBoard callback\ndef tb_callback():\n    #Create a log dir for storing tensorboard logs\n    logdir = os.path.join(\"/content/logs\",\n                          datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\"))\n    return tf.keras.callbacks.TensorBoard(log_dir=logdir)","execution_count":null,"outputs":[]},{"metadata":{"id":"wctJK4TQkfSn"},"cell_type":"markdown","source":"## Early stopping callback\n\nHelps our model from overfitting, by stopping training if a certain evaluation metric stops improving.\n\nhttps://www.tensorflow.org/api_docs/python/tf/keras/callbacks/EarlyStopping"},{"metadata":{"id":"PriJMdvskMrt","trusted":false},"cell_type":"code","source":"early_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"val_accuracy\",\n                                                  patience=3)","execution_count":null,"outputs":[]},{"metadata":{"id":"GOFsZVGfm0QM"},"cell_type":"markdown","source":"## Training a model (on a subset of Data)\n\nFirst our model is going to train on 1000 images,to make sure everything is working ."},{"metadata":{"id":"lgVMcmnll162","trusted":false},"cell_type":"code","source":"NUM_EPOCHS = 100 #@param {type:\"slider\", min:10, max:100, step:10}","execution_count":null,"outputs":[]},{"metadata":{"id":"aiY-sp5XoB4E"},"cell_type":"markdown","source":"Let's create a model which trains our model\n\n- Create a model using `create_model()`.\n- Setup a TensorBoard callback using `tb_callback()`\n- Call a `fit` function on our model passing it the training data, validation data, no.of epochs to train for (`NUM_EPOCHS`) and callbacks we would like to use.\n- Return the model."},{"metadata":{"id":"OQ6X3xAFnfDM","trusted":false},"cell_type":"code","source":"def train_model():\n    \n    model = create_model()\n\n    tensorboard = tb_callback()\n\n    # Fitting the model\n    model.fit(x=train_data,\n              epochs=NUM_EPOCHS,\n              validation_data=val_data,\n              validation_freq=1,\n              callbacks=[tensorboard, early_stopping])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"id":"NjKqNfNdqj8N","outputId":"33975442-f40d-47b1-ae46-f30ca8c92713","trusted":false},"cell_type":"code","source":"model = train_model()","execution_count":null,"outputs":[]},{"metadata":{"id":"Cgpq3rKPQSVr"},"cell_type":"markdown","source":"> **NOTE:** Overfitting to begin with is a good thing! it means our model is learning!!!"},{"metadata":{"id":"CZM2ZJe5RUCU"},"cell_type":"markdown","source":"### Checking the TensorBoard logs\n\nThe tensorboard magic function(`%tensorboard`) will access the logs directly we created earlier and visualize them."},{"metadata":{"id":"_3umJAihrbIP","outputId":"f8dfd986-ca4d-4445-b4d0-2e911d41e23f","trusted":false},"cell_type":"code","source":"%tensorboard --logdir logs","execution_count":null,"outputs":[]},{"metadata":{"id":"yB8p9eRHfPC5"},"cell_type":"markdown","source":"## Making & Evaluating predictions using a trained model"},{"metadata":{"id":"jzDp9GfOR8DY","outputId":"7e21135f-36d5-4f8d-d8ac-d161a99792ef","trusted":false},"cell_type":"code","source":"predictions = model.predict(val_data, verbose=1)\npredictions","execution_count":null,"outputs":[]},{"metadata":{"id":"C9sksvlUjRn_","outputId":"34a39d5d-4189-430c-c745-adcd6a8533c0","trusted":false},"cell_type":"code","source":"predictions.shape # the val_data has 200 validation samples and each prediction is an array of probabilities of the perticular sample, the highest prob in the array is the max probability of the breed name. ","execution_count":null,"outputs":[]},{"metadata":{"id":"K_4kPErLi_dv","outputId":"226dfa58-f9af-4b1a-b38d-1a83d9ec4368","trusted":false},"cell_type":"code","source":"predictions[0]","execution_count":null,"outputs":[]},{"metadata":{"id":"oNccI8PojBrX","outputId":"a4ea6f39-5692-49fe-ce6c-c9ad17ccb787","trusted":false},"cell_type":"code","source":"np.sum(predictions[0])","execution_count":null,"outputs":[]},{"metadata":{"id":"x4IG-M36kkq-","outputId":"a764c0a5-6a66-47b4-c5eb-d87ecf6e88be","trusted":false},"cell_type":"code","source":"index = 69\nprint(f\"Max value: {np.max(predictions[index])}\")\nprint(f\"Sum: {np.sum(predictions[index])}\")\nprint(f\"Max index: {np.argmax(predictions[index])}\")\nprint(f\"Predicted label: {unique_breeds[np.argmax(predictions[index])]}\")","execution_count":null,"outputs":[]},{"metadata":{"id":"S0t7ZliwmjTn","outputId":"37dabbf7-484f-4e34-f93b-716a5943993d","trusted":false},"cell_type":"code","source":"def get_pred_label(prediction_probabilities):\n    \"\"\"\n    Turns arrary of predictions into labels\n    \"\"\"\n    return unique_breeds[np.argmax(prediction_probabilities)]\n\npred_label = get_pred_label(predictions[69])\npred_label","execution_count":null,"outputs":[]},{"metadata":{"id":"G1-2HmWTplWW"},"cell_type":"markdown","source":"Now since our validation data is still in a batch dataset, we will have to unbatch them to make predictionson validation images and make predictions on validation labels (truth labels)"},{"metadata":{"id":"4z45Rs35pAeM","trusted":false},"cell_type":"code","source":"# create a function to unbatch \n\ndef unbatchify(data):\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\n\nval_images, val_labels = unbatchify(val_data)","execution_count":null,"outputs":[]},{"metadata":{"id":"SinKdXGawoaE"},"cell_type":"markdown","source":"Now we've got ways to get:\n- prediction labels\n- validation labels (truth labels)\n- validation images\n\nLet's make some function to make these all a bit more visualize.\n\nWe'll create a function which:\n- Takes an array of prediction probabilities, an array of truth labels and an array of images and integers.\n- Convert the prediction probabilities to predicted labels.\n- Plot the predicted label, it's predicted probability, the truth label of the target image in a single plot"},{"metadata":{"id":"uTMZSKI_ru-g","trusted":false},"cell_type":"code","source":"def plot_pred(prediction_probabilities, labels, images, n=1):\n    pred_prob, true_label, image = prediction_probabilities[n], labels[n], images[n]\n    # Get pred label\n    pred_label = get_pred_label(pred_prob)\n\n    # plot image & remove ticks\n    plt.imshow(image)\n    plt.xticks([])\n    plt.yticks([])\n\n    # Change the colour of the title depending upon the prediction is right or wrong\n    if pred_label == true_label:\n        color = \"green\"\n    else:\n        color = \"red\"\n    \n    plt.title(\"{}  {:2.0f}%  {}\".format(pred_label,\n                                     np.max(pred_prob)*100,\n                                     true_label),\n              color=color)\n    pass","execution_count":null,"outputs":[]},{"metadata":{"id":"9Onj3SeOQ169","outputId":"0906891a-1dc4-4bbb-ff4b-5415e4d1dd72","trusted":false},"cell_type":"code","source":"plot_pred(prediction_probabilities=predictions,\n          labels=val_labels,\n          images=val_images,\n          n=100)","execution_count":null,"outputs":[]},{"metadata":{"id":"NXknrA1fr9uE"},"cell_type":"markdown","source":"Now we've got one function to visualize our model's top prediction,let's make anothe rto view our model's top 10 predictions.\n\nThis function will:\n- Take an input of prediction probabilities and the ground truth array and an integer.\n- Find the prediction label using `get_pred_label()`.\n- Find the top 10:\n    - Prediction probabilities indexes.\n    - Prediction probabilities values.\n    - Prediction labels.\n- Plot the top 10 prediction probability values, labels, colouring the truth label green."},{"metadata":{"id":"SFeLqZyFXFBn","trusted":false},"cell_type":"code","source":"# Confidence\ndef plot_pred_conf(prediction_probabilities, labels, n=1):\n    pred_prob, true_label = prediction_probabilities[n], labels[n]\n\n    pred_label = get_pred_label(pred_prob)\n\n    t10_pred_indexes = pred_prob.argsort()[-10:][::-1]\n    t10_pred_values = pred_prob[t10_pred_indexes]\n    t10_pred_labels = unique_breeds[t10_pred_indexes]\n\n    #Setup plot\n    t10_plot = plt.bar(np.arange(len(t10_pred_labels)),\n                       t10_pred_values,\n                       color=\"grey\")\n    plt.xticks(np.arange(len(t10_pred_labels)),\n               labels=t10_pred_labels,\n               rotation=\"vertical\")\n    \n    if np.isin(true_label, t10_pred_labels):\n        t10_plot[np.argmax(t10_pred_labels == true_label)].set_color(\"green\")\n    else:\n        pass","execution_count":null,"outputs":[]},{"metadata":{"id":"wuJCb9q8ccGE","outputId":"8bf3e081-7947-4641-8f6c-438c3732b87a","trusted":false},"cell_type":"code","source":"plot_pred_conf(prediction_probabilities=predictions,\n               labels=val_labels,\n               n=100)","execution_count":null,"outputs":[]},{"metadata":{"id":"NBoGOaxLvn-v"},"cell_type":"markdown","source":"Now let's check out few rpredictions and their different values."},{"metadata":{"id":"b-vSeLgXfsqh","outputId":"d5cf9b2c-f56e-415c-d488-c7cf294472d8","trusted":false},"cell_type":"code","source":"i_multiplier = 99\nnum_rows = 3\nnum_cols = 2\nnum_images = num_rows*num_cols\nplt.figure(figsize=(10*num_cols, 5*num_rows))\nfor i in range(num_images):\n    plt.subplot(num_rows, 2*num_cols, 2*i+1)\n    plot_pred(prediction_probabilities=predictions,\n              labels=val_labels,\n              images=val_images,\n              n=i+i_multiplier)\n    plt.subplot(num_rows, 2*num_cols, 2*i+2)\n    plot_pred_conf(prediction_probabilities=predictions,\n                   labels=val_labels,\n                   n=i+i_multiplier)\nplt.tight_layout(h_pad=1.0)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"id":"k3cFi42q0w3O"},"cell_type":"markdown","source":"## Saving and reloading the trained model"},{"metadata":{"id":"kJNrb22dxRDF","trusted":false},"cell_type":"code","source":"def save_model(model, suffix=None):\n    modeldir = os.path.join(\"/content/models\",\n                            datetime.datetime.now().strftime(\"%Y%m%d-%H%M%s\"))\n    model_path = modeldir + \"-\" + suffix + \".h5\" # save format of model.\n    print(f\"Save model to: {model_path}...\")\n    model.save(model_path)\n    return model_path","execution_count":null,"outputs":[]},{"metadata":{"id":"puhPpKqO2E6r","trusted":false},"cell_type":"code","source":"# Function for loading a trained model\ndef load_model(model_path):\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":{"id":"0PjezHHZ3DvX","outputId":"21e9c230-ba33-407d-d17f-e5d36bf44d59","trusted":false},"cell_type":"code","source":"# Save model that trained on 1000 images\nsave_model(model, suffix=\"1000-images-mobileNetv2-Adam\")","execution_count":null,"outputs":[]},{"metadata":{"id":"ZjgQolKaWFzl"},"cell_type":"markdown","source":"## Training on full data 🐶"},{"metadata":{"id":"8d0oUKH0WiNB","outputId":"c29e6c1c-3727-4883-dbcf-7683cc7be2a3","trusted":false},"cell_type":"code","source":"fdata = create_data_batches(X,\n                            y)","execution_count":null,"outputs":[]},{"metadata":{"id":"ccyTtG0rWusx","outputId":"e76b9f83-4fc5-4ddd-d78d-625048abd321","trusted":false},"cell_type":"code","source":"fdata.element_spec","execution_count":null,"outputs":[]},{"metadata":{"id":"HubsxXLVWyz4","outputId":"ff7ba6e5-1abb-4f7d-a370-9f4ef25d6452","trusted":false},"cell_type":"code","source":"fmodel = create_model()","execution_count":null,"outputs":[]},{"metadata":{"id":"p-fFnl_vXMp2","trusted":false},"cell_type":"code","source":"# Create callbacks\nfmodel_tensorboard = tb_callback()\n# NO validation set when training on all the data, so we can't monitor validation accuracy.\nfmodel_early_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"accuracy\",\n                                                         patience=3)","execution_count":null,"outputs":[]},{"metadata":{"id":"DFxSjO4hY8Rv"},"cell_type":"markdown","source":"**NOTE:** Running this cell will take a little while(maybe 30 mins for 1st EPOCH) becausethe GPU we are using in the runtime has to load all the images into memory."},{"metadata":{"id":"vmG7bY0NYQTc","outputId":"d508e82a-05d0-48aa-9c4d-b72e564144bd","trusted":false},"cell_type":"code","source":"fmodel.fit(x=fdata,\n           epochs=NUM_EPOCHS,\n           callbacks=[fmodel_tensorboard, fmodel_early_stopping])","execution_count":null,"outputs":[]},{"metadata":{"id":"zoVQCanSZkWs","outputId":"e19ee481-1650-415f-9366-b4bc07266c20","trusted":false},"cell_type":"code","source":"save_model(fmodel, suffix=\"FULL-mobileNetv2-Adam\")","execution_count":null,"outputs":[]},{"metadata":{"id":"YcbxWQ5mlIKV","outputId":"bf09d3b1-29e8-40d6-abb3-30042316d714","trusted":false},"cell_type":"code","source":"loaded_fmodel = load_model(\"/content/models/20200626-06161593152194-FULL-mobileNetv2-Adam.h5\")","execution_count":null,"outputs":[]},{"metadata":{"id":"uU90Y2vWl3qJ"},"cell_type":"markdown","source":"## Making Predictions on Test dataset\n\nSince our model has trained on images in the form of Tensor Batches, to make predictions on test dataset, we'll need to get in to the same format as trained dataset has.\n\nTo make predictions on test dataset, we'll have to:\n- Get the test image filenames.\n- Convert the filenames into test data batches using `create_data_batches()` and setting the `test_data` parameter to `True` (test data has no labels).\n- Make a predictions array by passing the test data batches to the `predict()` method called in our model."},{"metadata":{"id":"oQ1-cuVAlUWV","outputId":"abc695a8-f0fd-4310-f45a-d2c5213ee99b","trusted":false},"cell_type":"code","source":"test_path = \"test/\"\ntfilenames = [test_path + fname for fname in os.listdir(test_path)]\ntfilenames[:10]","execution_count":null,"outputs":[]},{"metadata":{"id":"vPwcOkdmpamM","outputId":"79c863ff-0979-4b79-a276-b7ca444e0dfa","trusted":false},"cell_type":"code","source":"tdata = create_data_batches(tfilenames, test_data=True)","execution_count":null,"outputs":[]},{"metadata":{"id":"XeLRsGbip7_v","outputId":"db44601a-22b5-4032-ca77-c3d1d0912ea6","trusted":false},"cell_type":"code","source":"tdata.element_spec","execution_count":null,"outputs":[]},{"metadata":{"id":"4GeTL9Q3qZw3"},"cell_type":"markdown","source":"**NOTE:** Calling `predict()` on fmodel and passing it the tdata will take long time to run."},{"metadata":{"id":"G4mfhLceqBEY","outputId":"efc0da72-d389-4eae-d076-74db0f85b58f","trusted":false},"cell_type":"code","source":"tpredictions = loaded_fmodel.predict(tdata,\n                             verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"id":"Q3zIBjzrrd8Z","trusted":false},"cell_type":"code","source":"# Save the predictions\nnp.savetxt(\"preds_array\", tpredictions, delimiter=\",\")","execution_count":null,"outputs":[]},{"metadata":{"id":"Eg3QNbu7vixx"},"cell_type":"markdown","source":"## Preparing test dataset predictions for Kaggle"},{"metadata":{"id":"xJ8U_ShWu5Ec","outputId":"43ca5b7f-f685-4232-bf12-1b1c0ddc0633","trusted":false},"cell_type":"code","source":"preds_df = pd.DataFrame(columns=[\"id\"] + list(unique_breeds))\npreds_df","execution_count":null,"outputs":[]},{"metadata":{"id":"QM_S1wKQxWg8","trusted":false},"cell_type":"code","source":"# Add test image ID's to predictions dataftame\ntest_ids = [os.path.splitext(path)[0] for path in os.listdir(test_path)]\npreds_df[\"id\"] = test_ids","execution_count":null,"outputs":[]},{"metadata":{"id":"YjtHVwzeyK-2","outputId":"0f7642a6-7d38-4781-eab9-b387d5255c4e","trusted":false},"cell_type":"code","source":"preds_df.head()","execution_count":null,"outputs":[]},{"metadata":{"id":"kHNwBco2yOJ5","outputId":"c7311b0d-2b4a-474d-cf63-3bf060918eb8","trusted":false},"cell_type":"code","source":"preds_df[list(unique_breeds)] = tpredictions\npreds_df.head()","execution_count":null,"outputs":[]},{"metadata":{"id":"uuf76ay8yqnJ","trusted":false},"cell_type":"code","source":"preds_df.to_csv(\"Full_model_predictions_submission.csv\",\n                index=False)","execution_count":null,"outputs":[]},{"metadata":{"id":"1sHtLmChSz1f","trusted":false},"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}