拿到了训练图片和标注文件xml
开始按voc结构来构造自己的数据集
--VOC
--Annotations
--ImageSets
--Main
--JPEGImages
这里只列出关键的,之后还会建立一个labels目录(Ubuntu大小写有无空格好敏感!!!)
这里面用到的文件夹是Annotation、ImageSets和JPEGImages。其中文件夹Annotation中主要存放xml文件,每一个xml对应一张图像,并且每个xml中存放的是标记的各个目标的位置和类别信息,命名通常与对应的原始图像一样;而ImageSets我们只需要用到Main文件夹,这里面存放的是一些文本文件,通常为train.txt、test.txt、2018_train.txt等,train.txt、test.txt该文本文件里面的内容是需要用来训练或测试的图像的名字(无后缀无路径),2018_train.txt包含所有的路径;JPEGImages文件夹中放我们已按统一规则命名好的原始图像。
因此,首先
1.新建文件夹VOC2007(通常命名为这个,也可以用其他命名,但一定是名字+年份,例如MYDATA2016,无论叫什么后面都需要改相关代码匹配这里,本例中以
VOC2007为例)
2.在VOC2007文件夹下新建三个文件夹
Annotation、ImageSets和JPEGImages,并把准备好的自己的原始图像放在JPEGImages文件夹下
3.在ImageSets文件夹中,新建三个空文件夹Layout、Main、Segmentation,然后把写了训练或测试的图像的名字的文本拷到Main文件夹下,按目的命名,我这里所有图像用来训练,故而Main文件夹下只有train.txt文件。
生成脚本:creat_list.py:
import os
from os import listdir, getcwd
from os.path import join
if __name__ == '__main__':
source_folder='/home/yolo_v2_tinydarknet/darknet/infrared/image/dout/'
dest='/home/yolo_v2_tinydarknet/darknet/infrared/train.txt'
dest2='/home/yolo_v2_tinydarknet/darknet/infrared/val.txt'
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<900):
train_file.write(file_name+'\n')
else :
val_file.write(file_name+'\n')
train_file.close()
val_file.close()
上面说的小代码运行后会生成该文件,把它拷进去即可。
1.生成相关文件
按darknet的说明编译好后,接下来在darknet-master/scripts文件夹中新建文件夹VOCdevkit,然后将整个VOC2007文件夹都拷到VOCdevkit文件夹下。
然后,需要利用scripts文件夹中的voc_label.py文件生成一系列训练文件和labels,具体操作如下:
首先需要修改voc_label.py中的代码,这里主要修改数据集名,以及类别信息,我的是VOC2007,并且所有样本用来训练,没有val或test,并且只检测人,故只有一类
目标,因此按如下设置
- import xml.etree.ElementTree as ET
- import pickle
- import os
- from os import listdir, getcwd
- from os.path import join
-
-
-
-
-
- sets=[('2007', 'train')]
- classes = [ "person"]
-
-
- 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):
- 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()
修改好后在该目录下运行命令:python voc_label.py,之后则在文件夹scripts\VOCdevkit\VOC2007下生成了文件夹lables,该文件夹下的画风是这样的
这里包含了类别和对应归一化后的位置(i guess,如有错请指正)。同时在scripts\下应该也生成了2007_train.txt这个文件,里面包含了所有训练样本的绝对路径。
2.配置文件修改
做好了上述准备,就可以根据不同的网络设置(cfg文件)来训练了。在文件夹cfg中有很多cfg文件,应该跟caffe中的prototxt文件是一个意思。这里以tiny-yolo-voc.cfg为例,该网络是yolo-voc的简版,相对速度会快些。主要修改参数如下
- .
- .
- .
- [convolutional]
- size=1
- stride=1
- pad=1
- filters=30 //修改最后一层卷积层核参数个数,计算公式是依旧自己数据的类别数filter=num×(classes + coords + 1)=5×(1+4+1)=30
- activation=linear
-
- [region]
- anchors = 1.08,1.19, 3.42,4.41, 6.63,11.38, 9.42,5.11, 16.62,10.52
- bias_match=1
- classes=1 //类别数,本例为1类
- coords=4
- num=5
- softmax=1
- jitter=.2
- rescore=1
-
- object_scale=5
- noobject_scale=1
- class_scale=1
- coord_scale=1
-
- absolute=1
- thresh = .6
- random=1
另外也可根据需要修改learning_rate、max_batches等参数。
修改好了cfg文件之后,就需要修改两个文件,首先是data文件下的voc.names。打开voc.names文件可以看到有20类的名称,本例中只有一类,检测人,因此将原来所有内容清空,仅写上person并保存。名字仍然用这个名字,如果喜欢用其他名字则请按一开始制作自己数据集的时候的名字来修改。
接着需要修改cfg文件夹中的voc.data文件。也是按自己需求修改,我的修改之后是这样的画风:
- classes= 1 //类别数
- train = /home/kinglch/darknet-master/scripts/2007_train.txt //训练样本的绝对路径文件,也就是上文2.1中最后生成的
- //valid = /home/pjreddie/data/voc/2007_test.txt //本例未用到
- names = data/voc.names //上一步修改的voc.names文件
- backup = /home/kinglch/darknet-master/results/ //指示训练后生成的权重放在哪
修改后按原名保存最好,接下来就可以训练了。
3.运行训练
上面完成了就可以命令训练了,可以在官网上找到一些预训练的模型作为参数初始值,也可以直接训练,训练命令为
- $./darknet detector train cfg/voc.data cfg/yolo-voc.cfg
如果用官网的预训练模型darknet.conv.weights做初始化,则训练命令为
- $./darknet detector train cfg/voc.data cfg/yolo-voc.cfg darknet19_448.conv.23
不过我没试成功,加上这个模型直接就除了final,不知道啥情况。当然也可以用自己训练的模型做参数初始化,万一训练的时候被人终端了,可以再用训练好的模型接上去接着训练。
训练过程中会根据迭代次数保存训练的权重模型,然后就可以拿来测试了,测试的命令同理:
./darknet detector test cfg/voc.data cfg/yolo-voc.cfg results/yolo-voc_6000.weights data/images.jpg
这样就完成了整个流程