1. 程式人生 > >使用pytorch版faster-rcnn訓練自己資料集

使用pytorch版faster-rcnn訓練自己資料集

使用pytorch版faster-rcnn訓練自己資料集

引言

最近在復現目標檢測程式碼(師兄強烈推薦FPN,但本文只針對Faster-RCNN),大家在能順利測試原始碼資料集後,翅膀是不是硬了?是否想使用自己的資料集爽一下,本文主要介紹如何“傻瓜式”訓練自己的資料集~之前的此類部落格都是介紹如何在原作者的caffe原始碼下進行資料集訓練,那麼本文針對目前形勢一片大好的pytorh版faster-rcnn原始碼進行訓練新的資料集,廢話不多說,Lets go!

faster-rcnn pytorch程式碼下載

pytorch版原始碼:https://github.com/jwyang/faster-rcnn.pytorch.git
具體配置此程式碼作者已在ReadMe介紹的很清楚,當然會有一些坑。
我復現程式碼的環境是python35+cuda8.0+Ubuntu14.04+Pytorch0.4.0(這個很重要,目前更高版本不支援)。
此處舉例幾個坑吧

  1. 不要以為拿過程式碼以後,就可以直接跑demo!除非你的/models裡面有訓練好的模型。。此處說的模型不是指Vgg或Resnet在分類資料集ImageNet下訓好的Transfer模型,而是指的是在目標檢測集VOC或COCO下進行fine-tune的模型。對於VOC2007資料集,訓練好後該模型大概1個G,所以程式碼作者沒有上傳到github,要不你就自己訓練,要不你就跟訓好的人要,不過建議你自己訓練,跑trainval_net.py。

  2. 訓練資料集命令列示例:

//訓練
$ CUDA_VISIBLE_DEVICES=1 python trainval_net.py --dataset pascal_voc --net vgg16 --bs 1 --nw 4  --cuda

“CUDA_VISIBLE_DEVICES”指代了gpu的id,這得看你實驗室伺服器哪塊gpu是閒置的。
在此給個檢視gpu執行情況的tip:

//檢視gpu執行情況
$ nvidia-smi

“–dataset”指代你跑得資料集名稱,我們就以pascal-voc為例。
“–net”指代你的backbone網路是啥,我們以vgg16為例。
"–bs"指的batch size。
“–nw”指的是worker number,取決於你的Gpu能力,我用的是Titan Xp 12G,所以選擇4。稍微差一些的gpu可以選小一點的值。
“–cuda”指的是使用gpu。
訓好的model會存到models資料夾底下。

  1. 測試命令列示例:
//批量測試
$  python test_net.py --dataset pascal_voc --net vgg16 --checksession 1 --checkepoch 20 --checkpoint 10021  --cuda

注意,這裡的三個check引數,是定義了訓好的檢測模型名稱,我訓好的名稱為faster_rcnn_1_20_10021,代表了checksession = 1,checkepoch = 20, checkpoint = 10021,這樣才可以讀到模型“faster_rcnn_1_20_10021”。訓練中,我設定的epoch為20,所以checkepoch選擇20,也就是選擇最後那輪訓好的模型,理論上應該是效果最好的。當然著也得看loss。

  1. demo命令列示例
//個例實驗
$ python demo.py --net vgg16  --checksession 1  --checkepoch 20 --checkpoint 10021 --cuda --load_dir models

此處我們需輸入使用的網路(vgg16),以及訓練好的模型路徑(models)。我們測試的圖片都在images資料夾裡。在此處有坑。作者提供了4張image做測試,因為測試完的影象會輸出到images資料夾裡,所以做完一次測試,images資料夾會有8張圖片(輸出圖片命名規則是在原影象檔名後面加上"_det"),而原作者沒有把他自己測試後的圖片刪去,所以大家在做demo測試時,別忘把以"_det"結尾的檢測輸出檔案先刪去,否則測試完你的images資料夾可能會得到16張影象。。
當然,你可以放一些你自己在網上搜的圖片在images資料夾裡進行demo測試,看看效果。但檢測類別一定在訓練的類別中要有啊~
VOC2007資料集的類別在路徑"/faster-rcnn.pytorch/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','plane')

放出一個識別網上的圖片還不錯的例子:
幾隻小鳥
在測試的時候,如果沒有gpu,則在命令列中不輸入"–cuda"。但使用python3.5的朋友可能會遇到以下錯誤:

//weakref.py出錯
  Exception ignored in: <function WeakValueDictionary.__init__.<locals>.remove at 0x7f294b5c0730>
    Traceback (most recent call last):
      File "/anaconda2/envs/py35/lib/python3.5/weakref.py", line 117, in remove
    TypeError: 'NoneType' object is not callable

解決方法如下:
https://github.com/python/cpython/commit/9cd7e17640a49635d1c1f8c2989578a8fc2c1de6#diff-a2f8f044364f136b5879679b60c19172
修改weakref.py後可完美解決。

訓練自己資料集

當你走到這一步,恭喜,你馬上就可以為所欲為了。在此只介紹適合於新手(我就是)的傻瓜式資料集製作方法。
我們以一個只檢測一類的資料集為例,我這裡是自己標註的飛機測試集,類別名稱為“plane”。

我們仍然採用VOC2007資料集的類。皮不變,只是把我們自己的資料集“塞進去”

---VOC2007
    ------Annotations
    ------ImagesSet
         ---------Main
    ------JPEGImages

真正“起作用”的訓練集其實是這四個資料夾,位置是

faster-rcnn.pytorch/data/VOCdevkit/VOC2007/

1.Annotations為標註資料夾,若干.xml檔案。每一個圖片都對應一個.xml檔案,其中儲存的是該圖片的名稱,長寬,目標框(GroundTrues)的左上右下座標,目標框的類別名稱。

2.ImagesSet資料夾下的Main裡,儲存了需要訓練圖片的名稱,以txt文字儲存。

3.JPEGImage資料夾儲存了原圖片。

所以看到這,你就明白,怎麼把我們的資料集塞進去了。
首先把我們的原圖塞進JPEGImage資料夾裡。當然原資料夾的圖片我們需要備份,並從JPEGImage裡移除。

然後,需要製作我們自己資料集的xml標註檔案,朋友們如果想問做出的xml檔案標準是啥樣的,因為不同的標註軟體生成的標註檔案五花八門,和VOC一樣的xml檔案怎麼製作?在此給個傳送門,大家耐心學習:

https://blog.csdn.net/gvfdbdf/article/details/52214008
https://blog.csdn.net/zcy0xy/article/details/79614862

在此也給出如何更改xml檔案中屬性值的方法,也是本人第一個github程式碼~連結如下:

https://github.com/XinZhangNLPR/Xml-document-modify.git

用這個程式碼可以任意改變xml裡的屬性值,比如你想把xml檔案中類別名稱改變,或把圖片名稱、路徑等值改變,參考上述程式碼連結。
在此放出我自己的資料集標註xml檔案:
xml檔案
圖中畫圈的屬性,需修改與VOC一樣,folder應修改為"VOC2007",類別的name屬性,也可修改為你想識別的類別,在此我將所有目標的name都改為"plane",修改程式碼見上述的github程式碼。
在所有xml檔案修改後,將它們放入Annotations資料夾中。

最後,自己製作trainval.txt,裡面儲存自己的待訓練圖片名稱,記住不要帶.jpg字尾,這個很簡單如下圖所示:
trainval.txt

製作好後將該檔案放入ImagesSet\Main

彈藥已裝好,下面需要為炮臺調準方向!修改python檔案。Ok我承認需要更改的幾個坑真的坑了我一個晚上。。
第一處:faster-rcnn.pytorch/lib/datasets/pascal_voc.py
pascal_voc
這個檔案裡存著VOC資料庫的class,需要更改我們識別的類別,我的做法是把原class註釋掉,把自己的class加進去,如圖,加入’plane’類,看到這你也許就知道啦,這裡的類名和前面xml檔案中,目標的name屬性應該是一樣的。

第二處:發生如下錯誤:

assert(boxes[:,2]>=boxes[:,0]).all()

基本上都會碰上,只要是你標註的框靠近邊緣,都會出這個錯誤,不用急,按照下面方法改,完美解決:

https://blog.csdn.net/xzzppp/article/details/52036794

第三處:發生如下錯誤:

Keyerror:'width'

OK,彆著急,一帆風順是不可能的,該句指的是得到的影象資料庫imdb檔案沒有‘width’,也就是沒有讀到影象的寬度值,而這個寬度值是通過圖片讀出來的,所以說明你的訓練資料夾JPEGImage中沒有ImagesSet\Main\trainval.txt裡列出的圖片,我查了下,圖片都放進去了,那為啥還出錯呢?
原因是!在訓練原資料集VOC時,影象數量是10021張(進行了資料增強),這時會儲存訓練資訊至快取中,檔案路徑為:

/home/zhangxin/faster-rcnn.pytorch/data/cache/voc_2007_trainval_gt_roidb.pkl

因此你在重新訓練新資料集的時候,會讀取這個快取配置,以加快訓練,那麼此時就入坑了,我的新集合只有1000張,所以訓練時讀的快取裡,需要讀的影象還是原來那10021張,那勢必會找不到這10021張影象,所以要做的就是,把這個快取檔案voc_2007_trainval_gt_roidb.pkl刪掉!

改完此處,可以完美進行訓練,當然訓練命令列不用變,怎麼樣,夠傻瓜吧~
訓練

第五處:faster-rcnn.pytorch/demo.py
訓完後,很想demo一下,看看訓出來的模型如何,如果你覺得能順利進行的話,那就圖樣圖森破了,你會陷入第五個坑:
demo
我們會發現,他說我們訓的模型,預測層是兩個節點(代表2類,飛機+背景),而測試的時候,發現模型是21類(原資料集的類數,20類+背景)。開始以為是訓練前網路的輸出類別數沒有設定好,於是加各種斷點找原因,但發現訓練時的網路預測的類數就是2類。

//此處普及下設定斷點程式碼
 import pdb;pdb.set_trace()

於是機智的我又好好想了一下,那一定是測試的時候出錯了,,而且上圖錯誤資訊也已經說了,是demo.py出問題了,於是,修改方法就有了,需修改demo.py檔案:
demo2
跟更改pascal_voc,py方法類似,更改自己訓練集的類別。。

好了,設定完以上內容,我們就可以開始測試啦!
走一波小飛機!
小飛機
有的個別效果不是很好,因為沒有調參,而且訓練集只有1000張,還沒有做資料增強,不過這都不是重點,重點是掌握了訓練自己資料集的技能!
最後給出一個小技巧,faster-rcnn對於每個圖片會給出300個檢測框,顯示的時候,會限制最大顯示框數量,同志們可以在以下路徑的檔案net_utils.py裡修改。

/home/zhangxin/faster-rcnn.pytorch/lib/model/utils/net_utils.py

fix

接下來工作

學無止境,這只是最舒服的應用新資料集的方法,還有很多其他方法,比如為你的新資料集建立類,正如pascal_voc.py檔案中所做的工作一樣~

參考文獻

[1]https://blog.csdn.net/sinat_30071459/article/details/51332084
[2]https://blog.csdn.net/hongxingabc/article/details/79039537
[3]https://blog.csdn.net/gvfdbdf/article/details/52214008
[4]https://blog.csdn.net/xzzppp/article/details/52036794
[5]https://blog.csdn.net/sinat_30071459/article/details/50723212