Fast R-CNN學習總結

回顧RCNN

在上一篇RCNN中,可以看到還是存在很多問題。其中最主要的就是訓練過程複雜:

  1. 先預訓練
  2. 再利用selective search產生的region proposals進行微調CNN網路
  3. 再用CNN提取到的region proposal的固定長度的特徵向量來訓練一組SVM
  4. 最後還要訓練一組BBox回歸器,還是需要用CNN來提取特徵

其中2,3,4中樣本數據的構造是不一樣的,所以還要分別構造各自的數據集。訓練過程中反覆用到CNN(要麼就用額外的存儲來保存特徵向量,代價很大)。

除了訓練,測試過程也比較慢,因為需要將產生的2k個region proposals依次通過CNN來提取特徵(沒有共享計算導致的結果)。

當然這些都不能否定RCNN在圖像檢測方面的突破。下面開始進入Fast R-CNN.


改進

  1. 很大程度上實現了end to end(除了region proposals的產生還是用的selective search)。
  2. 不再是將region proposals依次通過CNN,而是直接輸入原圖,來提取特徵(這樣一張圖只會CNN一次)。
  3. 網路同時輸出類別判斷以及bbox回歸建議(即兩個同級輸出),不再分開訓練SVM和回歸器。

網路結構

通用模型

具體的一個網路結構

可以看到輸入是原圖(歸一化)和在原圖上提取到的P個ROI(其中5*P的5代表:ROI序號以及4個代表幾何位子的參數,ROI的產生還是用的selective search)

改進2:

由圖可以看到上述的改進2,輸入的是原圖+ROIs,且只有原圖經過了一次CNN,所有ROIs共享卷積操作。之前說過雖然卷積的輸入可以不固定維度,但是網路的全連接層的維度是固定的。對於任意尺度的原圖,提取到的ROI也是不固定尺度的(輸入全連接層的一定是ROI的特徵向量,而不是原圖的)那麼問題來了:

  1. 如何從conv5中提取到的原圖的特徵向量中找到ROIs對應的特徵區域
  2. 找到後,不同維度的ROIs對應的特徵區域維度也不一樣,如何轉為固定維度的特徵向量

在進一步閱讀之前,需要先了解SPPnet中的金字塔池化,可以參考此博客。我總結一下:

  • 在原圖提取到的feature map中找ROI對應區域: x^{ (注 [ ] 是向下取整,知乎里似乎打不出對應的符號,就用[ ]代替了)。其中 x^{ 是ROI在feature map中的橫坐標, x 是ROI在原圖中的橫坐標,S是convs中所有的strides的乘積。例如下面,在ZF-5中S=2*2*2*2=16(包括conv和pool中的stride)

  • 找到ROI在feature Map中對應的區域後,再經過金字塔池化就得到了21*k維(k是之前卷積 核的個數)

Fast R-CNN中對金字塔池化進行改進,使用了其特例(只使用了一層),變成了ROI pooling。它的輸入維度不定h*w,輸出維度固定H*W。只需要根據h/H和w/W來調整池化框的大小即可。H和W的設置是根據後面連接的全連接層以及之前的卷積核數量而定。這樣就只經過了一次卷積,就可以獲得一張圖所有ROI的特徵向量(當然ROI pooling還是進行多次,每個ROI進行一次)。

到此知道了如何只在原圖的卷積操作上來得到各個ROI的固定長度的特徵向量(先找對應區域,再pooling)。即改進2就介紹到這,關於如何訓練這麼一層,後面再介紹。

改進3:

在網路結構中可以看到有兩個輸出:分類的分和bbox回歸,這樣就省去了再單獨訓練SVMs和回歸器。這就涉及到多任務訓練,共享輸入以及底層參數,再根據各自任務進行輸出。此時整個網路的損失函數則包括兩部分 L_{cls}和L_{loc} ,分別對應分類的損失和回歸的損失。

  • 分類的輸出是 P(P_{0},P_{1},……,P_{k}) ,共k個類,多一個是背景。
  • 回歸的輸出是一個四元組 t^u=(t^u_x,t^u_y,t^u_w,t^u_h)
  • L_{cls}(p,u)=-logp_u
  • L_{loc}(t^u,v)=sum_{iin{x,y,w,h}}smooth_{L_1}(t_i^u-v_i) smooth_{L_1}(x)=egin{cases} 0.5x^2, & 	ext{ $|x|<1$ } \ |x|-0.5, & 	ext{otherwise} end{cases}

其中u是真實類別,v是真實的平移縮放參數。

到這應該對Fast R-CNN有了大致上的了解,剩下的就是如何訓練以及細節(全連接層加速等)


訓練Fast R-CNN

1.預訓練:

和之前一樣。使用大數據集訓練一個大的網路

2.微調:

  • 先改變網路結構:1)將最後一個池化層改為ROI Pooling;2)將輸出層改為兩個同級輸出,一個用於分類,一個用於回歸。(挖坑:新加入的節點參數如何設置??
  • 構造數據集:利用了分層數據:一個mini-batch中先選擇N張原圖,再從N張圖中選擇R個region proposals(每張圖選R/N個)。實際操作中N=2,R=12。

挖坑:為什麼要這樣做??

  • ROI Pooling的訓練:如何反饋梯度

先來看如何在普通的max pooling中反饋梯度(可參考此博客)

其中 x_{i} 是輸入的第i個節點(即第i個小方格), y_{j} 是輸出的第j個節點。 x 是之前卷積的 輸出, 於是有:

frac{partial L}{partial x_i}=egin{cases} 0, & 	ext{$delta(i,j)=false$ } \ frac{partial L}{partial y_j}, & 	ext{$delta(i,j)=true$} end{cases}

其中 delta(i,j)quad是判別函數 ,若 x_{i} 是對應池化框中的最大值,即輸入i節點被輸出j節點選為最大值輸出,則有 frac{partial y_j}{partial x_{i}}=1 ,所以 frac{partial L}{partial x_i}= frac{partial L}{partial y_j}*frac{partial y_j}{partial x_i}= frac{partial L}{partial y_j},若沒有被選作為輸出,就跟 x_{i } 沒關係,對應的導數就為0。

有了上面的了解,再來看ROI pooling,其中不一樣的是 x_{i} 可能是多個感興趣區域的重合部分。例如

注意,紅色框中的小格子是一個pooling的格子(這裡紅色框最終會pooling成3*3的尺寸),其實還可以細分,每個小格子又由多個節點構成(可以理解為一個個像素點, x_{i} 就是這一個個節點)。所以圖中有很多節點是重合的。其實這些節點的導數只需要做一個累加就好:

frac{partial L}{partial x_i}=Sigma_{r,j}delta(i,r,j)frac{partial L}{partial y_{rj}}

其中 y_{rj} 代表的第r個ROI的第j個輸出節點(因為一幅圖有多個ROI),有了 frac{partial L}{partial x_i} 後,再往前求梯度就和以前學的向後傳播演算法一樣了。

  • 損失究竟是什麼:之前說了損失是兩個部分的和,所以:

L(p,u,t^u,v)=L_{cls}(p,u)+lambda[uge1]L_{loc}(t^u,v)

[uge1]=egin{cases} 1, & 	ext{$u>1$ } \ 0, & 	ext{otherwise} end{cases}

現在有了網路結構,知道了ROI Pooling如何求導,有了損失函數,那麼一切就照舊了,可以愉快地開始訓練了。


全連接層加速

這部分工作是其他人的,論文作者引用過來,而且引用的剛剛好,這一部分就是利用了SVD分解,降低了計算複雜度。具體先就是將原來一個全連接層拆成了兩個,對應SVD中的兩個部份。了解SVD的人能很好的理解這部分,不了解的就繼續掙扎一下吧。。。

(我也不是很了解,所以坑就先留在這,下次更新)


總結:

通過引入ROI Pooling和兩個同級輸出頭,改變了RCNN中存在的訓練複雜以及測試速度慢等情況。很大程度上做到了end to end(對於end to end的理解可參考此文章的1.4節)。其中需要注意的就是:

  • 如何通過不同尺寸的輸入得到想同維度的特徵向量
  • 如何再原始圖的feature map中找到ROI的對應區域
  • ROI Pooling層的反饋如何進行
  • SVD加速全連接層

(關於留下的坑,就等著下次填了)


推薦閱讀:

吳恩達 DeepLearning.ai 課程提煉筆記(4-3)卷積神經網路 --- 目標檢測
目標檢測中region proposal的作用?
視頻中的目標檢測與圖像中的目標檢測具體有什麼區別?
為什麼SSD(Single Shot MultiBox Detector)對小目標的檢測效果不好?

TAG:深度学习DeepLearning | 目标检测 | 机器学习 |