1. 程式人生 > >論文筆記:Fast(er) RCNN

論文筆記:Fast(er) RCNN

這也 物體檢測 因此 sele 疑惑 修正 width 輸入 重點

在 RCNN 初步試水取得成功後,研究人員又迅速跟進,針對 RCNN 中的幾點不足提出改進,接連推出了 fast-rcnn 和 faster-rcnn。關於這兩篇論文,網上相關的文章實在是多如牛毛,因此,本篇博文不打算深入講解,只是不落俗套地介紹一下它們改進的痛點,基本流程,以及我自己對一些小問題的理解。

RCNN 的問題

我們先回憶一下 RCNN 做了哪些事情:

  1. Selective Search 選出候選區域(region proposal);
  2. CNN 對這些區域提取特征;
  3. SVM 對 CNN 提取的特征進行分類預測;
  4. 一個簡單的線性回歸模型做 bounding box regression(就是對候選區域進行微調)。

原作者之一 rgb 在 Fast RCNN 的論文中就提出了 RCNN 幾個很明顯的短板。首先,訓練是分階段進行的。為了訓練 RCNN,我們需要對 CNN 進行訓練,然後,在用它提取的特征對 SVM 進行訓練,完了還要訓練一個線性回歸模型,實在煩瑣至極。其次,訓練過程很耗費時間和磁盤空間。因為 CNN 是在 Selective Search 挑選出來的候選區域上進行的特征提取,而這些區域很多都是重疊的,換句話說,很多卷積運算都是重復的,另外,CNN 提取的特征需要先保存下來,以便後續對 SVM 的訓練,而這些高維度的特征,占據的空間都是幾百 G 大小。第三,檢測過程很緩慢。這一點和第二點很類似,基本是由卷積運算的重復進行造成的。

Fast RCNN的改進

基本思路

針對 RCNN 這幾個短板,很容易想到的一個改進就是對 CNN 卷積操作的結果進行重復利用,也就是說,我們可以先用 CNN 對整幅圖片提取特征,得到某一層的特征圖(一般是取全聯接層前面的那一層),然後,用 Selective Search 對原圖提取候選框,根據相應的縮放比例,可以在特征圖上找出候選框對應的區域,直接用這些區域的特征作為候選區域的特征即可。這樣,我們相當於只在原圖上做了一遍卷積操作,而不是每個候選區域做一遍。

除此之外,為了簡化訓練的流程。作者把 SVM 分類器換成 Softmax,和 CNN 整合成一個網絡,同時把 bounding box regression 也整合進網絡中(相當於同一個網絡同時進行物體判別和區域微調)。這樣,可以在保證準確率的同時,提高訓練的效率。

Fast RCNN 的改進可以用下面兩幅圖概括。其中,左圖是原 RCNN 的做法,而右圖則是 Fast RCNN 的做法。

技術分享圖片

以上兩點基本就是 Fast RCNN 所做的改進了。替換 SVM 這一步是很容易實現的,整合線性模型的操作也可以借助 multi-task CNN 的思想實現,但共享卷積操作卻會遇到一個嚴重的問題。因為卷積得到的特征,最後都需要送入全聯接層進行降維等操作,而全聯接層輸入向量的維度必須是固定。由於我們現在是在 feature map 上,根據 SS 提取的候選區域,截取了一小塊區域的特征作為該區域的圖片特征,因此肯定不符合全聯接層的要求(原本的全聯接層是針對整個 feature map 的維度進行計算的)。所以下面重點分析一下論文是怎麽處理的。

ROI Pooling Layer

為了讓全聯接層能夠接收 Conv-Pooling 後的特征,我們要麽是重新調整 pooling 後的特征維度,使它適應全聯接層,要麽是改變全聯接層的結構,使它可以接收任意維度的特征。後者一個有效的解決方案是 FCN(全卷積網絡),不過 Fast RCNN 出來之時還沒有 FCN,因此它采用的是前一種思路。

那要如何調整 pooling 後的特征呢?論文提出了一種 ROI Pooling Layer 的方法(ROI 指的是 Region of Interest)。事實上,這種方法並不是 Fast RCNN 的原創,而是借鑒了 SPPNet 的思路。關於 SPPNet,網上資料很多,就不再贅述了,所以我開門見山講一下 ROI Pooling Layer 是怎麽處理的。假設首個全聯接層接收的特征維度是 \(H * W * D\),例如 VGG16 的第一個 FC 層的輸入是 7 * 7 * 512,其中 512 表示 feature map 的層數。那麽,ROI Pooling Layer 的目標,就是讓 feature map 上的 ROI 區域,在經過 pooling 操作後,其特征輸出維度滿足 \(H * W\)。具體做法是,對原本 max pooling 的單位網格進行調整,使得 pooling 的每個網格大小動態調整為 \(\frac{h}{H} * \frac{w}{W}\)(假設 ROI 區域的長寬為 \(h * w\))。這樣,一個 ROI 區域可以得到 \(H * W\) 個網格。然後,每個網格內依然采用 max pooling 操作。如此一來,不管 ROI 區域大小如何,最終得到的特征維度都是 \(H * W * D\)

下圖顯示的,是在一張 feature map 上,對一個 5 * 7 的 ROI 區域進行 ROI Pooling 的結果,最後得到 2 * 2 的特征。

技術分享圖片

這時,可能有人會問,如果 ROI 區域太小怎麽辦?比如,拿 VGG16 來說,它要求 Pooling 後的特征為 7 * 7 * 512,如果碰巧 ROI 區域只有 6 * 6 大小怎麽辦?還是同樣的辦法,每個網格的大小取 \(\frac{6}{7} * \frac{6}{7} = 0.85 * 0.85\),然後,以寬為例,按照這樣的間隔取網格:

\([0, 0.85, 1.7, 2.55, 3.4, 4.25, 5.1, 5.95]\)

取整後,每個網格對應的起始坐標為:\([0, 1, 2, 3, 3, 4, 5]\)

CNN 學習回歸參數

解決 ROI Pooling Layer 後,Fast RCNN 的難點基本就解決了。不過,博主是那種容易鉆牛角尖的人,在剛開始看到用 CNN 預測 BBox Regression 時一直疑惑不解。我認為模型擬合的數據之間是要滿足因果關系的。假設我們輸入的圖片中包含一只貓,訓練階段,CNN 在對貓所在的 ROI 矩形區域進行矯正時,它是參考 ground truth 標定的矩形框進行修正的。下一次,假設我們輸入同樣的圖片,只不過圖片中貓的位置變化了(貓的姿勢等都不變,僅僅是位置變了),那麽,CNN 根據 ground truth 進行學習的修正參數,應該跟上一次是一樣的,但是,這一次它所參考的 ground truth 卻已經換了不同的坐標了,那它又要怎麽學習呢?

在查了跟 Bounding Box Regression 相關的資料後,我才發現自己犯蠢了。其實,Bounding Box Regression 學的是一個微調的坐標參數,是一個相對值。也就是說,不管同一個物體在圖片中的位置怎麽變,網絡要學習的,都是相對真實 ground truth 的坐標偏移和尺寸變化,跟物體的絕對位置沒有半毛錢關系。

當模型訓練好後,對於某一特征,網絡已經知道這種特征應該如何調整矩形框了。說得簡單粗暴一點,就是網絡已經知道,對於 Selective Search 找出來的這種物體,它的矩形框偏離了多少,該如何調整。

(前面這一段說得比較繞,不過應該也沒幾個人會被這種問題卡住~囧~)

前面說到,Fast RCNN 將物體檢測和微調矩形框的任務用一個網絡一起學習。其實,就是讓 CNN 學習兩個代價函數,其中一個用於物體檢測,另一個用於 BBox Regression。

物體檢測的函數是常見的 Softmax,而 BBox Regression 則是一個比較特殊的函數:
\[ L_{loc}(t^u,v)=\sum_{i \in \{x,y,w,h\}}smooth_{L_1}(t_i^u-v_i) \]
其中,
\[ smooth_{L_1}(x)=\begin{cases} 0.5x^2 & \text{if |x|<1} \\ |x|-0.5 & \text{otherwise} \end{cases} \]
式中的 \(|x|\) 采用的是 \(L_1\) 範數。\(t^u=(t_x^u, t_y^u, t_w^u, t_h^u)\) 表示預測的矩形框(其實就是 Selective Search 找出來的包含物體的區域),x, y, w, h 分別表示矩形區域的中心坐標以及寬高。而 \(v=(v_x, v_y, v_w, v_h)\) 則是 ground truth。

而網絡總的代價函數為:
\[ L(p,u,t^u,v)=L_{cls}(p,u)+\lambda[u \ge 1]L_{loc}(t^u,v) \]
\(L_{cls}\) 是 softmax 對應的 log 函數,\(\lambda\) 是一個權重,文中取 1,\([u \ge 1]\) 表示只有矩形框中檢測到物體才會執行 \(L_{loc}\) 函數。

Faster RCNN的進擊

Faster RCNN,顧名思義,就是比 Fast RCNN 更快。那 Fast RCNN 中,還有什麽地方存在短板呢?研究人員發現,檢測部分基本都在一個網絡中進行了,但候選區域粗提取的工作(region proposal)還是在 CPU 中進行(用 Selective Search)。而 Selective Search 本質上也是對圖像特征的分析,那為什麽這塊分析的工作不直接利用卷積網絡運算的結果呢?而且,如果能把所有工作統一起來共同放在 GPU 中進行,不正了了偏執狂們的一樁心願嗎?!於是,人們開始研究,有沒有辦法用一個網絡來取代 Selective Search。這也導致 Faster RCNN 的誕生。

Region Proposal Network

Faster RCNN 提出了一種 Region Proposal Network(RPN),看名字就知道,這個網絡是用來提取 region 的。在傳統的物體檢測算法中,我們一般是用滑動窗口來掃描原圖,然後針對每個窗口提取特征。RPN 的思路與之類似,不過,為了共享卷積層的運算,它是在卷積網絡的 feature map 上,以每個特征點為中心,用一個 \(n * n\) 的矩形窗口進行掃描。論文中,n 被設為 3。那我們該如何判斷窗口內是否有物體呢?由於卷積網絡得到的 feature map 在尺寸上和原圖存在一定的比例關系,所以,我們可以把滑動窗口按比例換算回原圖,然後對比原圖的 ground truth,根據某種事先定好的規則,來判斷這個窗口是否包含物體(比如,跟 ground truth 的矩形的 IoU 大於某個閾值就認為包含物體)。在 \(n * n\) 的窗口之上,論文又用一個 \(n * n\) 的卷積層,對窗口範圍內的 feature map 進行卷積,然後用全聯接網絡輸出二分類的結果(前景還是背景)以及對矩形窗口的粗調整(類似 Fast RCNN 中的 bounding box regression,不過這一步的調整相對粗糙一些)。

上面就是 RPN 的基本思想了。總的來說,可以認為 RPN 就是在滑動窗口上,接著的一個小網絡,這個網絡會判斷窗口內是否有物體,以及會對原圖的窗口進行粗調整(原圖的窗口是 feature map 上的窗口按比例換算得到的)。

不過,直接根據滑動窗口換算回原圖存在一個 bug。試想一下,如果 ground truth 只占這個窗口的一部分,而且這部分剛好是物體的重要部位,那我們應該認為這個窗口有物體還是沒物體呢?

技術分享圖片

所以,為了防止這種尷尬的事情發生,或者說,為了防止有些窗口被漏撿,我們在換算回原圖的窗口時,要嘗試不同的窗口尺寸,而不是規規矩矩按照固定的縮放比例。比如,我們可以稍微將原圖的窗口調大一些,或調小一些,或將長寬的比例做調整,總之,就是盡可能 match 到窗口內的 ground truth。論文一共試了 k 種組合(實驗中,取了 9 種組合,窗口面積為 {128, 256, 512} x 長寬比為 {1:1, 1:2, 2:1})。feature map 上的一個點對應一個窗口,這個窗口內的特征輸入 RPN 網絡後,最終輸出 \(k * 2\) 個分類結果(表示 k 個窗口分別對應前景還是後景)以及 \(k * 4\) 個窗口粗調整的結果(表示 k 個窗口應該怎樣調整)。論文中,這些原圖上的窗口又被稱為 Anchor,以便和 feature map 上的滑動窗口區分開。註意,feature map 上的滑動窗口尺寸始終是 \(3 * 3\),而且每次都只移動一步。有人可能會問,如果滑動窗口對應的 Anchor 中,存在多個物體怎麽辦?不影響的,因為 RPN 只判斷前景跟後景,不做細致分類,而且,RPN 的輸出中,k 個窗口會對應 k 個輸出。如果有兩個 Anchor 對應兩個物體,那麽,RPN 會將這兩個 Anchor 都標記為 前景,並且根據它們各自的輸出,微調這兩個 Anchor 的位置。

訓練的時候,作者隨機挑選兩張圖片,並從每張圖片上總共挑出 256 個 ground truth 作為 proposals(包括前景和後景),然後,再根據滑動窗口,挑選出大約 2400 個 Anchors。RPN 的 loss 函數包括兩部分:
\[ L({p_i}, {t_i})=\frac{1}{N_{cls}}\sum_i L_{cls}(p_i, p_i^*)+\lambda \frac{1}{N_{reg}}\sum_i p_i^*L_{reg}(t_i, t_i^*) \]
其中,

\(L_{cls}\) 是一個二分類函數,_

\(L_{reg}\) 則是bounding box regression 函數(具體的跟 Fast RCNN 一樣),

\(p_i\) 表示網絡找到的 Anchor 區域中存在物體的概率(1 代表前景,0 代表背景),而 \(t_i\) 則是每個 Anchor 的矩形框位置和大小參數,

\(p_i^*\)\(t_i^*\) 則是 ground truth 對應的前後景概率以及窗口位置,

歸一化項中,\(N_{cls}\) 取 batch 的大小(256),\(N_{reg}\) 取 Anchors 的數目(約為 2400)。

總的來說,RPN 可以用下面這幅圖表示:

技術分享圖片

RPN + Fast RCNN

RPN 訓練完成後,我們相當於得到一個神經網絡版本的 Selective Search。那接下來的工作跟 Fast RCNN 就基本一樣了,根據 RPN 找到的 proposal,Fast RCNN 在 feature map 上對這個 proposal 區域的特征進一步分析,判斷是什麽物體,以及對窗口位置進一步微調。

不過,這其中有很多可以優化的細節。比如,在 RPN 網絡之前,我們需要先對圖像做卷積操作,而這一部分操作和 Fast RCNN 是可以共享的。這裏借用參考博文的一張圖來介紹一下整個網絡架構。

技術分享圖片

首先,原始圖片會經過一個共享的卷積層,得到 feature map。之後,RPN 在這個 feature map 上按照之前的描述提取 proposal,而 Fast RCNN 部分會繼續輸入到它的卷積層中,得到更高層的 feature map,然後在這個 feature map 上,根據提取到的 proposal,按照 Fast RCNN 的流程判斷物體,以及做 bounding box regression。

訓練的時候,RPN 和 Fast RCNN 是分開交替進行訓練的,這裏面涉及到的 trick 較多,很多文章也都有介紹,我這裏就不贅述了。預測部分則是一氣呵成,不用再經過其他處理,完全實現了 end-to-end。

參考

  • 邊框回歸(Bounding Box Regression)詳解
  • RCNN, Fast-RCNN, Faster-RCNN的一些事
  • SPPNet-引入空間金字塔池化改進RCNN
  • 一箭N雕:多任務深度學習實戰
  • Faster R-CNN: Down the rabbit hole of modern object detection
  • RCNN,Fast RCNN,Faster RCNN 總結

論文筆記:Fast(er) RCNN