之前整理过一篇关于fasterrcnn的文章,文中详细介绍了fasterrcnn原理分析,近期由于工作需要利用fasterrcnn进行模型训练,故记录如下。
环境配置可参考:https://github.com/rbgirshick/py-faster-rcnn/blob/master/README.md,作者提供了较详细的安装步骤。
(1)在进行这一步之前,需已经在自己的机器上配置好caffe环境以及各种依赖项的安装,在配置之前,需确保已经安装以下几个python包:cython、easydict和python-opencv。安装命令如下:
pip install cython
pip install easydict
apt-get install python-opencv
(2)从github上clone项目,注意!一定要在clone时加入–recursive参数,不然会很麻烦,也不要直接下载,在机器上装个git来clone,这样会省去很多时间,下载的话caffe环境相关内容不能下载下来。
git clone –recursive https://github.com/rbgirshick/py-faster-rcnn.git
(3)Cython模块编译
cd $FRCN_ROOT /lib
make
(4)caffe和pycaffe的编译
在编译之前,需要复制$FRCN_ROOT/caffe-fast-rcnn 的Makefile.config.example,然后重命名为Makefile.config。
需要注意的是里面有几个配置需要添加
打开USE_CUDNN=1,这个选项默认情况下是关闭的,需要打开让CUDA支持DNN
打开WITH_PYTHON_LAYER=1,默认关闭,需打开,因为FasterRCNN需要支持Python接口。
执行以下命令进行编译
cd $FRCN_ROOT/caffe-fast-rcnn
make all -j && make pycaffe
(1).下载训练好的模型,下载后这个faster_rcnn_models文件夹在$FRCN_ROOT/data下面,可以从data/README.md中查看关于这个的详细介绍。这些模型是在VOC 2007 上训练的。(可在data/scripts/fetch_faster_rcnn_models.sh文件中复制URL用迅雷下载)
(2)运行demo
cd $FRCN_ROOT
./tools/demo.py
(1)下载训练、验证以及测试集和VOCdevkit
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCdevkit_08-Jun-2007.tar
(2)解压
tar xvf VOCtrainval_06-Nov-2007.tar
tar xvf VOCtest_06-Nov-2007.tar
tar xvf VOCdevkit_08-Jun-2007.ta
文件结构如下:
$VOCdevkit/ # 开发工具包
$VOCdevkit/VOCcode/ # VOC实用代码
$VOCdevkit/VOC2007# 图片集, 注释, 等等
# 一些其他的目录
将VOCdevkit改名为VOCdevkit2007,然后放到data文件夹下,亦可以使用软连接的方式,
cd $FRCN_ROOT/data
ln -s $VOCdevkit VOCdevkit2007
(3)下载预训练模型
cd $FRCN_ROOT
./data/scripts/fetch_imagenet_models.sh
(4)训练模型
a.使用交替优化(alternating optimization)算法来训练和测试Faster R-CNN,输出的结果在 $FRCN_ROOT/output下
cd $FRCN_ROOT
./experiments/scripts/faster_rcnn_alt_opt.sh [GPU_ID] [NET] [--set ...]
# GPU_ID是你想要训练的GPUID
# 你可以选择如下的网络之一进行训练:ZF, VGG_CNN_M_1024, VGG16
# --set ... 运行你自定义fast_rcnn.config参数,例如.
# --set EXP_DIR seed_rng1701 RNG_SEED 1701
#例如命令
./experiments/scripts/faster_rcnn_alt_opt.sh 0 ZF pascal_voc
b.使用近似联合训练( approximate joint training),输出的结果在 $FRCN_ROOT/output下,这个方法是联合RPN模型和Fast R-CNN网络训练。而不是交替训练。用此种方法比交替优化快1.5倍,但是准确率相近。所以推荐使用这种方法。
cd $FRCN_ROOT
./experiments/scripts/faster_rcnn_alt_opt.sh [GPU_ID] [NET] [--set ...]
# GPU_ID是你想要训练的GPUID
# 你可以选择如下的网络之一进行训练:ZF, VGG_CNN_M_1024, VGG16
# --set ... 运行你自定义fast_rcnn.config参数,例如.
# --set EXP_DIR seed_rng1701 RNG_SEED 1701
#例如命令
./experiments/scripts/faster_rcnn_alt_opt.sh 0 ZF pascal_voc
使用end2end的训练方式训练VGG16,使用指令如下:
./experiments/scripts/faster_rcnn_end2end.sh 0 VGG16 pascal_voc
由于需要训练自己的数据集,所以需要对这个工程各个目录的作用有所了解
利用labelImg工具进行数据标注,标注文件放在VOC2007/Annotations,图像文件放在VOC2007/JPEGImages目录下,这样做的目的是减少代码的修改量。生成生成ImageSet\Main里的四个txt文件,分别是:trainval.txt(训练和验证集总和)、train.txt(训练集)、val.txt(验证集)、test.txt(测试集),trainval集占整个数据集的70%,train集占trainval集的70%,val集占trainval集的30%,test集占整个数据集的30%。
可参考如下代码进行划分:
%%
%该代码根据已生成的xml,制作VOC2007数据集中的trainval.txt;train.txt;test.txt和val.txt
%trainval占总数据集的70%,test占总数据集的30%;train占trainval的70%,val占trainval的30%;
%上面所占百分比可根据自己的数据集修改
%注意修改下面两个路径
xmlfilepath='/home/linbiyuan/py-faster-rcnn/data/VOCdevkit2007/VOC2007/Annotations';
txtsavepath='/home/linbiyuan/py-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Main/';
xmlfile=dir(xmlfilepath);
numOfxml=length(xmlfile)-2;%减去.和.. 总的数据集大小
trainval=sort(randperm(numOfxml,floor(numOfxml*0.7)));%trainval为数据集的50%
test=sort(setdiff(1:numOfxml,trainval));%test为剩余50%
trainvalsize=length(trainval);%trainval的大小
train=sort(trainval(randperm(trainvalsize,floor(trainvalsize*0.7))));
val=sort(setdiff(trainval,train));
ftrainval=fopen([txtsavepath 'trainval.txt'],'w');
ftest=fopen([txtsavepath 'test.txt'],'w');
ftrain=fopen([txtsavepath 'train.txt'],'w');
fval=fopen([txtsavepath 'val.txt'],'w');
for i=1:numOfxml
if ismember(i,trainval)
fprintf(ftrainval,'%s\n',xmlfile(i+2).name(1:end-4));
if ismember(i,train)
fprintf(ftrain,'%s\n',xmlfile(i+2).name(1:end-4));
else
fprintf(fval,'%s\n',xmlfile(i+2).name(1:end-4));
end
else
fprintf(ftest,'%s\n',xmlfile(i+2).name(1:end-4));
end
end
fclose(ftrainval);
fclose(ftrain);
fclose(fval);
fclose(ftest);
(1)修改prototxt配置文件
这些配置文件都在models下的pascal_voc下。里面有三种网络结构:ZF、VGG16、VGG_CNN_M_1024,本文选择的是VGG16 。每个网络结构中都有三个文件夹,分别是faster_rcnn_end2end、faster_rcnn_alt_opt、faster_rcnn。使用近似联合训练,比交替优化快1.5倍,但是准确率相近,所以推荐使用这种方法。更改faster_rcnn_end2end文件夹下的train.prototxt和test.prototxt.
train.prototxt中需要更改的地方有4处,分别在 input_data、roi_data、cls_score、bbox_pred层:
layer {
name: 'input-data'
type: 'Python'
top: 'data'
top: 'im_info'
top: 'gt_boxes'
python_param {
module: 'roi_data_layer.layer'
layer: 'RoIDataLayer'
param_str: "'num_classes': 2" #这里改为训练类别数+1
}
}
layer {
name: 'roi-data'
type: 'Python'
bottom: 'rpn_rois'
bottom: 'gt_boxes'
top: 'rois'
top: 'labels'
top: 'bbox_targets'
top: 'bbox_inside_weights'
top: 'bbox_outside_weights'
python_param {
module: 'rpn.proposal_target_layer'
layer: 'ProposalTargetLayer'
param_str: "'num_classes': 2" #这里改为训练类别数+1
}
}
layer{
name:"cls_score"
inner_product_param {
num_output: 2 #这里改为训练类别数+1
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layer{
name:"bbox_pred"
inner_product_param {
num_output: 8 #这里改为(类别数+1)*4
weight_filler {
type: "gaussian"
std: 0.001
}
bias_filler {
type: "constant"
value: 0
}
}
}
test.prototxt修改2处,分别为cls_score、bbox_pred层
layer {
name: "cls_score"
type: "InnerProduct"
bottom: "fc7"
top: "cls_score"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 2 #改为训练类别数+1
layer {
name: "bbox_pred"
type: "InnerProduct"
bottom: "fc7"
top: "bbox_pred"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 8 #改为(训练类别数+1)*4
(2)修改lib/datasets/pascal_voc.py,将类别改成自己的类别
这里有一个注意点就是,这里的类别以及你之前的类别名称最好是全部小写,假如是大写的话,则会报keyError的错误,这时只需要在pascal_voc。py中第218行的lower去掉即可。
datasets目录下主要有三个文件,分别是
(1) factory.py:这是一个工厂类,用类生成imdb类并且返回数据库供网络训练和测试使用;
(2) imdb.py:是数据库读写类的基类,封装了许多db的操作;
(3) pascl_voc.pyRoss用这个类来操作
(3)修改lib/datasets/imdb.py修改
imdb.py文件修改为如下,修改2部分中的三行代码,是为了防止出现下面提到的问题1。
def append_flipped_images(self):
num_images = self.num_images
#widths = self._get_widths()
widths = [PIL.Image.open(self.image_path_at(i)).size[0]
for i in xrange(num_images)]
for i in xrange(num_images):
boxes = self.roidb[i]['boxes'].copy()
oldx1 = boxes[:, 0].copy()
oldx2 = boxes[:, 2].copy()
boxes[:, 0] = widths[i] - oldx2 - 1
boxes[:, 2] = widths[i] - oldx1 - 1
for b in range(len(boxes)): # 修改2
if boxes[b][2] < boxes[b][0]:#
boxes[b][0] = 0 #
assert (boxes[:, 2] >= boxes[:, 0]).all()
entry = {'boxes' : boxes,
'gt_overlaps' : self.roidb[i]['gt_overlaps'],
'gt_classes' : self.roidb[i]['gt_classes'],
'flipped' : True}
self.roidb.append(entry)
self._image_index = self._image_index * 2
(4)开始训练
可将输出过程重定向输入到log文件中。
./experiments/scripts/faster_rcnn_end2end.sh 0 VGG16 pascal_voc > /home/***/test.log 2>&1
注意:训练前需要将data/cache中的pki文件以及VOCdevkit2007中annotations_cache的缓存删掉。
(1)修改class
根据自己的label将class修改
(2)增加训练的模型
NETS = {'vgg16': ('VGG16',
'VGG16_faster_rcnn_final.caffemodel'),
'zf': ('ZF',
'ZF_faster_rcnn_final.caffemodel'),
'vgg16_test':('VGG','vgg_cnn_m_1024_faster_rcnn_iter_70000.caffemodel')}
(3)修改prototxt,如果用的是VGG,就不用修改
prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
'faster_rcnn_end2end', 'test.prototxt')
(4)检测
./tools/demo.py –net vgg_test
结果会出现带边框的图像。
可以使用tools/reval.py文件,对训练过程中的测试结果进行重新测试,可用matlab code测试(需配置相关环境)
python tools/reval.py output/faster_rcnn_end2end/voc_2007_test/vgg16_faster_rcnn_iter_50000/
原因分析:检查自己数据发现,左上角坐标(x,y)可能为0,或标定区域溢出图片
而faster rcnn会对Xmin,Ymin,Xmax,Ymax进行减1操作,如果Xmin为0,减一后变为65535
解决方法:
1、修改lib/datasets/imdb.py,append_flipped_images()函数
数据整理,在一行代码为 boxes[:, 2] = widths[i] - oldx1 - 1下加入代码:
for b in range(len(boxes)):
if boxes[b][2]< boxes[b][0]:
boxes[b][0] = 0
2、修改lib/datasets/pascal_voc.py,_load_pascal_annotation(,)函数
将对Xmin,Ymin,Xmax,Ymax减一去掉
解决方法:
删除data文件夹和VOCdevkit2007文件夹中的cache文件
原因分析:原因是windows下的文件是dos格式,即每一行结尾以\r\n来标识,而linux下的文件是unix格式,行尾则以\n来标识。
cat -A ,如果输出结果中行末尾是^M , 则 是 d o s 格 式 , 如 果 行 末 尾 只 是 ,则是dos格式,如果行末尾只是 ,则是dos格式,如果行末尾只是,则是unix格式。
解决方法:
vim ,编辑文件,执行“: set ff=unix”,将文件设置为unix格式,然后执行“:wq”,保存退出
原因可能是没有将faster-rcnn中的某些库包含到库中,打开~/.bashrc文件:
export PYTHONPATH="$PYTHONPATH:~/py-faster-rcnn/caffe-fast-rcnn/python:~/py-faster-rcnn/lib"
问题分析:snapshot保存路径问题
后续会参考代码进行阅读理解,会进行一些记录,方便后续查看
Faster-rcnn 源码学习(一)