Ubuntu16+GPU环境训练yolov3-tiny

参考链接:https://www.cnblogs.com/xieqi/p/9818056.html

参考链接:https://www.cnblogs.com/shuiyj/p/13185303.html

 参考链接:YOLOV3中Darknet中cfg文件说明和理解:https://www.cnblogs.com/hls91/p/10911997.html

 

辛辛苦苦搭载好GPU环境,环境搭载参考这个

现在要开始测试下效果

参考链接:https://pjreddie.com/darknet/yolo/

一,测试

(1),如果尚未安装Darknet,则应先进行安装

git clone https://github.com/pjreddie/darknet
cd darknet
make

您已经在cfg/子目录中拥有YOLO的配置文件您将必须在此处下载预训练重量文件(237 MB)或只是运行此:

wget https://pjreddie.com/media/files/yolov3.weights

然后运行检测器!

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg

你将看到以下输出:

layer     filters    size              input                output
    0 conv     32  3 x 3 / 1   416 x 416 x   3   ->   416 x 416 x  32  0.299 BFLOPs
    1 conv     64  3 x 3 / 2   416 x 416 x  32   ->   208 x 208 x  64  1.595 BFLOPs
    .......
  105 conv    255  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 255  0.353 BFLOPs
  106 detection
truth_thresh: Using default '1.000000'
Loading weights from yolov3.weights...Done!
data/dog.jpg: Predicted in 0.029329 seconds.
dog: 99%
truck: 93%
bicycle: 99%

这说明没有问题。

 

(2)更改检测阈值

默认情况下,YOLO仅显示置信度为.25或更高的对象。您可以通过将-thresh <val>标志传递yolo命令来更改此设置例如,要显示所有检测,可以将阈值设置为0:

./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg -thresh 0

(3) 训练YOLO VOC

要培训YOLO,您需要2007年至2012年的所有VOC数据。(如果你和我一样用自己的数据训练yolo,则不需要下面这一步)

要获取所有数据,请创建一个目录以存储所有数据,然后从该目录运行:

wget https://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar
wget https://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar
wget https://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar
tar xf VOCtrainval_11-May-2012.tar
tar xf VOCtrainval_06-Nov-2007.tar
tar xf VOCtest_06-Nov-2007.tar

现在将有一个VOCdevkit/子目录,其中包含所有VOC培训数据。

生成VOC标签

现在我们需要生成Darknet使用的标签文件。Darknet希望.txt为每个图像提供一个文件,并在图像中为每个地面真实对象添加一行,如下所示:

<object-class> <x> <y> <width> <height>

 

下载预训练的卷积权重(用自己的数据训练则可以不需要这一步)

为了进行训练,我们使用在Imagenet上预先训练的卷积权重。我们使用darknet53模型的权重您可以在此处下载卷积层的权重(76 MB)。也可以自行选择其他权重文件。

wget https://pjreddie.com/media/files/darknet53.conv.74

训练模型

现在我们可以训练!运行命令(官方指导文件中命令):

./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74

 这上面基本上都是参考链接中有的,我把要用到的重要步骤给翻译整理了一下。

 

二,训练自己的数据

(1),标注图像

在标注前可以使用脚本对图像进行重命名,参考链接:https://www.cnblogs.com/gezhuangzhuang/p/10539792.html

推荐使用labelimg工具进行标注,参考我的博文链接:https://www.cnblogs.com/vincent212212/p/13262109.html

(2),制作数据集

我们可以仿照VOCdevkit的格式存储我们标注的xml文件和图像。

例如,建立traindata数据集文件夹,将VOCdevkit复制到traindata下,并且在traindata文件夹下添加voc_label.py脚本,参考如下:(你可以修改为自己的classes)

import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]

classes = ["corner","tcorner","crosscorner"]


def convert(size, box):
    dw = 1./(size[0])
    dh = 1./(size[1])
    x = (box[0] + box[1])/2.0 - 1
    y = (box[2] + box[3])/2.0 - 1
    w = box[1] - box[0]
    h = box[3] - box[2]
    x = x*dw
    w = w*dw
    y = y*dh
    h = h*dh
    return (x,y,w,h)

def convert_annotation(year, image_id):
    in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
    out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')
    tree=ET.parse(in_file)
    root = tree.getroot()
    size = root.find('size')
    w = int(size.find('width').text)
    h = int(size.find('height').text)

    for obj in root.iter('object'):
        difficult = obj.find('difficult').text
        cls = obj.find('name').text
        if cls not in classes or int(difficult)==1:
            continue
        cls_id = classes.index(cls)
        xmlbox = obj.find('bndbox')
        b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))
        bb = convert((w,h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')

wd = getcwd()

for year, image_set in sets:
    if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):
        os.makedirs('VOCdevkit/VOC%s/labels/'%(year))
    image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
    list_file = open('%s_%s.txt'%(year, image_set), 'w')
    for image_id in image_ids:
        list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
        convert_annotation(year, image_id)
    list_file.close()

os.system("cat 2007_train.txt 2007_val.txt > train.txt") 
os.system("cat 2007_train.txt 2007_val.txt 2007_test.txt > train.all.txt")

在VOCdevkit中建立VOC2007中添加test.py脚本,内容如下,仅供参考(你可以修改分配比例和文件路径)

import os
import random

trainval_percent = 0.3
train_percent = 0.7
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()

将自己标注的xml文件放到Annotations文件夹下,将图像放到JPEGImages文件夹下。

1,cd到VOC2007下,运行test.py

先运行这个脚本将Annotations里的xml文件随机的分发到对应文件夹里,分发到比例是可以改的。

2,然后cd到traindata下,运行voc_label.py

这几个py文件都比较好理解,可以稍微看一下代码

运行完之后会得到2007_train.txt,2007_test.txt等txt文件。

3,修改Cfg以获取Pascal数据,(不要在windows环境中修改)

在cfg文件夹中的voc.data中,下面以我的路径举例

  1 classes= 3
  2 train  = /home/.../mydarknet/darknet/traindata/train.txt
  3 valid  =/home/.../mydarknet/darknet/traindata/2007_test.txt 
4 names =/home/.../mydarknet/darknet/traindata/voc.names
5 backup =/home/.../mydarknet/darknetbackup

 4,修改cfg文件夹下的voc.names文件,(不要在windows环境中修改)

修改为自己分类的class名字。

比如,我这里改为:

corner
tcorner
crosscorner

5,修改cfg文件夹下的yolov3-tiny.cfg文件,如下是我的cfg文件,供大家参考(不要在windows环境中修改)

[net]
# Testing
#batch=1
#subdivisions=1
# Training
batch=32
subdivisions=2

width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
tee result/log/training.log
learning_rate=0.001
burn_in=1000
max_batches = 240000 # 5200000
policy=steps
steps=400000,450000
scales=.1,.1

[convolutional]
batch_normalize=1
filters=16
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=2

[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky

[maxpool]
size=2
stride=1

[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky

###########

[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky

[convolutional]
size=1
stride=1
pad=1
filters=24 # (class+5)*3
activation=linear



[yolo]
mask = 3,4,5
anchors = 10,14,  23,27,  37,58,  81,82,  135,169,  344,319
classes=3
num=6
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

[route]
layers = -4

[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky

[upsample]
stride=2

[route]
layers = -1, 8

[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky

[convolutional]
size=1
stride=1
pad=1
filters=24 # (class+5)*3
activation=linear

[yolo]
mask = 0,1,2
anchors = 10,14,  23,27,  37,58,  81,82,  135,169,  344,319
classes= 3 
num=6
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

几点注意:

1,训练时注销掉testing(前面添加#),同理测试时注销掉training

# Testing
#batch=1
#subdivisions=1

2,yolotiny训练过程中有两个输出层,要将输出层之前的卷积滤波修改为自己合适的,例如

filters=24 # (class+5)*3

3,在两个输出层中要把class改成合适自己的,例如,我的训练分为三类,我就改为了3

 

(3),开始训练

训练指令:./darknet detector train <data_cfg> <model_cfg> <weights> -gpus <gpu_list> 

我的训练命令如下,(文件路径可修改为自己的)

./darknet detector train mycfg/voc.data mycfg/yolov3-tiny.cfg yolov3-tiny.conv.15



如果需要生成loss-iter曲线,在执行训练命令的时候加一下管道,tee一下log:命令如下:
./darknet detector train mycfg/voc.data mycfg/yolov3-tiny.cfg yolov3-tiny.conv.15 | tee result/log/training.log

生成的training文件需要绘制曲线的话,可以参考此链接的脚本:https://blog.csdn.net/qq_34806812/article/details/81459982

3,补充注意事项

 1,在mycfg中的yolov3-tiny.cfg文件中,可以修改训练参数。

比如中的max_batches = 250000,表示最大训练步数,可以自己修改。

还可以把training下面的batch改小一点,以免报错,我这里batch=32.

2,训练中,在mycfg中的yolov3-tiny.cfg文件中,testing下面的batch和subdivisions前面要加#号注释掉。training下面的两项要保留。

测试时,在mycfg中的yolov3-tiny.cfg文件中,training下面的batch和subdivisions前面要加#号注释掉。testing下面的两项要保留。

3,在不同的环境下,还要更改darknet中的makefile文件配置,例如,用的GPU训练,可以参考如下配置。

makefile中的配置如下。

GPU=1

CUDNN=1

OPENCV=1

OPENMP=1

DEBUG=0

4,如果在训练中出现无法找到训练文件的情况,Couldn't open file: train.txt

很有可能是你的文件格式不对,很可能是因为你在windows环境下修改了这些文件。

请检查生成的几个txt文件的格式,检查方法参考链接:https://liumin.blog.csdn.net/article/details/99687482

如果txt文件没问题,请检查voc.data,cfg等文件内容格式是否有问题。

 5,训练的过程中,出现部分nan是正常的,但是全部是nan的话,就是你的数据集的问题了。

6,训练过程中,什么时候训练的可以了,可以关注avg指标,训练收敛后,一般会降低到0.1一下。

 

不断更新ing

posted @ 2020-06-22 18:22  yk要努力  阅读(567)  评论(0编辑  收藏  举报