1. 程式人生 > >【faster-rcnn】訓練自己的資料集時的坑

【faster-rcnn】訓練自己的資料集時的坑

既然faster-rcnn原版發表時候是matlab版程式碼,那就用matlab版程式碼吧!不過遇到的坑挺多的,不知道python版會不會好一點。

======= update =========
總體上包括這些步驟,請注意檢查:
1 獲取資料;(標準資料集/比賽資料/自行收集資料)
2 整理圖片名和標註資訊格式、指定訓練集和測試集;(轉voc格式,同時記得修改vocinit.m中類別資訊;或者自己修改程式碼中讀取資料的地方)
3 正確使用均值影象:手動算一個或用預設的減去128,別用錯
4 選擇網路與設定網路引數(solver和net);(根據業務需求和視訊記憶體大小設定;修改網路中目標類別數量)
5 檢查batch_size;
6 檢查anchor;
7 清空cache目錄;
8 開始訓練;
9 確保電腦供電且不會休眠睡眠;
10 執行測試;整理測試結果
======= update =========

anyway,這裡記錄一下我遇到的幾個坑

這裡假設你已經配置好了faster-rcnn。我是在win10下配置的,顯示卡GTX 970,使用ZF網路。

0. 準備資料集

官方訓練時用的是voc2007系列資料,那就轉換成這個系列的好了,主要包括:0.下載資料集 1.整理圖片 2.xml格式的annotation檔案 3.txt格式指定訓練集、測試集、驗證集、訓練驗證集,以及每個類別各自的這四種檔案

0.0 下載資料集

看具體情況,比如做某個比賽,那就下載;如果是自己收集的資料集,那就統一放到一起

0.1 整理圖片

主要是圖片格式統一,比如都是png
以及,命名規範,比如統一是6位長度的數字:000001.png,並且序號是連續的
訓練圖片和測試圖片都放在一個JPEGImages

目錄裡

0.2 xml格式的annotation檔案

其實voc2007這種方式:為每張圖片編寫一個xml檔案,記錄圖片各種元資訊(作者、檔名、寬度高度深度、來源),以及bounding box座標資訊(左上、右下定點)等,很蛋疼啊,圖片多的話每次處理xml檔案讀寫I/O就增大了。anyway,遵守標準的好處是省的自己造各種工具。

這裡貼一個例子好了,000001.xml:

<annotation>
    <folder>VOC2007</folder>
    <filename>000001.png</filename>
    <source>
        <database
>
My Database</database> <annotation>VOC2007</annotation> <image>flickr</image> <flickrid>NULL</flickrid> </source> <owner> <flickrid>NULL</flickrid> <name>chriszz</name> </owner> <size> <width>1280</width> <height>720</height> <depth>3</depth> </size> <segmented>0</segmented> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>369</xmin> <ymin>403</ymin> <xmax>409</xmax> <ymax>418</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>434</xmin> <ymin>375</ymin> <xmax>443</xmax> <ymax>401</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>461</xmin> <ymin>368</ymin> <xmax>471</xmax> <ymax>395</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>571</xmin> <ymin>473</ymin> <xmax>593</xmax> <ymax>490</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>674</xmin> <ymin>470</ymin> <xmax>683</xmax> <ymax>478</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>693</xmin> <ymin>471</ymin> <xmax>714</xmax> <ymax>480</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>976</xmin> <ymin>413</ymin> <xmax>998</xmax> <ymax>438</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>1004</xmin> <ymin>396</ymin> <xmax>1011</xmax> <ymax>410</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>1024</xmin> <ymin>388</ymin> <xmax>1031</xmax> <ymax>405</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>1046</xmin> <ymin>388</ymin> <xmax>1071</xmax> <ymax>406</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>1114</xmin> <ymin>390</ymin> <xmax>1143</xmax> <ymax>410</ymax> </bndbox> </object> <object> <name>sign</name> <pose>Unspecified</pose> <truncated>0</truncated> <difficult>0</difficult> <bndbox> <xmin>913</xmin> <ymin>431</ymin> <xmax>928</xmax> <ymax>458</ymax> </bndbox> </object> </annotation>

記得所有xml檔案的檔名要和圖片序號一一對應:000001.xml對應000001.png
並且,所有xml檔案放到Annotations目錄中

0.3 txt檔案指定訓練集、測試集等

在ImageSets/Main目錄下儲存這些檔案。比如我的任務是檢測交通標識,只有一個類別需要檢測,或者說是二分類問題,只需要判斷一個bbox區域是否為交通標識(sign),那麼我建立sign對應的4個檔案;以及4個表示總體的訓練、驗證、訓練驗證、測試的txt檔案:

其中,sign_train、sign_test、sign_trainval、sign_val每行格式相同

圖片id(不帶字尾,不用全路徑) +1-1(表示這張圖片中是否包含sign類別的區域)

對於我的情況,類別標籤都是+1

然後是train、val、trainval、test檔案,其中trainval是train和val的拼接。

這裡我是需要

1 修改faster-rcnn的幾個程式碼細節

1.0 experiments\script_faster_rcnn_VOC2007_ZF.m第30、31行

這裡預設居然是用select search生成region proposal,我也是醉了。
改成:

dataset                     = Dataset.voc2007_trainval(dataset, 'train', use_flipped);
dataset                     = Dataset.voc2007_test(dataset, 'test', false);

1.1 experiments\+Dataset\voc2007_test.m第11行、第14行,test改成val

這個真的是太坑了,在這裡我卡了大半天。為什麼會卡在這個地方,然後程式一直執行出錯呢?以及,程式出錯大概如下:

錯誤使用 proposal_prepare_image_roidb>scale_rois (line 110) 兩個輸入陣列的單一維度必須相互匹配,...

設斷點debug後發現,roidb_train裡各種欄位都有值(比如gt、座標、閾值、類別等);而roidb_val裡面是空的。
實際上是在experiments\+Faster_RCNN_Train\do_proposal_train.m裡面,把dataset.roidb_test賦值給roidb_val了:

function model_stage = do_proposal_train(conf, dataset, model_stage, do_val)
    if ~do_val
        dataset.imdb_test = struct();
        dataset.roidb_test = struct();
    end

    model_stage.output_model_file = proposal_train(conf, dataset.imdb_train, dataset.roidb_train, ...
                                    'do_val',           do_val, ...
                                    'imdb_val',         dataset.imdb_test, ...
                                    'roidb_val',        dataset.roidb_test, ...   # 尼瑪,在這裡賦值了
                                    'solver_def_file',  model_stage.solver_def_file, ...
                                    'net_file',         model_stage.init_net_file, ...
                                    'cache_name',       model_stage.cache_name);
end

問題就是在這裡了,不多說。那麼接下來就是把experiments\+Dataset\voc2007_test.m第11行、第14行,test改成val,保證以後在imdb\cache目錄下有val的mat資料存在,roidb_val也不會說裡面內容都為空的了。

2 修改網路引數

看到下面這張圖應該知道要改那幾個檔案了:

具體可以參考小鹹魚的faster-rcnn matlab版的配置