本篇文章记录了在centos7(Linux)上使用YOLOv3训练自己数据的操作步骤,YOLOv3使用AlexeyAB大神改进的darknet(Github地址),内容也主要参考自其中,使用其它系统或框架的同学可以酌情参考或直接阅读Github。
题外话:第一次写博客,可能存在诸多问题和遗漏,欢迎大家指出更正。
由于环境的准备工作不是本篇文章的重点,这里只做简单叙述。
根据Github上的要求:
darknet源码下载地址:https://github.com/AlexeyAB/darknet
下载解压后进入darknet根目录,根据机器情况修改Makefile文件:
GPU=1 # 是否使用GPU
CUDNN=1 # 是否使用CUDNN
CUDNN_HALF=1 # 是否为Tensor核心加速,
Titan V / Tesla V100 / DGX-2及更高版本显卡可以使用
OPENCV=1 # 是否使用OPENCV
OPENMP=0 # 是否使用OPENMP
修改后进行编译,在darknet根目录执行:
make
yolo_mark下载地址:https://github.com/AlexeyAB/Yolo_mark
对于每个图片,yolo_mark输出一个txt文件,每一行代表一个bounding box,格式如下:
<类别>
设该bounding box中心的绝对坐标为(
,
该bounding box在绝对坐标下宽高为(
,
图片的宽高为(
,
则每个参数的含义如下:
参数 | 含义 |
---|---|
<类别> |
该bounding box内物体的类别,为[0, class-1]之间整数 |
|
|
|
|
|
|
|
例:1 0.609766 0.660417 0.388281 0.215278
图片的存放位置可以自行决定,但建议存放在darknet根目录下的data目录下,方便管理。
进入data目录,创建用于存放数据的文件夹,命名为obj (目录名可以根据自己需求更改):
cd data
mkdir obj
将图片文件和对应的txt标注文件一起存放进data/obj/
目录下。
注意:图片文件和对应的txt标注文件的文件名要保持一致。
作用:训练数据集路径。
在data目录下创建train文件train.txt (文件名可以自行更改,但要保持前后一致),文件内容为用作训练数据的图片路径。如:
我要使用data/obj/
目录下的如下文件进行训练:
obj_0.jpg obj_130.jpg obj_152.jpg
obj_0.txt obj_130.txt obj_152.txt
则对应的train.txt
文件内容为:
data/obj/obj_0.jpg
data/obj/obj_130.jpg
data/obj/obj_152.jpg
作用:验证数据集路径。使用map指令验证模型效果时,程序会调用该路径。
在data目录下创建valid文件test.txt (文件名可以自行更改,但要保持前后一致),文件内容为作为验证数据的文件路径,格式与train文件相同。
作用:指明类别名称。
在data目录下创建names文件obj.names (文件名可以自行更改,但要保持前后一致),文件内容为每一类检测物体的名称,具体如下:
如果我要检测两类物体,类别0代表apple,类别1代表orange,则obj.names内容为:
apple
orange
需要注意顺序,第一行对应类别0,第二行对应类别1,依此类推。
作用:指明上述各个文件的位置。
在data目录下创建data文件obj.data (文件名可以自行更改,执行指令时保持输入参数一致即可),文件内容如下:
classes = 2 # 检测物体类别数,如:检测apple和orange两类物体,则类别数为2。
train = data/train.txt # train文件位置,需保持路径及文件名前后一致。
valid = data/test.txt # valid文件位置,需保持路径及文件名前后一致。
names = data/obj.names # names文件位置,需保持路径及文件名前后一致。
backup = backup/ # 训练过程产生的模型参数文件会保存在该文件夹下,
# 这里设置为darknet根目录下的backup文件夹。
作用:神经网络的详细构建参数。
在darknet根目录的cfg文件夹下,复制yolov3.cfg命名为yolo-obj.cfg (文件名可以自行更改,执行指令时保持输入参数一致即可)。
修改文件内容:
batch=64 # 每个迭代训练的图片数,一个迭代更新一次参数
subdivisions=8 # 将一个迭代的图片分成subdivisions次进行训练,内存不足时可以适当调大
# 这里batch=64,subdivisions=8,则每个subdivision训练的图片数量为64/8=8
...
max_batches=4000 # 最大迭代次数,建议设置为(classes*2000), 比如识别两类物体,则设置为4000
# 如果训练效果不理想,也可以调大,通过测试集的mAP判断模型是否可用或是否过拟合
steps=3200,3600 # 迭代到steps对应的次数时,学习率衰减,衰减系数通过scales设定,
# 建议将steps设置为max_batches的80%和90%
另外,在三个[yolo]
层中,将classes
修改为识别类别数,如classes=2
;
在三个位于[yolo]
层之前的[convolutional]
层中,将filters
修改为(classes + 5) × 3,如filters=21
。
注意,要将filters
设置为整数,不能直接写表达式。
cfg文件中的部分参数含义如下1,2,3,4:
[net]
# Testing # 测试时,将batch和subdivisions设为1
# batch=1
# subdivisions=1
# Training
batch=64 # 每个迭代训练的图片数
subdivisions=8 # 将每个迭代分成subdivisions次训练,内存不足时可以适当调大
width=416 # 输入图像宽度
height=416 # 输入图像高度
channels=3 # 输入图像通道数
# darknet有resize步骤,不需要预先将图片转换成设定的宽高
# width和height影响图片在网络中的分辨率,可以自行调整为32的倍数
momentum=0.9 # 梯度下降中的动量参数
decay=0.0005 # 权重衰减正则项,防止过拟合
# 每次学习参数后,将参数按照decay的比例进行降低,防止过拟合
angle=0 # 通过旋转增加数据
saturation = 1.5 # 通过更改饱和度增加数据
exposure = 1.5 # 通过更改曝光度增加数据
hue=.1 # 通过更改色调增加数据
learning_rate=0.001 # 学习率
burn_in=1000 # 小于burn_in使用默认学习率策略,大于burn_in使用设定的学习策略,详见参考2
max_batches=4000 # 最大迭代次数,即停止条件
policy=steps # 学习率调整策略,详见参考3
steps=3200,3600 # 迭代次数达到steps时,使学习率衰减
scales=.1,.1 # 学习率衰减系数
...
[yolo]
mask = 0,1,2 # YOLOv3中共提前预设了9种尺寸的anchor,每个yolo层负责其中3种尺寸的预测
# 如:这个yolo层负责第0,1,2个anchor的预测
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
# 预设anchor的width和height,可以预先自行对ground truth做k-means聚类得到
classes=2 # 预测物体的种类数
num=9 # YOLO划分的每个网格内预测的bounding box数量
jitter=.3 # [存疑]数据扩充的抖动操作
ignore_thresh = .7 # 当bounding box与ground truth的IOU不是最大,但大于ignore_thresh时,
# 网络会忽略其confidence的更改,既不奖励也不惩罚。这种做法借鉴自Faster RCNN
# 注:IOU最大的bounding box的confidence会被奖励,IOU过小的会被惩罚
truth_thresh = 1
random=1 # 关闭则图片大小与输入大小一致,打开则每迭代几次后,网络会随机更改输入尺寸
# 想提升训练速度时可以关闭,即random=0
下载预训练好的权重文件darknet53.conv.74
到darknet根目录下。
地址:https://pjreddie.com/media/files/darknet53.conv.74
使用配置好的data文件,cfg文件,以及下载的预训练权重文件,开始训练自己的数据。
在darknet根目录下(包含可执行文件darknet
的目录)执行如下命令:
./darknet detector train data/obj.data cfg/yolo-obj.cfg darknet53.conv.74
使用指定GPU训练,如使用0号和1号GPU训练,则加上参数-gpus 0,1
,执行:
./darknet detector train data/obj.data cfg/yolo-obj.cfg darknet53.conv.74 -gpus 0,1
训练过程不显示损失变化图,则加上参数-dont_show
,执行:
./darknet detector train data/obj.data cfg/yolo-obj.cfg darknet53.conv.74 -dont_show
在上一次训练好的模型的基础上继续训练,将权重文件更改即可。
比如上一次训练好的权重文件为backup/
目录下的yolo-obj_final.weights
文件,则执行:
./darknet detector train data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_final.weights
更多详细参数,参考项目的Github说明。
输出参数格式如下:
...
Region 82 Avg IOU: 0.830165, Class: 0.999033, Obj: 0.936065, No Obj: 0.002346, .5R: 1.000000, .75R: 1.000000, count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000005, .5R: -nan, .75R: -nan, count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000001, .5R: -nan, .75R: -nan, count: 0
Region 82 Avg IOU: 0.831569, Class: 0.990958, Obj: 0.845798, No Obj: 0.002309, .5R: 1.000000, .75R: 1.000000, count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000002, .5R: -nan, .75R: -nan, count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000001, .5R: -nan, .75R: -nan, count: 0
Region 82 Avg IOU: 0.814712, Class: 0.991421, Obj: 0.605646, No Obj: 0.001831, .5R: 1.000000, .75R: 1.000000, count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000002, .5R: -nan, .75R: -nan, count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000001, .5R: -nan, .75R: -nan, count: 0
1481: 0.094071, 0.133265 avg loss, 0.000100 rate, 3.951930 seconds, 94784 images
...
可以看到有两种输出参数,下面分别进行说明1。
Region 82 Avg IOU: 0.814712, Class: 0.991421, Obj: 0.605646, No Obj: 0.001831, .5R: 1.000000, .75R: 1.000000, count: 2
Region 94 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000002, .5R: -nan, .75R: -nan, count: 0
Region 106 Avg IOU: -nan, Class: -nan, Obj: -nan, No Obj: 0.000001, .5R: -nan, .75R: -nan, count: 0
这三行代表一个subdivision内的参数,分别代表了三种尺寸anchor的结果,具体含义如下:
参数 | 含义 |
---|---|
Avg IOU | 该subdivision内,bounding box与ground truth的平均IOU |
Class | 物体分类的正确率,期望其趋于1 |
Obj | 期望其趋于1 |
No Obj | 期望其趋于0 |
.5R | IOU=0.5时的recall |
.75R | IOU=0.75时的recall |
count | 该subdivision内,正样本(即检测到正确物体)的个数 |
注意,一个subdivision训练的图片数量,等于batch / subdivisions
。
1481: 0.094071, 0.133265 avg loss, 0.000100 rate, 3.951930 seconds, 94784 images
这一行表示一次迭代(batch个图片)的训练输出参数,具体含义如下:
参数 | 含义 |
---|---|
1481 | 当前迭代次数 |
0.094071 | 总体Loss[存疑] |
0.133265 avg loss | 平均Loss,判断模型效果的重要指标 |
0.000100 rate | 当前学习率 |
3.951930 seconds | 本次迭代到目前所用的时长 |
94784 images | 所有迭代中,训练过的图片总量 |
输出的权重文件保存在backup/
目录下。
每1000次迭代自动保存一次,每100次迭代自动更新backup/yolo-obj_last.weights
文件。
使用验证集查看模型mAP,precision,recall,F1,命令如下:
假设训练好的模型权重文件为backup/
目录下的yolo-obj_final.weights
,则执行:
./darknet detector map data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_final.weights
输出格式如下:
detections_count = 744, unique_truth_count = 712
class_id = 0, name = apple, ap = 100.00 %
class_id = 1, name = orange, ap = 99.97 %
for thresh = 0.25, precision = 1.00, recall = 1.00, F1-score = 1.00
for thresh = 0.25, TP = 712, FP = 1, FN = 0, average IoU = 91.33 %
IoU threshold = 50 %
mean average precision ([email protected]) = 0.999841, or 99.98 %
假设图片路径为data/p1.jpg
,则执行:
./darknet detector test data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_final.weights data/p1.jpg
检测结果为darknet根目录下的predictions.jpg
。
假设视频路径为data/video.avi
,则执行:
./darknet detector demo data/obj.data cfg/yolo-obj.cfg backup/yolo-obj_final.weights data/video.avi
cfg文件参数及训练输出参数参考自:Yolov3参数理解 ↩︎ ↩︎
burn_in参数参考自:darknet-配置参数burn-in ↩︎
policy参数参考自:学习率改变策略 ↩︎
ignore_thresh参数参考自:论文 - YOLO v3
这篇对YOLOv3的讲解很详细,建议想深入了解的同学阅读一下。 ↩︎