天天看點

Faster-rcnn環境搭建與訓練自己的資料Faster-RCNN環境搭建與訓練自己的資料

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)工程目錄簡介

由于需要訓練自己的資料集,是以需要對這個工程各個目錄的作用有所了解

  1. caffe-fast-rcnn:caffe架構目錄
  2. data:用來存放pretrained模型以及讀取檔案的cache緩存,還有一些下載下傳模型的腳本
  3. experiments:存放配置檔案以及運作的log檔案,另外這個目錄下有scripts,裡面存放end2end和alt_opt兩種訓練方式的腳本
  4. lib:用來存放一些python接口檔案,如其下的datasets主要負責資料庫讀取,config負責一些訓練的配置選項
  5. models:裡面存放了三個模型檔案,小型網絡ZF,中型網絡VGG_CNN_M_1024以及大型網絡VGG16,根據你的硬體條件來選擇使用哪種網絡,ZF和VGG_CNN_M_1024需要至少3G記憶體,VGG16需要更多的記憶體,但不會超過11G。
  6. output:這裡存放的是訓練完成後的輸出目錄,這是運作了訓練後才會出現的目錄
  7. 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儲存路徑問題

繼續閱讀