Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Grad CAM implementation with Tensorflow 2
import cv2
import numpy as np
import tensorflow as tf
IMAGE_PATH = './cat.jpg'
LAYER_NAME = 'block5_conv3'
CAT_CLASS_INDEX = 281
img = tf.keras.preprocessing.image.load_img(IMAGE_PATH, target_size=(224, 224))
img = tf.keras.preprocessing.image.img_to_array(img)
model = tf.keras.applications.vgg16.VGG16(weights='imagenet', include_top=True)
grad_model = tf.keras.models.Model([model.inputs], [model.get_layer(LAYER_NAME).output, model.output])
with tf.GradientTape() as tape:
conv_outputs, predictions = grad_model(np.array([img]))
loss = predictions[:, CAT_CLASS_INDEX]
output = conv_outputs[0]
grads = tape.gradient(loss, conv_outputs)[0]
gate_f = tf.cast(output > 0, 'float32')
gate_r = tf.cast(grads > 0, 'float32')
guided_grads = tf.cast(output > 0, 'float32') * tf.cast(grads > 0, 'float32') * grads
weights = tf.reduce_mean(guided_grads, axis=(0, 1))
cam = np.ones(output.shape[0: 2], dtype = np.float32)
for i, w in enumerate(weights):
cam += w * output[:, :, i]
cam = cv2.resize(cam.numpy(), (224, 224))
cam = np.maximum(cam, 0)
heatmap = (cam - cam.min()) / (cam.max() - cam.min())
cam = cv2.applyColorMap(np.uint8(255*heatmap), cv2.COLORMAP_JET)
output_image = cv2.addWeighted(cv2.cvtColor(img.astype('uint8'), cv2.COLOR_RGB2BGR), 0.5, cam, 1, 0)
cv2.imwrite('cam.png', output_image)
@cordeirojoao

This comment has been minimized.

Copy link

@cordeirojoao cordeirojoao commented Mar 10, 2020

Hello Raphael,
First of all, thank you very much for sharing this work :)

I have read your article “Interpretability of Deep Learning Models with Tensorflow 2.0” at https://www.sicara.ai/blog/2019-08-28-interpretability-deep-learning-tensorflow and implemented the example to understand how exactly works.
Now I’m struggling to understand how to achieve my goal related to signal classification, and those using 1D CNN. I have used your example, that I tried to adjust for 1D, but I can’t understand the results I’m getting.
I was wonder if you can give me some help with this? I would really appreciate it :)
Thank you very much for your time.

my e-mail: joao_cordeiro@iscte-iul.pt

@RaphaelMeudec

This comment has been minimized.

Copy link
Owner Author

@RaphaelMeudec RaphaelMeudec commented Mar 11, 2020

Hello !

Could you provide where you're at so far? So I can have an idea of the model shape. Please include the shape of your input data so I can test it on my side

Best

@cordeirojoao

This comment has been minimized.

Copy link

@cordeirojoao cordeirojoao commented Mar 20, 2020

Hi Raphael,
Thank you very much for the reply :)
Sorry for the late reply, but Corona virus have really changed my working plans and only now I was able to get back to work.

Please find the following link what I achieved to do.
https://github.com/cordeirojoao/ECG_Processing/blob/master/Ecg_keras_v9-Raphael.ipynb

I fell a lit beat lost with the results.
Is the last picture giving the GradCam results that would be expectable? The most important point on all the ECG beat (size 300) it's the one near 110 moment? And the ones that have no importance at all are the ones just before 100?

Once again thank you very much for your help :)

Hello !

Could you provide where you're at so far? So I can have an idea of the model shape. Please include the shape of your input data so I can test it on my side

Best

@RaphaelMeudec

This comment has been minimized.

Copy link
Owner Author

@RaphaelMeudec RaphaelMeudec commented Mar 22, 2020

@cordeirojoao Yes, indeed. Elements of the array with the largest values (hence green on the plot) are the most important (according to grad cam method)

@nickkimer

This comment has been minimized.

Copy link

@nickkimer nickkimer commented Mar 25, 2020

Do you have any suggestions for editing this code for cases when the gradient is 0 with very confident decisions outputted by softmax output layer?

@RaphaelMeudec

This comment has been minimized.

Copy link
Owner Author

@RaphaelMeudec RaphaelMeudec commented Mar 27, 2020

@nickkimer You can replace the last softmax layer with a linear layer. I'm also working on Ablation CAM in tf-explain which solves this gradient issue.

@cordeirojoao

This comment has been minimized.

Copy link

@cordeirojoao cordeirojoao commented Mar 27, 2020

@cordeirojoao Yes, indeed. Elements of the array with the largest values (hence green on the plot) are the most important (according to grad cam method)

Thank you for the quick reply :)
So I guess I did the code the right way, I was not sure.

I have several plots on the code. When you refer to look for the green points (largest values) it's not clear to me which plot to look. I'm a little bit confused.
Should it be the one below the comment "Apply guided backpropagation"?

Image

@cordeirojoao

This comment has been minimized.

Copy link

@cordeirojoao cordeirojoao commented Apr 8, 2020

@RaphaelMeud Sorry for bothering you again, but I'm still a little bit confused and I would like to hear your comments on my last comment.
Thank you very much

@RaphaelMeudec

This comment has been minimized.

Copy link
Owner Author

@RaphaelMeudec RaphaelMeudec commented Apr 8, 2020

@cordeirojoao yes indeed, I'm refering to this one!

@cordeirojoao

This comment has been minimized.

Copy link

@cordeirojoao cordeirojoao commented Apr 8, 2020

@cordeirojoao yes indeed, I'm refering to this one!

@RaphaelMeud thank you very much for that. Really appreciate it :)

@sravanth99

This comment has been minimized.

Copy link

@sravanth99 sravanth99 commented Apr 8, 2020

Thank you so much! you saved my day : ).

@sdbonte

This comment has been minimized.

Copy link

@sdbonte sdbonte commented Apr 16, 2020

Thank you for this elegant implementation. I have a small question: is it possible that gate_f and gate_r are never used? Is this an error?

@RaphaelMeudec

This comment has been minimized.

Copy link
Owner Author

@RaphaelMeudec RaphaelMeudec commented Apr 16, 2020

@sdbonte Indeed, they could have been used on line 25 but for some reason I decided to rebuild them.

@Jeremynadal33

This comment has been minimized.

Copy link

@Jeremynadal33 Jeremynadal33 commented Apr 17, 2020

First of all, thank you very much for sharing! Nevertheless, I have a question if you have time.
I am dealing with multi-variate time series so it is 1D convolutions but I guess the method is the same as with 2D.

How would you retrieve the heat maps/activation maps for each different inputs of your network? Because if the same filters are used for all inputs, I feel like the heat map will be identical for every feature. (I am quite new in this field so I apologies if anything I say is incorrect)
If so, would you recommend treating each input individually to use Grad Cam like method?

Thanks in advance!

@RaphaelMeudec

This comment has been minimized.

Copy link
Owner Author

@RaphaelMeudec RaphaelMeudec commented Apr 17, 2020

@Jeremynadal33 Could you provide a minimal example of your data/model (ideally with np.random.random so I can have an idea of the input shapes)?

@Jeremynadal33

This comment has been minimized.

Copy link

@Jeremynadal33 Jeremynadal33 commented Apr 17, 2020

@Jeremynadal33 Could you provide a minimal example of your data/model (ideally with np.random.random so I can have an idea of the input shapes)?

Capture d’écran 2020-04-17 à 11 49 59

You may find attached a snapshot of the data (it is a synthetic dataset but here there are three features each of the same length under the form of time series and one time series target of specific length). You can see some specific events in time series 2 and 3 and I would like to know if the network's attention is focused on those events. (Additionally, there might be an event in time series 1 but not the case in that sample)
I made several models all different (functional mostly like that one for example but possibly with more convolutional layers).
Capture d’écran 2020-04-17 à 11 52 46

And lastly, how does cv2 resize the output shape back into the image proportion?
Thank you very much and I will put more code into a GitHub rep if you need more.

@SelComputas

This comment has been minimized.

Copy link

@SelComputas SelComputas commented May 28, 2020

Hi, I was wondering if you had any input as to how one would go about implementing this with a pre-trained (frozen) .pb model?

@KDHAP

This comment has been minimized.

Copy link

@KDHAP KDHAP commented Aug 27, 2020

Hello.

I want run your code with my dataset(images).

width = 224, height = 112 and My model structure is MobileNetV2.

So, I fixed your code for my dataset.

then, LAYER_NAME = 'block5_conv3' -> 'Conv_1'(Last Convolution Layer in MobileNetV2).
CAT_CLASS_INDEX = 281 -> 456 (number of class)

And I load an image randomly in my dataset.

After run the code,

this error is occured.

Traceback (most recent call last):
File "C:/Users/BV_WorkStation/PycharmProjects/MobileNetV3-TF-master/BV_Denom_Classification_test_Grad-CAM.py", line 31, in
loss = predictions[:, CAT_CLASS_INDEX]
File "C:\Users\BV_WorkStation\anaconda3\envs\tensorflow\lib\site-packages\tensorflow\python\util\dispatch.py", line 201, in wrapper
return target(*args, **kwargs)
File "C:\Users\BV_WorkStation\anaconda3\envs\tensorflow\lib\site-packages\tensorflow\python\ops\array_ops.py", line 1042, in _slice_helper
name=name)
File "C:\Users\BV_WorkStation\anaconda3\envs\tensorflow\lib\site-packages\tensorflow\python\util\dispatch.py", line 201, in wrapper
return target(*args, **kwargs)
File "C:\Users\BV_WorkStation\anaconda3\envs\tensorflow\lib\site-packages\tensorflow\python\ops\array_ops.py", line 1214, in strided_slice
shrink_axis_mask=shrink_axis_mask)
File "C:\Users\BV_WorkStation\anaconda3\envs\tensorflow\lib\site-packages\tensorflow\python\ops\gen_array_ops.py", line 10320, in strided_slice
_ops.raise_from_not_ok_status(e, name)
File "C:\Users\BV_WorkStation\anaconda3\envs\tensorflow\lib\site-packages\tensorflow\python\framework\ops.py", line 6921, in raise_from_not_ok_status
six.raise_from(core._status_to_exception(e.code, message), None)
File "", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: slice index 456 of dimension 1 out of bounds. [Op:StridedSlice] name: strided_slice/

Process finished with exit code 1

and full code

from future import absolute_import
from future import division
from future import print_function

import os
import tensorflow as tf
from tensorflow import keras
import numpy as np
import random
import cv2

data_dir = "G:\ATEC_AP\KDH\Fitness\DB\"
predict_dir = "G:\ATEC_AP\KDH\Fitness\DB\predict_img\"
random_img_path = random.choice(os.listdir(predict_dir))

LAYER_NAME = 'Conv_1'
CAT_CLASS_INDEX = 456
input_width = 224
input_height = 112

img = tf.keras.preprocessing.image.load_img(predict_dir + random_img_path, target_size=(input_height, input_width),
color_mode='grayscale')
img = tf.keras.preprocessing.image.img_to_array(img)

model = tf.keras.models.load_model(data_dir + "MobileNetV2_20_112_224_08_25_17_55" + ".h5")
model.summary()
grad_model = tf.keras.models.Model([model.inputs], [model.get_layer(LAYER_NAME).output, model.output])

with tf.GradientTape() as tape:
conv_outputs, predictions = grad_model(np.array([img]))
loss = predictions[:, CAT_CLASS_INDEX]

output = conv_outputs[0]
grads = tape.gradient(loss, conv_outputs)[0]

gate_f = tf.cast(output > 0, 'float32')
gate_r = tf.cast(grads > 0, 'float32')
guided_grads = tf.cast(output > 0, 'float32') * tf.cast(grads > 0, 'float32') * grads

weights = tf.reduce_mean(guided_grads, axis=(0, 1))

cam = np.ones(output.shape[0: 2], dtype=np.float32)

for i, w in enumerate(weights):
cam += w * output[:, :, i]

cam = cv2.resize(cam.numpy(), (input_width, input_height))
cam = np.maximum(cam, 0)
heatmap = (cam - cam.min()) / (cam.max() - cam.min()) ##

cam = cv2.applyColorMap(np.uint8(255*heatmap), cv2.COLORMAP_JET)

output_image = cv2.addWeighted(cv2.cvtColor(img.astype('uint8'), cv2.COLOR_RGB2BGR), 0.5, cam, 1, 0)

cv2.imwrite('cam.png', output_image)

Please help me

Tensorflow Version is 2.1.0

@limbachia

This comment has been minimized.

Copy link

@limbachia limbachia commented Sep 21, 2020

I have a question similar to that of @Jeremynadal33. Even my data has several features.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.