I am building a CNN model using Resnet50 to identify to classify 5 objects. The images of the objects were taken on my desk so there is a portion of my desk in every object. The code to initialize the model is, like so,
model = Sequential()
pretrained_model= tf.keras.applications.ResNet50(include_top=False,
input_shape=(180,180,3),
pooling='avg',classes=5,
weights='imagenet')
for layer in pretrained_model.layers:
layer.trainable=False
model.add(pretrained_model)
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dense(2, activation='softmax'))
I compiled the model and fit it and it works as expected.
The model isn't working great, the predictions are not very accurate. I suspect that the model is being trained on the portions of my desk and I would like to use class activation maps to know if that's true.
The tutorials I have seen have class activation maps code for a model that has been built from scratch. I understand that we need to add a global average pooling layer followed by a dense layer with softmax
activation to enable class activations.
The Resnet50 model ends with a global average pooling layer which I found out by running,
pretrained_model.layers
so I simply had to add the dense layer which I added by running,
model.add(pretrained_model)
model.add(Dense(2, activation='softmax'))
but when I print out the summary of this model, I get,
Model: "sequential_3"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
resnet50 (Functional) (None, 2048) 23587712
_________________________________________________________________
dense_3 (Dense) (None, 2) 4098
=================================================================
Total params: 23,591,810
Trainable params: 4,098
Non-trainable params: 23,587,712
I am following Laurence Moroney's example and he says we have to extract weights from the global average pooling layer and the dense layer which I am not able to do with the model I just created.
Is there a way to expand the resnet50 (Functional)
layer to access the global average pooling layer?
Edit
I am continuing my queries here since it is part of the my actual question, i.e enabling class activation maps with transfer learning.
As mentioned in the comments, I can obtain the last convolution layer by providing,
model.layers[0].layers[-5]
After obtaining the weights of the dense layer and the last conv layer, I tried creating the cam_model, like so,
cam_model = Model(inputs=(model.layers[0].layers[0].input), outputs=(model.layers[0].layers[-5].output, model.layers[1].output))
which results in this error,
ValueError: Graph disconnected: cannot obtain value for tensor KerasTensor(type_spec=TensorSpec(shape=(None, 180, 180, 3), dtype=tf.float32, name='resnet50_input'), name='resnet50_input', description="created by layer 'resnet50_input'") at layer "resnet50". The following previous layers were accessed without issue: ['conv1_pad', 'conv1_conv', 'conv1_bn', 'conv1_relu', 'pool1_pad', 'pool1_pool', 'conv2_block1_1_conv', 'conv2_block1_1_bn', 'conv2_block1_1_relu', 'conv2_block1_2_conv', 'conv2_block1_2_bn', 'conv2_block1_2_relu', 'conv2_block1_3_conv', 'conv2_block1_0_conv', 'conv2_block1_0_bn', 'conv2_block1_3_bn', 'conv2_block1_add', 'conv2_block1_out', 'conv2_block2_1_conv', 'conv2_block2_1_bn', 'conv2_block2_1_relu', 'conv2_block2_2_conv', 'conv2_block2_2_bn', 'conv2_block2_2_relu', 'conv2_block2_3_conv', 'conv2_block2_3_bn', 'conv2_block2_add', 'conv2_block2_out', 'conv2_block3_1_conv', 'conv2_block3_1_bn', 'conv2_block3_1_relu', 'conv2_block3_2_conv', 'conv2_block3_2_bn', 'conv2_block3_2_relu', 'conv2_block3_3_conv', 'conv2_block3_3_bn', 'conv2_block3_add', 'conv2_block3_out', 'conv3_block1_1_conv', 'conv3_block1_1_bn', 'conv3_block1_1_relu', 'conv3_block1_2_conv', 'conv3_block1_2_bn', 'conv3_block1_2_relu', 'conv3_block1_3_conv', 'conv3_block1_0_conv', 'conv3_block1_0_bn', 'conv3_block1_3_bn', 'conv3_block1_add', 'conv3_block1_out', 'conv3_block2_1_conv', 'conv3_block2_1_bn', 'conv3_block2_1_relu', 'conv3_block2_2_conv', 'conv3_block2_2_bn', 'conv3_block2_2_r...
My model.summary
looks like this,
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
resnet50 (Functional) (None, 2048) 23587712
_________________________________________________________________
dense (Dense) (None, 5) 10245
=================================================================
Total params: 23,597,957
Trainable params: 10,245
Non-trainable params: 23,587,712
and the first few layers of my model.layers[0].summary()
looks like this,
Model: "resnet50"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input_2 (InputLayer) [(None, 180, 180, 3) 0
__________________________________________________________________________________________________
conv1_pad (ZeroPadding2D) (None, 186, 186, 3) 0 input_2[0][0]
__________________________________________________________________________________________________
conv1_conv (Conv2D) (None, 90, 90, 64) 9472 conv1_pad[0][0]
__________________________________________________________________________________________________
I think the graph is getting disconnected at the resnet50
layer but I have no idea where to find it. Can someone please help.
CodePudding user response:
To print out the layers of the resnet
model try this: model.layers[0].summary()
. If you want to access the GlobalAveragePooling
layer, which happens to be the last layer of the model, then try this:
global_max_pooling = model.layers[0].layers[-1]
. Note, however, that the GlobalAveragePooling
layer itself does not have any weights.