一、前言:
学无止境,在学习YOLO v3的理论及使用方法时,有以下文章及github开源代码为我提供了很大帮助,特此附上链接,表示感谢!希望对您也有参考借鉴的意义!
二、学习笔记 / 翻译分析
1. 论文链接:https://pjreddie.com/media/files/papers/YOLOv3.pdf
2. 论文翻译:
3. 论文详解:
4. 整理笔记:
(1) tensorflow yolov3训练自己的数据集,详细教程
(2)【论文解读】Yolo三部曲解读——Yolov3
(3) yolo系列之yolo v3【深度解析】
(4) YOLOv2 论文笔记
三、源码
1.(推荐)https://github.com/YunYang1994/tensorflow-yolov3
四、运行出现问题及解决办法
1. 训练自己的类别(单类别不会出错,多类别会出错)时,加载coco的预训练模型,会报错加载错误。部分报错内容如下:
Error--- Restoring from checkpoint failed. This is most likely due to a mismatch between the current graph and the graph from the checkpoint. Please ensure that you have not altered the graph expected based on the checkpoint. Original error:
2 root error(s) found.
(0) Invalid argument: Assign requires shapes of both tensors to match. lhs shape= [1,1,512,27] rhs shape= [1,1,512,18]
[[node loader_and_saver/save/Assign_93 (defined at D:/personal/new_packages/try/train.py:103) ]]
[[loader_and_saver/save/RestoreV2/_74]]
(1) Invalid argument: Assign requires shapes of both tensors to match. lhs shape= [1,1,512,27] rhs shape= [1,1,512,18]
[[node loader_and_saver/save/Assign_93 (defined at D:/personal/new_packages/try/train.py:103) ]]
0 successful operations.
0 derived errors ignored.
解决办法(对单类别/多类别均适用):
将train.py的108行 self.loader = tf.train.Saver(self.net_var)
改为
variables_to_restore = [v for v in self.net_var if v.name.split('/')[0] not in ['conv_sbbox','conv_mbbox','conv_lbbox']]
self.loader = tf.train.Saver(variables_to_restore)
以上解决办法来自:https://github.com/YunYang1994/tensorflow-yolov3/issues/297,感谢mengqp1994。
解决思路源于train.py的77行-86行:
with tf.name_scope("define_first_stage_train"):
self.first_stage_trainable_var_list = []
for var in tf.trainable_variables():
var_name = var.op.name
var_name_mess = str(var_name).split('/')
if var_name_mess[0] in ['conv_sbbox', 'conv_mbbox', 'conv_lbbox']:
self.first_stage_trainable_var_list.append(var)
first_stage_optimizer = tf.train.AdamOptimizer(self.learn_rate).minimize(self.loss,
var_list=self.first_stage_trainable_var_list)
五、一点个人笔记
- 在验证部分有一个变量min_overlap,它是用来判断tp和fp的,即所预测的正样本对不对,ovmax的计算也是IOU的思想。(非极大值抑制nms用的是iou_threshold)
具体代码:
# set minimum overlap
for idx, prediction in enumerate(predictions_data):
file_id = prediction["file_id"]
gt_file = tmp_files_path + "/" + file_id + "_ground_truth.json"
ground_truth_data = json.load(open(gt_file))
ovmax = -1
gt_match = -1
# load prediction bounding-box
bb = [float(x) for x in prediction["bbox"].split()]
for obj in ground_truth_data:
# look for a class_name match
if obj["class_name"] == class_name:
bbgt = [float(x) for x in obj["bbox"].split()]
bi = [max(bb[0], bbgt[0]), max(bb[1], bbgt[1]), min(bb[2], bbgt[2]), min(bb[3], bbgt[3])]
iw = bi[2] - bi[0] + 1
ih = bi[3] - bi[1] + 1
if iw > 0 and ih > 0:
# compute overlap (IoU) = area of intersection / area of union
ua = (bb[2] - bb[0] + 1) * (bb[3] - bb[1] + 1) + (bbgt[2] - bbgt[0]
+ 1) * (bbgt[3] - bbgt[1] + 1) - iw * ih
ov = iw * ih / ua
if ov > ovmax:
ovmax = ov
gt_match = obj
# set minimum overlap
min_overlap = MINOVERLAP
if specific_iou_flagged:
if class_name in specific_iou_classes:
index = specific_iou_classes.index(class_name)
min_overlap = float(iou_list[index])
if ovmax >= min_overlap:
if "difficult" not in gt_match:
if not bool(gt_match["used"]):
# true positive
tp[idx] = 1
gt_match["used"] = True
count_true_positives[class_name] += 1
# update the ".json" file
with open(gt_file, 'w') as f:
f.write(json.dumps(ground_truth_data))
else:
# false positive (multiple detection)
fp[idx] = 1
else:
# false positive
fp[idx] = 1
- 关于训练热身warm up的相关内容,可看文章深度学习之“训练热身”(warm up)–学习率的设置。