1. 训练流程
1.1. 准备数据
所有的相关数据都在../data/training/
路径下:
其中pic
存放所有图片,json
存放所有图片的json标注,all
存放所有图片的.txt
标注,另外三个则分别是训练集、验证集和测试集的.txt
标注。
我们最初的数据是原始图片+Json
标注文件,每个Json
文件对应一张图片。我们需要输入模型的数据是原始图片+.txt
标注文件,每一行对应一张图片。
标注文件的转化可以通过./tools/data_process/random_select.py
实现。实现转化还需要class.name
文件,作用是将json中的类名转化成数字。class.name
的格式如下:
car
tyre
对应关系是:car
—0
,tyre
—1
生成的.txt
文件,每行格式如下:
0 ../data/training/pic/image01_00041.png 1 3342 1244 3603 1610 0 2804 755 3840 1611 0 1818 801 2679 976
- 第一个元素
0
是图片序号 - 第二个元素
../data/training/pic/image01_00041.png
是图片的相对train.py
的相对路径 - 后面每五个元素为一组,每组代表一个目标的分类及其坐标。以第一组
1 3342 1244 3603 1610
为例:- 第一个值
1
为分类代号,和class.name
里的排序对应,即car
- 后面四个值分别为标注框的
x_min
、y_min
、x_max
、y_max
- 第一个值
1.2. 准备模型
1.2.2 聚类算法生成anchors
yolo v3利用k_means聚类算法生成prior anchors,直接运行get_kmeans.py
即可。有两个参数需要注意一下:
- annotation_path:train.txt的路径,这一般不会变
- 函数
get_kmeans
的第二个参数:anchors的数量,目前设置为9,以后有需要可以修改
程序运行结束后会显示生成的anchors,将其复制到./config/my_anchors.txt
即可:
60,117, 105,156, 255,69, 179,189, 150,297, 272,352, 490,421, 979,527, 1970,1190
1.2.3 weights conversion
本模型采用迁移学习的训练方式,先在网上下载coco数据集预训练的权值文件,然后生成yolo v3的checkpoint文件。具体操作:
(1)下载yolov3.weights,放在../data/restore_weights/
路径下
(2)运行convert_weight.py
,生成的checkpoint文件(yolov3.ckpt)将会存放在同目录下
这样我们就得到了一个经过coco数据集预训练好的yolo v3模型,输入数据就可以训练了。
1.3. 训练
有了数据和模型之后就可以开始进一步训练了,目前采用two_stage的训练策略。
按照目前的经验,stage one训练约20个周期,然后选择其中最好的一个模型进入stage two,stage two同样训练约20个周期,然后选择最好的模型作为最终输出的模型。采用这种训练策略,在./arg.py
中有几个参数是需要修改的。
1.3.1 stage one
恢复预训练的模型,冻结backbone,采用较大的初始学习率训练head,具体参数:
restore_path = '../data/restore_weights/yolov3.ckpt' # 采用预训练好的模型
learning_rate_init = 1e-3 # 初始学习率,较大
restore_part = ['yolov3/darknet53_body'] # 恢复的网络部分, 这里只回复body,也就是说head部分从头开始训练
update_part = ['yolov3/yolov3_head'] # 继续训练的网络部分, 这里只训练head,说明body被冻结,还是原来coco预训练的那些值
1.3.2 stage two
恢复stage训练的模型,不冻结,采用较小的初始学习率训练backbone和head,具体参数:
restore_path = '../data/restore_weights/yolov3.ckpt' # 采用预训练好的模型
learning_rate_init = 1e-4 # 初始学习率,较大
restore_part = ['yolov3/darknet53_body'] # 恢复的网络部分, 这里只回复body,也就是说head部分从头开始训练
update_part = ['yolov3/yolov3_head'] # 继续训练的网络部分, 这里只训练head,说明body被冻结,还是原来coco预训练的那些值
1.4. 训练的输出
完成训练后我们会得到如下输出:
1.4.1 events 文件
存放在../data/logs/
路径下,events文件主要记录了模型训练过程中loss变化情况,可以直接打开tensorboard查看loss曲线,也可以将loss的值读出来自己绘图,后者的灵活性更高。下图展示的是读取多个events文件并绘制loss曲线:
1.4.2 loss.txt
存放在../data/
路径下,每完成一个周期的训练,都会在验证集中进行验证,loss.txt
记录的就是每次验证得到的结果:
======> Epoch: 1, global_step: 1567.0, lr: 0.000666242 <======
EVAL: Class 0: Recall: 0.7610, Precision: 0.2332, AP: 0.5112
EVAL: Class 1: Recall: 0.9528, Precision: 0.4849, AP: 0.8984
EVAL: Recall: 0.8687, Precison: 0.3428, mAP: 0.7048
EVAL: loss: total: 15.27, xy: 7.60, wh: 6.29, conf: 0.88, class: 0.51
每次输出信息包括周期数、步数、学习率、每个类别的AP等评价指标以及各种loss
1.4.3 checkpoint模型文件
存放在../data/checkpoint/
路径下,checkpoint是训练模型最重要的输出,它记录了模型和权重的信息,可以说它就是我们训练模型唯一需要的结果,其他的都只是辅助文件罢了。文末的附件有对checkpoint文件的介绍。
目前的模型保存策略是:
- 每5个周期保存一次,可以在
arg.py
修改save_epoch
的值以变更 - 如果当前周期验证的结果比之前的都要好,那么这个周期也会保存,并且文件名含有
best
字样,比较结果好坏用的是mAP
2. 评价流程
评价主要分两步,第一步输出相关数据并计算评价指标,第二步分析结果
2.1 运行评价程序
要得到相关数据有以下几个操作要执行,有些繁琐,后续会进行优化
- 将训练得到的模型文件填入
args_eval.py
:
`restore_path = “…/…/…/data/checkpoint/best_model_Epoch_16_step_13327.0_mAP_0.9558_loss_6.7667_lr_8.847359e-05” - 直接运行
eval.py
得到两个类别的准确率、召回率、PR曲线和AP - 直接运行
test_data_detect.py
,检测测试集的图片,这一步有两个输出:标注文件,以及标注信息(包括真实和预测)在图片上的展示,如图:
- 直接运行
calcu_iou_acc.py
计算各类别的IoU和acc
3. 预测
- 将需要检测的图片放在
./data/image_detect_in/
里面 - 修改
image_detect.py
里面的模型文件:
"restore_path": "../data/checkpoint/model-epoch_15_step_15679_loss_7.0378_lr_6.8987e-05"
然后运行即可得到预测到的标注文件,格式为xml,同时也会有展示: