<jupyter_start><jupyter_text>Grad-CAMThis example interactively demonstrates Grad-CAM using nnabla's pre-trained model.Grad-CAM : Visual Explanation from Deep Networks via Gradient-based LocalizationRamprasaa<NAME> et. al., arXiv (2017) https://arxiv.org/abs/1610.02391  PreparationLet's start by installing nnabla and accessing [nnabla-examples repository](https://github.com/sony/nnabla-examples).<jupyter_code>!pip install nnabla
!git clone https://github.com/sony/nnabla-examples.git
%cd nnabla-examples/responsible_ai/gradcam<jupyter_output><empty_output><jupyter_text>Import dependencies<jupyter_code>import os
import cv2
import urllib.request
import numpy as np
import matplotlib.pyplot as plt
import nnabla as nn
from nnabla.utils.image_utils import imread
from nnabla.models.imagenet import VGG16

from gradcam import gradcam
from gradcam import overlay_images<jupyter_output><empty_output><jupyter_text>Image Preparation Download image to apply Grad-CAM for.<jupyter_code>url = 'https://upload.wikimedia.org/wikipedia/commons/4/4e/A_crab_spider_on_a_flower_preying_upon_a_euglossine_bee%2C_while_a_butterfly_looks_for_nectar.jpg'
img_path = 'input_flower_moth_spider.jpg'
if not os.path.isfile(img_path):
    tgt = urllib.request.urlopen(url).read()
    with open(img_path, mode='wb') as f:
        f.write(tgt)<jupyter_output><empty_output><jupyter_text>Take a look at what the image looks like.  We can see a flower in the middle on which a butterfly rests.<jupyter_code>img = imread(img_path, size=(224, 224), channel_first=True)
plt.imshow(img.transpose(1,2,0))
plt.show()<jupyter_output><empty_output><jupyter_text>Network DefinitionLoading the model is very simple.You can choose other models such as `VGG11`, `VGG13`, by specifying the model's name as an argument. Of course, you can choose other pretrained models as well. See the [Docs](https://nnabla.readthedocs.io/en/latest/python/api/models/imagenet.html).**NOTE**: If you use the `VGG16` for the first time, nnabla will automatically download the weights from `https://nnabla.org` and it may take up to a few minutes.<jupyter_code>model = VGG16()
batch_size = 1
x = nn.Variable((batch_size,) + model.input_shape)
# set training True since gradient of variable is necessary for Grad-CAM
vgg = model(x, training=True, returns_net=True)
vgg_variables = vgg.variables<jupyter_output><empty_output><jupyter_text>We now define the input, and extract the necessary outputs.  middle_layer: the last convolution layer  pred: final output of the model<jupyter_code>target_label_indices = {
    'butterfly': 326,# lycaenid, lycaenid butterfly
    'flower': 985,# daisy
    'spider': 74,# garden spider
}

input_name = list(vgg.inputs.keys())[0]
vgg_variables[input_name].d = img
middle_layer = vgg_variables['VGG16/ReLU_13']
pred = vgg_variables["VGG16/Affine_3"]
selected = pred[:, target_label_indices['butterfly']]<jupyter_output><empty_output><jupyter_text>Let's see how the model predicted the image.  We can see the model classified the image as we expect.  Labels regarding butterfly comes high, while flower is also recognized although it is14th ranked probability.<jupyter_code>selected.forward()
predicted_labels = np.argsort(-pred.d[0])
for i, predicted_label in enumerate(predicted_labels[:15]):
        print(f'Top {i+1}, Label index: {predicted_label},  Label name: {model.category_names[predicted_label]}')<jupyter_output><empty_output><jupyter_text>Grad-CAM Computation Execute backward computation to calculate gradient to use for Grad-CAM.<jupyter_code>selected.backward()<jupyter_output><empty_output><jupyter_text>Let's compute the heatmap using the gradient with respect to the last convolution layer.<jupyter_code>heatmap = gradcam(middle_layer)<jupyter_output><empty_output><jupyter_text>VisualizationTake a look at how the heatmap looks like in the layer of interest.<jupyter_code>plt.matshow(heatmap)
plt.show()<jupyter_output><empty_output><jupyter_text>Then we overlay the heatmap onto the original image to understand where the model focused.<jupyter_code>base_img = imread(img_path, size=(224, 224))
overlaid_img_butterfly = overlay_images(base_img, heatmap)<jupyter_output><empty_output><jupyter_text>Now we overlay the heatmap onto the original image to understand where the model focused.  We can speculate the model recognized the butterfly, focusing on its wing.<jupyter_code>plt.imshow(overlaid_img_butterfly)
plt.show()<jupyter_output><empty_output><jupyter_text>Let's use flower as the label of interest to see how the model see the image this time by calculating Grad-CAM. Reset gradient first.<jupyter_code>for k, v in vgg_variables.items():
    if 'VGG16/' in k:
        v.grad.zero()<jupyter_output><empty_output><jupyter_text>Calculate gradient and Grad-CAM same as for butterfly.<jupyter_code>selected_daisy = pred[:, target_label_indices['flower']]
selected_daisy.backward()
heatmap_daisy = gradcam(middle_layer)
plt.matshow(heatmap_daisy)
plt.show()<jupyter_output><empty_output><jupyter_text>We can see the model focus is widely spread comparing to than for butterfly as if the heatmap wrapped the flower.<jupyter_code>overlaid_img_daisy = overlay_images(base_img, heatmap_daisy)
plt.imshow(overlaid_img_daisy)
plt.show()<jupyter_output><empty_output><jupyter_text>Finally, compare images in oneline to enable to see the differences clearly.<jupyter_code>images = {
    'original': base_img,
    'butterfly': overlaid_img_butterfly,
    'flower': overlaid_img_daisy,
}


row = 1
col = len(images)
fig, axes = plt.subplots(row, col, figsize=(15,15))

for i, (k, v) in enumerate(images.items()):
    axes[i].imshow(v)
    axes[i].set_title(k)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09878499735868991, 'fraction_numerical': 0.012678288431061807, 'mean_word_length': 6.7701778385772915, 'pattern_counts': {'":': 0, '<': 66, '<?xml version=': 0, '>': 66, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '71577', 'license': 'Apache-2.0', 'n_tokens_mistral': 1992, 'n_tokens_neox': 1855, 'n_words': 485, 'path': 'interactive-demos/gradcam.ipynb', 'repo_name': 'JonathanLehner/nnabla-examples', 'size': '5687'}