Grad_Cam运行报错:ValueError: Unable to determine penultimate `Conv` or `Pooling` layer for layer_idx: 2

之前一直想可视化模型的注意力热力图,找到了gradcam算法,具体是调用keras-vis的库。但是一直调试一直报错很苦恼,前前后后搞了一个月才成功跑通,于是今天准备写个博客记录一下心路历程,也方便后来者参考,不必再浪费太多时间在debug上

问题描述:
在用预训练模型VGG16做base_model并finetune时,报如下错误:

ValueError: Unable to determine penultimate Conv or Pooling layer for layer_idx: 2

但是如果是自己定义的模型就可以正常输出。

看起来应该是一个找不到对应layer的错误。于是很自然地我就查看了model的summary:

Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
vgg16 (Model)                (None, 7, 7, 512)         14714688  
_________________________________________________________________
flatten_1 (Flatten)          (None, 25088)             0         
_________________________________________________________________
visualized_layer (Dense)     (None, 1)                 25089     
=================================================================
Total params: 14,739,777
Trainable params: 25,089
Non-trainable params: 14,714,688
_________________________________________________________________

很显然,问题出在那个‘vgg16’上。我用的是操作更为简洁的Sequential搭建序列,模型设置如下:

base_model = VGG16(weights='imagenet',include_top=False,input_shape=IMG_SIZE+(3,))
base_model.trainable=False
NUM_CLASSES = 1
model = Sequential()
model.add(base_model)
model.add(layers.Flatten())
model.add(layers.Dense(NUM_CLASSES,activation='sigmoid',name='visualized_layer'))

之后DEBUG时发现我的代码在调用grad_cam时输入的layer_Idx是2(对应visualized_layer),然而在真实模型结构中很显然这层的索引绝对不止2,因此问题就出在Sequential对base_model的模型表述方式上。很显然这里Sequential把base_model看作一个不可拆分的整体,因此grad_cam也无法得到模型每一层输出的具体张量了(猜测)。
之后尝试过手动指定layer_Idx(也就是百度vgg16的网络结构,数一数有几层,然后手动输入Dense层的索引),但都已失败告终。

解决方式是:
使用keras.models.Model()来函数式定义网络结构。
这能够允许grad_cam算法获得打包好的预训练模型内部layers的信息。而这些信息是gradcam算法运行所需要的。
这可能相比于简介的Sequential显得有些复杂,但说他能够更全面的定义整个网络结构,也更具有可操作性。修改后的代码如下:

base_model = VGG16(weights='imagenet',include_top=False,input_shape=IMG_SIZE+(3,))
mid_layer=layers.Flatten()
mid_layer_tensor=mid_layer(base_model.output)
output_layer=layers.Dense(2,activation='softmax',name='visualized_layer')
output_layer_tensor=output_layer(mid_layer_tensor)
model = Model(inputs=base_model.input,outputs=output_layer_tensor)
for layer in model.layers:
    layer.trainable = False
model.layers[-1].trainable = True
model.layers[-2].trainable = True

注意:使用Model()后要手动设置for循环来指定冻结层(也就是有预训练权重的层)。要不然会默认全部训练。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值