從結(jié)構(gòu)、原理到實(shí)現(xiàn),F(xiàn)aster R-CNN全解析(原創(chuàng))

論文鏈接 Faster R-CNN Towards Real-Time Object:
https://arxiv.org/pdf/1506.01497.pdf
tensorflow源碼鏈接:
https://github.com/smallcorgi/Faster-RCNN_TF

Faster R-CNN是目標(biāo)檢測(cè)界的大神Ross Girshick 2015年提出的一個(gè)很經(jīng)典的檢測(cè)結(jié)構(gòu),它將傳統(tǒng)的Selective Search提取目標(biāo)的方法替換成網(wǎng)絡(luò)訓(xùn)練來實(shí)現(xiàn),使得全流程的檢測(cè)、分類速度大幅提升。
圖1是Faster R-CNN的基本結(jié)構(gòu),由以下4個(gè)部分構(gòu)成:
1、特征提取部分:用一串卷積+pooling從原圖中提取出feature map;
2、RPN部分:這部分是Faster R-CNN全新提出的結(jié)構(gòu),作用是通過網(wǎng)絡(luò)訓(xùn)練的方式從feature map中獲取目標(biāo)的大致位置;
3、Proposal Layer部分:利用RPN獲得的大致位置,繼續(xù)訓(xùn)練,獲得更精確的位置;
4、ROI Pooling部分:利用前面獲取到的精確位置,從feature map中摳出要用于分類的目標(biāo),并pooling成固定長(zhǎng)度的數(shù)據(jù);

圖1:Faster R-CNN結(jié)構(gòu)(點(diǎn)擊放大)

一、特征提取部分

特征提取部分就是圖1中輸入圖片和feature map間的那一串卷積+pooling,這部分和普通的CNN網(wǎng)絡(luò)中特征提取結(jié)構(gòu)沒有區(qū)別,可以用VGG、ResNet、Inception等各種常見的結(jié)構(gòu)實(shí)現(xiàn)(只使用全連接層之前的部分),這部分不再詳述。

二、RPN部分

目標(biāo)識(shí)別有兩個(gè)過程:首先你要知道目標(biāo)在哪里,要從圖片中找出要識(shí)別的前景,然后才是拿前景去分類。在Faster R-CNN提出之前常用的提取前景(本文稱為提取proposal)的方法是Selective Search,簡(jiǎn)稱SS法,通過比較相鄰區(qū)域的相似度來把相似的區(qū)域合并到一起,反復(fù)這個(gè)過程,最終就得到目標(biāo)區(qū)域,這種方法相當(dāng)耗時(shí)以至于提取proposal的過程比分類的過程還要慢,完全達(dá)不到實(shí)時(shí)的目的;到了Faster R-CNN時(shí),作者就想出把提取proposal的過程也通過網(wǎng)絡(luò)訓(xùn)練來完成,部分網(wǎng)絡(luò)還可以和分類過程共用,新的方法稱為Reginal Proposal Network(RPN),速度大大提升。
圖2粉色框內(nèi)就是RPN,它做兩件事:1、把feature map分割成多個(gè)小區(qū)域,識(shí)別出哪些小區(qū)域是前景,哪些是背景,簡(jiǎn)稱RPN Classification,對(duì)應(yīng)粉色框中上半分支;2、獲取前景區(qū)域的大致坐標(biāo),簡(jiǎn)稱RPN bounding box regression,對(duì)應(yīng)下半分支;


圖2:RPN和Proposal Layer結(jié)構(gòu)

1、RPN Classification

RPN Classification的過程就是個(gè)二分類的過程。先要在feature map上均勻的劃分出KxHxW個(gè)區(qū)域(稱為anchor,K=9,H是feature map的高度,W是寬度),通過比較這些anchor和ground truth間的重疊情況來決定哪些anchor是前景,哪些是背景,也就是給每一個(gè)anchor都打上前景或背景的label。有了labels,你就可以對(duì)RPN進(jìn)行訓(xùn)練使它對(duì)任意輸入都具備識(shí)別前景、背景的能力。
在圖2上半分支可以看到rpn_cls_score_reshape模塊輸出的結(jié)構(gòu)是[1,9*H,W,2],就是9xHxW個(gè)anchor二分類為前景、背景的概率;anchor_target_layer模塊輸出的是每一個(gè)anchor標(biāo)注的label,拿它和二分類概率一比較就能得出分類的loss。
一個(gè)feature map有9xHxW個(gè)anchor,就是說每個(gè)點(diǎn)對(duì)應(yīng)有9個(gè)anchor,這9個(gè)anchor有1:1、1:2、2:1三種長(zhǎng)寬比,每種長(zhǎng)寬比都有三種尺寸(見圖3)。一般來說原始輸入圖片都要縮放到固定的尺寸才能作為網(wǎng)絡(luò)的輸入,這個(gè)尺寸在作者源碼里限制成800x600,9種anchor還原到原始圖片上基本能覆蓋800x600圖片上各種尺寸的坐標(biāo)。


圖3:feature map每個(gè)點(diǎn)對(duì)應(yīng)個(gè)不同尺寸的anchor

要注意的是在實(shí)際應(yīng)用時(shí)并不是把全部HxWx9個(gè)anchor都拿來做label標(biāo)注,這里面有些規(guī)則來去除效果不好的anchor,具體的規(guī)則如下:
1、覆蓋到feature map邊界線上的anchor不參與訓(xùn)練;
2、前景和背景交界地帶的anchor不參與訓(xùn)練。這些交界地帶即不作為前景也不作為背景,以防出現(xiàn)錯(cuò)誤的分類。在作者原文里把IOU>0.7作為標(biāo)注成前景的門限,把IOU<0.3作為標(biāo)注成背景的門限,之間的值就不參與訓(xùn)練,IOU是anchor與ground truth的重疊區(qū)域占兩者總覆蓋區(qū)域的比例,見示意圖4;
3、訓(xùn)練時(shí)一個(gè)batch的樣本數(shù)是256,對(duì)應(yīng)同一張圖片的256個(gè)anchor,前景的個(gè)數(shù)不能超過一半,如果超出,就隨機(jī)取128個(gè)做為前景,背景也有類似的篩選規(guī)則;


圖4:IOU概念

2、RPN bounding box regression

RPN bounding box regression用于得出前景的大致位置,要注意這個(gè)位置并不精確,準(zhǔn)確位置的提取在后面的Proposal Layer bounding box regression章節(jié)會(huì)介紹。提取的過程也是個(gè)訓(xùn)練的過程,前面的RPN classification給所有的anchor打上label后,我們需用一個(gè)表達(dá)式來建立anchor與ground truth的關(guān)系,假設(shè)anchor中心位置坐標(biāo)是[Ax, Ay],長(zhǎng)高為Aw和Ah,對(duì)應(yīng)ground truth的4個(gè)值為[Gx,Gy,Gw,Gh],他們間的關(guān)系可以用公式1來表示。[dx(A), dy(A), dw(A), dh(A)]就是anchor與ground truth之間的偏移量,由公式1可以推導(dǎo)出公式2,這里用對(duì)數(shù)來表示長(zhǎng)寬的差別,是為了在差別大時(shí)能快速收斂,差別小時(shí)能較慢收斂來保證精度:

公式1

公式2

有了這4個(gè)偏移量,你就可以拿他們?nèi)ビ?xùn)練圖2 RPN中下面一個(gè)分支的輸出。完成訓(xùn)練后RPN就具備識(shí)別每一個(gè)anchor到與之對(duì)應(yīng)的最優(yōu)proposal偏移量的能力([d'x(A), d'y(A), d'w(A), d'h(A)]),換個(gè)角度看就是得到了所有proposal的位置和尺寸。要注意的是如果一個(gè)feature map中有多個(gè)ground truth,每個(gè)anchor只會(huì)選擇和它重疊度最高的ground truth來計(jì)算偏移量。

3、RPN的loss計(jì)算

RPN訓(xùn)練時(shí)要把RPN classification和RPN bounding box regression的loss加到一起來實(shí)現(xiàn)聯(lián)合訓(xùn)練。公式3中Ncls是一個(gè)batch的大小256,Lcls(pi, pi*)是前景和背景的對(duì)數(shù)損失,pi是anchor預(yù)測(cè)為目標(biāo)的概率,就是前面rpn_cls_score_reshape輸出的前景部分score值,pi*是前景的label值,就是1,將一個(gè)batch所有l(wèi)oss求平均就是RPN classification的損失;公式3中Nreg是anchor的總數(shù),λ是兩種 loss的平衡比例,ti是圖2中rpn_bbox_pred模塊輸出的[d'x(A), d'y(A), d'w(A), d'h(A)],t*i是訓(xùn)練時(shí)每一個(gè)anchor與ground truth間的偏移量,t*iti用smooth L1方法來計(jì)算loss就是RPN bounding box regression的損失:

公式3:RPN的loss

公式4

關(guān)于Smooth L1的原理,請(qǐng)參考:
http://pages.cs.wisc.edu/~gfung/GeneralL1/L1_approx_bounds.pdf

三、Proposal Layer部分

得到proposal大致位置后下一步就是要做準(zhǔn)確位置的回歸了。在RPN的訓(xùn)練收斂后我們能得到anchor相對(duì)于proposal的偏移量[d'x(A), d'y(A), d'w(A), d'h(A)](要注意這里是想對(duì)于proposal的,而不是相對(duì)于ground truth的),有了偏移量再根據(jù)公式1就能算出proposal的大致位置。在這個(gè)過程中HxWx9個(gè)anchor能算出HxWx9個(gè)proposal,大多數(shù)都是聚集在ground truth周圍的候選框,這么多相近的proposal完全沒必要反而增加了計(jì)算量,這時(shí)就要用一些方法來精選出最接近ground truth的proposal,Ross Girshick給了三個(gè)步驟:
1、先選出前景概率最高的N個(gè)proposal;
2、做非極大值抑制(NMS)
3、NMS后再次選擇前景概率最高的M個(gè)proposal;
經(jīng)歷這三個(gè)步驟后能夠得到proposal的大致位置,但這還不夠,為了得到更精確的坐標(biāo),你還要利用公式2再反推出這個(gè)大致的proposal和真實(shí)的ground truth間還有多少偏移量,對(duì)這個(gè)新的偏移量再來一次回歸才是完成了精確的定位。
上面的過程比較繞,反復(fù)在偏移量、anchor、ground truth間切換,下面的示意圖可以加深理解:

圖5

proposal精確位置回歸時(shí)計(jì)算loss的公式和公式3中RPN bounding box regression的loss計(jì)算方法完全相同,也用smooth L1方法。

四、ROI Pooling部分

結(jié)構(gòu)篇:

ROI Pooling做了兩件事:1、從feature maps中“摳出”proposals(大小、位置由RPN生成)區(qū)域;2、把“摳出”的區(qū)域pooling成固定長(zhǎng)度的輸出。
圖6是pooling過程的示意圖,feature map中有兩個(gè)不同尺寸的proposals,但pooling后都是7x7=49個(gè)輸出,這樣就能為后面的全連接層提供固定長(zhǎng)度的輸入。這種pooling方式有別于傳統(tǒng)的pooling,沒有任何tensorflow自帶的函數(shù)能實(shí)現(xiàn)這種功能,你可以自己用python寫個(gè)ROI Pooling的過程,但這樣就調(diào)用不了GPU的并行計(jì)算能力,所以作者的源碼里用C++來實(shí)現(xiàn)整個(gè)ROI Pooling。


圖6:ROI Pooling過程

釋疑篇:

為什么要pooling成固定長(zhǎng)度的輸出呢?這個(gè)其實(shí)來自于更早提出的SPP Net,RPN網(wǎng)絡(luò)提取出的proposal大小是會(huì)變化的,而分類用的全連接層輸入必須固定長(zhǎng)度,所以必須有個(gè)從可變尺寸變換成固定尺寸輸入的過程。在較早的R-CNN和Fast R-CNN結(jié)構(gòu)中都通過對(duì)proposal進(jìn)行拉升(warp)或裁減(crop)到固定尺寸來實(shí)現(xiàn),拉升、裁減的副作用就是原始的輸入發(fā)生變形或信息量丟失(圖7),以致分類不準(zhǔn)確。而ROI Pooling就完全規(guī)避掉了這個(gè)問題,proposal能完整的pooling成全連接的輸入,而且沒有變形,長(zhǎng)度也固定。


圖7:早期的網(wǎng)絡(luò)通過crop或warp來得到固定尺寸的輸入

源碼篇:

lib\roi_pooling_layer目錄下文件用來實(shí)現(xiàn)ROI Pooling。先來看roi_pooling_op.cc,里面有4個(gè)類:


圖8:roi_pooling_op.cc

CPU和GPU版本的具體流程差異不大,只是后者通過CUDA來實(shí)現(xiàn),具體的代碼就不貼了,下面一張圖里各個(gè)參數(shù)的名稱對(duì)應(yīng)著代碼里前向pooling計(jì)算時(shí)參數(shù)的取名(在RoiPoolOp類的Compute()函數(shù)中),圖中的proposal被分割成7x7個(gè)小方塊(圖中藍(lán)色的小方塊),每個(gè)藍(lán)色的大小是bin_size_w x bin_size_h ,其中的最大值就是一個(gè)pooling的結(jié)果,一個(gè)proposal共有49個(gè)pooling輸出??梢詫?duì)照下圖和代碼來理解:


圖9:RoiPoolOp類中前向計(jì)算中(Compute()函數(shù))各個(gè)參數(shù)對(duì)應(yīng)的含義

五、訓(xùn)練過程

前面介紹了Faster R-CNN的結(jié)構(gòu),最后看下訓(xùn)練方法,為了便于說明,我們把RPN中的rpn classification和rpn bounding box regression統(tǒng)稱為RPN訓(xùn)練;把proposal layer中對(duì)proposal精確位置的訓(xùn)練和最終的準(zhǔn)確分類訓(xùn)練統(tǒng)稱為R-CNN訓(xùn)練。Ross Girshick在論文中介紹了3種訓(xùn)練方法:
Alternating training:RPN訓(xùn)練和R-CNN訓(xùn)練交替進(jìn)行,共交替兩次。訓(xùn)練時(shí)先用ImageNet預(yù)訓(xùn)練的結(jié)果來初始化網(wǎng)絡(luò),訓(xùn)練RPN,用得到的proposal再訓(xùn)練R-CNN,之后用R-CNN訓(xùn)練出的參數(shù)來初始網(wǎng)絡(luò),再訓(xùn)練一次RPN,最后用RPN訓(xùn)練出的參數(shù)來初始化網(wǎng)絡(luò),最后訓(xùn)練次R-CNN,就完成了全部的訓(xùn)練過程。
Approximate joint training:這里與前一種方法不同,不再是串行訓(xùn)練RPN和R-CNN,而是嘗試把二者融入到一個(gè)網(wǎng)絡(luò)內(nèi)一起訓(xùn)練。這里Approximate 的意思是指把RPN bounding box regression部分反向計(jì)算得到的梯度完全舍棄,不用做更新網(wǎng)絡(luò)參數(shù)的權(quán)重。Approximate joint training相對(duì)于Alternating traing減少了25-50%的訓(xùn)練時(shí)間。
Non-approximate training:該方法和Approximate joint training基本一致,只是不再舍棄RPN bounding box regression部分得到的梯度。

本文開頭提供的源碼使用的是第三種方法,把4個(gè)部分的loss都加到了一起來訓(xùn)練,它的速度要更快。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容