0

I would like to draw a class activation map for a model built upon EfficeintNet B3. But when I follow different tutorials and codes from different sources, it simply fails....

#load images
img = tf.keras.preprocessing.image.load_img(
        base, target_size=(img_height, img_width))
img_array = tf.keras.preprocessing.image.img_to_array(img)
img_array = tf.expand_dims(img_array, 0) # Create a batch
predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])


last_conv = model.layers[2].layers[-3]

grad_model = tf.keras.models.Model(
    [model.inputs], [last_conv.output, model.output])

Can't build a grad_model

ValueError: Graph disconnected: cannot obtain value for tensor KerasTensor(type_spec=TensorSpec(shape=(None, 300, 300, 3), dtype=tf.float32, name='input_1'), name='input_1', description="created by layer 'input_1'") at layer "stem_conv". The following previous layers were accessed without issue: []

This is the model:

 Model: "sequential_1"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    sequential (Sequential)      (None, 300, 300, 3)       0         
    _________________________________________________________________
    rescaling (Rescaling)        (None, 300, 300, 3)       0         
    _________________________________________________________________
    efficientnet-b3 (Functional) (None, 10, 10, 1536)      10783528  
    _________________________________________________________________
    global_average_pooling2d (Gl (None, 1536)              0         
    _________________________________________________________________
    dropout (Dropout)            (None, 1536)              0         
    _________________________________________________________________
    dense (Dense)                (None, 128)               196736    
    _________________________________________________________________
    dense_1 (Dense)              (None, 5)                 645       
    =================================================================
Innat
  • 16,113
  • 6
  • 53
  • 101
Maximus
  • 75
  • 8
  • Is there any one help? – Maximus Dec 01 '21 at 03:45
  • try this https://keras.io/examples/vision/grad_cam/ – Innat Dec 01 '21 at 05:21
  • I tried but failed....cannot do this --> grad_model = tf.keras.models.Model( [model.inputs], [model.get_layer(last_conv_layer_name).output, model.output] ) Error saying: f'Graph disconnected: cannot obtain value for tensor {x} ' – Maximus Dec 01 '21 at 05:46
  • 1
    I think here is the issue of yours `last_conv = model.layers[2].layers[-3]` - look into it. – Innat Dec 01 '21 at 08:10
  • You are right. But I don't know what the problem is. – Maximus Dec 01 '21 at 09:38
  • Anyone can help? with tf.GradientTape() as tape: last_conv_layer = model.layers[2].get_layer('top_activation') iterate = tf.keras.models.Model([model.inputs], [model.output, last_conv_layer.output]) ....... I think the problem lies at "last_conv_layer", so there is error to generate iterate. When I remove last_conv_layers.output, iterate can be generated successfully – Maximus Feb 23 '22 at 15:02
  • Are you looking for CAN or Grad-CAM? – Innat Feb 23 '22 at 15:40
  • I am looking for any method that can display heatmap on the photo..... – Maximus Feb 23 '22 at 16:39
  • For these heatmap to work, it seems that the final output layer must be directly next to the last convolutional layer? So my model as shown above does not work? – Maximus Feb 23 '22 at 16:40

1 Answers1

0

To address the graph disconnected value error, you need to build the grad cam model properly. Here is one of the ways to build a model for grad-cam.

import tensorflow as tf 
from tensorflow import keras
from tensorflow.keras import layers

inputs = tf.keras.Input(shape=(300, 300, 3))

x = keras.applications.EfficientNetB3(
    input_tensor=inputs, # pass input to input_tensor 
    include_top=False,
    weights=None
)

# flat the base model with x.output 
x = layers.GlobalAveragePooling2D()(x.output) 

# others 
x = layers.Dense(128)(x)
x = layers.Dropout(0.5)(x)
x = layers.Dense(5)(x)

model = keras.Model(inputs, x)

for i, layer in enumerate(model.layers[-10:]):
    print(i, layer.name, layer.output_shape, layer.trainable)
0 block7b_project_bn (None, 10, 10, 384) True
1 block7b_drop (None, 10, 10, 384) True
2 block7b_add (None, 10, 10, 384) True
3 top_conv (None, 10, 10, 1536) True
4 top_bn (None, 10, 10, 1536) True
5 top_activation (None, 10, 10, 1536) True  # < - We will pick this 2D maps
6 global_average_pooling2d_2 (None, 1536) True
7 dense_2 (None, 128) True
8 dropout (None, 128) True
9 dense_3 (None, 5) True

Build Grad-CAM Model

grad_model = keras.models.Model(
    [model.inputs], 
    [
        model.get_layer('top_activation').output, 
        model.output
     ]
)

Check

With your setup, you would get a disconnected error with the following code. But now, it wouldn't happen.

import numpy as np 

image = np.random.rand(1, 300, 300, 3).astype(np.float32) 

with tf.GradientTape() as tape:
    convOutputs, predictions = grad_model(tf.cast(image, tf.float32))
    loss = predictions[:, tf.argmax(predictions[0])]

grads = tape.gradient(loss, convOutputs)
print(grads.shape) 
(1, 10, 10, 1536) # NO DISCONNECTED ERROR

To get the heatmaps from your grad-cam model, check the following answers and sources as references.

Innat
  • 16,113
  • 6
  • 53
  • 101
  • You should be able to solve your issue. Let me know. – Innat Feb 23 '22 at 20:32
  • When I reload the model, model = tf.keras.models.load_model(data_dir), the efficientNet CNN is wrapped within layer2 of the model. grad_model = tf.keras.models.Model( [model.inputs], [model.layers[2].get_layer('top_activation').output, model.output]) I still get a graph disconnection error. – Maximus Feb 24 '22 at 03:17
  • There is a data augmentation layer before CNN, not sure if this is the problem... – Maximus Feb 24 '22 at 03:18
  • The model and weight is here: https://drive.google.com/drive/folders/1i95pwnZMABxlpuVI3i9rx73GDBDbooWp?usp=sharing – Maximus Feb 24 '22 at 03:23
  • And some of the test photos are here: https://drive.google.com/drive/folders/17T87pRvZPJcvS5f2BVbvscVNJmskmcMv?usp=sharing – Maximus Feb 24 '22 at 03:24
  • ValueError: Graph disconnected: cannot obtain value for tensor KerasTensor(type_spec=TensorSpec(shape=(None, 300, 300, 3), dtype=tf.float32, name='input_1'), name='input_1', description="created by layer 'input_1'") at layer "stem_conv". The following previous layers were accessed without issue: [] – Maximus Feb 24 '22 at 15:10
  • The graph disconnection seems to occur at the very first convolutional layer of EfficientNet – Maximus Feb 24 '22 at 15:11
  • In any case, could you please help generate the heatmap overlay on the photos with the model, which are in the google drive shown above, and send it back to me? Thanks a lot......My email is maximus3219@gmail.com – Maximus Feb 24 '22 at 15:40