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

Flower ·
更新时间:2024-11-13
· 964 次阅读

之前一直想可视化模型的注意力热力图,找到了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循环来指定冻结层(也就是有预训练权重的层)。要不然会默认全部训练。


作者:Bunny_COM



TO for cam conv

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章