最近,跑faster rcnn需要训练自己的数据集,所以必须先跑faster rcnn模型。 例如,让公共数据集先跑,证明模型没有问题。 第二步是自己创建数据集以进行培训和测试。 有两种方法可以创建自己的目标发现数据集。 第一个是自己写,另一个是将自己的数据集更改为与公共数据集相同的结构。 当然,第二种方法更简单。 有了第二种方法,又开始自己写数据集的时候就没那么难受了。
系统ubuntu16。 假设在开始之前,你已经有一个可以跑步的faster rcnn模型,需要在自己的数据集上训练。
除语义分割外,主要使用VOC2007文件夹下的Annotations文件夹、ImageSets文件和JPEGImages文件夹。 使用的目标检测voc格式大致如下。
PASCAL_VOC07
(VOCdevkit
local
results
VOC2007
() Annotations
() ImageSets
(()main
() JPEGImages
VOCcode
Annotations文件夹包含作为标记信息的xml文件。 例如,VOC数据集的000001图像的标签信息在里面,存储在中央的文件名、图像的长度、宽度和通道存储在里面,0指示该图像无需被语义上分割,每个表示物体,其中有物体名称
VOC2007
000001.jpg
the VOC 2007数据库
PASCAL VOC2007
flickr
341012865
里德卡梅尔斯
Jinky the Fruit Bat
353
500
3
0
杜格
左后卫
1
0
48
240
195
371
佩尔森
左后卫
1
0
8
12
352
498
最简单的方法是将自己的数据集格式更改为voc格式。 最重要的是,需要变更的地方主要是和中之和。 可以使用标注工具label me进行这些修改。 标签me可以选择以voc的xml格式保存。
ImageSets文件夹中最多只能使用Main文件夹。 Main文件夹包含名为A_test、A_train和A_trainval的txt文件。 指示test/train/trainval中有哪些图像,以及test/train/trainval中的图像是否有a类。 例如,在A_test.txt中,000001 -1表示000001图像属于test,-1表示000001图像中没有a类。
000001 -1
000002 -1
000003 -1
.
编写python小程序,将现有的xml信息分别写入A_test.txt、A_train.txt、A_trainval.txt、B_test.txt、B_train.txt和b_train 首先,将它们保存到单独的列表中。
导入操作系统
import XML.etree.celementtreeaset
a,b,C=[],[],[]
forfileinOS.listdir(path ) :
tree=et.parse(OS.path.join ) path,file ) )
root=tree.getroot (
forobjinroot.findall(object ) ) :
name=obj.find('name ' ).text
if name=='A':
file=root.find('path ' ).text
file=file.split('' ) ) )。
file=file[-1][:-4]
a .是append (文件)
elif name=='B':
file=root.find('path ' ).text
file=file.split('' ) ) )。
file=file[-1][:-4]
b .应用程序(文件)。
elif name=='C':
file=root.find('path ' ).text
file=file.split('' ) ) )。
file=file[-
1][:-4]C.append(file)
剩下的是随机将数据集分成train和test,还有一些txt的操作,这些操作和你的数据集有关,代码需要根据自己的数据集来写。上面完成了A_test.txt、A_train.txt、A_trainval.txt的制作。
JPEGImages文件夹中存放的都是图片文件,没什么好说的,把自己的图片放在JPEGImages文件夹中就行。
现在你的voc数据集就制作完成了。
制作完数据集还需要相应的修改代码。如果你的数据集少,没有办法分成train、val、test三部分,可以只分成train和test两部分,factory.py中有一段代码
# Set up voc__
for year in ['2007', '2012']:
for split in ['train', 'val', 'trainval', 'test']:
name = 'voc_{}_{}'.format(year, split)
__sets[name] = (lambda split=split, year=year: pascal_voc(split, year))
pascal_voc(split, year)生成了pascal_voc子类,在pascal_voc.py文件中根据实际情况需要修改pascal_voc构造函数的路径以及类别。
class pascal_voc(imdb):
def __init__(self, image_set, year, devkit_path=None):
imdb.__init__(self, 'voc_' + year + '_' + image_set)
self._year = year
self._image_set = image_set
self._devkit_path = self._get_default_path() if devkit_path is None else devkit_path
self._data_path = os.path.join(self._devkit_path, 'VOC' + self._year)
self._classes = ('__background__', # always index 0
'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair',
'cow', 'diningtable', 'dog', 'horse',
'motorbike', 'person', 'pottedplant',
'sheep', 'sofa', 'train', 'tvmonitor')
#balabala....
pascalvoc('train', '2007')表示生成pascal voc2007格式的训练数据集,pascalvoc('test', '2007')表示生成pascal voc2007格式的测试数据集。同时,如果你的数据集只有训练和测试集,ImageSets/Main中的txt文件就不再是一个类有3个txt,而是只有A_train.txt和A_test.txt。所以制作txt的代码也需要修改。
上面基本是跑通自己的目标检测数据集需要修改的地方,如果已经有一个跑通了的目标检测网络,就可以开始训练自己的数据集了。
下面记录一下关于数据集代码的调用关系,实在是太复杂了。
从开始的imdb, roidb, ratio_list, ratio_index = combined_roidb(imdb_name)
在get_roidb函数中,首先用到datasets/factory.py的get_imdb函数,get_imdb函数返回相应的pascalvoc('xxx', 'yyyy')的pascalvoc类(imdb基类)。接着get_training_roidb函数从image database获得roi database
然后filter_roidb函数去除没有bounding box的图片,接着rank_roidb_ratio函数按照roi的长宽比排序。
所以返回的imdb, roidb, ratio_list, ratio_index表示image database、roi database、长宽比、长宽比索引。
之后就是写一个torch.utils.data.Dataset子类,将roi database包装成pytorch的Dataset的抽象类。还要写个torch.utils.data.sampler.Sampler基础采样器的子类,控制数据集的采样方式,注意的是如果数据集大小不能被batch_size整除的时候,余下部分的处理。最后,有了上面两个子类,就可以使用torch.utils.data.DataLoader加载数据了。总结就是重写了classtorch.utils.data.DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0,......)的dataset和sampler。
剩下的就是送入网络训练。