Darknet yolov3-tiny 训练自己的数据集步骤

        最近项目需要要进行yolov3-tiny训练自己的数据,参考了一些网上的方法和自己以前做faster-rcnn的经验,总结了自己步骤,以供学习。本文前提是已经编译过opencv源码,安装好cuda和cudnn等,我的博客中有编译和安装参考。

        Darknet github地址:https://github.com/pjreddie/darknet

1、源码准备和编译

下载darknet源码,修改Makefile,将opencv、cuda和cudnn的值均改为1

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

修改Makefile的前几行如下:

GPU=1
CUDNN=1
OPENCV=1

编译darknet:

make

至此,已经可以利用darknet检测,下载yolov3-tiny的预训练模型可以进行测试

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

得到的结果如下:
在这里插入图片描述

2、准备自己的数据

(1)为了最小除程度减少代码的改写,在darknet主目录建立文件下如下:

---VOCdevkit
	---VOC2007
		---Annotations
		---ImageSets
			---Main
		---JPEGImages

其中Annotations存放xml文件,JPEGImages存放对应的图片文件,此外ImageSets中Main函数是为了方便后续步骤中得到训练和测试图片的索引号

(2)图片打标签,并将自己打标好的xml文件和图片重新命名

这里我按照自己的命名规则得到,参考我另一篇博客(以jpg格式图片为例,其他格式需要简单修改代码):https://blog.csdn.net/zhou4411781/article/details/100929972

重命名后得到的xml文件如下:
在这里插入图片描述

(3)将命名好的图片和文件放到/VOCdevkit/VOC2007文件夹下的对应位置,并利用代码提取每个图片的索引号,提取代码位于VOC2007文件下,运行get_voc_2007_main.py即可得到,其中get_voc_2007_main.py的内容如下:

import os
import random

trainval_percent = 0.66  #可以自己修改
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:
            ftrain.write(name)
        else:
            fval.write(name)
    else:
        ftest.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

(4)利用/script中的voc_label.py生成训练和测试的文件路径,需要修改自己的训练类别(这里以3类为例),这里我只用了一个文件,故代码还去掉了与2012数据集相关的代码:

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 = ["box", "pen", "laptop"]


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

在darknet主目录可以得到:2007_test.txt、2007_train.txt、2007_val.txt、train.txt、 train.all.txt,我们暂时先用到 train.txt和 2007_test.txt,主要是图片的存放路径,txt内容如下:

在这里插入图片描述

在/VOCdevkit/VOC2007 中还生成了一个labels文件夹,主要记录每张图片的打标签的bouding box位置,labels文件如下:

在这里插入图片描述

(5)修改cfg/voc.data

classes= 3
train  = /home/yasin/darknet/train.txt
valid  = /home/yasin/darknet/2007_test.txt
names = data/voc.names
backup = backup

(6)修改cfg/yolov3-tiny.cfg

将如下的Training参数打开,关闭Testing参数

[net]
#Testing
#batch=1
#subdivisions=1
#Training
batch=64
subdivisions=16

找到如下位置(以yolo为关键字),修改filters和classes,整个文本共有2个filters和2个classes需要修改

[convolutional]
size=1
stride=1
pad=1
filters=24  #### 改为3*(classes +5)
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

(7)修改data/voc.names,修改为自己的类别

box
pen
laptop

3、训练模型

./darknet partial ./cfg/yolov3-tiny.cfg ./yolov3-tiny.weights ./yolov3-tiny.conv.15 15
sudo ./darknet detector train cfg/voc.data cfg/yolov3-tiny.cfg yolov3-tiny.conv.15

(参考:darknet - Tiny YOLOv3 test and training (测试 and 训练))

可能问题CUDA Error: out of memory darknet: ./src/cuda.c:36: check_error: Assertio `0’ failed.

解决方法:需要将yolov3-tiny.cfg中的由subdivisions改大。
subdivision:这个参数很有意思的,它会让你的每一个batch不是一下子都丢到网络里。而是分成subdivision对应数字的份数,一份一份的跑完后,在一起打包算作完成一次iteration。这样会降低对显存的占用情况。如果设置这个参数为1的话就是一次性把所有batch的图片都丢到网络里,如果为2的话就是一次丢一半。(windows下训练yolo时出现CUDA Error: out of memory问题的解决:https://blog.csdn.net/qq_33485434/article/details/80432054)

训练过程中的参数含义如下(https://blog.csdn.net/lilai619/article/details/79695109):

Avg IOU:   当前迭代中,预测的box与标注的box的平均交并比,越大越好,期望数值为1;

Class:     标注物体的分类准确率,越大越好,期望数值为1;

obj:       越大越好,期望数值为1;

No obj:    越小越好;

.5R:       以IOU=0.5为阈值时候的recall; recall = 检出的正样本/实际的正样本

0.75R:     以IOU=0.75为阈值时候的recall;

count:     正样本数目。

4、模型测试

训练得到的模型文件位于/backup文件中,源码中(examples/detector.c)当迭代小于1000时每隔100次保存一次模型,当大于1000时每10000次迭代保存一次模型,可以自行修改保存规则。

以10000迭代得到的模型为例测试:

./darknet detector test cfg/voc.data cfg/yolov3-tiny.cfg backup/yolov3-tiny_10000.weights VOCdevkit/VOC2007/JPEGImages/000022.jpg

测试结果如下:

在这里插入图片描述

发布了64 篇原创文章 · 获赞 92 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/zhou4411781/article/details/105112058
今日推荐