我看了网上很多yolo教程,可能是因为电脑环境和配置的不一样,所以我并没有完全通过网上教程成功训练自己的数据集,接下来我将我自己完全亲自测试并且最后成功训练数据集的教程记录如下:
训练自己的数据集有如下几步:
准备数据集并且安装yolo
制作数据集的标签生成xml文件
将xml文件转成txt文件
修改配置文件
下载预训练模型进行训练
**第一步:**安装yolo并且准备自己的数据集(图片格式是jpg格式),安装yolo参照网址:https://pjreddie.com/darknet/yolo/
**第二步:**制作数据集标签生成xml文件:
大家在这里需要安装安装 labelImg (标数据用),我在网上试了很多教程,最后我推荐大家按照这个网址的教程装:https://www.cnblogs.com/new-age/p/7071289.html 装完之后用labelImg做标签并将生成的xml文件保存在xml文件夹下。
第三步:将xml文件转成txt格式,这一步大家可以采用这篇博客里的代码http://blog.csdn.net/qq_34484472/article/details/73135354#reply,代码亲自运行过没有错误。可是经过代码转换后原图片会损失,因此在训练的时候会出现无法读取图片的问题,如出现STB Reason:unknown image type这个问题是说明是你的图片出现了问题,因此你可以将损坏的图片进行替换就可以正确训练了。
最后在训练前您需要准备这几个文件夹:
backup文件夹是用于保存训练模型的,如下图:
第四步:
在darknet/cfg/voc.data文件中进行如下修改:
classes= 1(由于我只训练车牌这一个类)
train =/home/tlx/darknet/mydata/trainImagePath.txt(训练图片的路径)
valid = /home/tlx/darknet/mydata/validateImagePath.txt(验证图片的路径)
names = data/plate.names
在cfg/yolo-voc.cfg文件中的[region]中的classes改为1(只有一个类),将[region]上面的一个卷积层的filters改为30,计算公式为filters=(classes+coord+1)*NUM,因此是(1+4+1)*5=30
**第五步:**下载预训练模型,下载地址为:
http://pjreddie.com/media/files/darknet19_448.conv.23
将模型保存在放在darknet文件夹下,并在darknet文件夹路径下运行命令进行训练:
./darknet detector train cfg/voc.data cfg/yolo-voc.cfg cfg/darknet19_448.conv.23
**第六步:**测试模型代码:
./darknet detector test cfg/voc.data cfg/yolo-voc.cfg backup/yolo-voc_500.weights data/0033.jpg
注意:
如果测试时出现权重不能识别目标的情况,是因为yolo-voc.cfg文件开头的Traing下面两行没有注释掉,并且把Testing下面两行去掉注释就可以正常使用啦!
代码:
首先是将labelImg生成的xml转换成txt文件
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
xml_label_Dir = '/home/tlx/Main/' # 需转换的xml路径
txt_label_Dir ='/home/tlx/Annotations/txt/' # 转换得的txt文件保存路径
classes = ["bird", "car"] #有几类就写几个
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)
if not os.path.exists(txt_label_Dir):
os.makedirs(txt_label_Dir)
for rootDir, dirs, files in os.walk(xml_label_Dir):
for file in files:
file_name = file.split('.')[0]
out_file = open(txt_label_Dir + '%s.txt' % (file_name), 'w')
in_file = open("%s/%s" % (rootDir, file))
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')
out_file.close()
其次是将获取图片的绝对路径传给voc.data,代码如下:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
DataDir = '/home/tlx/JPEGImages'
out_file = open('data_image_path.txt','w')
for root,dirs,files in os.walk(TrainDir):
for file in files:
out_file.write('%s/%s\n'%(root,file))
out_file.close()