YOLO是强大的目标检测开源库 ,目前支持多个类别的目标检测,如自行车、人、动物、标识等,检测速度比较快,V2下检测速度在普通显卡上可以实时对视频流目标检测,虽然对小目标效果欠佳,但是大多数应用下还是有实际应用意义。相关详细介绍可以参考:https://pjreddie.com/darknet/yolo/?utm_source=next.36kr.com,论文地址:https://pjreddie.com/media/files/papers/YOLOv3.pdf。尽管yolo实现了100多类目标检测,但是应用是多样性的,需要检测检测的目标类型成千上万,因此,下面将要介绍如何使用yolo训练出自己想要的目标检测模型。
本文主要参考这篇英文博客:https://timebutt.github.io/static/how-to-train-yolov2-to-detect-custom-objects/。
我使用的是VS2013,因此下载yolo的Windows版本,先check out源代码:
git clone https://github.com/AlexeyAB/darknet.git
然后在\darknet\build\darknet目录中找到darknet.sln打开,如果是应为cuda版本问题,可能打不开工程,不过没有关系,在解决方案视图中找到darknet工程文件,选择编解工程文件,找到里面的cuda版本,改成自己安装的版本,关掉解决方案,重新打开或者选择reload,就可以看到源代码文件了。编译,顺利通过。
准备配置文件:obj.data,包含以下内容:
classes= 1
train = train.txt
valid = test.txt
names = obj.names
backup = backup/
classes表示类别数量,我只是训练1类,所以等于1;train表示训练集,对应的是文件名,文件中包含了所有用于训练的图片文件名;valid表示测试集合,同训练集一样,文件中包含了所有训练时所用的测试图片名;names表示类别的名称,这里由obj.names指定;backup表示训练时的中间weights文件存放目录,如果没有对应目录,需要建立一个目录,否则开启训练时保持weights文件会报错。obj.names中的每一行表示一个类别,第一行的类别序号为0,以此下去至classes-1。
train.txt部分截图:
obj.names 部分截图:
这里只有NFPA一类。
接下标记数据,生成train.txt和test.txt文件:
这里我使用BBBox Label Tool标记图片,下载地址:https://github.com/puzzledqs/BBox-Label-Tool,使用python编写。如果没有配置python环境,需要配置python环境,这里不累述。OK,使用命令行打开标注界面:
在dir中输入001,可以看到如下界面:
左边一列是例子,可以不用管,需要标注的图片在中间显示,标记的结果在Bounding boxes中显示,如下:
可以选择某一个标记结果然后Delete,也可以clear掉当前图片所有结果。点击下一个的时候或者上一个的时候,自动保存。标记结果,例如:
2
51 54 213 214
56 234 165 325
第一行表示标记的框的数量2,第二行开始表示标记的矩形框,分别表示左上角x坐标、y坐标,右下角x坐标、有坐标,这些都是绝对坐标值,没有归一化。
标注是个需要耐心的过程,如果需要检测结果有个准确一点的位置,那么标注样本时就需要标注的紧凑些,尽量刚好包含目标。注意,这个工具同个只能标注同一类,标注不同的类别时,需要使用不同的目录。
标注完成之后,接下来需要把坐标归一化:
YOLO训练采用这样的标注格式:
分别表示类别序号、目标中心x坐标和y坐标、目标宽度和高度。
使用https://github.com/Guanghan/darknet/blob/master/scripts/convert.py这个脚本进行转换,需要注意的是:
classes = ["NFPA"]
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)
"""-------------------------------------------------------------------"""
""" Configure Paths"""
mypath = "labels/001/"
outpath = "labels/002/"
cls = "NFPA"
数组classes = [“NFPA”]填入所有的类,cls = “NFPA”指定当前需要转换的类别。mypath = “labels/001/” 为原始目录,outpath = “labels/002/”为转换之后的输出目录。我认为这里需要增加边界检查,所以增加红框中的几行:
OK,转换之后,需要生成train.txt文件和test.txt文件。将标注图片和convert之后生成的文件归在path_data = ‘data/obj/’目录下,使用如下python脚本生成train.txt和test.txt:
import glob, os
# Current directory
current_dir = os.path.dirname(os.path.abspath(__file__))
# Directory where the data will reside, relative to 'darknet.exe'
path_data = 'data/obj/'
# Percentage of images to be used for the test set
percentage_test = 10;
# Create and/or truncate train.txt and test.txt
file_train = open('train.txt', 'w')
file_test = open('test.txt', 'w')
# Populate train.txt and test.txt
counter = 1
index_test = round(100 / percentage_test)
for pathAndFilename in glob.iglob(os.path.join(current_dir, "*.jpg")):
title, ext = os.path.splitext(os.path.basename(pathAndFilename))
if counter == index_test:
counter = 1
file_test.write(path_data + title + '.jpg' + "\n")
else:
file_train.write(path_data + title + '.jpg' + "\n")
counter = counter + 1
OK,数据准备完成,修改cfg/yolo-obj.cfg文件:
第3行:batch=64,表示每个训练步骤使用64张图片;
第4行: 根据显存大小可以设置subdivisions=8,等于16;
第244行: classes=1,只有一类;
第237行: filters=(classes + 5)*5;
使用如下命令开启训练:
例如:
darknet.exe detector train cfg/obj.data cfg/yolo-obj.cfg darknet19_448.conv.23
darknet19_448.conv.23可以在这里下载:https://pjreddie.com/media/files/darknet19_448.conv.23
正常界面像这样:
经过几个小时或几天的训练,最后会得到yolo-obj_final.weights,OK,可以用来检测目标了。
darknet.exe detector test cfg/obj.data cfg/yolo-obj.cfg yolo-obj_final.weights