Faster-RCNN環境搭建與訓練自己的資料
0 前言
之前整理過一篇關于fasterrcnn的文章,文中詳細介紹了fasterrcnn原理分析,近期由于工作需要利用fasterrcnn進行模型訓練,故記錄如下。
1.環境搭建與demo運作
1).配置環境
環境配置可參考: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
2).運作demo
(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
2.訓練PASCAL VOC 2007的資料集
(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
3.訓練自己的資料集
1)工程目錄簡介
由于需要訓練自己的資料集,是以需要對這個工程各個目錄的作用有所了解
- caffe-fast-rcnn:caffe架構目錄
- data:用來存放pretrained模型以及讀取檔案的cache緩存,還有一些下載下傳模型的腳本
- experiments:存放配置檔案以及運作的log檔案,另外這個目錄下有scripts,裡面存放end2end和alt_opt兩種訓練方式的腳本
- lib:用來存放一些python接口檔案,如其下的datasets主要負責資料庫讀取,config負責一些訓練的配置選項
- models:裡面存放了三個模型檔案,小型網絡ZF,中型網絡VGG_CNN_M_1024以及大型網絡VGG16,根據你的硬體條件來選擇使用哪種網絡,ZF和VGG_CNN_M_1024需要至少3G記憶體,VGG16需要更多的記憶體,但不會超過11G。
- output:這裡存放的是訓練完成後的輸出目錄,這是運作了訓練後才會出現的目錄
- tools:裡面存放的是訓練和測試的Python檔案
2)準備資料集
利用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);
3)修改代碼
(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的緩存删掉。
4)測試結果
(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
結果會出現帶邊框的圖像。
5)重新驗證
可以使用tools/reval.py檔案,對訓練過程中的測試結果進行重新測試,可用matlab code測試(需配置相關環境)
python tools/reval.py output/faster_rcnn_end2end/voc_2007_test/vgg16_faster_rcnn_iter_50000/
6)出現問題:
1. 訓練時出現assert (boxes[:, 2] >= boxes[:, 0]).all()的問題
原因分析:檢查自己資料發現,左上角坐标(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減一去掉
2.訓練過程中出現overlaps = entry[‘max_overlaps’],KeyError: 'max_overlaps’問題
解決方法:
删除data檔案夾和VOCdevkit2007檔案夾中的cache檔案
3.linux下執行shell腳本時報錯:-bash: ./a.sh: /bin/bash^M: bad interpreter: No such file or directory。
原因分析:原因是windows下的檔案是dos格式,即每一行結尾以\r\n來辨別,而linux下的檔案是unix格式,行尾則以\n來辨別。
cat -A ,如果輸出結果中行末尾是^M , 則 是 d o s 格 式 , 如 果 行 末 尾 隻 是 ,則是dos格式,如果行末尾隻是 ,則是dos格式,如果行末尾隻是,則是unix格式。
解決方法:
vim ,編輯檔案,執行“: set ff=unix”,将檔案設定為unix格式,然後執行“:wq”,儲存退出
4.ImportError: No module named rpn.proposal_layer
原因可能是沒有将faster-rcnn中的某些庫包含到庫中,打開~/.bashrc檔案:
export PYTHONPATH="$PYTHONPATH:~/py-faster-rcnn/caffe-fast-rcnn/python:~/py-faster-rcnn/lib"
5.訓練過程中出現Check failed:proto.SerializeTOstream(&output)錯誤,訓練終止
問題分析:snapshot儲存路徑問題