{"cells":[{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"# end-to_end_Multi-class-Doggo-Breed-Classification\nthis notebook builds an end-to-end multiclass image classifier using TenserFlow 2.0 and TenserFlow Hub"},{"metadata":{},"cell_type":"markdown","source":"## 1. Problem Statement\nIdentifying The Breed of a dog given an image of a Dog."},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## 2. Data\nfrom Kaggle"},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## 3. Evaluation\nThe Evaluation is a file with prediction probabilities for each dog breed of each test image.\n\n"},{"metadata":{},"cell_type":"markdown","source":"## 4. Features\nsome information about the data:\n* We are dealing with images (Unstructured data) so it's  probably use deep learning / transfer learning .\n* There are 120 breeds of dogs (this means there are 120 different classes)\n* There are around 10k+ images in the training set (these images have labels)\n* There are around 10k+ images in the test set (these images have no labels we'll want to predict them)\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Import necessary tools into kaggle\nimport tensorflow as tf\nimport tensorflow_hub as hub\nprint(\"TF version : \",tf.__version__)\nprint(\"TF Hub version : \", hub.__version__)\n\n# Cheak for GPU availability\nprint(\"GPU\",\"available (Yes !)\" if tf.config.list_physical_devices(\"GPU\") else \"Not Available\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"## Getting our data ready (turning into tensors)\n\nWith all machine learning models, our data has to be in numerical format. So  that's what we'll be doing first. Tuning our images into tensors (numerical representation).\n\nLet's Start By acessing our data and cheaking out the labels"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cheakout the labels of our data\nimport pandas as pd\nlabels_csv = pd.read_csv(\"../input/dog-breed-identification/labels.csv\")\nprint(labels_csv.describe())\nprint(labels_csv.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv[\"breed\"].value_counts().plot.bar(figsize=(20,10));","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv[\"breed\"].value_counts().median()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's view an image\nfrom IPython.display import Image\nImage(\"../input/dog-breed-identification/train/001513dfcb2ffafc82cccf4d8bbaba97.jpg\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Getting images and labels\nlet's get a list of all our images file pathnames"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_csv.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create pathnames from image ID's\nfilenames = [\"../input/dog-breed-identification/train/\"+names+\".jpg\" for names in labels_csv[\"id\"] ]\n# Cheak the first 10\nfilenames[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cheak weather number of filenames matches number of actual image files\nimport os\nif len(os.listdir(\"../input/dog-breed-identification/train/\"))==len(filenames):\n    print(\"Filenames match equal ammount of files ! Proceed\")\nelse:\n    print(\"filenames do not match actual ammount of files, cheak the target directory.\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"Image(filenames[9275])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Since we've now got our training image filepaths in a list, let's prepare our labels "},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nlabels = labels_csv[\"breed\"].to_numpy()\n# labels = np.array(labels)  # Does same thing as above\nlabels , len(labels)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# See if number of labels matches the number of filenames\nif len(labels) == len(filenames):\n    print(\"Number of labels matches number of filenames !\")\nelse:\n    print(\"Number of labels does not match number of filenames, cheak data directories\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Find the unique label values\nunique_breeds = np.unique(labels)\nunique_breeds,len(unique_breeds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Trun a single label into array of booleans\nprint(labels[0])\nlabels[0] == unique_breeds","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# turn every label into a boolean array\nboolean_labels = [label == unique_breeds for label in labels]\nboolean_labels[:2]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Example : Turning boolean array into integers\nprint(labels[0]) # original label\nprint(np.where(unique_breeds==labels[0])) # index where label occurs\nprint(boolean_labels[0].argmax()) # index where label occurs in boolean array\nprint(boolean_labels[0].astype(int)) # there will be a 1 where the sample label occurs","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(labels[2])\nprint(boolean_labels[2].astype(int))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filenames[:10]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating our own validation set \nSince the dataset from kaggle does'nt come with a validation set , we are going to create our own ."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setup X and Y variables \nX = filenames \nY = boolean_labels\nlen(filenames)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We're going to start off experimenting  with-1000 images and increase as needed"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Set number of images to use for experimenting\nNUM_IMAGES = 1000 #@param {type:\"slider\", min:1000 , max:10000 ,step:100 } works with colab","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's split our data into train and validation sets\nfrom sklearn.model_selection import train_test_split\n\nnp.random.seed(42)\n# Split them into training and validation of total size Num_Images\nX_train,X_valid,Y_train,Y_valid = train_test_split(X[:NUM_IMAGES],Y[:NUM_IMAGES],test_size=0.2,random_state=42)\n\nlen(X_train),len(Y_train),len(X_valid),len(Y_valid)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train[:2] ,Y_train[:2]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preprocessing Images(turning images into Tensors )\nTo preprocess our images into Tensors  We are going to write a function which does the few things:\n1. Take an image filepath as input \n2. Use TensorFlow to read the file and save it to a variable \"image\"\n3. Turn our \"image\" (a jpg) into Tensors\n4. Normalize our image (convert color channel values from 0-255 to 0-1)\n4. Resize the \"image to be a shape of (244, 244)\n5. Return the modified image \n\nBefore we do lets see what importing an image looks like "},{"metadata":{"trusted":true},"cell_type":"code","source":"# Convert image into NumPy array\nfrom matplotlib.pyplot import imread\nimage = imread(filenames[42])\nimage.shape\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image.max(),image.min()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Turn image into Tensor\ntf.constant(image)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tensor = tf.io.read_file(filenames[26])\ntensor","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tensor = tf.image.decode_jpeg(tensor ,channels=3)\ntensor","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"tensor = tf.image.convert_image_dtype(tensor, tf.float32)\ntensor","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Define image size \nIMG_SIZE = 224\n\n# Create a function for preprocessing images \ndef process_image(image_path,img_size=IMG_SIZE):\n    \"\"\"\n    Takes an image file path and turns the image into tensors\n    \"\"\"\n    \n    # Read in a image file \n    image = tf.io.read_file(image_path)\n    \n    # Turn the jpeg 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 to our desired value \n    image = tf.image .resize(image, size=[IMG_SIZE, IMG_SIZE])\n    \n    return image","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Turning our data into batches\n\nWhy turn our data into batches ?\n\nLet's say you're trying to process 10k+ images in one go... they all might not fit into memory \n\nSo that's why we do about 32 (this is the batch size) images at a time (you can manually adjust the batch size if need be)\n\nIn order to use Tenserflow effectively, we need our data in the form of Tensor tuples which look likes this `(image,label)`"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a simple 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","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"(process_image(X[42]),tf.constant(Y[42]))","execution_count":null,"outputs":[]},{"metadata":{},"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 make a function to turn all of our data ('X' and 'Y') into batches !"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Define the batch size, 32 is a good start\nBATCH_SIZE = 32\n\n# Create a function to turn into a batches \n\ndef create_data_batches(X, Y=None,batch_size=BATCH_SIZE, valid_data=False , test_data=False):\n    \"\"\"\n    Creates batches of data out of image (X) and label (Y) pairs.\n    Suffles the data if it is training data but does'nt suffle if it is validation data.\n    Also accepts test data as input (no labels)\n    \"\"\"\n    # If the data is a test dataset, we probably don't have labels\n    if test_data:\n        print(\"Creating test data batches... \")\n        data = tf.data.Dataset.from_tensor_slices((tf.constant(X)))  # Only filepaths (NO labels)\n        data_batch = data.map(process_image).batch(BATCH_SIZE)\n        return data_batch\n    \n    # If the data is a valid dataset , we don't need to suffle 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    # Training dataset\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        # Shffling pathnames and labels before mapping image processor function is faster than suffling 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 training data into batches\n        data_batch = data.batch(BATCH_SIZE)\n        \n    return data_batch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create training and validation data batches\ntrain_data = create_data_batches(X_train, Y_train)\nval_data = create_data_batches(X_valid, Y_valid ,valid_data=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cheakout the 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\nOur data is now batches, however, these can be a little hard to understand/comprehend, let's visualize the data batches"},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Create a function for viewing images in a data batch\ndef show_25_images(images,labels):\n    fig = plt.figure(figsize=(10,10))\n    for i in range(0,25):\n        fig.add_subplot(5,5,i+1)\n        plt.imshow(images[i])\n        plt.title(unique_breeds[train_labels[i].argmax()])\n        plt.axis(\"off\")\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_images, train_labels = next(train_data.as_numpy_iterator())\nlen(train_images),len(train_labels)\n\n# Now let's visualize the data in a training batch\nshow_25_images(train_images, train_labels)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# noe let's visualize our validation set\nvalid_images, valid_labels= next(val_data.as_numpy_iterator())\nshow_25_images(valid_images, valid_labels)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Building a model\n**Before we build a modelthere are few things we need to define:**\n\n* The input shape  (our images shape, in the form of tensor ) to our model.\n* The output shape (images labels, in the form of Tensors) of our model.\n* The URL of the model we want to use.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Setup the  input to the model\nINPUT_SHAPE = [None, IMG_SIZE,IMG_SIZE,3] # batch,height, Width ,colour channels\n\n# Setup the Output shape of the model\nOUTPUT_SHAPE = len(unique_breeds)\n\n# Setup model URL from tensorflow hub\nMODEL_URL = \"https://tfhub.dev/google/imagenet/mobilenet_v2_130_224/classification/4\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"\n\nNow we've got our inputs ,outputs and model ready to go.\n\nLet's put them together into a Keras deep learning model\n\nKnowing this ,let's create a function which:\n* Takes the input shape, output shape and the model we've choosen as parameters \n* Defines the layers in a Keras model in sequential fashion (do this first, then this then that ).\n* Compiles the model (says it should be evaluated and improved).\n* Builds the model (tells the model the input shape it'll be getting.\n* Returns the model\n\nAll of these steps can be found here https://www.tensorflow.org/guide/keras/overview"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a  function which builds a keras model \ndef create_model(input_shape=INPUT_SHAPE, output_shape=OUTPUT_SHAPE,model_url=MODEL_URL):\n    print(\"building model with : \",MODEL_URL)\n    \n    # Setup the model layers\n    model = tf.keras.Sequential([\n        hub.KerasLayer(MODEL_URL), # Layer 1 (input layer)\n        tf.keras.layers.Dense(units=OUTPUT_SHAPE,\n                             activation= \"softmax\")  # Layer 2 (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 the model\n    model.build(INPUT_SHAPE)\n    \n    return model\n    ","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":"# Creating callbacks\nCallbacks are helper functions a model can use during a training to do such things as save its progress, cheak its progress or stop training early if a model stops improving\n\nwe'll create two callbacks , one for Tensorboard which helps track our models progress and another for early stopping which prevents our model for training too long "},{"metadata":{"trusted":true},"cell_type":"markdown","source":"### Tensorboard callback\nTo setup a TensorBoard callback ,we need to do 3 things :\n\n1. Load the TensorBoard notebook extension\n2. Create a TensorBoard callback which is able to save logs to directory and pass it to our models fit function.\n3. Vissualize our models training logs with the `%tensorboard` magic function (we'll do this after model training).\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load TensorBoard notebook extension\n%load_ext tensorboard","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import datetime\n\n# Create a function to build a TensorBoard callback\ndef create_tensorboard_callback():\n    # Create a log directory for storing TensorBoard logs\n    logdir= os.path.join(\"../working/outputs/logs\",datetime.datetime.now().strftime(\"%Y%m%d-%H%M%S\"))\n    return tf.keras.callbacks.TensorBoard(logdir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"### Early Stopping Callback\n Early Stopping helps our model from overfitting by stopping training if certain evaluation metric stops improving "},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create early stopping callback\nearly_stopping =tf.keras.callbacks.EarlyStopping(monitor=\"val_accuracy\",patience=3)\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training a model (on subset of data)\n\nOur first model is only going to train on 1000 images, to make sure everything is working.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"NUM_EPOCHS = 100 #@param {type:\"slider\" ,min:10 , max:100}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Cheak to make sure we're still running on the GPU\nprint(\"GPU\",\"available (Yes !)\" if tf.config.list_physical_devices(\"GPU\") else \"Not Available\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's Create a function which trains a model\n\n* Create a model using `create_model()`\n* Setup the TensorBoard callback using `create_tensorboard_callback()`\n* Call the `fit()` function on out model passing it the train data, validation data,number of epochs to train for (`NUM_EPOCHS`) and the callbacks we'd like to use\n* Return the model\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Build a function to train and return a trained model\ndef train_model():\n    \"\"\"\n    Trains a given model and returns the trained version.\n    \"\"\"\n    # Create a model\n    model = create_model()\n    # Create new TensorBoard  sessiion everytime we train a model\n    tensorboard = create_tensorboard_callback()\n    # Fit the model to the data passing it the callbacks we created\n    model.fit(x=train_data,\n             epochs=NUM_EPOCHS,\n             validation_data= val_data,\n             validation_freq= 1,\n             callbacks= [tensorboard, early_stopping])\n    #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":"**Question : ** It looks like our model is overfitting far better on the training dataset than the validation  dataset, what are some ways to prevent model overfitting in deep learning neural networks? \n\n**Note : ** Overfitting to begin with is a good thing it means our model is learning!!! "},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Cheaking the TensorFlow logs\nthe tensorflow magic function (`%tensorboard`) will access the logs directory we created earlier and visualize its contents"},{"metadata":{"trusted":true},"cell_type":"code","source":"\n%tensorboard --logdir working/outputs/logs\n!kill 5770","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Making and evaluating predictions using a trained model"},{"metadata":{"trusted":true},"cell_type":"code","source":"val_data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = model.predict(val_data, verbose= 1)\npredictions","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(Y_valid)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# First prediction\nindex = 1\nprint(predictions[index])\nprint(f\"Max value (probablity of prediction): {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])]}\")\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"having the above functionality is great but we want to able to do ot at scale\n\nAnd it would be even better if we could see the image the prediction is being made on !\n\n**Note : **Prediction probablities are also known as confidence levels\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Turn the prediction probablities into their respctive label (easier to understand)\ndef get_pred_label(prediction_probabilities):\n    \"\"\"\n    turns an array of prediction probablities into labels.\n    \"\"\"\n    return unique_breeds[np.argmax(prediction_probabilities)]\n\n# Get a predicted label based on an array of prediction probablities \npred_label = get_pred_label(predictions[81])\npred_label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"Since now our validation data is still in a batch dataset, we'll have to unbatchify it to make predictions on the validation images and then compare those predictions to the validation labels(truth labels).\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"val_data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# create a function to unbatch a batch dataset\n\ndef unbatchify(data):\n    \"\"\"\n    Takes a batched dataset of (image, label) Tensors and returns separate arrays of images and labels.\n    \"\"\"\n    images = []\n    labels = []\n    # Loop through unbatched data\n    for image,label in data.unbatch().as_numpy_iterator():\n        images.append(image)\n        labels.append(unique_breeds[np.argmax(label)])\n    return images,labels\n\n# Unbatchify the validation data\nval_images ,val_labels = unbatchify(val_data)\nval_images[0] , val_labels[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"Now we got ways to get :\n\n* Prediction labels\n* Validation labels (truth labels)\n* Validation images\n\nLet's make some function to make these all a bit more visaulize\n\nWe'll create a function which :\n* Takes an array of prediction probablities, an array of truth labels and an array of images and integers.\n* Convert the prediction probablities to a predicted label.\n* Plot the predicted label , its predicted probablities truth label and the target image on a single plot.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_pred(prediction_probabilities, labels, images ,n=1):\n    \"\"\"\n    View the prediction, ground truth and image of the sample n\n    \"\"\"\n    pred_prob, true_label,image =prediction_probabilities[n] ,labels[n],images[n]\n    \n    # Get the pred label\n    pred_label = get_pred_label(pred_prob)\n    \n    # Plot image & remove ticks\n    plt.imshow(image)\n    plt.xticks([])\n    plt.yticks([])\n    # Change the color 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    # Change plot title to be predicted, probablity of prediction and truth label\n    plt.title(\"{} {:2.0f}% {}\".format(pred_label,\n                                     np.max(pred_prob)*100,\n                                     true_label),color=color)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_pred(prediction_probabilities= predictions,\n         labels= val_labels,\n         images= val_images,\n         n=77)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now we'll got one function to visualize our models top prediction , let's make another to view our model top 10 predictions \n\nThis function will:\n* Take an input of prediction probablities array and a ground truth array and an integer\n* Find the prediction 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 probablity values and labels , colouring the true label green"},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_pred_conf(prediction_probabilities , labels , n):\n    \"\"\"\n    Plus the top 10 highest prediction confidence along with the truth label for sample n.\n    \"\"\"\n    pred_prob, true_label = prediction_probabilities [n], labels[n]\n    \n    # Get the predicted label\n    pred_label = get_pred_label(pred_prob)\n    \n    # Find the top 10 prediction confidence indexes\n    top_10_pred_indexes = pred_prob.argsort()[-10:][::-1]\n    # Find the top 10 prediction confidence values\n    top_10_pred_values = pred_prob[top_10_pred_indexes]\n    # Find the top 10 prediction labels\n    top_10_pred_labels = unique_breeds[top_10_pred_indexes]\n    \n    # Setup plot \n    top_plot = plt.bar(np.arange(len(top_10_pred_labels)),\n                      top_10_pred_values,\n                      color=\"grey\")\n    plt.xticks(np.arange(len(top_10_pred_labels)),\n              labels=top_10_pred_labels,\n              rotation=\"vertical\")\n    \n    # Change the colour of true label\n    if np.isin(true_label, top_10_pred_labels):\n        top_plot[np.argmax(top_10_pred_labels == true_label)].set_color(\"green\")\n    else:\n        pass","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_pred_conf(prediction_probabilities=predictions,\n              labels=val_labels,\n              n=96\n              )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"Now we've got some function to help us visualize our predictions and evaluate our model, let's cheak out "},{"metadata":{"trusted":true},"cell_type":"code","source":"# Let's cheak out a few predictions and their different values \ni_multiplier = 20\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()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"** Challange ** How would you create a confusion matrix with our models predictions and true labels?\n"},{"metadata":{},"cell_type":"markdown","source":"# Saving and reloading a trained model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a function to save a model\ndef save_model(model, suffix=None):\n    \"\"\"\n    Saves a given model in a models directory and appends a suffix (string)\n    \"\"\"\n    # Create a model directory pathname with current time\n    modeldir = os.path.join(\"../working/models\",datetime.datetime.now().strftime(\"%Y%m%d-%H%M%s\"))\n    model_path = modeldir + \"-\" +suffix+\".h5\" # save format to 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":"# Create a function to load a train model \ndef load_model(model_path):\n    \"\"\"\n    Loads a save 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":{},"cell_type":"markdown","source":"Now we've got functions to save and load a trained model , let's make sure they work !"},{"metadata":{"trusted":true},"cell_type":"code","source":"! cd ../working","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"! mkdir models","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Save our model trained on 1000 images \nsave_model_path=save_model(model, suffix=\"1000-images-mobilenetv2-Adam\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Load a train model\nloaded_1000_image_adam_model = load_model(save_model_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Evaluate the loaded model \nloaded_1000_image_adam_model.evaluate(val_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Evaluate the pre-saved model\nmodel.evaluate(val_data)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training a big dog model on full dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"len(X) , len(Y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create a data set from a full dataset \nfull_data = create_data_batches(X,Y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"full_data","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create A model for full model\nfull_model = create_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create full model callbacks\nfull_model_tensorboard = create_tensorboard_callback()\n# No validation set when training on all the data, so we can't monitor validation accuracy \nfull_model_early_stopping = tf.keras.callbacks.EarlyStopping(monitor=\"accuracy\",patience=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Note : **Running the cell below will take a little while (maybe up to 30 min fo rthe first epoch ) because the GPU we're using in the runtime has to load all of the images into memory."},{"metadata":{"trusted":true},"cell_type":"code","source":"# Fit the full model to the full data\nfull_model.fit(x=full_data,\n              epochs=NUM_EPOCHS,\n              callbacks=[full_model_tensorboard, full_model_early_stopping])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"save_model(full_model,suffix=\"full-image-model-mobilenetv2-Adam\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Making Predictions on the test dataset\nSince our model has been trained on images in the form of tensors batches , to make predictions on the test data, we'll have to get into the same format.\n\nLuckily we created `create_data_batches()` earlier whichcan take a list of filenames as input and convert them into Tensor batches\n\nTo make predictions on the test data ,we'll: \n* Get the test image filenames \n* Convert the filenames into test data batches using `create_data_batches` and setting the `test_data` parameter to the `true` (since the test data does'nt have labels).\n* Make a predictions array by passing the test batches to the `predict()` method called on our model.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"import os \n# Load test image filenames\ntest_path = \"../input/dog-breed-identification/test/\"\ntest_filenames = [test_path + fname for fname in os.listdir(test_path)]\ntest_filenames\nids=[i[:-4] for i in os.listdir(test_path)]\ntest_filenames","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Create test databatch\ntest_data=create_data_batches(test_filenames,test_data=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Note : ** calling `predict()` on our full model and passing it test data batch will take a long time to run (above an hour)"},{"metadata":{"trusted":true},"cell_type":"code","source":"# make predictions on test data using full model\ntest_predictions = full_model.predict(test_data, verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_predictions","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.savetxt(\"../working/outputs/preds_array.csv\",test_predictions,delimiter=\",\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission=pd.DataFrame(test_predictions,columns=unique_breeds)\nsubmission.insert(0,\"id\",ids)\nsubmission","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv(\"../working/outputs/preds_array.csv\",index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Apply Our Model on our own images"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating a function to apply model on our own images\n\ndef identify_breed(filepath):\n    temp = create_data_batches([filepath,],test_data=True)\n    result = full_model.predict(temp, verbose = 1)\n    result = unique_breeds[result.argmax()]\n    return result\n\nxi = '../input/dog-breed-identification/test/1672018bbbc549cc43a14d9129197f08.jpg'\nprint(identify_breed(xi))","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}