Darknet Yolov4创建数据集并使用

介绍机场行李筐智能分拣项目的安装环境之 darknet yolov4

1 前言

使用darknet yolov4是为了检测行李筐。需要已经安装好显卡驱动、CUDA、cuDNN、opencv。环境安装好后,需要制作自己的数据集。

yolov4权重文件:链接: https://pan.baidu.com/s/1VBA_f473r98KKtIOiXqlWw 提取码: m5nk。

2 检测环境安装是否完善

下载yolov4源码:链接: https://pan.baidu.com/s/1eLHbEg06EZXZvX45wgJHGQ 提取码: qghn。

解压后从该文件夹打开Terminal,执行

1
2
3
make clean
make -j8
./darknet detect cfg/yolov4.cfg yolov4.weights data/dog.jpg

执行后输出如下图片,表示安装成功。

01

3 制作自己的数据集

  1. 首先用相机拍一定数量的图片作为数据集,然后用LabelImg软件对图片进行打标签,得到图片所对应的xml文件。

  2. 将darknet源码中的 data 文件夹下的内容删除,并建立下图所示的4个文件夹和一个 sel_train_test.py 空文件。

02

  1. 将原始图片存放在data/images目录下。
  2. 将打标签后得到的xml文件存放在 data/Annotations 目录下。
  3. 在 darknet 目录下新建文件 vocbox.names,并写入自己的标签内容,例如
    1
    2
    gray
    white
  4. 打开第2步新建的 /darknet/data/sel_train_test.py,具体代码内容件附录1。

    该脚本实现的功能是:将训练集和测试集区分开,从原始图片中每10张取一张作为测试集,得到训练集和测试集图片的序号,并分别存放在darknet/data/ImageSets/train.txt和darknet/data/ImageSets/test.txt。

    注意修改脚本中第5~7行保存文件的路径。

  5. 在darknet/data目录下打开Terminal,执行

    1
    python sel_train_test.py
  6. 在darknet目录下新建voc_label.py文件,该文件中的代码见附录2,修改的地方在代码中!!!表示。

    该脚本的目的是将打标签得到的xml文件转为txt文件,并保存在darknet/data/labels文件夹;
    同时获取训练集和测试集图片的完整路径,并保存在darknet/train.txt和darknet/test.txt。

  7. 在darknet目录下打开Terminal,执行

    1
    python voc_label.py
  8. 将darknet/data/labels文件夹下的txt文件拷贝到 darknet/data/images 文件夹下。

  9. 在 darknet 目录下新建文件 vocbox.data,写入如下内容并保存
    1
    2
    3
    4
    5
    classes= 2
    train = /home/robot/Downloads/darknet/train.txt
    valid = /home/robot/Downloads/darknet/test.txt
    names = /home/robot/Downloads/darknet/vocbox.names
    backup = backup

    注意:依据自己的数据集修改分类数、以及执行 voc_label.py 文件后得到的 train.txt 和 test.txt 路径。

4 配置文件的修改

4.1 makefile文件的修改

打开darknet/Makefile,找到前几行的代码,修改如下

1
2
3
4
5
6
7
GPU=1               # 训练时使用CUDA进行加速训练(CUDA应该在 /usr/local/cuda文件夹下)
CUDNN=1 # 使用CUDNN v5-v7进行加速(cuDNN应该在 /usr/local/cudnn文件夹下)
CUDNN_HALF=1 # 为Tensor Cores (在Titan V / Tesla V100 / DGX-2等)上进行加速训练和推理。
OPENCV=1 # OpenCV可以读取视频或者图片
AVX=0
OPENMP=0
LIBSO=1 # 生成动态链接库

4.2 cfg文件的修改

打开darknet/cfg/yolov4-relu.cfg(或者其他的cfg,relu表示用relu激活函数)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
## step1
batch=64 # Training标签下,原来就是64,根据gpu自己选择,但必须是2的倍数
subdivisions=16 # 如果out of memory,则32或64,依次倍增。或者64,32,...,1,依次倍减batch值

## step2
width=608 # 图片宽和高,这边我没有修改,该值必须被32整除。
height=608
max_batches=500500 # 该值最少是classes*2000
steps=400000,450000 # 该值是 max_batches的80% 和 90%

## step3,修改classess,和打标签时的分类数一致
classes=2 # 每个yolo标签下都需要修改,共三处

## step4,修改紧挨 yolo 标签上面的 convolutional
filters=21 # 计算方法为(classes + 5)x3,共三处

cfg文件的参数含义可以参考: 关于yolo配置文件以及训练时各参数的含义.

5 开始训练

1
2
3
4
5
cd darknet
sudo ldconfig
make clean
make -j8
sudo ./darknet detector train vocbox.data cfg/yolov4-relu.cfg yolov4.conv.137 -i 0 -map

如果没有权重文件 yolov4.conv.137,可以从如下地址下载:

链接: https://pan.baidu.com/s/1XiBjueBZ6lLKfhJyJo887A 提取码: 67ra

训练完成后,会得到一张损失函数图,以及存放在darknet/backup目录下的权重文件。

03

6 测试训练结果

1
2
cd darknet
sudo ./darknet detector test vocbox.data cfg/yolov4-relu.cfg ./backup/yolov4-relu_final.weights

运行后,从Terminal中再输入相应的测试图片路劲即可。

附录

附录1 sel_train_test.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
source_folder='/home/robot/Downloads/darknet/data/images' #!!!! Modify
dest='/home/robot/Downloads/darknet/data/ImageSets/train.txt' #!!!! Modify
dest2='/home/robot/Downloads/darknet/data/ImageSets/test.txt' #!!!! Modify
file_list=os.listdir(source_folder)
train_file=open(dest,'a')
val_file=open(dest2,'a')
for file_obj in file_list:
file_path=os.path.join(source_folder,file_obj)

file_name,file_extend=os.path.splitext(file_obj)

file_num=int(file_name)

if(file_num % 10 == 0):
val_file.write(file_name+'\n')
else :
train_file.write(file_name+'\n')
train_file.close()
val_file.close()

附录2 voc_label.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

sets=['train','test']

classes = ["gray", "white"] #!!! Modify classes based on your labels!

def convert(size, box):
dw = 1./size[0]
dh = 1./size[1]
x = (box[0] + box[1])/2.0
y = (box[2] + box[3])/2.0
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):
def convert_annotation(image_id):
# in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
in_file = open('data/Annotations/%s.xml'%(image_id))
# out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, image_id), 'w')
out_file = open('data/labels/%s.txt'%(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 image_set in sets:
if not os.path.exists('data/labels/'):
os.makedirs('data/labels/')
image_ids = open('data/ImageSets/%s.txt'%(image_set)).read().strip().split()
list_file = open('%s.txt'%(image_set), 'w')
for image_id in image_ids:
list_file.write('%s/data/images/%s.jpg\n'%(wd, image_id)) #!!!! Modify the format of pictures based on your source pictures!
convert_annotation( image_id)
list_file.close()
------ 本文结束感谢您的阅读------
Donate a cup of cola?