{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"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\nimport numpy as np # linear algebra\n# import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\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 20GB 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","metadata":{"_uuid":"44532a42-f2e3-4d70-80ed-61845de1b55d","_cell_guid":"52bbbacb-85f2-42b8-997c-9742156d245f","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#importing shutil for file copying\nimport shutil","metadata":{"_uuid":"d7ab2835-adce-497d-89bd-c94bc08f0d10","_cell_guid":"ec51d376-ca64-4f8e-8142-f0f33df20b45","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Making the required folder from the existing code. Don't be dumb reuse code, sometimes.","metadata":{"_uuid":"0fc3f9e6-a936-4e07-87f8-7f5138231739","_cell_guid":"4050a7f0-ebb9-42ca-9d72-cba9b884df4c","trusted":true}},{"cell_type":"code","source":"# unziping the train zip and test zip file after copying them to the working folder \n# remember in kaggle input folder have been given only read only acess by the admin\n# hence we copy in the working folder and then complete our job\n!rm -rf ./train ./cats_and_dogs_small ./train.zip ./cats_and_dogs_small_2.h5 ./cats_and_dogs_small_1.h5 ./cats_and_dogs_small_3.h5\n# making the copy of the test and train dir from the input dir since it is read-only\n!ls -lrt\n# !cp /kaggle/input/dogs-vs-cats/test1.zip /kaggle/working\n# !unzip /kaggle/working/test1.zip \n!cp /kaggle/input/dogs-vs-cats/train.zip /kaggle/working\n!unzip /kaggle/working/train.zip\n!cd /kaggle/working\n# use this block wisely\n\n# checking the contents of my working directory\n# use this wisely\nfor dirname, _, filenames in os.walk('/kaggle/working'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n        \n!cd /kaggle/working\n!ls -lrt\n\n# first lets set the base paths and make the necessary directories for working out our problem\noriginal_dataset_dir = '/kaggle/working'\nbase_dir = '/kaggle/working/cats_and_dogs_small'\nos.mkdir(base_dir)\ntrain_dir = os.path.join(base_dir,'train')\nos.mkdir(train_dir)\nvalidation_dir = os.path.join(base_dir, 'validation')\nos.mkdir(validation_dir)\ntest_dir = os.path.join(base_dir, 'test')\nos.mkdir(test_dir)\n\n# now lets make the cats and dogs directories in them for housing the cats and the dogs images\ntrain_cats_dir = os.path.join(train_dir, 'cats')\nos.mkdir(train_cats_dir)\ntrain_dogs_dir = os.path.join(train_dir, 'dogs')\nos.mkdir(train_dogs_dir)\nvalidation_cats_dir = os.path.join(validation_dir, 'cats')\nos.mkdir(validation_cats_dir)\nvalidation_dogs_dir = os.path.join(validation_dir, 'dogs')\nos.mkdir(validation_dogs_dir)\ntest_cats_dir = os.path.join(test_dir, 'cats')\nos.mkdir(test_cats_dir)\ntest_dogs_dir = os.path.join(test_dir, 'dogs')\nos.mkdir(test_dogs_dir)\n\n# Now we will be copying the actual data from the base directory to the working directories\nfnames = ['cat.{}.jpg'.format(i) for i in range(1000)]\nfor fname in fnames:\n    src = os.path.join(os.path.join(original_dataset_dir,'train'), fname)\n    dst = os.path.join(train_cats_dir, fname)\n    shutil.copyfile(src, dst)\nfnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]\nfor fname in fnames:\n    src = os.path.join(os.path.join(original_dataset_dir,'train'), fname)\n    dst = os.path.join(validation_cats_dir, fname)\n    shutil.copyfile(src, dst)\nfnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]\nfor fname in fnames:\n    src = os.path.join(os.path.join(original_dataset_dir,'train'), fname)\n    dst = os.path.join(test_cats_dir, fname)\n    shutil.copyfile(src, dst)\nfnames = ['dog.{}.jpg'.format(i) for i in range(1000)]\nfor fname in fnames:\n    src = os.path.join(os.path.join(original_dataset_dir,'train'), fname)\n    dst = os.path.join(train_dogs_dir, fname)\n    shutil.copyfile(src, dst)\nfnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]\nfor fname in fnames:\n    src = os.path.join(os.path.join(original_dataset_dir,'train'), fname)\n    dst = os.path.join(validation_dogs_dir, fname)\n    shutil.copyfile(src, dst)\nfnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]\nfor fname in fnames:\n    src = os.path.join(os.path.join(original_dataset_dir,'train'), fname)\n    dst = os.path.join(test_dogs_dir, fname)\n    shutil.copyfile(src, dst)\n    \n    \n# Now for ease of use I will do something\n# since the train folder contains too many images which we don't need I will delete it.\n!rm -rf ./train\n\n!rm -rf ./train.zip","metadata":{"_uuid":"7504d40c-a73e-4d2a-9dbb-9e9b4f1bfb01","_cell_guid":"f71e9d3f-6cbb-4ff9-8d9c-31e47449216c","collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Checking the folders made and their content.","metadata":{"_uuid":"7fbf4713-9d33-48cd-90b8-f054bcb2fc7e","_cell_guid":"a0f75b3f-f3dc-4396-afe2-5c61c9e607d2","trusted":true}},{"cell_type":"code","source":"# checking the that data have been properly copied or not\nprint('total training cat images:', len(os.listdir(train_cats_dir)))\nprint('total training dog images:', len(os.listdir(train_dogs_dir)))\nprint('total validation cat images:', len(os.listdir(validation_cats_dir)))\nprint('total validation dog images:', len(os.listdir(validation_dogs_dir)))\nprint('total test cat images:', len(os.listdir(test_cats_dir)))\nprint('total test dog images:', len(os.listdir(test_dogs_dir)))","metadata":{"_uuid":"ffbb6a0c-64dd-4572-b9cf-15bd0a95d8ef","_cell_guid":"b131c4ad-2d5a-458a-834f-a390623b57d0","collapsed":false,"jupyter":{"outputs_hidden":false},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualization of ConvNet Learning\n\nIt’s often said that deep-learning models are “black boxes”: learning representations that are difficult to extract and present in a human-readable form. Although this is partially true for certain types of deep-learning models, it’s definitely not true for convnets. The representations learned by convnets are highly amenable to visualization, in large part because they’re representations of visual concepts. Since 2013, a wide array of techniques have been developed for visualizing and interpreting these representations. We won’t survey all of them, but we’ll cover three of the most accessible and useful ones:\n\n* Visualizing intermediate convnet outputs (intermediate activations)—Useful for understanding how successive convnet layers transform their input, and for getting a first idea of the meaning of individual convnet filters.\n\n* Visualizing convnets filters—Useful for understanding precisely what visual pattern or concept each filter in a convnet is receptive to.\n\n* Visualizing heatmaps of class activation in an image—Useful for understanding which parts of an image were identified as belonging to a given class, thus allowing you to localize objects in images.\n\n\n**Visualizing intermediate activations**\nVisualizing intermediate activations consists of displaying the feature maps that are output by various convolution and pooling layers in a network, given a certain input (the output of a layer is often called its activation, the output of the activation function). This gives a view into how an input is decomposed into the different filters learned by the network. You want to visualize feature maps with three dimensions: width, height, and depth (channels). Each channel encodes relatively independent features, so the proper way to visualize these feature maps is by independently plotting the contents of every channel as a 2D image. \n\nFirst let's start by loading the saved model from the previous example:","metadata":{}},{"cell_type":"code","source":"from keras.models import load_model # usiing load_model to the load the model from a different notebook\nmodel = load_model('/kaggle/input/cats-vs-dogs-models/cats_and_dogs_small_2 (2).h5')\nmodel.summary()  # checking the model summary","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now , we will get a picture of a cat, not part of the images the network was trained on.","metadata":{}},{"cell_type":"code","source":"img_path = '/kaggle/working/cats_and_dogs_small/train/cats/cat.999.jpg' # seting the image path\n\nfrom keras.preprocessing import image # image from keras to preprocess the image\n\nimg = image.load_img(img_path, target_size=(150, 150)) # loading the image and resizing it into the target size of 150 x 150 pixels\nimg_tensor = image.img_to_array(img) # converting the image into a image array\nimg_tensor = np.expand_dims(img_tensor, axis=0) # changing the shape of the array to give the tensor its required $D shape\nimg_tensor /= 255.  # converting the value of the tensor as float values ranged between 0 and 1\n# Its shape is (1, 150, 150, 3)\nprint(img_tensor.shape) # checking the shape of the tensor","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" # importing mathplolib and checking the picture we are gonna use\nimport matplotlib.pyplot as plt\nplt.imshow(img_tensor[0])\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In order to extract the feature maps you want to look at, you’ll create a Keras model that takes batches of images as input, and outputs the activations of all convolution and pooling layers. To do this, you’ll use the Keras class Model. A model is instantiated using two arguments: an input tensor (or list of input tensors) and an output tensor (or list of output tensors). The resulting class is a Keras model, just like the Sequential models you’re familiar with, mapping the specified inputs to the specified outputs. What sets the Model class apart is that it allows for models with multiple outputs, unlike Sequential. ","metadata":{}},{"cell_type":"code","source":"# import models from keras \nfrom keras import models\nlayer_outputs = [layer.output for layer in model.layers[:8]] # storing the output of the 8 layers in a list\nactivation_model = models.Model(inputs=model.input, outputs=layer_outputs) # instatiating the input and output layers ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# making prediction on the image\nactivations = activation_model.predict(img_tensor)\n# storing all the activations in the first layer \nfirst_layer_activation = activations[0]\nprint(first_layer_activation.shape)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# checking out some of the activation by the filers\nplt.matshow(first_layer_activation[0, :, :, 4], cmap='viridis')\nplt.matshow(first_layer_activation[0, :, :, 7], cmap='viridis')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"You’ll extract and plot every channel in each of the eight activation maps, and you’ll stack the results in one big image tensor, with channels stacked side by side.","metadata":{}},{"cell_type":"code","source":"# now we will plot all the activations of all the layers in the base of our pretrained network\n\nlayer_names = []\n\nfor layer in model.layers[:8]:\n    layer_names.append(layer.name)  # appending layer names in a list\n    \nimages_per_row = 16 # setting the number of activations we will align in each network\n\n# instantiating a loop to create the plot that will show the activations\n\n\nfor layer_name, layer_activation in zip(layer_names, activations):\n    n_features = layer_activation.shape[-1] # storing the number of features\n    \n    size = layer_activation.shape[1] # storing the activation size\n    \n    n_cols = n_features // images_per_row # calculating the number of colums based on number of features\n    \n    display_grid = np.zeros((size * n_cols, images_per_row * size)) # making a Tensor of zeros\n    \n    # iterating through the each elemet in the tensor and setting their values\n    for col in range(n_cols):\n        for row in range(images_per_row):\n            # storing the layer activation and applying some mathematical operation on them\n            channel_image = layer_activation[0,\n                                             :,\n                                             :,\n                                             col * images_per_row + row]\n            channel_image -= channel_image.mean()\n            channel_image /= channel_image.std()\n            channel_image *= 64\n            channel_image += 128\n            channel_image = np.clip(channel_image, 0, 255).astype('uint8')\n            display_grid[col * size : (col + 1) * size,\n                         row * size : (row + 1) * size] = channel_image\n    scale = 1. / size\n    plt.figure(figsize=(scale * display_grid.shape[1],\n    scale * display_grid.shape[0]))\n    plt.title(layer_name)\n    plt.grid(False)\n    plt.imshow(display_grid, aspect='auto', cmap='viridis')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There are a few things to note here:\n\n* The first layer acts as a collection of various edge detectors. At that stage, the activations retain almost all of the information present in the initial picture. \n\n* As you go higher, the activations become increasingly abstract and less visually interpretable. They begin to encode higher-level concepts such as “cat ear” and “cat eye.” Higher presentations carry increasingly less information about the visual contents of the image, and increasingly more information related to the class of the image. \n\n* The sparsity of the activations increases with the depth of the layer: in the first layer, all filters are activated by the input image; but in the following layers, more and more filters are blank. This means the pattern encoded by the filter isn’t found in the input image. ","metadata":{}},{"cell_type":"markdown","source":"We have just evidenced an important universal characteristic of the representations learned by deep neural networks: the features extracted by a layer become increasingly abstract with the depth of the layer. The activations of higher layers carry less and less information about the specific input being seen, and more and more information about the target (in this case, the class of the image: cat or dog). A deep neural network effectively acts as an information distillation pipeline, with raw data going in (in this case, RGB pictures) and being repeatedly transformed so that irrelevant information is filtered out (for example, the specific visual appearance of the image), and useful information is magnified and refined (for example, the class of the image).\nThis is analogous to the way humans and animals perceive the world: after observing a scene for a few seconds, a human can  remember which abstract objects were present in it (bicycle, tree) but can’t remember the specific appearance of these objects. \n\nIn fact, if you tried to draw a generic bicycle from memory, chances are you couldn’t get it even remotely right, even though you’ve seen thousands of bicycles in your lifetime.\n","metadata":{}},{"cell_type":"markdown","source":"\n**Visualizing convnet filters**\n\nAnother easy way to inspect the filters learned by convnets is to display the visual pattern that each filter is meant to respond to. This can be done with gradient ascent in input space: applying gradient descent to the value of the input image of a convnet so as to maximize the response of a specific filter, starting from a blank input image. The resulting input image will be one that the chosen filter is maximally responsive to.\n\nThe process is simple: you’ll build a loss function that maximizes the value of a given filter in a given convolution layer, and then you’ll use stochastic gradient descent to adjust the values of the input image so as to maximize this activation value. For instance, here’s a loss for the activation of filter 0 in the layer block3_conv1 of the VGG16 network, pretrained on ImageNet.","metadata":{}},{"cell_type":"code","source":"# importing the VGG16 model from keras\nfrom keras.applications import VGG16\nfrom keras import backend as K # importing keras backed\nimport tensorflow as tf # importing tensorflow\ntf.compat.v1.disable_eager_execution() # disabling eager execution for this problems sake\n\nmodel = VGG16(weights='imagenet',\n              include_top=False) # instantiating the model\nlayer_name = 'block3_conv1'\nfilter_index = 0\nlayer_output = model.get_layer(layer_name).output # getting the layer output \nloss = K.mean(layer_output[:, :, :, filter_index]) # applying mean on the output ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary() # checking the model summary to look into what we are dealing","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"To implement gradient descent, you’ll need the gradient of this loss with respect to the model’s input. To do this, you’ll use the gradients function packaged with the backend module of Keras.\n\nA non-obvious trick to use to help the gradient-descent process go smoothly is to normalize the gradient tensor by dividing it by its L2 norm (the square root of the average of the square of the values in the tensor). This ensures that the magnitude of the updates done to the input image is always within the same range.\n\n","metadata":{}},{"cell_type":"code","source":"\ngrads = K.gradients(loss, model.input)[0] # calculating the gradient\n\ngrads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5) # taking the mean square root value of the gradient","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now you need a way to compute the value of the loss tensor and the gradient tensor, given an input image. You can define a Keras backend function to do this: iterate is a function that takes a Numpy tensor (as a list of tensors of size 1) and returns a list of two Numpy tensors: the loss value and the gradient value.","metadata":{}},{"cell_type":"code","source":"# computing the loss tensor and gradient tensor\niterate = K.function([model.input], [loss, grads]) \nloss_value, grads_value = iterate([np.zeros((1, 150, 150, 3))])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# converting the input data\ninput_img_data = np.random.random((1, 150, 150, 3)) * 20 + 128.\nstep = 1.\nfor i in range(40):\n    loss_value, grads_value = iterate([input_img_data])\n    input_img_data += grads_value * step","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The resulting image tensor is a floating-point tensor of shape (1, 150, 150, 3), with values that may not be integers within [0, 255]. Hence, you need to postprocess this tensor to turn it into a displayable image. You do so with the following straightforward utility function.","metadata":{}},{"cell_type":"code","source":"# converting the tesnsor values such ythat it ranges between 0 and 1\ndef deprocess_image(x):\n    x -= x.mean()\n    x /= (x.std() + 1e-5)\n    x *= 0.1\n    x += 0.5\n    x = np.clip(x, 0, 1)\n    x *= 255\n    x = np.clip(x, 0, 255).astype('uint8')\n    return x","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now you have all the pieces. Let’s put them together into a Python function that takes as input a layer name and a filter index, and returns a valid image tensor representing the pattern that maximizes the activation of the specified filter.","metadata":{}},{"cell_type":"code","source":"def generate_pattern(layer_name, filter_index, size=150):\n    # Build a loss function that maximizes the activation\n    # of the nth filter of the layer considered.\n    layer_output = model.get_layer(layer_name).output\n    loss = K.mean(layer_output[:, :, :, filter_index])\n\n    # Compute the gradient of the input picture wrt this loss\n    grads = K.gradients(loss, model.input)[0]\n\n    # Normalization trick: we normalize the gradient\n    grads /= (K.sqrt(K.mean(K.square(grads))) + 1e-5)\n\n    # This function returns the loss and grads given the input picture\n    iterate = K.function([model.input], [loss, grads])\n    \n    # We start from a gray image with some noise\n    input_img_data = np.random.random((1, size, size, 3)) * 20 + 128.\n\n    # Run gradient ascent for 40 steps\n    step = 1.\n    for i in range(40):\n        loss_value, grads_value = iterate([input_img_data])\n        input_img_data += grads_value * step\n        \n    img = input_img_data[0]\n    \n    return deprocess_image(img)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# checking the use of function once \n# if it is working properly\nplt.imshow(generate_pattern('block1_conv1', 0))\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It seems that filter 0 in layer block3_conv1 is responsive to a polka-dot pattern. Now the fun part: you can start visualizing every filter in every layer. For simplicity, you’ll only look at the first 64 filters in each layer, and you’ll only look at the first layer of each convolution block (block1_conv1, block2_conv1, block3_conv1, block4_conv1, block5_conv1). You’ll arrange the outputs on an 8 × 8 grid of 64 × 64 filter patterns, with some black margins between each filter pattern.\n    ","metadata":{}},{"cell_type":"code","source":"for layer_name in ['block1_conv1', 'block2_conv1', 'block3_conv1', 'block4_conv1']:\n    size = 64\n    margin = 5\n\n    # This a empty (black) image where we will store our results.\n    results = np.zeros((8 * size + 7 * margin, 8 * size + 7 * margin, 3), dtype = int)\n\n\n    for i in range(8):  # iterate over the rows of our results grid\n        for j in range(8):  # iterate over the columns of our results grid\n            # Generate the pattern for filter `i + (j * 8)` in `layer_name`\n            filter_img = generate_pattern(layer_name, i + (j * 8), size=size)\n\n            # Put the result in the square `(i, j)` of the results grid\n            horizontal_start = i * size + i * margin\n            horizontal_end = horizontal_start + size\n            vertical_start = j * size + j * margin\n            vertical_end = vertical_start + size\n            \n            results[horizontal_start: horizontal_end, vertical_start: vertical_end, :] = filter_img\n            \n            \n    # Display the results grid\n    plt.figure(figsize=(20, 20))\n    plt.imshow(results)\n    plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"These filter visualizations tell you a lot about how convnet layers see the world: each layer in a convnet learns a collection of filters such that their inputs can be expressed as a combination of the filters. This is similar to how the Fourier transform decomposes signals onto a bank of cosine functions. The filters in these convnet filter banks get increasingly complex and refined as you go higher in the model:\n\n* The filters from the first layer in the model (block1_conv1) encode simple directional edges and colors (or colored edges, in some cases).\n* The filters from block2_conv1 encode simple textures made from combinations of edges and colors. \n* The filters in higher layers begin to resemble textures found in natural images: feathers, eyes, leaves, and so on.","metadata":{}},{"cell_type":"markdown","source":"**Visualizing heatmaps of class activation **\n\nI’ll introduce one more visualization technique: one that is useful for understanding\nwhich parts of a given image led a convnet to its final classification decision. This is helpful for debugging the decision process of a convnet, particularly in the case of a classification mistake. It also allows you to locate specific objects in an image. This general category of techniques is called class activation map (CAM) visualization, and it consists of producing heatmaps of class activation over input images. A class activation heatmap is a 2D grid of scores associated with a specific output class, computed for every location in any input image, indicating how important each location is with respect to the class under consideration.\n\n\nThe specific implementation you’ll use is the one described in “Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization.”2 It’s very simple: it consists of taking the output feature map of a convolution layer, given an input image, and weighing every channel in that feature map by the gradient of the class with respect to the channel. Intuitively, one way to understand this trick is that you’re weighting a spatial map of “how intensely the input image activates different channels” by “how important each channel is with regard to the class,” resulting in a spatial map of “how intensely the input image activates the class.”","metadata":{}},{"cell_type":"code","source":"from keras.applications.vgg16 import VGG16 # importing VGG16\nmodel = VGG16(weights='imagenet') # loading the model with the weighhts used in Imagenet","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we need to convert a image into numpy array  of size 224 × 244, convert it to a Numpy float32 tensor, and apply\nthese preprocessing rules.\n","metadata":{}},{"cell_type":"code","source":"# importing preprocess_input, decode_predictions from vgg16\nfrom keras.applications.vgg16 import preprocess_input, decode_predictions\n\n# setting the image path and converting teh image to an array\n\nimg_path = '../input/african-elephant/antelope-park-6Rbqy9jS7xs-unsplash.jpg'\nimg = image.load_img(img_path, target_size=(224, 224)) # reshaped into size of 224 x 224\nx = image.img_to_array(img) # converting the values into tensors\nx = np.expand_dims(x, axis=0) # expanding it to the required dimension\nx = preprocess_input(x)\n\n\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"You can now run the pretrained network on the image and decode its prediction vector back to a human-readable format:","metadata":{}},{"cell_type":"code","source":"preds = model.predict(x) # predicting based on the model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":" print('Predicted:', decode_predictions(preds, top=3)[0]) # checking the preictions","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The top three classes predicted for this image are as follows:\n\n* African elephant (with 92.5% probability)\n* Tusker (with 7% probability)\n* Indian elephant (with 0.4% probability)","metadata":{}},{"cell_type":"markdown","source":"The network has recognized the image as containing an undetermined quantity of African elephants. The entry in the prediction vector that was maximally activated is the one corresponding to the “African elephant” class.","metadata":{}},{"cell_type":"code","source":" np.argmax(preds[0]) ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"To visualize which parts of the image are the most African elephant–like, let’s set up the Grad-CAM process.","metadata":{}},{"cell_type":"code","source":"# using the grad- cam process to visualize partsof the image\nafrican_elephant_output = model.output[:, 386]\nlast_conv_layer = model.get_layer('block5_conv3')\ngrads = K.gradients(african_elephant_output, last_conv_layer.output)[0]\npooled_grads = K.mean(grads, axis=(0, 1, 2))\niterate = K.function([model.input],\n                     [pooled_grads, last_conv_layer.output[0]])\npooled_grads_value, conv_layer_output_value = iterate([x])\nfor i in range(512):\n    conv_layer_output_value[:, :, i] *= pooled_grads_value[i]\n\n# making a heatmap of the output from the network\nheatmap = np.mean(conv_layer_output_value, axis=-1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"For visualization purposes, you’ll also normalize the heatmap between 0 and 1. ","metadata":{}},{"cell_type":"code","source":"# normalizing the heatmap\nheatmap = np.maximum(heatmap, 0)\nheatmap /= np.max(heatmap)\nplt.matshow(heatmap)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Finally, you’ll use OpenCV to generate an image that superimposes the original image on the heatmap you just obtained.","metadata":{}},{"cell_type":"code","source":"# importing opencv to look into the superimposed image\nimport cv2\nimg = cv2.imread(img_path)\nheatmap = cv2.resize(heatmap, (img.shape[1], img.shape[0]))\nheatmap = np.uint8(255 * heatmap)\nheatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)\nsuperimposed_img = heatmap * 0.4 + img\n\ncv2.imwrite('./elephant_cam.jpg', superimposed_img)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"So this how the ConvNet identified that it is an African Elephant. Superimposition is really a great tool to visualize the learning as to why I guess it is pretty visible if you just download and check out the heatmap superimposed elephant image","metadata":{}}]}