深度学习RCNN, Fast-RCNN, Faster-RCNN的一些事
? rbg大神的深度神經網絡檢測算法系列RCNN、Fast-RCNN、Faster-RCNN可謂是理論與實踐的經典范例,論文創新點足夠,在github上開源的代碼更是造福廣大碼農,本文以當前最新Faster-RCNN的python實現(https://github.com/rbgirshick/py-faster-rcnn)為準,嘗試對rcnn系列算法中的幾個關鍵核心點進行詳細的分析:
- RCNN -> Fast-RCNN -> Faster-RCNN
- 圖片區域分析核心:ROI Pooling層
- 對象bbox預測:?Bounding-box Regression
- 用神經網絡輸出proposal:RPN層
- Faster-RCNN訓練步驟
RCNN -> Fast-RCNN -> Faster-RCNN
這里不得不先提的就是為什么會有RCNN這一系列的檢測算法,以及為什么它們會被稱為深度對象檢測的開山之作,我們知道,在CNN火起來之前,對象檢測這一問題基本是遵循著“設計手工特征(Hand-crafted feature)+分類器”的思路,而且由于存在著區域搜索的步驟,所以可以認為是計算機用一個小的矩形窗口不斷在圖像上滑動、縮放,然后用分類器預測當前滑動窗口所在區域是否存在一個感興趣的對象,自從CNN在CV領域流行起來以后,很多人都開始想,既然CNN的特征比傳統手工特征好這么多,那么為什么不用深度神經網絡做檢測呢?
RCNN算法的核心思想就是對每個區域通過CNN提取特征,然后接上一個分類器預測這個區域包含一個感興趣對象的置信度,也就是說,轉換成了一個圖像分類問題(類似imagenet),后面接的這個分類器可以是獨立訓練的svm也可以是簡單的softmax分類。在RCNN論文里,作者還提到兩個保證檢測速度的關鍵點:1.所有類別的分類器共享相同的特征輸入;2.與傳統特征相比,深度特征維度一般比較低,比如VGG16里的4096維。
但是很可惜,即使使用了selective search等預處理步驟來提取潛在的bounding box作為輸入,但是RCNN仍會有嚴重的速度瓶頸,原因也很明顯,就是計算機對所有region進行特征提取時會有重復計算,Fast-RCNN正是為了解決這個問題誕生的,作者提出了一個可以看做單層sppnet的網絡層,叫做ROI Pooling,這個網絡層可以把不同大小的輸入映射到一個固定尺度的特征向量,而我們知道,conv、pooling、relu等操作都不需要固定size的輸入,因此,在原始圖片上執行這些操作后,雖然輸入圖片size不同導致得到的feature map尺寸也不同,不能直接接到一個全連接層進行分類,但是可以加入這個神奇的ROI Pooling層,對每個region都提取一個固定維度的特征表示,再通過正常的softmax進行類型識別。另外,之前RCNN的處理流程是先提proposal,然后CNN提取特征,之后用SVM分類器,最后再做bbox regression,而在Fast-RCNN中,作者巧妙的把bbox regression放進了神經網絡內部,與region分類和并成為了一個multi-task模型,實際實驗也證明,這兩個任務能夠共享卷積特征,并相互促進。Fast-RCNN很重要的一個貢獻是成功的讓人們看到了Region Proposal+CNN這一框架實時檢測的希望,原來多類檢測真的可以在保證準確率的同時提升處理速度,也為后來的Faster-RCNN做下了鋪墊。
Fast-RCNN之后的問題已經非常清晰,就是我們能不能把region proposal部分也放到GPU上?rbg大神給的答案當然又是yes,于是有了Faster-RCNN,出現了一個end-to-end的CNN對象檢測模型。作者提出,網絡中的各個卷積層特征其實可以用來預測類別相關的region proposal,不需要事先執行諸如selective search之類的算法,但是如果簡單的在前面增加一個專門提proposal的網絡又顯得不夠elegant,所以最終把region proposal提取和Fast-RCNN部分融合進了一個網絡模型,雖然訓練階段仍然要分多步,但是檢測階段非常方便快捷,準確率也與原來的Fast-RCNN相差不多,從此,再也不用擔心region proposal提取耗時比實際對象檢測還多這種尷尬場景了。
ROI Pooling
首先需要介紹RCNN系列里的一個核心算法模塊,即ROI Pooling。我們知道在ImageNet數據上做圖片分類的網絡,一般都是先把圖片crop、resize到固定的大小(i.e. 224*224),然后輸入網絡提取特征再進行分類,而對于檢測任務這個方法顯然并不適合,因為原始圖像如果縮小到224這種分辨率,那么感興趣對象可能都會變的太小無法辨認。RCNN的數據輸入和SPPNet有點類似,并不對圖片大小限制,而實現這一點的關鍵所在,就是ROI Pooling網絡層,它可以在任意大小的圖片feature map上針對輸入的每一個ROI區域提取出固定維度的特征表示,保證后續對每個區域的后續分類能夠正常進行。
ROI Pooling的具體實現可以看做是針對ROI區域的普通整個圖像feature map的Pooling,只不過因為不是固定尺寸的輸入,因此每次的pooling網格大小得手動計算,比如某個ROI區域坐標為 (x1,y1,x2,y2)
,那么輸入size為 (y2?y1)?(x2?x1) ,如果pooling的輸出size為 pooled_height?pooled_width ,那么每個網格的size為 y2?y1pooled_height?x2?x1pooled_width,具體代碼可在roi_pooling_layer.cpp中的Forward_cpu
函數里找到,比較簡單。
作者并沒有對Backward階段實現CPU代碼,所以只能在roi_pooling_layer.cu中查看,即ROIPoolBackward函數,其具體進行的操作可以用論文里的一行公式形容,
?L?x=∑r∈R∑y∈r[y pooled x]?L?y
其中 R
表示R個輸入ROI區域以及對應的R個輸出feature,x和y分別表示輸入的feature map和輸出的feature,整個公式的意思就是,"During back-propagation, derivatives?flow through the RoI pooling layer. The RoI pooling layer's?backwards function computes the partial derivative of the?loss function with respect to each input variable x by summing?over all RoIs that max-pooled x in the forward pass.",另外,由于實際實現是采用的是Max Pooling,因此y pooled x表示“x在該網格區域中最大,然后y被assign到x的值”,而具體每個網格中哪個點的值最大,也是在Forward過程中就已經記錄,存儲在了argmax_data變量里。
Bounding-box Regression
有了ROI Pooling層其實就可以完成最簡單粗暴的深度對象檢測了,也就是先用selective search等proposal提取算法得到一批box坐標,然后輸入網絡對每個box包含一個對象進行預測,此時,神經網絡依然僅僅是一個圖片分類的工具而已,只不過不是整圖分類,而是ROI區域的分類,顯然大家不會就此滿足,那么,能不能把輸入的box坐標也放到深度神經網絡里然后進行一些優化呢?rbg大神于是又說了"yes"。在Fast-RCNN中,有兩個輸出層:第一個是針對每個ROI區域的分類概率預測, p=(p0,p1,?,pK)
;第二個則是針對每個ROI區域坐標的偏移優化, tk=(tkx,tky,tkw,tkh) , 0≤k≤K是多類檢測的類別序號。這里我們著重介紹第二部分,即坐標偏移優化。
假設對于類別 k?
,在圖片中標注了一個groundtruth坐標: t?=(t?x,t?y,t?w,t?h) ,而預測值為 t=(tx,ty,tw,th),二者理論上越接近越好,這里定義損失函數:
Lloc(t,t?)=∑i∈{x,y,w,h}smoothL1(ti,t?i)
其中
smoothL1(x)={0.5x2|x|?0.5|x|≤1otherwise
這里, smoothL1(x)
中的x即為 ti?t?i (感覺前一個公式為作者筆誤,該寫成 smoothL1(ti?t?i) ),即對應坐標的差距。該函數在 (?1,1)之間為二次函數,而其他區域為線性函數,作者表示這種形式可以增強模型對異常數據的魯棒性,整個函數在matplotlib中畫出來是這樣的
對應的代碼在smooth_L1_loss_layer.cu中。
RPN層
Faster-RCNN最大一點貢獻應該算是其把proposal部分從網絡外邊嵌入了網絡里邊,從此一個網絡模型即可完成end-to-end的檢測任務而不需要我們在前面手動先執行一遍proposal的搜索算法。其實如果回過頭來看看幾年前比較流行的檢測算法,比如HOG+SVM和DPM什么的,同樣是需要用分類器逐個對一些矩形框里提取出來的特征進行分類,只不過那時是全圖設置好stride、scale等參數然后搜索,不像selective search這些算法會去對圖像進行內容分析,然后輸出一些可疑的矩形候選框。
某種程度上,RPN也可以算作一個全圖搜索的粗檢測器,圖片在輸入網絡后,依次經過一些卷積、池化層,然后得到的feature map被手動劃分為 n×n
個矩形窗口(論文中n=3),準備后續用來選取proposal,并且此時坐標依然可以映射回原圖。需要注意兩點問題:1.在到達全連接層之前,卷積層和Pooling層對圖片輸入大小其實沒有size的限制,因此RCNN系列的網絡模型其實是不需要實現把圖片resize到固定大小的;2.n=3看起來很小,但是要考慮到這是非常高層的feature map,其size本身也沒有多大,因此 3×39個矩形中,每個矩形窗框都是可以感知到很大范圍的。
在劃分為 n×n
個窗口后,我們把每個矩形窗口的中心點當成一個基準點,然后圍繞這個基準點選取k(k=9)個不同scale、aspect?ratio的anchor(論文中3個scale和3個aspect ratio),對于每個anchor,首先在后面接上一個二分類softmax,有2個score輸出用以表示其是一個物體的概率與不是一個物體的概率,然后再接上一個bounding box的regressor,以及4個坐標輸出代表這個anchor的坐標位置,因此RPN的總體Loss函數可以定義為:
L({pi}{ti})=1Ncls∑iLcls(pi,p?i)+λ1Nreg∑ip?iLreg(ti,t?i)
這個公式里的 Lreg
即為上面提到的 smoothL1 函數,而該項前面的 p?i表示這些regressor的loss指針對正樣本而言,負樣本的預測會直接舍去。
另外在RPN訓練中有一個需要注意的地方是正負樣本的選擇,文中提到如果對每幅圖的所有anchor都去優化loss function,那么最終會因為負樣本過多導致最終得到的模型對正樣本預測準確率很低(It is possible to optimize?for the loss functions of all anchors, but this will?bias towards negative samples as they are dominate)。
Faster-RCNN訓練步驟
說完了Fast-RCNN和RPN,現在是時候來講Faster-RCNN最精華的部分了,也就是如何把這兩者放在同一個網絡結構中,如何訓練出這樣一個Multi-task的網絡模型。
我們知道,如果是分別訓練兩種不同任務的網絡模型,即使它們的結構、參數完全一致,但各自的卷積層內的卷積核也會向著不同的方向改變,導致無法共享網絡權重,Faster-RCNN提出了三種可能的方式:
上面說完了三種可能的訓練方法,可非常神奇的是作者發布的源代碼里卻傲嬌的用了另外一種叫做4-Step Alternating Training的方法,思路和迭代的Alternating training有點類似,但是細節有點差別(rbg大神這樣介紹訓練方式我也是醉了),具體來說:
總結
至此,關于RCNN系列檢測算法的關鍵部分已經全部介紹完畢,但應該還有很多真正的細節問題無法涉及到(其實也是因為好多細節實現我還沒看o(╯□╰)o),從我個人感受而言,rbg真心碉堡,算是難得一個既能寫paper又能coding的神人,而且最重要的一點,我的CVPR 2016論文里自己弄的一個數據集就借助了Fast-RCNN,否則應該沒有可能寫出這篇paper,在此再次跪謝rbg大神開放這么優秀的源代碼造福我等低端代碼搬運工!
from:?http://closure11.com/rcnn-fast-rcnn-faster-rcnn%E7%9A%84%E4%B8%80%E4%BA%9B%E4%BA%8B/
總結
以上是生活随笔為你收集整理的深度学习RCNN, Fast-RCNN, Faster-RCNN的一些事的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 空间金字塔Spatial Pyramid
- 下一篇: LDA-math-神奇的Gamma函数