零基础入门darknet-YOLO3或YOLOv3-Tiny模型训练

前言:有兴趣的可以先查看官网主页。接下来从零开始实现自己的一个简单demo:自动识别库里和杜兰特,从而入门darknet-YOLO3世界。总体来说,分为如下步骤: 数据集构建,训练模型,测试模型,评估模型。

一. 数据集构建

1. 收集图片与编号

这里的图片是从网上下载库里和杜兰特的图片。为了规划数据,减少出错的可能性,先给自己的图片编一个合理的序号,比如0001~0999。由于时间原因,只下载了68张图片,当然,这些数据对于训练一个很好的模型是远远不够的。

2. 标注数据

windows下labelImg标注工具使用介绍

做完图片标签的文件夹是这样的:

3. 利用voc制作自己的数据集

在目录下新建VOC2007,并在VOC2007下新建Annotations,ImageSets和JPEGImages三个文件夹。在ImageSets下新建Main文件夹。文件目录如下所示:
image
将自己的数据集图片拷贝到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()

生成后的目录结构如下所示:

image

二. 训练模型

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):

image

编译代码:

cd darknet
vim Makefile 
make

编译成功后,可以先下载预训练模型测试一下效果。

wget https://pjreddie.com/media/files/yolov3.weights
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

可以看到YOLO的detection结果。到这里,YOLOV3已经走通,是时候加入自己的数据开始训练了。

2. 加入自己的数据集

在代码darknet目录下新建khadas_ai文件夹(方便以后管理整个工程),进入此目录再新建VOCdevkit文件夹,然后把之前制作的VOC2007文件夹拷贝到VOCdevkit文件夹下。

image

YOLOV3的label标注的一行五个数分别代表类别(从 0 开始编号), BoundingBox 中心 X 坐标,中心 Y 坐标,宽,高。这些坐标都是 0~1 的相对坐标。和我们之前标注的label不同,因此我们需要下面的py文件帮我们转换label。

cd khadas_ai/
wget https://pjreddie.com/media/files/voc_label.py

image

这里需要修改两个地方,sets和classes,classes根据自己需要修改。

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。

image

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为例:

image

修改完后,拷贝yolov3-khadas_ai.cfg_train文件并重命名为yolov3-khadas_ai.cfg_test并作如下修改,用于测试模型使用。


其中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

训练一个晚上后:

每迭代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

  • khadas_ai/yolov3-khadas_ai.cfg_test:为测试的配置文件,只需要复制cfg/yolov3-KD.cfg_train的内容然后把batch和subdivisions 设置为1即可。
  • khadas_ai/yolov3-khadas_ai_last.weights:为模型权重。
  • khadas_ai/test.jpg:为测试图片的路径。
  • -thresh 0.5 设置阈值,例如0.1,如果没有标注框就设置低点,如果很低都还没有标注框,那可能是某个环节出问题了,再仔细检查一下每个步骤。

四. 评估模型

请参考此文档Darknet 评估训练好的网络的性能

补充:YOLOv3-Tiny

或许对于速度要求比较高的项目,YOLOV3-tiny才是我们的首要选择,这个网络的原理就是在YOLOv3的基础上去掉了一些特征层,只保留了2个独立预测分支,具体的结构图对比如下:

训练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

4 Likes