Search code examples
machine-learningkerasconv-neural-networkgradcam

Keras ValueError: The layer sequential has never been called and thus has no defined output


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.


Solution

  • 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.