I want to use Keras' Grad-CAM with my own CNN model. I have followed this https://keras.io/examples/vision/grad_cam/ where the function make_gradcam_heatmap is also from. I am new to CNNs so I might be missing something obvious, but why does it not recognise when I am running my model?
Here is my code:
import numpy as np
import os
import tensorflow as tf
import keras
from tensorflow.keras.models import load_model
import cv2
from tensorflow.keras.models import Model
os.environ["KERAS_BACKEND"] = "tensorflow"
from IPython.display import Image, display
import matplotlib as mpl
import matplotlib.pyplot as plt
img_path = '/Users/.../image_1.npy'
model = load_model('/Users/.../particle_classifier_model.h5')
model_builder = keras.applications.xception.Xception
preprocess_input = keras.applications.xception.preprocess_input
decode_predictions = keras.applications.xception.decode_predictions
image = np.load(img_path)
img_size = image.shape # should be an array of shape (240, 146)
def make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None):
# First, we create a model that maps the input image to the activations
# of the last conv layer as well as the output predictions
grad_model = keras.models.Model(
model.inputs, [model.get_layer(last_conv_layer_name).output, model.output]
)
# Then, we compute the gradient of the top predicted class for our input image
# with respect to the activations of the last conv layer
with tf.GradientTape() as tape:
last_conv_layer_output, preds = grad_model(img_array)
if pred_index is None:
pred_index = tf.argmax(preds[0])
class_channel = preds[:, pred_index]
# This is the gradient of the output neuron (top predicted or chosen)
# with regard to the output feature map of the last conv layer
grads = tape.gradient(class_channel, last_conv_layer_output)
# This is a vector where each entry is the mean intensity of the gradient
# over a specific feature map channel
pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))
# We multiply each channel in the feature map array
# by "how important this channel is" with regard to the top predicted class
# then sum all the channels to obtain the heatmap class activation
last_conv_layer_output = last_conv_layer_output[0]
heatmap = last_conv_layer_output @ pooled_grads[..., tf.newaxis]
heatmap = tf.squeeze(heatmap)
# For visualization purpose, we will also normalize the heatmap between 0 & 1
heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)
return heatmap.numpy()
last_conv_layer_name = "max_pooling2d_4"
image = image.reshape(1, 240, 146, 1)
preds = model.predict(image)
model.layers[-1].activation = None
heatmap = make_gradcam_heatmap(image, model, last_conv_layer_name)
plt.matshow(heatmap)
plt.show()
My data are numpy arrays of dimension (240, 146) which the CNN takes as input.
Figured it out. After loading the model, specifically define the input and output shapes again like
inputs = tf.keras.Input(shape=(240, 146, 1))
outputs = model(inputs)
and replace shape
with whatever dimensions your model takes.