深度學習目標檢測之 R-CNN 系列:Faster R-CNN 網絡詳解
深度學習目標檢測之 R-CNN 系列包含 3 篇文章:
1. 前言
這一篇文章主要是深入的理解 Faster R-CNN 網絡結構。
爲了深入的瞭解 Faster R-CNN,我這裏 clone 了一份 caffe 版本的 py-faster-rcnn,方便查看源代碼。如果編譯過程遇到 CUDNN 版本問題,可以參考 Caffe編譯時提示 CUDNN 版本不兼容的解決辦法 。
如果想對 Faster R-CNN 文件層次有更深入的認識,可以參考 Faster RCNN算法demo代碼解析 。
2. Faster R-CNN 網絡概覽
下圖大致描述了 Faster R-CNN 的過程。
下面這幅圖可能更清楚的表達了 Faster R-CNN 是如何工作的。只是需要注意的是下圖是 test 網絡。
-
- 將圖片輸入 CNN 網絡(比如 ZF/VGG 等預訓練好的分類模型),得到 feature maps;
-
- 將 feature maps 喂入 RPN(Region Proposal Network) 網絡得到 region proposals (包含第一次迴歸)。更具體的,RPN 首先生成一堆Anchor box,對其進行裁剪過濾後通過 softmax 判斷 anchors 屬於前景(foreground)或者背景(background),即是不是物體,所以這是一個二分類任務;同時,另一分支 bounding box regression 修正(迴歸) anchor box,形成較精確的 proposal,注意這並是最後得到的 proposal,後面還會再進行第二次迴歸;
-
- 將上兩步的輸出:feature maps 和 region proposals 喂入 RoI Pooling 層得到統一 size 的 feature maps;
-
- 將 3 輸出的 feature maps 輸入全連接層,利用 Softmax 進行具體類別的分類,同時,利用 L1 Loss 完成 bounding box regression 迴歸(第二次迴歸)操作獲得物體的精確位置。
3. CNN
這裏的 CNN 網絡也可以叫做 conv layers,因爲就是 conv + ReLU + Pooling 的組合,是沒有 fc 層的。以 VGG16(13 個 conv + 3 個 fc) 爲例,這裏僅僅保留了其 13 個 conv 層。
4. RPN
下圖是 RPN 網絡圖,通過兩個 1x1 的卷積層(conv)將 feature map 的 channel 分別變爲 18 和 36,分別用來做分類和 bonding box 迴歸。這裏面最爲關鍵的 layer 就是 rpn-data,幾乎所有核心的功能也都是在這個 layer 中完成。
4.1 rpn-data layer
下面我們來重點看一下 rpn-data layer。
layer {
name: 'rpn-data'
type: 'Python'
bottom: 'rpn_cls_score'
bottom: 'gt_boxes'
bottom: 'im_info'
bottom: 'data'
top: 'rpn_labels'
top: 'rpn_bbox_targets'
top: 'rpn_bbox_inside_weights'
top: 'rpn_bbox_outside_weights'
python_param {
module: 'rpn.anchor_target_layer'
layer: 'AnchorTargetLayer'
param_str: "'feat_stride': 16"
}
}
這裏的 rpn-data 的類型是 AnchorTargetLayer。具體的代碼可以參考
py-faster-rcnn/lib/rpn/anchor_target_layer.py
關於 AnchorTargetLayer 的解讀可以參考:
總的來說,這層幹了如下這些事情。
-
生成 anchor,並將超出圖像區域的anchor去除,得到有效的 anchor;
-
給每一個 anchor 分配 label,-1表示忽略該 anchor,0表示背景,1表示前景(物體),得到 labels;
-
計算 RPN 階段的迴歸目標 bbox_targets;
-
計算 bbox_inside_weights(將 label 爲 1 的 anchor 權重賦爲 1,其他的都賦爲 0)、bbox_outside_weights(將前景和背景 anchor 的總數記爲 n,則前景和背景 anchor 權重都賦爲 1/n,其它的 anchor 權重都賦爲 0),在計算 SmoothL1Loss 時用於加權;
-
上述過程得到的 labels, bbox_targets, bbox_inside_weights, bbox_outside_weights,它們第一個維度的長度和有效 anchor 的個數是相同的,最後對它們進行擴充,將無效的 anchor 所對應的 labels, bbox_targets, bbox_inside_weights, bbox_outside_weights 分別加入其中,使這四個輸出的第一個維度的長度等於生成anchor的個數。
4.2 Softmax with Loss
這個是 caffe 標準的 layer, 就是對 softmax 的輸出求 crossentropy loss。對於 RPN 而言就是一個二分類的交叉熵損失函數。
4.3 BBox 迴歸
假設我們對 anchor a 進行迴歸得到 predicated bbox p,那我們歸一化的目標是希望 p 無限接近於 ground true(標記的結果)t。
在二維平面上,從矩形框 p 變換到矩形框 t,顯然就是平移和縮放操作。假設 分別爲 p 的中心座標及寬和高; 分別爲 a 的中心座標及寬和高; 分別爲 t 的中心座標及寬和高。那麼從 p 到 a 的變換可以表示如下。
上面的 部分都是基於 計算出來的,表示如下。
其中 是預測的偏移量。根據上面的兩個式子可以將其表示如下。
同理。
這裏需要注意下面幾個問題:
-
爲什麼上面要用到 或者 ,上面可以看到 用來表示 scale 係數,顯然 scale 係數應該大於零,所以用 表示正好可以滿足,那爲什麼用 呢? 一個很重要的特性就是壓縮大值,也就是說採用這種 loss 可以減小大的目標對最後結果的影響,這樣可以改善模型只能學到大的目標的缺點。
-
對於 採用的是線性變化,但是對於 卻是用的非線性變化,這樣合理嗎?其實當 a 趨近於 t 時,可以認爲 是線性變化。
4.4 Smooth L1 Loss
Smooth L1 Loss 的數學表達式如下。
對於邊框預測迴歸問題,通常也可以選擇平方損失函數( L2 損失),但 L2 範數的缺點是當存在離羣點(outliers) 的時候,這些點會佔 loss 的主要組成部分。比如說真實值爲1,預測 10 次,有一次預測值爲 1000,其餘次的預測值爲 1 左右,顯然 loss 值主要由1000 主宰。所以 Fast RCNN 採用稍微緩和一點的絕對損失函數(smooth L1損失),它是隨着誤差線性增長,而不是平方增長。
注意:smooth L1 和 L1-loss 函數的區別在於,L1-loss 在 0 點處導數不唯一,可能影響收斂。smooth L1 的解決辦法是在 0 點附近使用平方函數使得它更加平滑。
更多內容可以參考 損失函數:L1 loss, L2 loss, smooth L1 loss。
5. RoI Pooling
ROI Pooling 的作用是將 RPN 輸出的 region proposal 轉換到相同的 size,然後再喂入 fc 層。RoI Pooling 還有一個進化版本 RoI Align。關於RoI Pooling 和 RoI Align 的介紹可以參考 ROI Pool和ROI Align。
6. 損失函數
Faster R-CNN 總共有四個損失函數,RPN 的分類和迴歸損失函數, Fast R-CNN 的分類和迴歸損失函數。RPN 的損失函數上面已經講過,和 Fast R-CNN 的損失函數類似。Fast R-CNN 的分類損失爲多分類交叉損失, 迴歸損失依然爲 smooth L1 loss。
更爲詳細的介紹可以參考 [https://blog.csdn.net/Mr_health/article/details/84970776](【Faster RCNN】損失函數理解).
7. Anchor 的壓縮
在整個過程中對 Anchor 進行了四次壓縮,分別如下:
- 在最開始劃分 anchor 的時候,忽略超出邊界的 anchor,大約 17000 個左右;
- 在 RPN 中進行 background(iou < 0.3)和 foreground(iou > 0.7) 劃分時,忽略介於 0.3 和 0.7 之間的 anchor(標記爲 -1);
- 對每一個預測爲 foreground 的 anchor 的 score,進行排序,保留排名考前的大約 12000 個 anchor;
- 非極大值抑制(NMS),首先找到 score 最高的 anchor,然後以此 anchor 作爲基準,計算其他的 anchor 與這個 anchor 的 iou,如果 iou 大於閾值,就認爲是同一個目標,直接捨棄這個 anchor,最後大約剩餘 2000 個左右的 anchor。