png

yolov3 训练自己的数据集

历时6个月,从零开始学习深度学习,第一个小目标是实现物体探测,在经历过多个坑后,今天终于实现了。记录一下过程。

1
   先放最后的测试结果,训练的类型是我和我导师的头像,大约50张图片(训练集+测试集),共两类型Liu 和 Okan.

yolov3 是c语言编写,网上有人已经将之改为pytorch框架下python的,关键是探测算法和cnn神经网络,了解了核心内容后可以根据需要更改为所用框架,用所需语言改写。

1.下载yolov3的工程

1
2
git clone https://github.com/pjreddie/darknet
cd darknet

2.修改配置文件

vi Makefile

1
2
3
GPU = 1 #用GPU进行训练,比cpu快得多,必须更改
CUDNN = 0
OPENCV = 0

保存

1
make

需要提前安装好cuda,cudnn,opencv(为了显示,非必须,版本不要太高)

3.建立数据集(方法一:收集数据,自己手动加标签)

darknet支持VOC和COCO数据集,方法如官网,下面介绍如何建立自己的数据集。

1
2
3
4
5
6
7
8
imgs\
    1.jpg
    2.jpg
    ......
labels\
    1.txt
    2.txt
    ......

数据格式如上: 准备好jpg格式图片,批量改名,批量更改分辨率,大概600像素左右就行,不用太大。 采用labelImg.exe这个工具加上标签即可,得到1.txt的数据文件。 其中1.txt 格式如下:

1
2
3
80 0.91796875 0.1525821 0.1171875 0.211267

类别号 方框中心归一化x 方框中心归一化y 方框宽度归一化 方框高度归一化

重命名bat脚本(windows):

1
2
3
4
5
6
7
    @echo off
    set a=00
    setlocal EnableDelayedExpansion
    for %%n in (*.jpg) do (
    set /A a+=1
    ren "%%n" "p!a!.jpg"
    )

3.建立数据集(方法二:收集图片背景数据,建立目标图片数据(png抠图),将目标图片随机叠加到背景,并自动记录位置标签)

  • 好处是一键生成
  • 详见 makeData.py
  • 同时可以一键生成全部配置文件,即省去以下4,6,7,8步,详见 makeCFG.py

4.生成 train.txt 和 val.txt

其实就是图片的路径,需要根据实际修改(比如添加路径imgs/)。

获得文件名bat脚本(windows)

1
DIR *.jpg  /B >train.txt

5.下载预训练模型

1
wget https://pjreddie.com/media/files/darknet53.conv.74
  • 重点:53指的是卷积层数,74指的是取前74层进行微调,最后几层一般是决定分类数量的,需要更改,因此只导入前数层的权重参数进行训练。

  • 采用partial进行参数自定义抽取 ./darknet partial yolov3.cfg yolov3.weights yolov3.conv.74 74

6.修改cfg/xxx.data

1
2
3
4
5
classes= 2 # 训练样本集的类别总数 
train  = /home/darknet/train.txt #train的路径为训练样本集所在的路径 
valid  = /home/darknet/val.txt #valid的路径为验证样本集所在的路径 
names = data/xxx.names #xxx.names文件所在的路径 
backup = backup

7.修改data/xxx.names

1
2
A
B

类别名称,根据自己需要修改

8.修改cfg/xxx.cfg

  • 如果是训练, batch=64,subdivisions=8,可以根据机器配置适当修改
  • 如果是测试, batch=1,subdivisions=1
  • 共有三处需要修改filters和classes(filters=3*(classes+5))
  • random=0即关闭多尺度训练(机器好不关闭)

cfg文件参数解释

参数 解释
batch 每一次迭代送到网络的图片数量。增大这个可以让网络在较少的迭代次数内完成一个epoch。在固定最大迭代次数的前提下,增加batch会延长训练时间,但会更好的寻找到梯度下降的方向。如果你显存够大,可以适当增大这个值来提高内存利用率。这个值是需要大家不断尝试选取的,过小的话会让训练不够收敛,过大会陷入局部最优。
subdivision 这个参数会让你的每一个batch不是一下子都丢到网络里。而是分成subdivision对应数字的份数,一份一份的跑完后,在一起打包算作完成一次iteration。会降低显存占用。如果设置为1的话就是一次性把所有batch的图片处理,如果为2的话就是一次一半。
angle 图片旋转角度,这个用来增强训练效果的。从本质上来说,就是通过旋转图片来变相的增加训练样本集。
saturation,exposure,hue 饱和度,曝光度,色调,这些都是为了增强训练效果用的。
learning_rate 学习率,训练发散的话可以降低学习率。学习遇到瓶颈,loss不变的话也减低学习率。
max_batches 最大迭代次数,训练自动停止条件。
policy 学习策略,一般都是step这种步进式。
step,scales 这两个是组合一起的,举个例子:learn_rate: 0.001, step:100,25000,35000 scales: 10, .1, .1 这组数据的意思就是在0-100次iteration期间learning rate为原始0.001,在100-25000次iteration期间learning rate为原始的10倍0.01,在25000-35000次iteration期间learning rate为当前值的0.1倍,就是0.001, 在35000到最大iteration期间使用learning rate为当前值的0.1倍,就是0.0001。随着iteration增加,降低学习率可以是模型更有效的学习,也就是更好的降低train loss。

[](test.cfg) [](train.cfg)

*重点*:注意windows和linux文本格式区别,linux下可以用cat xxx.txt 查看是否有^M

9.开始训练

从头训练用darknet53.conv.74,继续训练用训练好的权重参数(xxx_900.weights)

1
./darknet detector train cfg/xxx.data cfg/xxx.cfg darknet53.conv.74

多GPU

1
./darknet detector train cfg/xxx.data cfg/xxx.cfg darknet53.conv.74 -gpus 0,1,2,3

参数 解释
Region xx: cfg文件中yolo-layer的索引;
Avg IOU:    当前迭代中,预测的box与标注的box的平均交并比,越大越好,期望数值为1;
Class:        标注物体的分类准确率,越大越好,期望数值为1;
obj:            越大越好,期望数值为1;
No obj:      越小越好;
.5R:            以IOU=0.5为阈值时候的recall; recall = 检出的正样本/实际的正样本
0.75R:          以IOU=0.75为阈值时候的recall;
count:        正样本数目

*重点*:

  • 训练需要很久,50张图片100个epoch大概半小时
  • 刚开始loss很大,1000多,200个循环后,才勉强有效果,500个后才基本出结果,我训练了900个效果才稍好(loss降为0.3),据说要10000以上才好用(据说有人烧过GPU,慎重训练大数据)。
  • 某些层出现-nan是正常的,表示该卷积层上看不到特征图,往往是特征较小区域,没关系。

  • 当训练过程中需要输出log日志文件时,需要在训练时一起输出,命令:

    ./darknet detector train cfg/tiny-yolo.cfg tiny-yolo_8000.conv.9 2>1 | tee log.txt

  • 训练后测试无结果。原因一是训练发散;二是训练不充分,结果置信概率太低。

      (1)训练发散,看训练的时候迭代次数后边的两个loss值,如果这两个值不收敛就有问题。可以降低learning rate 和 提高batch;

    (2)训练不充分,可在test的时候渐降低 threshold,默认是.25。

12.开始测试

./darknet detector test cfg/xxx.data cfg/xxx.cfg backup/xxx_900.weights data/1.jpg

这样就生成了一开始的图片了predictions.jpg。