最近在学习 Faster R-CNN 模型,为了了解其中网络的结构,利用 PascalVOC 数据集,来扩展网络的类别(原来有 20 类)。过程分为:数据准备 ==> 相关文件修改 ==> 训练网络 ==> 测试
官网数据集镜像:https://pjreddie.com/projects/pascal-voc-dataset-mirror/
Pascal VOC 数据集中有训练时需要的图片、对应的标注文件(xml)和指定正负样本的文本文件(txt),分别放在 VOC2007 或 VOC2012 目录中的 JPEGImage、Annotations 和 ImageSets 的 Main 目录中。
本次训练的目的是在原有 20 类的基础上,扩展 3 类,分别是 cup、window、glasses
标注工具使用 LabelImage :github下载地址
需要安全 PyQt 和其他相关依赖项才能运行。
下载完后运行 LabelImage.py 文件即可,界面如下:
「Open Dir」 指定文件的路径;「Change Save Dir」 指定保存的 xlm 文件路径。
默认常用快捷键为:「w」 为画框,「a」 为上一张图片,「d」 为下一张图片,「ctrl + s」 为保存 xml 文件。
如果想要修改快捷键,可以打开 LabelImage.py 文件,在以下代码中(大概在213到276行)修改:
...
openNextImg = action('&Next Image', self.openNextImg, //里面有快捷键的功能和快捷键
'd', 'next', u'Open Next') //第三个参数('d')就是快捷键,可以修改
openPrevImg = action('&Prev Image', self.openPrevImg,
'a', 'prev', u'Open Prev')
verify = action('&Verify Image', self.verifyImg,
'space', 'verify', u'Verify Image')
save = action('&Save', self.saveFile,
'ctrl+s'', 'save', u'Save labels to file', enabled=False)
...
每画完一个框后,会让你选择所属类别:
如果想要修改预选类别,可以在 $LabelImage_ROOT/data
里面的 predefined_classes.txt
里修改。
数据标注完后,需要生成四个 txt 文件,分别为 class_train.txt、class_trainval.txt、class_val.txt、class_test.txt。
内容格式为下:
2008_000008 -1
2008_000015 -1
2008_000019 -1
2008_000023 -1
2008_000028 -1
2008_000033 1
2008_000036 -1
2008_000037 1
2008_000041 -1
2008_000045 -1
2008_000053 -1
2008_000060 -1
...
数据准备完后,
jpg 文件放在 \py-faster-rcnn\data\VOCdevkit2007\VOC2007\JPEGImage\ 里面
xml 文件放在 \py-faster-rcnn\data\VOCdevkit2007\VOC2007\Annotations\ 里面
txt 文件放在 \py-faster-rcnn\data\VOCdevkit2007\VOC2007\ImageSets\Main\ 里面
注意 txt 里面每一个类别都有对应的 train、val、trainval、test 文件,按照原来的数据格式去做,需要自己生成。
在训练开始之前,需要修改一些网络文件和下载 ImageNet 预训练模型。
1. cd $FRCN_ROOT/lib/datasets
,修改 pascal_voc .py
,添加自己的类
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', 'cup', 'window', 'glasses')
2. cd $FRCN_ROOT/lib/datasets
,修改 imdb.py
,
在 boxes[:, 2] = widths[i] - oldx1 -1
后面添加三行,如下:
...
boxes[:, 2] = widths[i] - oldx1 -1
for b in range(len(boxes)):
if boxes[b][2] < boxes[b][0]:
boxes[b][0] = 0
...
3. 修改 train.prototxt
和 test.prototxt
把所有的 21 替换为 24,这个数为 类别数 + 背景 = 23 + 1,按自己的类别数来改。然后把所有的 84 替换为 96,这个数为 (类别数 + 背景)× 4 = 96 ,也是按照自己的类别改。
4. 修改所有的 .pt
文件
如上,把所有的 21 替换为 24,把所有的 84 替换为 96
训练的时候需要使用 ImageNet 的预训练模型,所以需要准备:
cd $FRCN_ROOT
运行脚本文件:
./data/scripts/fetch_imagenet_models.sh
有可能需要才能下载或者下载速度慢。可以网上找网友下载。
删除缓存文件:
$FRCN_ROOT/data/VOCdevkit2007/annotations_cache/annots.pkl
$FRCN_ROOT/data/cache
下的 pkl 文件
如果不清除缓存可能会报错。
检查所有准备步骤没错后,就可以开始训练了。
命令如下:
cd $FRCN_ROOT
./experiments/scripts/faster_rcnn_end2end.sh [GPU_ID] [NET] [dataset]
第一个参数指定训练用的 GPU,第二个指定训练什么网络,这里使用 VGG16,第三个是指定数据集,这里为 pascal_voc
例如:
./experiments/scripts/faster_rcnn_end2end.sh 0 VGG16 pascal_voc
训练每次迭代大约为 0.2s ,迭代 70000 次,每 10000 次会生成一次 snapshot ,大概需要训练快 4 个小时训练完的网络保存在:
$FRCN_ROOT/output/faster_rcnn_end2end/voc_2007_trainval
训练中还是会遇到各种各样的报错,我把我自己的遇到的问题汇总了以下,参考训练和测试 Faster R-CNN 模型中遇到的问题。
网络训练完成后如果有 test 集会自动开始测试,最后输出所有类的 Average Precision (AP) 及 mean AP:
除了训练 VGG16 模型,我还再训练多一个 ResNet-50,在训练 ResNet-50 的时候我修改生成的 anchors 的尺度,增加了两个小的 anchors,提高了检测的精度,两个网络的 AP 做一个对比。
可以发现,残差网络所有类别的 AP 都有提高,有一部分类有明显提高:
上:VGG16 网络的 mAP;下:ResNet-50 网络的 mAP
由于官方给的文件里面没有 ResNet 网络训练的文件,可以参考 使用自己的数据训练 Faster R-CNN 的 ResNet-50 模型 。