Maskrcnn-benchmark利用自己的資料進行目標檢測和關鍵點檢測
介紹
本文主要利用了Facebook開源的Maskrcnn-benchmark來進行一個自己的專案,該專案的主要任務是對圖片中的電錶位置進行定位以及進行關鍵點的檢測。網上對Maskrcnn-benchmark訓練自己的資料大都集中在如何用於目標檢測的任務上,對關鍵點檢測的應用很少涉及,這篇文章對兩者都作一個闡述。(該文章最開始是我寫在CSDN上面的,現在打算搬運到知乎)
目錄
0 環境配置
1 目標檢測任務
1。1 資料準備
1。1。1 coco資料集的介紹
1。1。2 轉coco資料
1。1。3 資料檢驗
1。2 資料集在原始碼檔案中的組織結構
1。3 使用預訓練模型
1。4 原始碼檔案的修改
1。5 模型訓練
1。6 模型驗證
1。7 前傳
1。8 幾個常見的問題
2 關鍵點檢測任務
2。1 資料準備
2。2 原始碼檔案的修改
2。3 資料組織/訓練/驗證
2。4 前傳
0 環境配置
這一步假設機器裡面已經預裝了conda環境,請一定要耐心和細緻,按照要求一步步來,心態不要崩!!!首先按照官方各出的安裝步驟進行環境配置
注意:pytorch或pytorch night 的版本必須為1。0。0,torchvision版本也不能太舊,這裡使用0。2。2(這是個坑)!!! 安裝的時候需要安裝過去的版本,因此安裝命令需要給出版本,不然預設給定安裝最新的版本,那就呵呵了!
Requirements
PyTorch 1。0 from a nightly release。 It
will not
work with 1。0 nor 1。0。1。 Installation instructions can be found in
https://
pytorch。org/get-started
/locally/
torchvision from master
cocoapi
yacs
matplotlib
GCC >= 4。9
OpenCV
CUDA >= 9。0
Installation
conda create ——name maskrcnn_benchmark -y
conda activate maskrcnn_benchmark
conda install ipython pip
pip install ninja yacs cython matplotlib tqdm opencv-python
# pip install -i http://pypi。douban。com/simple/ ……
#如果速度慢可以考慮使用豆瓣的源
conda install -c pytorch pytorch-nightly torchvision
cudatoolkit=9。0
#上面的命令只能安裝最新版本,因此我們需要舊版本必須加上版本號,而且torchvision版本需要大於0。2。2
conda install -c pytorch pytorch-nightly=1。0。1 torchvision=2 。2。2 cudatoolkit=9。0
export INSTALL_DIR=$PWD
# install pycocotools
cd $INSTALL_DIR
git clone https://github。com/cocodataset/cocoapi。git
cd cocoapi/PythonAPI
python setup。py build_ext install
# install apex
cd $INSTALL_DIR
git clone https://github。com/NVIDIA/apex。git
cd apex
python setup。py install ——cuda_ext ——cpp_ext
# install PyTorch Detection
cd $INSTALL_DIR
git clone https://github。com/facebookresearch/maskrcnn-benchmark。git
cd maskrcnn-benchmark
#
python setup。py build develop
unset INSTALL_DIR
1 目標檢測任務
1.1 資料準備
Maskrcnn-benchmark支援voc和coco格式的資料,但voc格式似乎針對的任務比較單一,因此建議使用coco格式來準備自己的訓練資料。或者,如果自己有時間也可以嘗試寫一個自己的dataset類,仿照CocoDataset類來寫。
1.1.1 coco資料集的介紹
該部分網上各種教程很多,可自行甄別優質教程,關鍵是要全面,細緻。
1.1.2 轉coco資料
關於資料轉換部分,每個任務有每個任務的具體情形,無法一概而論,不過只要把coco資料集的基本結構瞭解了,接下來就是依葫蘆畫瓢的寫一個coco格式的。json檔案。這一步可能會比較耗費時間,但是如果耐心一點,也能很快寫出來。可以參照網上諸多的例如voc格式轉coco的程式碼,自己稍作修改一般能得到自己想要的結果。
1.1.3 資料檢驗
得到coco格式的資料之後最好是把標籤視覺化一下,當然如果嫌麻煩,可以先訓練,發現效果不行再回頭來核查資料。
1.2 資料集在原始碼檔案中的組織結構
假設你此時位於maskrcnn-benchmark/目錄下,datasets的組織結構如下
datasets
-> coco
-> annotations
-> instances_train2014。json //訓練標籤
-> instances_test2014。json //驗證標籤
-> train2014 //訓練圖片
-> val2014 //驗證圖
為了方便建議仿照上面這樣的coco標準命名,但上面的所有名字都不是一定要求這樣寫的,自己可以合理命名,只要程式中的各個與資料路徑有關的地方一一對應上即可。
1.3 使用預訓練模型
下面說明一下預訓練模型的使用,首先給出模型有關的配置檔案所在位置
maskrcnn-benchmark/configs/
裡面的所有。yaml檔案都可以使用,每一個裡面的有一個對應將使用的預訓練模型,訓練中會根據指定的配置檔案下載預訓練模型加以使用,在後面會進一步說明對。yaml檔案的更改和使用
1.4 原始碼檔案的修改
maskrcnn-benchmark/maskrcnn_benchmark/config/defaults。py
這是模型的一個總的預設配置檔案,需要作出一定修改
#此處解釋一下修改。MIN_SIZE_TRAIN ,。MAX_SIZE_TRAIN 的原因,***這裡如果設定的太大,很有可能會出現CUDA out of menmory的錯誤,這裡需要特別注意!!!***
#Size of the smallest side of the image during training
_C
。
INPUT
。
MIN_SIZE_TRAIN
=
(
400
,)
# (800,)
#Maximum size of the side of the image during training
_C
。
INPUT
。
MAX_SIZE_TRAIN
=
667
#Size of the smallest side of the image during testing
_C
。
INPUT
。
MIN_SIZE_TEST
=
400
#Maximum size of the side of the image during testing
_C
。
INPUT
。
MAX_SIZE_TEST
=
667
#下面的兩處修改也需要特別注意!!!必須和自己的類別相對應,如果沒有分類,那麼就為2
_C
。
MODEL
。
ROI_BOX_HEAD
。
NUM_CLASSES
=
2
#類別數量加1
_C
。
MODEL
。
RETINANET
。
NUM_CLASSES
=
2
#類別數量加1
configs/xxx。yaml檔案的修改
以
maskrcnn-benchmark/configse/2e_mask_rcnn_R_50_FPN_1x。yaml為例
下面藍色圈出來的地方必須修改:
一個是類別,如果這裡面沒有類別,與default。py中的一致,那麼程式會自動在defaults。py中尋找。
特別還有一個是DATASETS,這個是用來指定本次訓練所使用的資料集,為了方便我這裡沒有修改,就借用了coco_2014_train的名字,名字可以隨意起,但是在
maskrcnn-benchmark/maskrcnn_benchmark/config/paths_catalog。py
中需要有對應的資料集的路徑描述,且該路徑要與datasets/coco/裡面的檔案對應起來
BASE_LR,迭代次數,儲存間隔根據自己模型需要而定
maskrcnn-benchmark/maskrcnn_benchmark/config/paths_catalog.py
這裡面是對模型的所有資料集路徑的配置,前面。yaml檔案中指定的資料集必須在這裡面存在,譬如:下圖中紅色圈出來的就是和上面。yaml配置檔案相對應的資料集路徑。該路徑告訴了程式需要到coco/train2014;coco/annotations/instances_train2014。json去找訓練資料。
1.5 模型訓練
上面的資料準備,原始碼更改完畢後,就可以開始訓練任務了。
~/maskrcnn-benchmark$ python tools/train_net。py ——config-file configs/e2e_mask_rcnn_R_50_FPN_1x。yaml
模型首先會去下載預訓練模型,然後開始訓練過程,輸出的訓練日誌到
maskrcnn-benchmark/output/log。txt
同時訓練完畢後模型也會被儲存在
maskrcnn-benchmark/output/
路徑下xxx。pth即為輸出模型
1.6 模型驗證
前面的訓練完畢會給出對最終的輸出模型
maskrcnn-benchmark/output/model_final。pth
的驗證結果,一系列的AP值。但是我們隔一段迭代間隔就儲存了模型,現在要想驗證任意一箇中間模型該怎麼做呢?
首先複製一個e2e_mask_rcnn_R_50_FPN_1x。yaml重新命名為e2e_mask_rcnn_R_50_FPN_1x_predict。yaml
把WEIGHT這一行改成自己想要驗證的模型的路徑即可。比如上圖就是驗證迭代20000次的模型 然後執行
~/maskrcnn-benchmark$ python tools/test_net。py ——config-file configs/e2e_mask_rcnn_R_50_FPN_1x_predict。yaml
即可看到驗證結果
1.7 前傳
前傳過程需要仔細閱讀
maskrcnn-benchmark/demo/predictor.py
predictor.py
檔案包含了前傳過程的所有的程式碼,目標檢測,分割,關鍵點檢測等都有對應的前傳函式來處理! 看懂了predictor。py後,可以自己仿照著寫一個只用於目標檢測的前傳程式碼predict。py,其實就是將這一部分從predictor。py中摳出來。
主要使用的是coco_demo類中的compute_prediction方法
下面是一段示例程式碼:
predictions
=
coco_demo
。
compute_prediction
(
img
)
scores
=
predictions
。
get_field
(
“scores”
)
。
numpy
()
bbox
=
predictions
。
bbox
[
np
。
argmax
(
scores
)]
。
numpy
()
labelList
=
predictions
。
get_field
(
“labels”
)
。
numpy
()
#keypoints = predictions。get_field(“keypoints”)
#scores = keypoints。get_field(“logits”)
#kps = keypoints。keypoints
#kps = torch。cat((kps[:, :, 0:2], scores[:, :, None]), dim=2)。numpy()
#for region in kps:
#print(region。transpose((1, 0))[:2,])
#print(kps)
然後就可以把最終的bbox和型別(如果有的話)儲存在。csv檔案中儲存下來 最終的bbox輸出應當為兩個點
左上和右下
,這樣就確定了矩形定位框,達到了目標檢測的目的
為了說明前傳使用了哪個輸出模型,需要有一個。yaml檔案,可以和驗證過程使用同一個。yaml檔案,裡面指明需要使用的模型 output/xxx。pth
~/maskrcnn-benchmark$ python demo/predict ——config-file configs/e2e_mask_rcnn_R_50_FPN_1x_predict。yaml
1.8 幾個常見的問題
CUDA out of menmory :首先引起該問題的原因最可能是batch_size太大,需要去defaults。py中手動修改,但是如果調到1了還是報錯,那就是前面說的defaults。py中的MIN_SIZE_TRAIN ;MAX_SIZE_TRAIN……設定得太大,調小即可
loss NAN的錯誤,一般可以透過調小上面。yaml中的BASE_LR解決
幾乎所有問題都可以在源工程的issues下面找到
2 關鍵點檢測任務
由於任務的需要,對於輸入圖片中歪斜的目標,單單的目標定位框還無法滿足需求,這時更希望檢測出目標的幾個關鍵點來定位目標的具體位置和方向,因此還需要作一個關鍵點檢測的任務。原始碼中的關鍵點任務是對行人姿態的17個關鍵點進行檢測的,而我們的任務其實只需要檢測4個關鍵點,也即矩形的4個角點。
2.1 資料準備
相比於單純的矩形定位框檢測,對於關鍵點的檢測還需要在coco資料集中增加keypoints資料才能實現。
給coco的。json檔案的annotation增加兩個欄位:
‘keypoints’:[x0,y0,2,x1,y1,2,x2,y2,2,x3,y3,2] ‘num_keypoints’:4
解釋:x0,y0,x1,y1。。。表示關鍵點的座標,2表示該關鍵點是可見的且標註了。如果是1則表示標註了但不可見(譬如遮擋),是0則表示無關鍵點。
另外,給categories增加
‘keypoints’:[‘point0’,‘point1’,‘point2’,‘point3’], ‘skeleton’:[[0,1],[1,2],[2,3],[0,3]]
解釋:‘point0’,‘point1’,‘point2’,‘point3表示關鍵點的名字,’skeleton‘關鍵點之間的連線關係。需要根據自己的關鍵點的意義合理選擇更改。
2.2 原始碼檔案的修改
maskrcnn-benchmark/maskrcnn_benchmark/data/datasets/coco。py
第10行min_keypoints_per_image = 10改為min_keypoints_per_image = 1,因為我們只有四個關鍵點,如果該值大於4,則無法生成dataset。
這裡是一個很坑的的點,如果不修改,你會發現你的程式碼永遠讀不到資料!!!
maskrcnn-benchmark/maskrcnn_benchmark/config/defaults。py
_C。MODEL。ROI_KEYPOINT_HEAD。NUM_CLASSES = 17 改為 4 //原始碼是對行人姿態關鍵點定位,共17個關鍵點,我們只有4個關鍵點,因此需要對應。
maskrcnn-benchmark/maskrcnn_benchmark/structures/keypoints。py
原始碼的任務和我們的不同,因此要作出修改,譬如的對於我的任務就會作如下修改:
2.3 資料組織/訓練/驗證
同前面內容
2.4 前傳
前傳過程同樣是需要仔細閱讀
maskrcnn-benchmark/demo/predictor.py
predictor.py
檔案包含了前傳過程的所有的程式碼,目標檢測,分割,關鍵點檢測等都有對應的前傳函式來處理!下面的兩段段程式碼便為前傳過程中關鍵點匯出處理的部分,視覺化關鍵點!
仿照上面的程式碼可以自己重寫一個predict_keypoint。py,專門用作關鍵點的輸出和視覺化!對於傳入vis_keypoints的kps引數,其前兩行(座標)形式如下:
上面的輸出代表的測試的是兩幅電錶圖片,第一幅圖片輸出了6組(因為原圖上面可能存在多個錶盤,每一組可能代表一個電錶的錶盤)可能的關鍵點,第二幅圖片輸出了3組可能的關鍵點。每組有四個關鍵點:kp1,kp2,kp3,kp4。
下面給出寫出的部分前傳程式碼:
# for img_name in img_names:
df= pd。DataFrame(columns=[’x0‘, ’x1‘, ’x2‘, ’x3‘,’y0‘, ’y1‘, ’y2‘, ’y3‘])
for i, img_name in enumerate(tqdm(img_names)):
#print(img_name)
path = os。path。join(imgs_dir, img_name)
image = load(path)
# compute predictions
predictions = coco_demo。compute_prediction(image)
keypoints = predictions。get_field(“keypoints”)
scores = keypoints。get_field(“logits”)
kps = keypoints。keypoints
kps = torch。cat((kps[:, :, 0:2], scores[:, :, None]), dim=2)。numpy()
df。loc[img_name] = list(np。reshape(kps[0]。transpose((1, 0))[:2, ],(8,)))
df[’filename‘]=img_names
df。to_csv(’/home/hs/qyl_project/maskrcnn-benchmark_kps/forward/keypoints10k。csv‘,index=None)
#xy=pd。read_csv(’/home/hs/qyl_project/maskrcnn-benchmark_kps/forward/keypoints。csv‘)
xy=df
img_names=xy[’filename‘]
#img_path=’/home/hs/qyl_project/maskrcnn-benchmark_kps/forward/kpsForwardImgs‘
for i in range(len(img_names)):
fname=os。path。join(imgs_dir,img_names[i])
img = cv2。imread(fname)
point_size = 3
point_color = (0, 255, 0) # BGR
thickness = 4 # \u53ef\u4ee5\u4e3a 0 \u30014\u30018
points_list = [(int(xy[’x0‘][i]),int(xy[’y0‘][i])), (int(xy[’x1‘][i]),int(xy[’y1‘][i])), (int(xy[’x2‘][i]),int(xy[’y2‘][i])),(int(xy[’x3‘][i]),int(xy[’y3‘][i]))]
for point in points_list:
cv2。circle(img, point, point_size, point_color, thickness)
cv2。imwrite(os。path。join(’/home/hs/qyl_project/maskrcnn-benchmark_kps/forward/kpsForwardResults10k‘,img_names[i]), img)
參考文獻
【1】
https://
zhuanlan。zhihu。com/p/66
283696
【2】
https://
zhuanlan。zhihu。com/p/64
605565
上一篇:地面找平有幾種方法_地面找平步驟
下一篇:如何看待百萬英雄題目出錯?