一文讀懂「目標檢測」經典算法:RCNN,SPP-Net,Fast-RCNN,Faster-RCNN,YOLO,SSD

概述 Overview

在深度學習正式介入之前,傳統的「目標檢測」方法都是 區域選擇提取特征(顏色,紋理等)分類回歸 三部曲,這樣就有兩個難以解決的問題;其一是區域選擇的策略效果差、時間復雜度高;其二是手工提取的特征魯棒性較差。

云計算時代來臨后,「目標檢測」算法大家族主要劃分為兩大派系,一個是 R-CNN 系兩刀流,另一個則是以 YOLO 為代表的一刀流派。下面分別解釋一下 兩刀流一刀流

兩刀流
顧名思義,兩刀解決問題:

1、生成可能區域(Region Proposal) & CNN 提取特征
2、放入分類器分類并修正位置

這一流派的算法都離不開 Region Proposal ,即是優點也是缺點,主要代表人物就是 R-CNN 系。

一刀流
顧名思義,一刀解決問題,直接對預測的目標物體進行回歸
回歸解決問題簡單快速,但是太粗暴了,主要代表人物是 YOLOSSD


無論 兩刀流 還是 一刀流,他們都是在同一個天平下選取一個平衡點、或者選取一個極端——要么準,要么快。

兩刀流的天平主要傾向準,
一刀流的天平主要傾向快。

但最后萬劍歸宗,大家也找到了自己的平衡,平衡點的有略微的不同。

接下來我們花開兩朵各表一支,一朵 兩刀流 的前世今生,另一朵 一刀流 的發展歷史。

一、兩刀流 R-CNN

R-CNN 其實是一個很大的家族,自從 rbg 大神發表那篇論文,子孫無數、桃李滿天下。在此,我們只探討 R-CNN 直系親屬,他們的發展順序如下:

R-CNN -> SPP Net -> Fast R-CNN -> Faster R-CNN -> Mask R-CNN

其實說句良心話,最佩服的并不是 rbg 大神,而是提出了 SPP Net 的以何愷明為主的作者們
他們在整個家族進化的過程中,一致暗埋了一條主線:充分榨干 feature maps 的價值

1.1 R-CNN / 2013

論文:Rich feature hierarchies for accurate object detection and semantic segmentation

這篇論文,這個模型,是利用卷積神經網絡來做「目標檢測」的開山之作,其意義深遠不言而喻。

1.1.1核心貢獻

一、速度
傳統的區域選擇使用滑窗,每滑一個窗口檢測一次,相鄰窗口信息重疊高,檢測速度慢。R-CNN 使用一個啟發式方法(Selective search),先生成候選區域(使用選擇性搜索)再檢測,降低信息冗余程度,從而提高檢測速度。

二、特征提取
傳統的手工提取特征魯棒性差,限于如顏色、紋理等 低層次(Low level)的特征。使用 CNN (卷積神經網絡)提取特征,可以提取更高層面的抽象特征,從而提高特征的魯棒性。

選擇性搜索主要思想

論文:Selective Search for Object Recognition

組成目標物體通常有四個要素:變化尺度、顏色、結構(材質)、所占面積。選擇性搜索會確定物體在圖片中的這些特征,然后基于這些特征突出不同區域。下面是選擇搜索的一個簡單案例:

  • 首先將一張圖片作為輸入:
  • 之后,它會生成最初的sub-分割,將圖片分成多個區域:


  • 查看現有小區域,按照合并規則合并可能性最高的相鄰兩個區域,重復這種操作:

  • 最后,生成最終的目標物體位置(Region of Interest)。

1.1.2 基本流程

  1. 我們首先取一個預訓練卷積神經網絡CNN。
  2. 根據需要檢測的目標類別數量,訓練CNN的最后一層。
  3. 將以下圖片作為輸入:
  1. 之后,我們會用上文中的選擇性搜索得到感興趣區域(大約1k~2k個):
  1. 對這些區域重新改造,以讓其符合CNN的輸入尺寸要求,將這些區域輸入到CNN中,并經過卷積網絡:
  1. 對每個類別,我們都要訓練一個二元SVM(判斷物體是foreground or background,我們檢測的目標是foreground)。CNN為每個區域提取特征,利用SVM將這些區域分成不同類別:
2703090986-5bc5a1ba17ab7.png
  1. 最后,我們訓練一個線性回歸模型(bounding box regression),為每個辨識到的物體生成更精確的邊界框。:

bounding box regression原理

如圖9所示綠色框為飛機的Ground Truth(GT),紅色為提取的foreground anchors,即便紅色的框被分類器識別為飛機,但是由于紅色的框定位不準,這張圖相當于沒有正確的檢測出飛機。所以我們希望采用一種方法對紅色的框進行微調,使得foreground anchors和GT更加接近。

對于窗口一般使用四維向量 [x,y,w,h] 表示,分別表示窗口的中心點坐標和寬高。對于下圖,紅色的框A代表原始的Foreground Anchors,綠色的框G代表目標的GT,我們的目標是尋找一種關系,使得輸入原始的anchor A經過映射得到一個跟真實窗口G更接近的回歸窗口G',即:

  • 給定:anchorA = (A_x,A_y,A_w,A_h)GT = [G_x,G_y,G_w,G_h]
  • 尋找一種變換F,使得:F(A_x,A_y,A_w,A_h)=(G'_x,G'_y,G'_w,G'_h),其中(G'_x,G'_y,G'_w,G'_h)\approx (G_x,G_y,G_w,G_h)

那么經過何種變換F才能從圖中的anchor A變為G'呢? 比較簡單的思路就是:

  • 先做平移
    G'_x = A_w*d_x(A)+A_x

    G'_y = A_h*d_y(A)+A_y

  • 再做縮放
    G'_w = A_w*exp(d_w(A))

    G'_h = A_h*exp(d_h(A))

觀察上面4個公式發現,需要學習的是 d_{x}(A),d_{y}(A),d_{w}(A),d_{h}(A)這四個變換。當輸入的anchor A與GT相差較小時,可以認為這種變換是一種線性變換, 那么就可以用線性回歸來建模對窗口進行微調(注意,只有當anchors A和GT比較接近時,才能使用線性回歸模型,否則就是復雜的非線性問題了)。
接下來的問題就是如何通過線性回歸獲得 d_{x}(A),d_{y}(A),d_{w}(A),d_{h}(A) 了。線性回歸就是給定輸入的特征向量X, 學習一組參數W, 使得經過線性回歸后的值跟真實值Y非常接近,即Y=WX。對于該問題,輸入X是cnn feature map,定義為Φ;同時還有訓練傳入A與GT之間的變換量,即(t_{x}, t_{y}, t_{w}, t_{h})。輸出是d_{x}(A),d_{y}(A),d_{w}(A),d_{h}(A)四個變換。那么目標函數可以表示為:
d_*(A)=W_*^T\cdot \phi(A)

其中 \phi(A) 是對應anchor的feature map組成的特征向量, W_* 是需要學習的參數, d_*(A)是得到的預測值(*表示 x,y,w,h,也就是每一個變換對應一個上述目標函數)。為了讓預測值d_*(A)與真實值t_* 差距最小,設計損失函數:

\text{Loss}=\sum_{i}^{N}{(t_*^i-W_*^T\cdot \phi(A^i))^2}

函數優化目標為:

\hat{W}_*=\text{argmin}_{W_*}\sum_{i}^{n}(t_*^i- W_*^T\cdot \phi(A^i))^2+\lambda||W_*||^2\

需要說明,只有在GT與需要回歸框位置比較接近時,才可近似認為上述線性變換成立。
說完原理,對應于Faster RCNN原文,foreground anchor與ground truth之間的平移量 (t_x, t_y)與尺度因子 (t_w, t_h)如下:

t_x=(x-x_a)/w_a\ \ \ \ t_y=(x-y_a)/h_a

t_w=\log(w/w_a)\ \ \ \ t_h=\log(h/h_a)

對于訓練bouding box regression網絡回歸分支,輸入是cnn feature Φ,監督信號是Anchor與GT的差距 (t_x, t_y, t_w, t_h),即訓練目標是:輸入 Φ的情況下使網絡輸出與監督信號盡可能接近。
那么當bouding box regression工作時,再輸入Φ時,回歸網絡分支的輸出就是每個Anchor的平移量和變換尺度 (t_x, t_y, t_w, t_h),顯然即可用來修正Anchor位置了。

這就是RCNN檢測目標物體的方法。

1.1.3局限

訓練一個RCNN模型非常昂貴,并且步驟較多:

  • 根據選擇性搜索,要對每張圖片提取2000個單獨區域;

  • 用CNN提取每個區域的特征。假設我們有N張圖片,那么CNN特征就是N*2000;

  • 用RCNN進行目標檢測的整個過程有三個模型:

    • 用于特征提取的CNN

    • 用于目標物體辨別的線性SVM分類器

    • 調整邊界框的回歸模型。

這些過程合并在一起,會讓RCNN的速度變慢,通常每個新圖片需要40—50秒的時間進行預測,基本上無法處理大型數據集。

img

從結果上說,該方法將 PASCAL VOC 上的檢測率從 35.1% 提升到 53.7% ,提高了好幾個量級。雖然比傳統方法好很多,但是從現在的眼光看,只能是初窺門徑

1.2 SPP Net / 2014

論文:Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition

R-CNN 提出后的一年,以何愷明、任少卿為首的團隊提出了 SPP Net ,這才是真正摸到了卷積神經網絡的脈絡。也不奇怪,畢竟這些人鼓搗出了 ResNet 殘差網絡,對神經網絡的理解是其他人沒法比的。

1.2.1 核心貢獻

解決了R-CNN的兩個硬傷:

  1. 算力冗余
    先生成候選區域,再對區域進行卷積,這里有兩個問題:其一是候選區域會有一定程度的重疊,對相同區域進行重復卷積;其二是每個區域進行新的卷積需要新的存儲空間。

    何愷明等人意識到這個可以優化,于是把先生成候選區域再卷積,變成了先卷積后生成區域。“簡單地”改變順序,不僅減少存儲量而且加快了訓練速度。

  2. 圖片縮放

在R-CNN基本流程步驟5中,對搜索出的感興趣區域重新改造,以讓其符合CNN的輸入尺寸要求時,無論是剪裁(Crop)還是縮放(Warp),在很大程度上會丟失圖片原有的信息導致訓練效果不好,如上圖所示。直觀的理解,把車剪裁成一個門,人看到這個門也不好判斷整體是一輛車;把一座高塔縮放成一個胖胖的塔,人看到也沒很大把握直接下結論。人都做不到,機器的難度就可想而知了。

ROI池化層

何愷明等人發現了這個問題,于是思索有什么辦法能不對圖片進行變形,將圖片原汁原味地輸入進去學習。

最后,他們發現問題的根源是 FC Layer(全連接層)需要確定輸入維度,于是他們在輸入全連接層前定義一個特殊的池化層,將輸入的任意尺度 feature maps 組合成特定維度的輸出,這個組合可以是不同大小的拼湊,如同拼湊七巧板般。這就是ROI池化層。

具體來說,

  • 先將對應的feature map區域水平分為pooled_w ×pooled_h 的網格;
  • 對網格的每一份都進行max pooling處理。

這樣處理后,即使大小不同的proposal輸出結果都是 pooled_w ×pooled_h 固定大小,實現了固定長度輸出。

SPP Net 的出現是如同一道驚雷,不僅減少了計算冗余,更重要的是打破了固定尺寸輸入這一束縛,讓后來者享受到這一縷陽光。

1.3 Fast R-CNN / 2015

論文:Fast R-CNN

此時,我們的 rbg 大哥也按耐不住了——自己家的孩子,自己養大——于是憋出了一個大招 Fast R-CNN 。取這個名字的意思就是“兒子比爸爸強”,相對于原來的 Slow R-CNN,做了速度上的優化——就是快。

在這篇論文中,引用了 SPP Net 的工作,并且致謝其第一作者何愷明的慷慨解答。

1.3.1 核心貢獻

想要減少RCNN算法的計算時間,可以用什么方法?我們可不可以在每張圖片上只使用一次CNN即可得到全部的重點關注區域呢,而不是運行2000次。

RCNN的作者提出了一種想法,在每張照片上只運行一次CNN,然后找到一種方法在2000個區域中進行計算。在Fast RCNN中,我們將圖片輸入到CNN中,會相應地生成傳統特征映射。利用這些映射,就能提取出感興趣區域。之后,我們使用一個Rol池化層將所有提出的區域重新修正到合適的尺寸,以輸入到完全連接的網絡中。

簡單地說,這一過程含有以下步驟:

  1. 輸入圖片。
  2. 輸入到卷積網絡中,它生成感興趣區域。
  3. 利用Rol池化層對這些區域重新調整,將其輸入到完全連接網絡中。
  4. 在網絡的頂層用softmax層輸出類別。同樣使用一個線性回歸層,輸出相對應的邊界框。

所以,和RCNN所需要的三個模型不同,Fast RCNN只用了一個模型就同時實現了區域的特征提取、分類、邊界框生成。

另外,原來的 R-CNN 是先對候選框區域進行分類,判斷有沒有物體,如果有則對 Bounding Box 進行精修 回歸 。這是一個串聯式的任務,那么勢必沒有并聯的快,所以 rbg 就將原有結構改成并行——在分類的同時,對 Bbox 進行回歸。

這一改變將 BboxClfloss 結合起來變成一個 Loss 一起訓練,并吸納了 SPP Net 的優點,最終不僅加快了預測的速度,而且提高了精度。

1.3.2 基本流程

  1. 首先,輸入圖像:

  1. 圖像被傳遞到卷積網絡中,返回感興趣區域:


  1. 之后,在區域上應用Rol池化層,保證每個區域的尺寸相同:
  1. 這些區域被傳遞到一個完全連接的網絡中進行分類,并用softmax和線性回歸層同時返回邊界框:


1.3.3 局限

但是即使這樣,Fast RCNN也有某些局限性。它同樣用的是選擇性搜索作為尋找感興趣區域的,這一過程通常較慢。與RCNN不同的是,Fast RCNN處理一張圖片大約需要2秒。但是在大型真實數據集上,這種速度仍然不夠理想。

1.4 Faster R-CNN / 2015

論文:Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks

眾人拾柴火焰高,原來 SPP Net 的人馬和 rbg 一起研究憋大招,在 rbg何愷明 綻放完光芒后,任少卿 老哥發出了太陽般的光芒——RPN 的概念讓人不得不服。

1.4.1 核心貢獻

Faster R-CNN 前,我們生產候選區域都是用的一系列啟發式算法,基于 Low Level 特征生成區域。這樣就有兩個問題:

第一個問題 是生成區域的靠譜程度隨緣,而 兩刀流 算法正是依靠生成區域的靠譜程度——生成大量無效區域則會造成算力的浪費、少生成區域則會漏檢;
第二個問題 是生成候選區域的算法是在 CPU 上運行的,而我們的訓練在 GPU 上面,跨結構交互必定會有損效率。

那么怎么解決這兩個問題呢?

于是乎,任少卿等人提出了一個 Region Proposal Networks 的概念,利用神經網絡自己學習去生成候選區域。

這種生成方法同時解決了上述的兩個問題,神經網絡可以學到更加高層、語義、抽象的特征,生成的候選區域的可靠程度大大提高;可以從上圖看出 RPNsRoI Pooling 共用前面的卷積神經網絡——將 RPNs 嵌入原有網絡,原有網絡和 RPNs 一起預測,大大地減少了參數量和預測時間。

RPNs 中引入了 anchor 的概念,feature map 中每個滑窗位置都會生成 kanchors,然后判斷 anchor覆蓋的圖像是前景還是背景,同時回歸 Bbox 的精細位置,預測的 Bbox 更加精確。

兩刀流 的兩刀并入同一個網絡,這一操作足夠載入史冊了。

1.4.2 基本流程

Faster RCNN基本結構

Faster RCNN其實可以分為4個主要內容:

  1. Conv layers。作為一種CNN網絡目標檢測方法,Faster RCNN首先使用一組基礎的conv+relu+pooling層提取image的feature maps。該feature maps被共享用于后續RPN層和全連接層。
  2. Region Proposal Networks。RPN網絡用于生成region proposals。該層通過softmax判斷anchors屬于foreground或者background,再利用bounding box regression修正anchors獲得精確的proposals。
  3. Roi Pooling。該層收集輸入的feature maps和proposals,綜合這些信息后提取proposal feature maps,送入后續全連接層判定目標類別。
  4. Classification。利用proposal feature maps計算proposal的類別,同時再次bounding box regression獲得檢測框最終的精確位置。

具體來說可看下圖:VGG16模型中的faster_rcnn_test.pt的網絡結構

可以清晰的看到該網絡對于一副任意大小PxQ的圖像,首先縮放至固定大小MxN,然后將MxN圖像送入網絡;而Conv layers中包含了13個conv層+13個relu層+4個pooling層;RPN網絡首先經過3x3卷積,再分別生成foreground anchors與bounding box regression偏移量,然后計算出proposals;而Roi Pooling層則利用proposals從feature maps中提取proposal feature送入后續全連接和softmax網絡作classification(即分類proposal到底是什么object)。

Conv layers

Conv layers包含了conv,pooling,relu三種層。如圖2,Conv layers部分共有13個conv層,13個relu層,4個pooling層。這里有一個非常容易被忽略但是又無比重要的信息,在Conv layers中:

  1. 所有的conv層都是:keneral_size = 3,pad = 1,stride = 1
  2. 所有的pooling層都是:keneral_size = 2,pad = 0 ,stride = 2

為何重要?在Faster RCNN Conv layers中對所有的卷積都做了擴邊處理( pad=1,即填充一圈0),導致原圖變為 (M+2)x(N+2)大小,再做3x3卷積后輸出MxN 。正是這種設置,導致Conv layers中的conv層不改變輸入和輸出矩陣大小。如圖3:

img

類似的是,Conv layers中的pooling層kernel_size=2,stride=2。這樣每個經過pooling層的MxN矩陣,都會變為(M/2)x(N/2)大小。綜上所述,在整個Conv layers中,conv和relu層不改變輸入輸出大小,只有pooling層使輸出長寬都變為輸入的1/2。
那么,一個MxN大小的矩陣經過Conv layers固定變為(M/16)x(N/16)!這樣Conv layers生成的featuure map中都可以和原圖對應起來。

Region Proposal Networks(RPN)

經典的檢測方法生成檢測框都非常耗時,如OpenCV adaboost使用滑動窗口+圖像金字塔生成檢測框;或如R-CNN使用SS(Selective Search)方法生成檢測框。而Faster RCNN則拋棄了傳統的滑動窗口和SS方法,直接使用RPN生成檢測框,這也是Faster R-CNN的巨大優勢,能極大提升檢測框的生成速度。

img

上圖4展示了RPN網絡的具體結構。可以看到RPN網絡實際分為2條線:

一路用來判斷候選框是前景還是背景,它先reshape成一維向量,softmax分類anchors獲得foreground和background(檢測目標是foreground),然后reshape恢復為二維feature map。故經過這一步之后,我們就可以舍棄背景anchors了。大部分的anchors都是屬于背景,故這一步可以篩選掉很多無用的anchor,從而減少全連接層的計算量。對于經過了3x3的卷積后得到的256個feature map,先經過1x1的卷積,變換為18個feature map。然后reshape為一維向量,經過softmax判斷是前景還是背景。此處reshape的唯一作用就是讓數據可以進行softmax計算。然后輸出識別得到的前景anchors。

下面一路用于計算對于anchors的bounding box regression偏移量,以獲得精確的proposal(也就是確定候選框的位置)。

而最后的Proposal層則負責綜合foreground anchors和bounding box regression偏移量獲取proposals,同時剔除太小和超出邊界的proposals。其實整個網絡到了Proposal Layer這里,就完成了相當于目標定位的功能。

關于1x1卷積
img

如上圖,輸入有3個通道,同時有2個卷積核。對于每個卷積核,先在輸入3個通道分別作卷積,再將3個通道結果加起來得到卷積輸出。所以對于某個卷積層,無論輸入圖像有多少個通道,輸出圖像通道數總是等于卷積核數量
對多通道圖像做1x1卷積,其實就是將輸入圖像于每個通道乘以卷積系數后加在一起,即相當于把原圖像中本來各個獨立的通道“聯通”在了一起。

候選框(anchors):

所謂anchors,實際上就是一組由rpn/generate_anchors.py生成的矩形。直接運行作者demo中的generate_anchors.py可以得到以下輸出:

[[ -84.  -40.   99.   55.]
 [-176.  -88.  191.  103.]
 [-360. -184.  375.  199.]
 [ -56.  -56.   71.   71.]
 [-120. -120.  135.  135.]
 [-248. -248.  263.  263.]
 [ -36.  -80.   51.   95.]
 [ -80. -168.   95.  183.]
 [-168. -344.  183.  359.]]

其中每行的4個值(x_1, y_1, x_2, y_2)代表矩形左上和右下角點坐標。9個矩形共有3種形狀,長寬比為大約為width:height \in \left \{ 1:1,1:2,2:1 \right \} 三種,如下圖。實際上通過anchors就引入了檢測中常用到的多尺度方法。

那么這9個anchors是做什么的呢?借用Faster RCNN論文中的原圖,如圖7,遍歷Conv layers計算獲得的feature maps,為每一個點都配備這9種anchors作為初始的檢測框。這樣做獲得檢測框很不準確,不用擔心,后面還有2次bounding box regression可以修正檢測框位置。

假設在conv5 feature map中每個點上有k個anchor(默認k=9),而每個anhcor要分foreground和background,所以每個點由256d feature轉化為cls=2k scores;而每個anchor都有(x, y, w, h)對應4個偏移量,所以reg=4k coordinates。

補充一點,全部anchors拿去訓練太多了,訓練程序會在合適的anchors中隨機選取128個postive anchors+128個negative anchors進行訓練。

softmax判定foreground與background

一副MxN大小的矩陣送入Faster RCNN網絡后,到RPN網絡變為(M/16)x(N/16),不妨設 W=M/16,H=N/16。在進入reshape與softmax之前,先做了1x1卷積,如圖9:

img

圖9 RPN中判定fg/bg網絡結構

該1x1卷積的caffe prototxt定義如下:

layer {
  name: "rpn_cls_score"
  type: "Convolution"
  bottom: "rpn/output"
  top: "rpn_cls_score"
  convolution_param {
    num_output: 18   # 2(bg/fg) * 9(anchors)
    kernel_size: 1 pad: 0 stride: 1
  }
}

可以看到其num_output=18,也就是經過該卷積的輸出圖像為WxHx18大小。這也就剛好對應了feature maps每一個點都有9個anchors,同時每個anchors又有可能是foreground和background,所有這些信息都保存WxHx(9*2)大小的矩陣。為何這樣做?后面接softmax分類獲得foreground anchors,也就相當于初步提取了檢測目標候選區域box(一般認為目標在foreground anchors中)。
那么為何要在softmax前后都接一個reshape layer?其實只是為了便于softmax分類,至于具體原因這就要從caffe的實現形式說起了。在caffe基本數據結構blob中以如下形式保存數據:

blob=[batch_size, channel,height,width]

對應至上面的保存bg/fg anchors的矩陣,其在caffe blob中的存儲形式為[1, 2x9, H, W]。而在softmax分類時需要進行fg/bg二分類,所以reshape layer會將其變為[1, 2, 9xH, W]大小,即單獨“騰空”出來一個維度以便softmax分類,之后再reshape回復原狀。貼一段caffe softmax_loss_layer.cpp的reshape函數的解釋,非常精辟:

"Number of labels must match number of predictions; "
"e.g., if softmax axis == 1 and prediction shape is (N, C, H, W), "
"label count (number of labels) must be N*H*W, "
"with integer values in {0, 1, ..., C-1}.";

綜上所述,RPN網絡中利用anchors和softmax初步提取出foreground anchors作為候選區域。

對proposals進行bounding box regression

在了解bounding box regression后,再回頭來看RPN網絡第二條線路,如圖。

先來看一看上圖11中1x1卷積的caffe prototxt定義:

layer {
  name: "rpn_bbox_pred"
  type: "Convolution"
  bottom: "rpn/output"
  top: "rpn_bbox_pred"
  convolution_param {
    num_output: 36   # 4 * 9(anchors)
    kernel_size: 1 pad: 0 stride: 1
  }
}

可以看到其 num_output=36,即經過該卷積輸出圖像為WxHx36,在caffe blob存儲為[1, 4x9, H, W],這里相當于feature maps每個點都有9個anchors,每個anchors又都有4個用于回歸的[d_x(A),d_y(A).d_w(A),d_h(A)]變換量。

Proposal Layer

Proposal Layer負責綜合所有[d_x(A),d_y(A).d_w(A),d_h(A)]變換量和foreground anchors,計算出精準的proposal,送入后續RoI Pooling Layer。還是先來看看Proposal Layer的caffe prototxt定義:

layer {
  name: 'proposal'
  type: 'Python'
  bottom: 'rpn_cls_prob_reshape'
  bottom: 'rpn_bbox_pred'
  bottom: 'im_info'
  top: 'rois'
  python_param {
    module: 'rpn.proposal_layer'
    layer: 'ProposalLayer'
    param_str: "'feat_stride': 16"
  }
}

Proposal Layer有3個輸入:fg/bg anchors分類器結果rpn_cls_prob_reshape,對應的bbox reg的[d_x(A),d_y(A).d_w(A),d_h(A)]變換量rpn_bbox_pred,以及im_info;另外還有參數feat_stride=16,這和圖4是對應的。
首先解釋im_info。對于一副任意大小PxQ圖像,傳入Faster RCNN前首先reshape到固定MxN,im_info=[M, N, scale_factor]則保存了此次縮放的所有信息。然后經過Conv Layers,經過4次pooling變為WxH=(M/16)x(N/16)大小,其中feature_stride=16則保存了該信息,用于計算anchor偏移量。

img

圖13

Proposal Layer forward(caffe layer的前傳函數)按照以下順序依次處理:

  1. 生成anchors,利用[d_x(A),d_y(A).d_w(A),d_h(A)]對所有的anchors做bbox regression回歸(這里的anchors生成和訓練時完全一致)
  2. 按照輸入的foreground softmax scores由大到小排序anchors,提取前pre_nms_topN(e.g. 6000)個anchors,即提取修正位置后的foreground anchors。
  3. 限定超出圖像邊界的foreground anchors為圖像邊界(防止后續roi pooling時proposal超出圖像邊界)
  4. 剔除非常小(width<threshold or height<threshold)的foreground anchors
  5. 進行非極大值抑制 non maximum suppression
  6. 再次按照nms后的foreground softmax scores由大到小排序fg anchors,提取前post_nms_topN(e.g. 300)結果作為proposal輸出。

之后輸出proposal=[x_1, y_1, x_2, y_2],注意,由于在第三步中將anchors映射回原圖判斷是否超出邊界,所以這里輸出的proposal是對應MxN輸入圖像尺度的,這點在后續網絡中有用。另外我認為,嚴格意義上的檢測應該到此就結束了,后續部分應該屬于識別了~
RPN網絡結構就介紹到這里,總結起來就是:
生成anchors -> softmax分類器提取foreground anchors -> bbox reg回歸foreground anchors -> Proposal Layer生成proposals

Classification

Classification部分利用已經獲得的proposal feature maps,通過full connect層與softmax計算每個proposal具體屬于那個類別(如人,車,電視等),輸出cls_prob概率向量;同時再次利用bounding box regression獲得每個proposal的位置偏移量bbox_pred,用于回歸更加精確的目標檢測框。Classification部分網絡結構如圖16。

img

圖16 Classification部分網絡結構圖

從PoI Pooling獲取到7x7=49大小的proposal feature maps后,送入后續網絡,可以看到做了如下2件事:

  1. 通過全連接和softmax對proposals進行分類,這實際上已經是識別的范疇了
  2. 再次對proposals進行bounding box regression,獲取更高精度的rect box

二、一刀流 YOLO & SSD

一刀流的想法就比較暴力,給定一張圖像,使用回歸的方式輸出這個目標的邊框和類別。一刀流最核心的還是利用了分類器優秀的分類效果,首先給出一個大致的范圍(最開始就是全圖)進行分類,然后不斷迭代這個范圍直到一個精細的位置,如上圖從藍色的框框到紅色的框框。

這就是一刀流回歸的思想,這樣做的優點就是快,但是會有許多漏檢。

2.1 YOLO / 2015

論文:YOLO

2.1.1 核心貢獻

YOLO將物體檢測作為回歸問題求解。基于一個單獨的end-to-end網絡,完成從原始圖像的輸入到物體位置和類別的輸出。從網絡設計上,YOLO與rcnn、fast rcnn及faster rcnn的區別如下:

  1. YOLO訓練和檢測均是在一個單獨網絡中進行。YOLO沒有顯示地求取region proposal的過程。而rcnn/fast rcnn 采用分離的模塊(獨立于網絡之外的selective search方法)求取候選框(可能會包含物體的矩形區域),訓練過程因此也是分成多個模塊進行。Faster rcnn使用RPN(region proposal network)卷積網絡替代rcnn/fast rcnn的selective
    search模塊,將RPN集成到fast rcnn檢測網絡中,得到一個統一的檢測網絡。盡管RPN與fast rcnn共享卷積層,但是在模型訓練過程中,需要反復訓練RPN網絡和fast rcnn網絡(注意這兩個網絡核心卷積層是參數共享的)。

  2. YOLO將物體檢測作為一個回歸問題進行求解,輸入圖像經過一次inference,便能得到圖像中所有物體的位置和其所屬類別及相應的置信概率。而rcnn/fast rcnn/faster rcnn將檢測結果分為兩部分求解:物體類別(分類問題),物體位置即bounding box(回歸問題)。

    preview

2.1.2基本流程

YOLO檢測網絡包括24個卷積層和2個全連接層,如下圖所示。

preview

其中,卷積層用來提取圖像特征,全連接層用來預測圖像位置和類別概率值。

整體來看,Yolo算法采用一個單獨的CNN模型實現end-to-end的目標檢測,整個系統如下圖所示:首先將輸入圖片resize到448x448,然后送入CNN網絡,最后處理網絡預測結果得到檢測的目標。相比R-CNN算法,其是一個統一的框架,其速度更快,而且Yolo的訓練過程也是end-to-end的。

img

具體來說,Yolo的CNN網絡將輸入的圖片分割成 S×S 網格,然后每個單元格負責去檢測那些中心點落在該格子內的目標,如圖所示:

img
邊界框置信度

可以看到狗這個目標的中心落在左下角一個單元格內,那么該單元格負責預測這個狗。每個單元格會預測 B個邊界框(bounding box)以及邊界框的置信度(confidence score)。所謂置信度其實包含兩個方面,一是這個邊界框含有目標的可能性大小,二是這個邊界框的準確度。前者記為 Pr(object) ,當該邊界框是背景時(即不包含目標),此時 Pr(object)=0 。而當該邊界框包含目標時, Pr(object)=1。邊界框的準確度可以用預測框與實際框(ground truth)的IOU(intersection over union,交并比)來表征,記為 \text{IOU}^{truth}_{pred}。因此置信度可以定義為:
Pr(object)*\text{IOU}^{truth}_{pred}

邊界框的大小與位置可以用4個值來表征:(x, y,w,h),其中 (x,y) 是邊界框的中心坐標,而 wh是邊界框的寬與高。還有一點要注意,中心坐標的預測值 (x,y) 是相對于每個單元格左上角坐標點的偏移值,并且單位是相對于單元格大小的,單元格的坐標定義如圖6所示。而邊界框的 wh 預測值是相對于整個圖片的寬與高的比例,這樣就保證了邊界框中心點不會超過單元格,但是框的邊界可以超過單元格。4個元素的大小應該在 [0,1] 范圍。這樣,每個邊界框的預測值實際上包含5個元素: (x,y,w,h,c),其中前4個表征邊界框的大小與位置,而最后一個值是置信度。

類別置信度

還有分類問題,對于每一個單元格其還要給出預測出N個類別概率值,其表征的是由該單元格負責預測的邊界框其目標屬于各個類別的概率。但是這些概率值其實是在各個邊界框置信度下的條件概率,即 Pr(class_{i}|object) 。以此計算出各個邊界框類別置信度(class-specific confidence scores):
Pr(class_{i}|object)*Pr(object)*\text{IOU}^{truth}_{pred}=Pr(class_{i})*\text{IOU}^{truth}_{pred}

邊界框類別置信度表征的是該邊界框中目標屬于各個類別的可能性大小以及邊界框匹配目標的好壞。一般會根據類別置信度來過濾網絡的預測框。

img

總結一下,每個單元格需要預測 B*5+N個值。如果將輸入圖片劃分為 S\times S 網格,那么最終預測值為 S*S*(B*5+N) 大小的張量。整個模型的預測值結構如下圖所示。對于PASCAL VOC數據,其共有20個類別,如果使用 S=7,B=2 ,那么最終的預測結果就是 7\times 7\times 30大小的張量。

image

2.1.3網絡訓練

在訓練之前,先在ImageNet上進行了預訓練,其預訓練的分類模型采用圖8中前20個卷積層,然后添加一個average-pool層和全連接層。預訓練之后,在預訓練得到的20層卷積層之上加上隨機初始化的4個卷積層和2個全連接層。整個網絡的流程如下圖所示:

img

損失函數:

其中,coordErroriouErrorclassError分別代表預測數據與標定數據之間的坐標誤差、IOU誤差和分類誤差。

loss=\sum_{i=0}^{S^{2} }{coordError + iouError + classError}

YOLO對上式loss的計算進行了如下修正。

  1. 位置相關誤差(坐標、IOU)與分類誤差對網絡loss的貢獻值是不同的,因此YOLO在計算loss時,使用!\lambda _{coord} =5修正coordError

  2. 在計算IOU誤差時,包含物體的格子與不包含物體的格子,二者的IOU誤差對網絡loss的貢獻值是不同的。若采用相同的權值,那么不包含物體的格子的confidence值近似為0,變相放大了包含物體的格子的confidence誤差在計算網絡參數梯度時的影響。

    可以這樣理解,整個 YOLO 系統其實最有效的地方就是那些包含了目標中心點的網格它們所預測的 2 個 bbox,所以它們這 2 個 bbox 的位置信息就至關重要,所以它們的坐標就不允許它們變化劇烈,所以就需要添加一個系數放大它們的誤差,進而達到懲罰的目的。而沒有包含目標的網格,雖然它們也會預測 bbox,也會有 confidence 的預測,但基本等同于無效,所以可以看做它們對于整體的 Loss 而言,沒有那么重要,因此要減弱它們對于 Loss 的影響,以防止它去干擾正常的包含了目標的那些 bbox 的 confidence 表現。

    為解決這個問題,YOLO 使用\lambda _{noobj} =0.5修正iouError。(注:此處的包含是指存在一個物體,它的中心坐標落入到格子內)。

  3. 對于相等的誤差值,大物體誤差對檢測的影響應小于小物體誤差對檢測的影響。這是因為,相同的位置偏差占大物體的比例遠小于同等偏差占小物體的比例。比如預測一個小的 bbox,groundtruth 的 width 是 4,它預測是 3,那么它的誤差是 1,再預測一個大的 bbox,groundtruth 的 width 是 100,預測值是 99,那么誤差也是 1。很容易發現,進行小尺寸的 bbox 預測時,誤差更敏感,所以 sum-sqaured error 手段需要改良。

    YOLO將物體大小的信息項(w和h)進行求平方根來改進這個問題。還是用剛才的例子,小的 bbox width prediction = 3,groundtruth = 4,誤差為 0.067。大的 bbox width prediction = 99,groundtruth = 100,誤差為 0.0025。

綜上,YOLO在訓練過程中Loss計算如下式所示:

img

其中,x,y,w,C,p為網絡預測值,x,y,w,C,\widehat{p}帽 為標注值。\Pi _{i}^{obj}表示物體落入格子i中,\Pi _{ij}^{obj}\Pi _{ij}^{noobj} 分別表示物體落入與未落入格子i的第j個bounding box內。

注:
YOLO方法模型訓練依賴于物體識別標注數據,因此,對于非常規的物體形狀或比例,YOLO的檢測效果并不理想。
YOLO采用了多個下采樣層,網絡學到的物體特征并不精細,因此也會影響檢測效果。
YOLO loss函數中,大物體IOU誤差和小物體IOU誤差對網絡訓練中loss貢獻值接近(雖然采用求平方根方式,但沒有根本解決問題)。因此,對于小物體,小的IOU誤差也會對網絡優化過程造成很大的影響,從而降低了物體檢測的定位準確性。

2.1.4局限

雖然每個格子可以預測B個bounding box,但是最終只選擇只選擇IOU最高的bounding box作為物體檢測輸出,即每個格子最多只預測出一個物體。當物體占畫面比例較小,如圖像中包含畜群或鳥群時,每個格子包含多個物體,但卻只能檢測出其中一個。這是Yolo算法的一個缺點,在后來的改進版本中,Yolo9000是把類別概率預測值與邊界框是綁定在一起的。

2.2 SSD / 2015

論文:SSD

SSD 就在 YOLO 的主意上添加了 Faster R-CNN 的 Anchor 概念,并融合不同卷積層的特征做出預測。

我們從上圖就可以很明顯的看出這是 YOLO 分治網絡Faster R-CNN Anchor 的融合,這就大大提高了對小物體的檢測。這里作者做實驗也提到和 Faster R-CNN 一樣的結果,這個 Anchor 的數量和形狀會對性能造成較大的影響。

除此之外,由于這個 Anchor 是規整形狀的,但是有些物體的擺放位置是千奇百怪的,所以沒有 數據增強 前的效果比增強后的效果差 7 個百分點。直觀點理解,做輕微地角度扭曲讓 Anchor 背后的神經元“看到”更多的信息。

還有一個重大的進步是結合了不同尺寸大小 Feature Maps 所提取的特征,然后進行預測。這是 FPN 網絡提出前的第一次做 Feature Pyramid 的嘗試,這個特征圖金字塔結合了不同層的信息,從而結合了不同 尺寸大小 的特征信息。

這個嘗試就大大地提高了識別的精度,且高分辨率(尺寸大)的 Feature Map 中含有更多小物體的信息,也是因為這個原因 SSD 能夠較好的識別小物體。

除此之外,和 YOLO 最大的區別是,SSD 沒有接 FC 減少了大量的參數量、提高了速度。

小結 / 2018

回顧過去,從 YOLO 到 SSD ,人們兼收并蓄把不同思想融合起來。

YOLO 使用了分治思想,將輸入圖片分為 SxS 的網格,不同網格用性能優良的分類器去分類。
YOLO v1 也有和當年其它杰出的目標檢測系統做對比,但在今天來看,這個并不十分重要,重要的是我們需要理解 YOLO 快的原因。

  • YOLO 就是一個撒漁網的捕魚過程,一次性搞定所有的目標定位。
  • YOLO 快的原因在于比較粗的粒度將輸入圖片劃分網格,然后做預測。

YOLO 的算法精髓都體現在它的 Loss 設計上及作者如何針對問題改進 Loss,這種思考問題的方式才是最值得我們學習的。

SSD 將 YOLO 和 Anchor 思想融合起來,并創新使用 Feature Pyramid 結構。

但是 Resize 輸入,必定會損失許多的信息和一定的精度,這也許是一刀流快的原因。

無論如何,YOLO 和 SSD 這兩篇論文都是讓人不得不贊嘆他們想法的精巧,讓人受益良多。

三、總結 Summary

在「目標檢測」中有兩個指標:快(Fast)準(Accurate)

一刀流代表的是快,但是最后在快和準中找到了平衡,第一是快,第二是準。
兩刀流代表的是準,雖然沒有那么快但是也有 6 FPS 可接受的程度,第一是準,第二是快。

兩類算法都有其適用的范圍,比如說實時快速動作捕捉,一刀流更勝一籌;復雜、多物體重疊,兩刀流當仁不讓。沒有不好的算法,只有不合適的使用場景。

四、一些概念

1. IOU

IoU度量兩個框之間的重疊。我們用它來測量我們預測的框與ground truth(真實物體邊界)的重疊程度。在一些數據集中,我們預先定義了一個IoU閾值(比如0.5)來分類預測是真陽性還是假陽性。

2. mAP

相關概念

mAP: mean Average Precision, 即各類別AP的平均值

AP: PR曲線下面積,后文會詳細講解

PR曲線: Precision-Recall曲線

Precision: TP / (TP + FP) 在你認為的正樣本中, 有多大比例真的是正樣本

Recall: TP / (TP + FN) 在真正的正樣本中, 有多少被你找到了

TP: IoU>0.5的檢測框數量(同一Ground Truth只計算一次)

FP: IoU<=0.5的檢測框,或者是檢測到同一個GT的多余檢測框的數量

FN: 沒有檢測到的GT的數量

明確問題: 大背景是object detection, 我就以正在學的RetinaNet應用背景為例, 識別出來的每一個框都有N+1個score, 對應著N個class和1個background, 我們會選score最高的那個作為最終的判斷。

問題核心: 我們需要一個對于score的threshold, 為什么呢? 比如在一個bounding box里, 我識別出來鴨子的score最高, 可是他也只有0.1, 那么他真的是鴨子嗎? 很可能他還是負樣本。 所以我們需要一個閾值, 如果識別出了鴨子而且分數大于這個閾值才真的說他是正樣本, 否則他是負樣本

那么threshold到底是怎么影響precision和recall的呢? 我們還是用鴨子的例子

  • 如果threshold太高, prediction非常嚴格, 所以我們認為是鴨子的基本都是鴨子,precision就高了;但也因為篩選太嚴格, 我們也放過了一些score比較低的鴨子, 所以recall就低了
  • 如果threshold太低, 什么都會被當成鴨子, precision就會很低, recall就會很高

這樣我們就明確了threshold確實對鴨子的precision和recall產生影響和變化的趨勢, 也就帶來了思考, precision不是一個絕對的東西,而是相對threshold而改變的東西, recall同理, 那么單個用precision來作為標準判斷, 就不合適。 這是一場precision與recall之間的trade off, 用一組固定值表述不夠全面, 因為我們根據不同的threshold, 可以取到不同(也可能相同)的precision recall值。 這樣想的話對于每個threshold,我們都有(precision, recall)的pair, 也就有了precision和recall之間的curve關系

有了這么一條precision-recall curve, 他衡量著兩個有價值的判斷標準, precision和recall的關系, 那么不如兩個一起動態考慮, 就有了鴨子這個class的Average Precision, 即curve下的面積, 他可以充分的表示在這個model中, precision和recall的總體優劣。

最后, 我們計算每個class的Average Precision, 就得到了mean Average Precision

非極大值抑制(NMS):

RCNN會從一張圖片中找出n個可能是物體的矩形框,然后為每個矩形框為做類別分類概率:

img

就像上面的圖片一樣,定位一個車輛,最后算法就找出了一堆的方框,我們需要判別哪些矩形框是沒用的。非極大值抑制的方法是:先假設有6個矩形框,根據分類器的類別分類概率做排序,假設從小到大屬于車輛的概率 分別為A、B、C、D、E、F。

(1)從最大概率矩形框F開始,分別判斷A~E與F的重疊度IOU是否大于某個設定的閾值;

(2)假設B、D與F的重疊度超過閾值,那么就扔掉B、D;并標記第一個矩形框F,是我們保留下來的。

(3)從剩下的矩形框A、C、E中,選擇概率最大的E,然后判斷E與A、C的重疊度,重疊度大于一定的閾值,那么就扔掉;并標記E是我們保留下來的第二個矩形框。

就這樣一直重復,找到所有被保留下來的矩形框。

非極大值抑制(NMS)顧名思義就是抑制不是極大值的元素,搜索局部的極大值。這個局部代表的是一個鄰域,鄰域有兩個參數可變,一是鄰域的維數,二是鄰域的大小。這里不討論通用的NMS算法,而是用于在目標檢測中用于提取分數最高的窗口的。例如在行人檢測中,滑動窗口經提取特征,經分類器分類識別后,每個窗口都會得到一個分數。但是滑動窗口會導致很多窗口與其他窗口存在包含或者大部分交叉的情況。這時就需要用到NMS來選取那些鄰域里分數最高(是行人的概率最大),并且抑制那些分數低的窗口。

參考資料 Reference

  1. R-CNN “Rich feature hierarchies for accurate object detection and semantic segmentation”
  2. SPP Net “Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition”
  3. Fast R-CNN “Fast R-CNN”
  4. Faster R-CNN “Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks”
  5. Mask R-CNN “Mask R-CNN”
  6. YOLO “You Only Look Once: Unified, Real-Time Object Detection”
  7. SSD “SSD: Single Shot MultiBox Detector”
  8. YOLO9000 “YOLO9000: Better, Faster, Stronger”
  9. 一文讀懂Faster RCNN
  10. 基于深度學習的「目標檢測」算法綜述
  11. RCNN- 將CNN引入目標檢測的開山之作
    12.https://blog.csdn.net/briblue/article/details/84794511
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容