前言:有兴趣的可以先查看官网主页。接下来从零开始实现自己的一个简单demo:自动识别库里和杜兰特,从而入门darknet-YOLO3世界。总体来说,分为如下步骤: 数据集构建,训练模型,测试模型,评估模型。
1. 收集图片与编号
这里的图片是从网上下载库里和杜兰特的图片。为了规划数据,减少出错的可能性,先给自己的图片编一个合理的序号,比如0001~0999。由于时间原因,只下载了68张图片,当然,这些数据对于训练一个很好的模型是远远不够的。
2. 标注数据
windows下labelImg标注工具使用介绍
做完图片标签的文件夹是这样的:
image3134×989 984 KB
3. 利用voc制作自己的数据集
在目录下新建VOC2007,并在VOC2007下新建Annotations,ImageSets和JPEGImages三个文件夹。在ImageSets下新建Main文件夹。文件目录如下所示:
将自己的数据集图片拷贝到JPEGImages目录下。将数据集label的xml文件拷贝到Annotations目录下。在VOC2007下新建test.py文件夹,将下面代码拷贝进去运行,将生成四个文件:train.txt,val.txt,test.txt和trainval.txt。
import os
import random
trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)
ftrainval = open('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/val.txt', 'w')
for i in list:
name = total_xml[i][:-4] + '\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftest.write(name)
else:
fval.write(name)
else:
ftrain.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
生成后的目录结构如下所示:
二. 训练模型
1. 下载与安装darknet框架
下载AlexeyAB大神的darknet代码
git clone https://github.com/AlexeyAB/darknet.git
YOLOV3使用一个开源的神经网络框架Darknet53,使用C和CUDA,有CPU和GPU两种模式。不建议使用CPU模式训练,否则会慢得要死。代码默认使用的是CPU模式,要切换成GPU模型,修改Makefile文件。
GPU模式Makefile文件配置(需要另外安装cuda,cudnn,opencv):
编译代码:
cd darknet
vim Makefile
make
编译成功后,可以先下载预训练模型测试一下效果。
wget https://pjreddie.com/media/files/yolov3.weights
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
image857×167 6.29 KB
可以看到YOLO的detection结果。到这里,YOLOV3已经走通,是时候加入自己的数据开始训练了。
2. 加入自己的数据集
在代码darknet目录下新建khadas_ai文件夹(方便以后管理整个工程),进入此目录再新建VOCdevkit文件夹,然后把之前制作的VOC2007文件夹拷贝到VOCdevkit文件夹下。
YOLOV3的label标注的一行五个数分别代表类别(从 0 开始编号), BoundingBox 中心 X 坐标,中心 Y 坐标,宽,高。这些坐标都是 0~1 的相对坐标。和我们之前标注的label不同,因此我们需要下面的py文件帮我们转换label。
cd khadas_ai/
wget https://pjreddie.com/media/files/voc_label.py
这里需要修改两个地方,sets和classes,classes根据自己需要修改。
image1211×359 15.3 KB
cd khadas_ai/
python voc_label.py
cat 2007_train.txt 2007_val.txt > train.txt
运行该文件,khadas_ai目录下会生成三个txt文件2007_train.txt,2007_val.txt,2007_test.txt,VOCdevkit下的VOC2007目录也会多生成一个labels文件夹,点开目录txt文件看已经转化成YOLOV3需要的格式了。此时自己的数据集正式完成。
3. 创建*.names file
其中保存的是你的所有的类别,每行一个类别,如data/coco.names,khadas_ai/khadas_ai.names。
4. 创建*.data file
其中保存的是很多配置信息,如 data/coco.data,khadas_ai/khadas_ai.names。
classes= 2 #修改成自己训练的种类数
train = khadas_ai/train.txt #修改成自己train.txt的路径
valid = khadas_ai/2007_test.txt #评估测试的图片的路径,用于后面的评估测试
names = khadas_ai/khadas_ai.names #修改成自己的类别名的路径
backup = khadas_ai/ #训练的权重所存放的路径
results = results #评估测试结果存放路径,也可以自己定义
eval = coco #选择map计算方式
5. 修改cfg文件
拷贝cfg文件夹下的yolov3.cfg文件到khadas_ai目录并重命名为yolov3-khadas_ai.cfg_train,然后做几处修改即可:
搜 yolo, 总共会搜出3个含有yolo的地方。
每个地方都必须要改2处, filters:3*(5+len(classes));
其中:classes: len(classes) = 2,这里以我们的demo为例:
修改完后,拷贝yolov3-khadas_ai.cfg_train文件并重命名为yolov3-khadas_ai.cfg_test并作如下修改,用于测试模型使用。
image1524×330 32.1 KB
其中subdivision:这个参数很有意思的,它会让你的每一个batch不是一下子都丢到网络里。而是分成subdivision对应数字的份数,一份一份的跑完后,在一起打包算作完成一次迭代。这样会降低对显存的占用情况。如果设置这个参数为1的话就是一次性把所有batch的图片都丢到网络里,如果为2的话就是一次丢一半。
6. 开始训练
如果读者按照步骤已经耐心的到这里,可以舒一口气,离成功只差一步了。
下载darknet53的预训练模型。
cd darknet
wget https://pjreddie.com/media/files/darknet53.conv.74
./darknet detector train khadas_ai/khadas_ai.data khadas_ai/yolov3-khadas_ai.cfg_train darknet53.conv.74 -dont_show
训练一个晚上后:
image512×603 26.5 KB
image3381×199 24.2 KB
每迭代10000次就会在khadas_ai文件夹上生成一个模型权重。
18797: 0.012223, 0.013508 avg loss, 0.001000 rate, 4.101127 seconds, 1203008 images, 362.918440 hours left
#### 输出参数说明:
18797: 指示当前训练的迭代次数
0.012223: 是总体的Loss(损失)
0.013508 avg loss: 是平均Loss,这个数值应该越低越好,一般来说,一旦这个数值低于0.060730 avg就可以终止训练了。
0.0001000 rate: 代表当前的学习率,是在.cfg文件中定义的。
4.101127 seconds: 表示当前批次训练花费的总时间。
1203008 images: 这一行最后的这个数值是75188*16的大小,表示到目前为止,参与训练的图片的总量。
将待测试图片放到khadas_ai/test.jpg,然后运行:
./darknet detector test khadas_ai/voc.data khadas_ai/yolov3-khadas_ai.cfg_test khadas_ai/yolov3-khadas_ai_last.weights khadas_ai/test.jpg -thresh 0.5
image997×124 5.47 KB
请参考此文档Darknet 评估训练好的网络的性能
或许对于速度要求比较高的项目,YOLOV3-tiny才是我们的首要选择,这个网络的原理就是在YOLOv3的基础上去掉了一些特征层,只保留了2个独立预测分支,具体的结构图对比如下:
image1510×1384 233 KB
image912×1835 179 KB
训练yolov3-tiny和yolov3过程差不多一样。具体过程如下:
1,先是获得训练好的yolov3-tiny的权重用来test:
wget https://pjreddie.com/media/files/yolov3-tiny.weights
2,然后获得卷积层的权重用来训练自己的数据:
./darknet partial cfg/yolov3-tiny.cfg yolov3-tiny.weights yolov3-tiny.conv.15 15
3,开始训练
./darknet detector train khadas_ai/khadas_ai.data khadas_ai/yolov3-khadas_ai_tiny.cfg_train yolov3-tiny.conv.15 -dont_show
其中yolov3-khadas_ai_tiny.cfg_train文件从拷贝cfg文件夹下的yolov3-tiny.cfg文件而来,然后修改参数方法与yolov3一样。
4,测试训练
./darknet detector test khadas_ai/khadas_ai.data khadas_ai/yolov3-khadas_ai_tiny.cfg_test khadas_ai/yolov3-khadas_ai_tiny_last.weights khadas_ai/test.jpg -thresh 0.1
其中yolov3-khadas_ai_tiny.cfg_test 文件从拷贝yolov3-khadas_ai_tiny.cfg_train文件而来,然后修改参数方法与yolov3一样。
后记:文章所用到的图片与脚本都放在此代码库khadas_ai分支上:
git clone https://github.com/khadas/khadas_android_npu_library -b khadas_ai
image881×71 5.71 KB