2019独角兽企业重金招聘Python工程师标准>>>
1、环境准备
Darknet官网:https://pjreddie.com/darknet/yolo/
GitHub地址:https://github.com/pjreddie/darknet
Windows版本可参考:https://github.com/AlexeyAB/darknet
参照官网流程:下载源码,编译,下载基于voc或者coco数据集已训练好的权重文件,进行目标检测测试。
一切顺利的话,则可以准备自己的数据集进行训练了。
2、准备数据
准备好训练图片(以武器图片识别为例),参考VOC Data数据集格式,样本统一采用jpg格式的图像,名字上也使用像VOC一样类似000001.jpg、000002.jpg的格式命名。
按VOC数据集的结构放置图像文件。VOC的结构如下:
--VOC
--Annotations
--ImageSets
--Main
--Layout
--Segmentation
--JPEGImages
--SegmentationClass
--SegmentationObject
这里面用到的文件夹是Annotations、ImageSets和JPEGImages。其中文件夹Annotations中主要存放xml文件,每一个xml对应一张图像,并且每个xml中存放的是标记的各个目标的位置和类别信息,命名通常与对应的原始图像一样;而ImageSets我们只需要用到Main文件夹,这里面存放的是一些文本文件,通常为train.txt、test.txt等,该文本文件里面的内容是需要用来训练或测试的图像的名字(无后缀无路径);JPEGImages文件夹中放我们已按统一规则命名好的原始图像。
1.新建文件夹WeaponData
2.在WeaponData文件夹下新建三个文件夹Annotations、ImageSets和JPEGImages,并把准备好的自己的原始图像放在JPEGImages文件夹下
3.在ImageSets文件夹中,新建三个空文件夹Layout、Main、Segmentation,然后把写了训练或测试的图像的名字的文本拷到Main文件夹下,按训练(train)、验证(val)、测试(test)的目的命名(见后文)。
3、标注数据集
在获取到大量数据之后,为了实现目标检测,还需要对图片进行物体类别和位置的标注。Darknet使用xml文件格式来存储标注的物体坐标位置,训练自己的数据可以参考Pascal VOC Data数据集的文件夹以及文件组成结构创建相应的label文件。标注图片相关工具有很多,这里以labelImg为例,操作如下图:
标注完成后,在Annotation文件夹下便会生成所有图片的物体标注信息,每张图片对应一个xml文件。最后生成的文件如下:
其中每个xml文件中包含了图片的大小,所标注物体的类别及坐标位置。
4、准备训练
1、将所有样本按一定比例分为训练集、测试集、验证集三部分,比如按训练集、测试集、验证集的比例3:1:1分布,分别生成三个文件train.txt、val.txt、test.txt:
可以使用自己熟悉的语言写生成生成,文件中每一行就是一个文件名,不含扩展名,如下图所示:
2、将WeaponData文件夹、Darknet源码上传到服务器上(如果一开始就在服务器上做则省略),比如放到 /opt/dev/yolo 文件夹下,其中 /opt/dev/yolo/darknet为源码。
3、 在/opt/dev/yolo文件夹中新建文件夹VOCdevkit,再将前面准备好的整个WeaponData文件夹都拷到VOCdevkit文件夹下,并重命名为VOC2018(如果不重命名的话就需要修改voc_label.py脚本中相应位置来匹配文件夹名称)。
mkdir VOCdevkit
mv WeaponData VOCdevkit/VOC2018
4、 下载voc_label.py文件到/opt/dev/yolo下:
cd /opt/dev/yolo
wget https://pjreddie.com/media/files/voc_label.py
并修改voc_label.py中的sets和classes部分:
最后运行该脚本:
python voc_label.py
完成后便会在文件夹/opt/dev/yolo/VOCdevkit/WeaponData下生成了文件夹lables, 文件夹里面包含了类别和对应归一化后的位置,同时在/opt/dev/yolo/下应该也生成了2018_train.txt、2018_test.txt、2018_val.txt三个文件,里面包含了所有样本的绝对路径。
再执行如下命令,将2018_train.txt和2018_val.txt的内容都用于训练:
cat 2018_train.txt 2018_val.txt > train.txt
5、配置文件修改
1、修改/opt/dev/yolo/darknet/data/voc.names,改为需要识别的目标类别:
aeroplane
person
building
ship
vehicle
2、 修改cfg/voc.data
classes= 5
train = /opt/dev/yolo/train.txt
valid = /opt/dev/yolo/2018_test.txt
names = /opt/dev/yolo/darknet/data/voc.names
backup = /opt/dev/yolo/results
其中classes为样本类别数, train 为训练样本的文件路径,valid为验证样本文件路径,names为类别文件,backup为权重文件备份目录(先创建好)。
3、 修改cfg/yolo-voc.2.0.cfg (也可以用 cfg/yolo-voc.cfg )
修改最后一个卷基层的filters和最后一个region的classes。
其中,filters=num×(classes + coords + 1)=5*(5+4+1)=50,这里只有5个类别。
[convolutional]
size=1
stride=1
pad=1
filters=50
activation=linear
[region]
anchors = 1.08,1.19, 3.42,4.41, 6.63,11.38, 9.42,5.11, 16.62,10.52
bias_match=1
classes=5
coords=4
num=5
softmax=1
jitter=.2
rescore=1
……
6、修改 Makefile 文件
训练最好使用GPU,否则CPU非常慢,源码默认没有开启,一开始没有注意被坑了很久。
安装 cuda+cudnn 参考:https://www.cnblogs.com/573177885qq/p/6632576.html
然后修改Makefile文件:
cd /opt/dev/yolo/darknet
vim Makefile
修改顶部的三行开启GPU和CUDNN:
GPU=1
CUDNN=1
OPENCV=1
以及后面的NVCC为自己的路径:
NVCC=/usr/local/cuda-8.0/bin/nvcc
重新编译:
make clean
make
7、开始训练
可以下载 ImageNet 的前23层预训练权重文件加快训练:
cd /opt/dev/yolo/darknet
wget https://pjreddie.com/media/files/darknet19_448.conv.23
然后执行如下命令开始训练:
./darknet detector train cfg/voc.data cfg/yolo-voc.2.0.cfg ./darknet19_448.conv.23
如果需要分析输出日志的话,可以在命令后面使用tee将日志输出到文件。
训练时间比较长,可以观察loss,如果稳定到一定程度,则可以停止训练。
下面是训练过程的每一轮迭代输出例子:
Loaded: 0.000031 seconds
Region Avg IOU: 0.805040, Class: 0.929115, Obj: 0.777778, No Obj: 0.004146, Avg Recall: 0.875000, count: 8
Region Avg IOU: 0.826887, Class: 0.999643, Obj: 0.778379, No Obj: 0.006632, Avg Recall: 0.916667, count: 12
Region Avg IOU: 0.760517, Class: 0.999070, Obj: 0.698473, No Obj: 0.004795, Avg Recall: 0.846154, count: 13
Region Avg IOU: 0.840628, Class: 0.999687, Obj: 0.805357, No Obj: 0.005085, Avg Recall: 0.900000, count: 10
Region Avg IOU: 0.670166, Class: 0.944164, Obj: 0.620956, No Obj: 0.004349, Avg Recall: 0.777778, count: 18
Region Avg IOU: 0.849498, Class: 0.999253, Obj: 0.743897, No Obj: 0.006114, Avg Recall: 0.933333, count: 15
Region Avg IOU: 0.625192, Class: 0.957918, Obj: 0.562712, No Obj: 0.005363, Avg Recall: 0.550000, count: 20
Region Avg IOU: 0.711634, Class: 0.999687, Obj: 0.687795, No Obj: 0.006114, Avg Recall: 0.941176, count: 17
29391: 1.344486, 1.478107 avg, 0.000100 rate, 4.674087 seconds, 1881024 images
以上截图显示了所有训练图片的一个批次(batch),批次大小的划分根据我们在 .cfg 文件中设置的subdivisions参数。在我使用的 .cfg 文件中 batch = 64 ,subdivision = 8,所以在训练输出中,训练迭代包含了8组,每组又包含了8张图片,跟设定的batch和subdivision的值一致。
(注: 也就是说每轮迭代会从所有训练集里随机抽取 batch = 64 个样本参与训练,所有这些 batch 个样本又被均分为 subdivision = 8 次送入网络参与训练,以减轻内存占用的压力)
针对上图中最后一行中的信息 ,含义如下:
- 29391: 指示当前训练的迭代次数
- 1.344486: 是总体的Loss(损失)
- 1.478107 avg: 是平均Loss,这个数值应该越低越好,一般来说,一旦这个数值低于0.060730 avg就可以终止训练了(由于我的样本质量不太好,这里值一直降不下去)。
- 0.000100 rate: 代表当前的学习率,是在.cfg文件中定义的。
- 4.674087 seconds: 表示当前批次训练花费的总时间。
- 1881024 images: 表示到目前为止,参与训练的图片的总量。
8、测试
训练到一定阶段,中间输出权重可以拿来做识别测试,比如将10000次迭代的文件用于测试:
./darknet detector test cfg/voc.data cfg/yolo-voc.2.0.cfg yolo-voc_10000.weights data/person.jpg
这里需要注意的是,一定要使用./darknet detector test命令,指定自己的 voc.data和cfg文件。
检测结果会输出到predictions.png(或者predictions.jpg)中,可打开查看是否检测正确。