Mask R-CNN
- 2020 年 8 月 9 日
- 筆記
Mask R-CNN
論文:Mask R-CNN
0. 簡介
先有請作者自己介紹一下這項工作——摘要:
-
提出一個通用的Object Instance segmentation模型,同時檢測+分割,速度5fps。
-
基於Faster-RCNN,與BoundingBox預測分支平行加了一個Mask預測分支(FCN)。
-
能用於其他任務,如人體姿態估計。
-
沒有用花里胡哨的Tricks,希望它能成為Instance-Level Recognition研究的”solid baseline”(現在看,何愷明大神確實說到做到了)
MaskRCNN做為雙階段實例分割的代表作,是入門實例分割領域值得或者說必須學習的經典。整體沿用目標檢測領域FasterRCNN的思想,在最後的Head部分加入與邊框分類及回歸平行的另外一個分支來預測此框內的Mask。
接下來:
-
首先簡單回顧FasterRCNN模型結構
-
MaskRCNN模型結構
-
ROI Align(來源於ROI pooling的mis-alignment問題)
-
Mask預測及分類的解耦(LossFunction)
-
實驗
1.Faster RCNN
雙階段目標檢測算法,如上圖所示整體流程:
- 首先用ResNet-FPN做BackBone提取特徵
- 然後RPN(Region Proposal Network)得到FeatureMap中的ROI
- 使用RIO pooling處理RIO變成固定尺寸
- Head部分做邊框的分類與回歸
ResNet-FPN
因為FasterRCNN和MaskRCNN採用的都是ResNet-FPN主幹網絡,所以這裡先介紹,在熟悉ResNet的基礎上看一下ResNet-FPN:
FPN(Feature Pyramid Network)是一種旨在解決多尺度問題而提出的算法,下圖(a)(c)(d)展示了三種典型的多尺度問題處理方式:(a)將圖片縮放為不同size,(c)使用不同層次的FeatureMap,(d)特徵金字塔網絡。
FPN結構中包括自下而上,自上而下和橫向連接三種,如下圖所示。這種結構可以將各個層級的特徵進行融合,使其同時具有強語義信息和強空間信息。
FPN是一種通用結構,可以結合各種backbone使用,下圖及為ResNet-FPNd的整體結構。最終產生的是特徵金字塔[P2, P3, P4, P5](其實還有P6,圖中缺少了)。那麼其後的RPN網絡在哪張特徵圖上產生ROI呢?FPN會利用一個公式選擇最合適尺度的FeatureMap來切ROI,詳情請見FPN的論文。

2.Mask RCNN
正如作者自己在論文中所說」Mask R-CNN is simple to implement and train given the Faster R-CNN framework「,確實只需要在FasterRCNN中的ROI Pooling(實際是改進後的ROI Align)後加入一個Mask分支——FCN(Fully Convolutional Networks)對每個ROI預測MasK即可,在這之前都與FasterRCNN相同。可以看出,MaskRCNN算法對於FasterRCNN有兩個重點:ROI Align、Mask預測分支,下面兩節詳細介紹:
3.ROI Align
ROI pooling & 缺陷
ROI pooling方法:在一張feature map中截取ROI,並將此ROI池化為規定大小。簡單的例子就能明白:假設現在有一個8×8大小的feature map,我們要在這個feature map上得到ROI,並且進行ROI pooling到2×2大小的輸出。假設ROI的bounding box為[x1, y1, x2, y2] = [0, 3, 7, 8]。將它劃分為2×2的網格,因為ROI的長寬除以2是不能整除的,所以會出現每個格子大小不一樣的情況。進行max pooling的最終輸入2×2的結果。
但ROI pooling方法存在不對齊(mis-alignment)問題,在目標檢測領域還好,但對於分割這一像素級任務就會有致命性問題。mis-alignment主要來源於兩次取整操作:
- x,y,w,h的取整。(上述例子中我們給的ROI位置為整數,但實際通過RPN得到的區域並不是整數的)
- 劃分小格時除不盡取整。(正如上面例子ROI寬為7,要分成2小格,不能整除,須取整)
ROI Align
ROI Align為了解決不對齊問題,將以上兩次取整操作全部保留本來的浮點數,重新設計了算法。為了保留浮點數,採用了雙線性插值,關於雙線性插值看下圖就可明白,計算公式可以自行百度,簡而概之關鍵,普通線性插值確定一點的值需要兩個點,雙線性插值需要四個點。
ROI Align操作。如下圖,虛線部分表示feature map,實線表示ROI,假設期望輸出ROI為2×2。若採樣點數是4,那我們首先將每個單元格子均分成四個小方格(如紅色線所示),每個小方格中心就是採樣點。這些採樣點的坐標通常是浮點數,所以需要對採樣點像素進行雙線性插值(如四個箭頭所示),就可以得到該像素點的值了。然後對每個單元格內的四個採樣點進行maxpooling,就可以得到最終的ROIAlign的結果。
使用ROI Align代替ROI pooling後,效果有十分顯著提升,實際效果:
4.Mask解耦(LossFunction)
MaskRCNN的總體損失函數為:
$$
L=L_{cls}+L_{box}+L_{mask}
$$
其中前兩項為框分類與回歸損失,與FasterRCNN一樣,這裡不再展開。 最後一項為Mask分割損失,是一個per-pixel sigmoid,假設一共有K個類別,則mask分割分支的輸出維度是 , 對於
中的每個點,都會輸出K個二值Mask(每個類別使用sigmoid輸出)。需要注意的是,計算loss的時候,並不是每個類別的sigmoid輸出都計算二值交叉熵損失,而是該像素屬於哪個類,哪個類的sigmoid輸出才要計算損失(如圖紅色方形所示)。並且在測試的時候,我們是通過分類分支預測的類別來選擇相應的mask預測。這樣,mask預測和分類預測就徹底解耦了。
這與FCN方法是不同,FCN是對每個像素進行多類別softmax分類,然後計算交叉熵損失,我們知道softmax輸出所有項之和等於1,每項數值可以認為是概率,這樣會造成類間競爭,而每個類別使用sigmoid輸出並計算二值損失,可以避免類間競爭。實驗表明,通過這種方法,可以較好地提升性能。
Sigmoid與Softmax對比實際提升效果:
5.代碼 實驗
學習過程中閱讀了代碼(pytorch)來理解算法,也進行了簡單的驗證實驗。
- 代碼學習推薦:pytorch-mask-rcnn
算法實現清晰明了,沒有多餘的東西,學習成本低,但使用的是pytorch0.4需要cuda9版本,我們的環境為cuda10不兼容,所以實際驗證實驗選擇在Fackbook官方框架實現的Detectron2中進行。(大概目前多數人都已經不使用cuda9版本了吧,如果只有單一cuda10環境但想要使用此代碼可以整一個容器環境,安裝cuda9即可)。
- 使用官方框架Detectron2進行驗證實驗:Detectron2
使用官方訓練好的ResNet101-FPN參數直接在COCO上運行:Mask的AP為38.629,與文章38.2基本符合甚至略高。
自己在COCO上訓練所得結果:Mask的AP為36.823,略低於官方數據,應該是訓練時由於顯卡顯存限制,我把batch_size由16改為4,影響了BN的效果所致。
參考及引圖:
//openaccess.thecvf.com/content_iccv_2017/html/He_Mask_R-CNN_ICCV_2017_paper.html
//medium.com/@jonathan_hui/image-segmentation-with-mask-r-cnn-ebe6d793272