对于深度学习网络,在我们指定数据集类别的情况下,Grad-CAM能够绘制出相应的热力图,让我们能够非常直观的看出网络关注的主要区域与特征是什么。本文主要记录在绘制热力图过程中,自己碰到的一些实际问题,希望能对小伙伴们有所帮助。
以下是本文的参考视频和代码链接,我主要看的是B站霹雳吧啦老师的视频和代码(感谢我导)
视频链接: 使用Pytorch实现Grad-CAM并绘制热力图_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1e3411j7x7/?spm_id_from=333.788.recommend_more_video.0&vd_source=e43c081338520d48e907ed94f3d8f6c8
代码:https://github.com/WZMIAOMIAO/deep-learning-for-image-processing
首先打开这个代码链接,找到pytorch_classification -> grad_cam这个文件夹,下载之后打开如下图:
我是将上述的代码中main.cnn.py这个文件单独在自己的模型文件夹中创立一个using_grad_cam.py,作为单独绘制热力图的工具脚本,同时将utils.py复制上自己的模型文件夹中,如下图:
接下来就讲讲我在代码上修改的坑:
错误一:TypeError: 'module' object is not callable
原因:实例化模型错误,这个是根据你实例化的方法去对应的。一定要写到具体的模型型号。
比如我的模型脚本是models.py,并且我想绘制的热力图具体型号是resnetXX
那就是model = models.resnetXX(num_classes=你对应数据集的类别),比如我使用的数据集共有38类那就是38。
错误二:TypeError: Expected state_dict to be dict-like, got
原因:这个问题是由于你保存权重的方式,和在绘制热力图脚本里的加载权重的方式不同,
将train脚本中的保存权重方式稍作修改即可,将模型权重以字典的形式保存即可。
注意:如果你修改完以上操作仍然告诉你权重加载的代码报错,并显示缺少键值,那么就在热力绘制图脚本中将加载权重的代码后面加上一个Strict=False即可。
错误三:AxisError: axis 3 is out of bounds for array of dimension 3
原因:本问题出在代码输出的要是列表,所以将utils.py中Grad-CAM里的函数稍作修改即可,将返回的对象强制转为列表,如下图:
错误四:AttributeError: ‘tuple‘ object has no attribute ‘cpu‘
原因:这个问题,主要是因为没有指定具体的某一层,而是将目标层直接设定为某个stage或是模块名,这样会导致target_layers是一个元组,就会一直报这个错。对于这个问题,首先你要清楚你的网络模型的结构,可以通过输出print(model)的方式来查看自己模型具体的层结构。给大家打个比方,下图是我输出模型结构的一小块,此时如果我设定target_layers=[model.patch_embed_a],那它就相当于被我设置成一个元组,但这样是无法应用在这个代码上的,我们需要继续细化到某一层,比如改成target_layers=[model.patch_embed_a.norm]这样就可以成功绘制热力图。
如下图所示:
以上就是我在将热力图代码融入自己模型和数据集所经历的坑,最后附带我根据自己数据集绘制的热力图,大家可以看到,经过训练之后的模型权重载入绘制的热力图能够让我们知道模型更加关注叶片的纹理。
原图: 绘制的热力图: