denseNet_localization.py的问题
如果说前期数据准备是整个项目开始的最大障碍,那么 denseNet_localization.py 就是终结它之前的终极考验(当然是对我这个菜鸡来说)。说实话,在这个.py文件中遇到太多关键的问题,以至于在我想把它们整理出来的时候一时间找不到头绪。和大哥在106接近两小时的debug,收获真的太多了(99%的工作为大哥完成)。下面我按时间线说一下遇到的主要问题以及解决方案。
1.missing keys、unexpected keys以及size mismatch
最开始我用两GPU训练,得到权重放在denseNet_localization.py中,如下图
出现问题:
① missing keys:n个网络层丢失+unexpected keys:n个未知网络层
② size mismatch for module.densenet121.classifier.0.weight: copying a param with shape torch.Size([1, 1024]) from checkpoint, the shape in current model is torch.Size([8, 1024]).
size mismatch for module.densenet121.classifier.0.bias: copying a param with shape torch.Size([1]) from checkpoint, the shape in current model is torch.Size([8]).
我首先注意到第一个问题,意识到权重少东西,但没有第一时间深入解决,而是直接在调用权重之后添加“False”将其消除。第二个问题是size不匹配的原因,我想到原始项目训练有8类目标,而我这次训练只选用了一个目标,我把8改为1,问题解决。
注意一下这个句子:model = torch.nn.DataParallel(model),这是一个多GPU训练调用的函数,我个人很反感这个函数,一个是由它引出的问题实在太多,包括上面的missing keys也和它有关,另外就是它多GPU的资源分配并不平均,导致资源的浪费,我们最后消除了这个函数,关于它我之后会详细研究一波,到时候再写一篇博客总结一下。
2.Invalid layer name: module.densenet121.features.denseblock4.denselayer16.conv.2
源码中,有这么一段:
GradCAM函数的功能大致可以概括为:选取一个层,以实现目标的localization可视化。分析densenet121网络结构,发现 densenet121.features.denseblock4.denselayer16.conv2 是很深入的层,所以作者选取它作为localization的层是很合理的,但 layer name 为什么会无效呢?这个问题在GitHub的issue里有提到,见此链接:GitHub issue#2但我按照那个老兄的方法修改,无济于事,到底是什么原因?
这里先按下不表,看第三个问题。
3. if id(module[1]) == key: if module[0] == target_layer:
这段代码折磨我们很久,个人认为也是整个.py文件最精髓的一段。也就是说,只有当两个条件都满足的时候,才能返回value值。通过debug发现,key的值是不变量,但众多的id(module[1])没有一个和key匹配的,就很离谱。但module[0]中发现了module.densenet121.features.denseblock4.denselayer16.conv2这个层的名称。经过一番苦苦查找和debug,我们突然发现在 Invalid layer name 前还有一个我们一直忽略的问题:
THCudaCheck FAIL file=/pytorch/aten/src/THC/THCGeneral.cpp line=405 error=11:invalid argume
经过查询,得知这个问题由于cuda版本和本机环境冲突导致。查找项目的cuda版本为8.0,而我们的系统cuda版本为10.1,好像看到了曙光。修改cuda版本,问题解决,但 Invalid layer name 这个问题仍然挥之不去,这时大哥说,有没有可能是多GPU训练的问题,导致权重分配不均,丢失值,而且版本也会影响网络层的命名。如果真是这个问题,那么 missing keys 和 Invalid layer name 都可以解决了。
我重新调用一个GPU训练数据,将权重放入 denseNet_localization.py 中,没有False,没有出现 missing keys,看来我们的想法是正确的。
debug key的值,发现这一次和 id.module[0]一一匹配,但 Invalid layer name 还是存在,再次debug,这次发现那个网络层的名字变成了 densenet121.features.denseblock4.denselayer16.conv2 ,修改后,成功生成 bbox.txt文件!修改cuda版本后,网络层名字也会改变。
后记
通过这次的经历,总结如下几点:
关键点:训练层名字(细心)
单GPU和多GPU问题(最好按照项目的做法来选取)
维度问题(类别数决定)
版本:cuda8.0—cuda10.1
Pytorch1.1.0—1.4.0
不同版本导致densenet网络层的名字不同
感谢大哥周末抽出时间帮我看代码、改代码,自己要学的东西太多了。目前项目算是告一段落,希望再接再厉!