将B_mobilenet_yolov4_lite的PANet改为原来的3x3卷积,命名为L_mobilenet-yolov4_VOC,即将B_yolov4的主干网络换为mobilenet,训练时报错:
Traceback (most recent call last):
File "/home/PycharmProjects/yolov4/L_mobilenet-yolov4_VOC_0717/train.py", line 221, in
pretrained_dict = {k: v for k, v in pretrained_dict.items() if np.shape(model_dict[k]) == np.shape(v)}
File "/home/PycharmProjects/yolov4/L_mobilenet-yolov4_VOC_0717/train.py", line 221, in
pretrained_dict = {k: v for k, v in pretrained_dict.items() if np.shape(model_dict[k]) == np.shape(v)}
KeyError: 'conv1.1.0.weight'
该问题的错误原因:加载的模型pretrained_dict文件中没有conv1.1.0.weight这个权重内容,打印网络模型和预训练模型的键值,发现键值不同。检查确定所有函数中的主干和权重等选择的都是同一个模型,且加载预训练权重也是mobilenet,即:网络结构一样,但结构命名不同。
尝试1:将220-222这三行代码注释掉,程序可以运行,但不知道会不会对结果造成影响。猜测:隐约记得所使用代码的主人在哪里说过,如果不加载主干权重默认加载他在VOC数据集上训练得到的权重,如果是这样的话再训练VOC数据集就。。。(将这三行注释掉后,打印model_dict好像是没有权重?也就是全是0或者1,这部分后续待探索)
尝试2:按照diudiu~bo的博客“Mobilenet-yolov4代码调试”记录,将
pretrained_dict = {k: v for k, v in pretrained_dict.items() if np.shape(model_dict[k]) == np.shape(v)}
替换为
pretrained_dict = {k: v for k, v in pretrained_dict.items() if k in model_dict}
结果:程序不再报错,可以运行,但貌似没有载入预训练权重,因为按照这样运行,在执行完
model_dict.update(pretrained_dict)后,打印model_dict,结果为空字典。
尝试3:分析预训练网络和当前网络,结构相同但命名不同,即对应的每一层名字不同,shape相同,因此,通过对比shape/size来载入预训练权重。参考https://blog.csdn.net/feizai1208917009/article/details/103598233#commentBox的方法一,将那一行代码替换为以下代码块:
# 取出预训练网络的参数字典
keys = []
for k, v in pretrained_dict.items():
keys.append(k)
i = 0
# 自己网络和预训练网络结构一致的层,使用预训练网络对应层的参数初始化
for k, v in model_dict.items():
if v.size() == pretrained_dict[keys[i]].size():
model_dict[k] = pretrained_dict[keys[i]]
i = i + 1
# print(model_dict)
将打印的model_dict的键值与预训练网络权重和原始model_dict对比,发现已正确载入预训练权重,即打印的结果为:model_dict的键和预训练网络权重的值。
但运行最后在if v.size() == pretrained_dict[keys[i]].size():这行报错:
IndexError: list index out of range
考虑是因为代码最后有i=i+1,在遍历完pretrained_dict之后,i又增加1,所以在下次循环时报错列表超出范围,因此,需要给i加个条件使遍历完pretrained_dict之后不进入循环,直接结束for循环,将代码改为如下格式:
# 取出预训练网络的参数字典
keys = []
j = 0
for k, v in pretrained_dict.items():
keys.append(k)
j = j + 1
# print(j)
i = 0
# 自己网络和预训练网络结构一致的层,使用预训练网络对应层的参数初始化
for k, v in model_dict.items():
if v.size() == pretrained_dict[keys[i]].size():
model_dict[k] = pretrained_dict[keys[i]]
i = i + 1
if i >= j:
break
# print(model_dict)
增加k为pretrained_dict中键值对的数量,i应该不大于j,否则就要退出循环,成功运行程序,并打印正确的载入的权重。
心得总结:在优化程序时,debug不能直观的看到所有数据,因此应该及时打印网络参数及shape进行分析,更直观。