接下来就讲讲我在代码上修改的坑:
错误一: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 <class ‘XX’>.
原因:这个问题是由于你保存权重的方式,和在绘制热力图脚本里的加载权重的方式不同,
将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]这样就可以成功绘制热力图。
如下图所示:
以上就是我在将热力图代码融入自己模型和数据集所经历的坑,最后附带我根据自己数据集绘制的热力图,大家可以看到,经过训练之后的模型权重载入绘制的热力图能够让我们知道模型更加关注叶片的纹理。
原图: 绘制的热力图: