-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathgradcam.py
101 lines (80 loc) · 3.21 KB
/
gradcam.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import cv2
import numpy as np
from PIL import Image
import tensorflow as tf
import tensorflow.keras as K
import matplotlib.pyplot as plt
from skimage.transform import resize
from tensorflow.keras.models import Model
def VizGradCAM(model, image, interpolant=0.5, plot_results=True):
"""VizGradCAM - Displays GradCAM based on Keras / TensorFlow models
using the gradients from the last convolutional layer. This function
should work with all Keras Application listed here:
https://keras.io/api/applications/
Parameters:
model (keras.model): Compiled Model with Weights Loaded
image: Image to Perform Inference On
plot_results (boolean): True - Function Plots using PLT
False - Returns Heatmap Array
Returns:
Heatmap Array?
"""
# Sanity Check
assert (
interpolant > 0 and interpolant < 1
), "Heatmap Interpolation Must Be Between 0 - 1"
last_conv_layer = next(
x for x in model.layers[::-1] if isinstance(x, K.layers.Conv2D)
)
target_layer = model.get_layer(last_conv_layer.name)
original_img = image
img = np.expand_dims(original_img, axis=0)
prediction = model.predict(img)
# Obtain Prediction Index
prediction_idx = np.argmax(prediction)
# Compute Gradient of Top Predicted Class
with tf.GradientTape() as tape:
gradient_model = Model([model.inputs], [target_layer.output, model.output])
conv2d_out, prediction = gradient_model(img)
# Obtain the Prediction Loss
loss = prediction[:, prediction_idx]
# Gradient() computes the gradient using operations recorded
# in context of this tape
gradients = tape.gradient(loss, conv2d_out)
# Obtain the Output from Shape [1 x H x W x CHANNEL] -> [H x W x CHANNEL]
output = conv2d_out[0]
# Obtain Depthwise Mean
weights = tf.reduce_mean(gradients[0], axis=(0, 1))
# Create a 7x7 Map for Aggregation
activation_map = np.zeros(output.shape[0:2], dtype=np.float32)
# Multiply Weights with Every Layer
for idx, weight in enumerate(weights):
activation_map += weight * output[:, :, idx]
# Resize to Size of Image
activation_map = cv2.resize(
activation_map.numpy(), (original_img.shape[1], original_img.shape[0])
)
# Ensure No Negative Numbers
activation_map = np.maximum(activation_map, 0)
# Convert Class Activation Map to 0 - 255
activation_map = (activation_map - activation_map.min()) / (
activation_map.max() - activation_map.min()
)
activation_map = np.uint8(255 * activation_map)
# Convert to Heatmap
heatmap = cv2.applyColorMap(activation_map, cv2.COLORMAP_JET)
# Superimpose Heatmap on Image Data
original_img = np.uint8(
(original_img - original_img.min())
/ (original_img.max() - original_img.min())
* 255
)
cvt_heatmap = cv2.cvtColor(heatmap, cv2.COLOR_BGR2RGB)
# Enlarge Plot
plt.rcParams["figure.dpi"] = 100
if plot_results == True:
plt.imshow(
np.uint8(original_img * interpolant + cvt_heatmap * (1 - interpolant))
)
else:
return cvt_heatmap