R-FCN 原理
R-FCN作者指出在圖片分類網絡中具有平移不變性(translation invariance),而目標在圖片中的位置也並不影響分類結果;但是檢測網絡對目標的位置比較敏感.因此Faster R-CNN將ROI的特征提取操作放在了最后分類網絡中間(靠后的位置)打破分類網絡的平移不變性,而不能直接放在網絡的末尾.但是這樣存在的問題是ROI特征提取不共享計算,導致計算量較大.
一般來講,網絡越深,其具有的平移旋轉不變性越強,這個性質對於保證分類模型的魯棒性有積極意義。然而,在檢測問題中,對物體的定位任務要求模型對位置信息有良好的感知能力,過度的平移旋轉不變性會削弱這一性能。研究發現,對於較深的全卷積神經網絡(Inception、ResNet 等),Faster-RCNN檢測框架存在着一個明顯的缺陷:檢測器對物體的位置信息的敏感度下降,檢測准確度降低。一般來講最直觀的解決方法是將RPN的位置向淺層移動(比如在ResNet中將RPN嵌入到conv4_x的位置),但這樣做會明顯增加 Fast-RCNN 部分的計算量,使得檢測速度明顯變慢。[1]
R-FCN正是為了解決這一問題,其采用巧妙的方式將ROI的計算部分共享,減輕了頭部的大小(后來出現的Light-head R-CNN更進一步).在VOC2007測試集上mAP達83.6%,比Faster R-CNN有所提升.同時速度提高2.5~20倍.
為了引入平移敏感性,作者在全卷積網絡的最后層之后添加了一個1x1卷積層輸出position-sensitive score map.每張score map中存放的是所有目標的某一部位的特征圖.每個目標被分成\(k\times k\)個網格區域(同Faster R-CNN的ROIPooling的參數,k通常取7或14等. score map的數量設置為\(k^2(C+1)\),對應ROI的\(k\times k\)個bin的特征圖.示意圖如下:
在位置敏感特征圖之后接上Position-sensitive RoI pooling:
輸入特征圖上的第(i,j)個bin位置的值為第(i,j)個score map上該bin對應位置的均值(這里采用了average pooling 的過程,當然用 max pooling 也可以),這樣得到一個通道數為C+1的\(k\times k\)大小的特征圖對應C+1個類別的得分,對每個類別的得分求和(或求平均)作為每個類別的score,然后通過softmax得到最大值對應的類別作為輸出.
所謂"位置敏感",其主要思想是在特征聚集時人工引入位置信息,從而有效改善較深的神經網絡對物體位置信息的敏感程度。
position-sensitive regression
與Faster R-CNN類似,接上與position-sensitive score map並列的回歸層(1x1卷積,輸出(bg/fg)x(dx, dy, dw, dh)x(score_maps_size^2)),在經過RoI pooling后每一個RoI會得到 4 個偏移量(這里在實現時還分背景/前景,所以是8個數值)。
計算速度提升: PSROI Pooling通過對ROI共享特征圖的方式, 以及通過用全局平均池化代替全連接層進行分類特征提取, 提高了計算速度.
在該網絡框架下,所有可學習的層,都是卷積形式,在訓練時可以很方便地進行 Online Hard Example Mining (OHEM, 在線難樣本挖掘) ,幾乎不會增加訓練時間。[2] 相比之下OHEM Fast R-CNN方法會使訓練時間加倍(A. Shrivastava, A. Gupta, and R. Girshick. Training region-based object detectors with online hard example mining. In CVPR, 2016.).
損失函數
分類的softmax損失加前景目標的回歸損失.
分類
R-FCN分類分支中支持兩種不同的方法: 類敏感和類無關: class-aware and agnostic, 這兩者的區別: [3]
class-agnostic 方法對每個目標框輸出8個數值(2類fg/bg x 4坐標), 而class-aware輸出(cls+1)x4個.agnostic 方法占用內存更少,運行速度更快. mAP跟訓練有關,可能會有些差別.
class-agnostic 方法通常作為預處理器,后邊需要接上分類器進一步對目標框進行分類.
Atrous 技巧
作者將最后1個池化層的步長從2減小到1,那么圖像將從縮小32倍變成只縮小16倍,這樣就提高了共享卷積層的輸出分辨率。而這樣做就要使用Atrous Convolution算法,具體參見論文Semantic Image Segmentation With Deep Convolutional Nets and Fully Connnected CRFS
實驗結果,通過下表可以看出訓練時RPN產生300個ROI, 結果就已經足夠好,沿用Faster R-CNN的2000的設置,反而有所下降. 另外可看出OHEM可以將結果提高3個百分點, 並且使用 OHEM 不會給訓練帶來額外的時間消耗.
R-FCN C++版
R-FCN C++版代碼取自原作者的官方PR: Microsoft/caffe/pull/107 ,
我將其集成到了我的C++版目標檢測caffe框架中: https://github.com/makefile/frcnn
RFCN OHEM 代碼理解
訓練時在前向傳播得到所有N個proposal的loss,從大到小排序后選擇前B個ROI進行反向傳播,其它的則忽略.而測試時和原來一樣,不做改變. 核心實現為BoxAnnotatorOHEM層, 使用方式如下:
layer {
bottom: "rois"
bottom: "per_roi_loss"
bottom: "labels"
bottom: "bbox_inside_weights"
top: "labels_ohem"
top: "bbox_loss_weights_ohem"
name: "annotator_detector"
type: "BoxAnnotatorOHEM"
box_annotator_ohem_param {
roi_per_img: 128
ignore_label: -1
}
propagate_down: false
propagate_down: false
propagate_down: false
propagate_down: false
}
注意到bottom里邊有個per_roi_loss 是每個roi的loss(SmoothL1Loss+SoftmaxWithLoss), 參數roi_per_img表示最大的 top N 個 RoI 用於反向傳播。 實現中使用std::sort(sorted_idx.begin(), sorted_idx.end(), [bottom_loss](int i1, int i2){return bottom_loss[i1] > bottom_loss[i2]; });
對loss值排序取前roi_per_img個作為輸出, 而其它roi被設置成被忽略的label(ignore_label=-1)和loss_weight=0.
另外,在設置上OHEM的一個區別是將bg_thresh_lo 設置為0, 不使用OHEM時設置為0.1(正樣本周圍的負樣本,這也算是一種簡單的難樣本挖掘方式,但是設置為0.1可能導致沒有樣本被選中,因此也可以設置成0). 將bg_thresh_lo 設置為0使得可以從更寬泛的樣本中選擇難樣本.