本文是物體檢測系列文章的第一部分,即理解基於區域的物體檢測模型工作原理,個人認為本文講解地比較透徹,通過翻譯也是一個進一步消化吸收的過程。如有翻譯不當之處,請批評指正。

【譯自】:medium.com/@jonathan_hu

在這個系列中,我們將嘗試深入理解物體檢測任務。第一部分我們將介紹基於區域的物體檢測模型,包括Fast R-CNN,Faster R-CNN,R-FCN以及FPN。第二部分我們將學習單次檢測模型。第三部分我們將討論性能以及一些實現上的問題。通過學習本文,我們將學習內部工作原理,注意事項以及改善點。通過這些能夠更加深入地理解物體檢測任務。

  • 第一部分:理解基於區域的物體檢測模型工作原理(Faster R-CNN, R-FCN, FPN)
  • 第二部分:理解單次檢測模型工作原理(SSD,YOLO),FPN以及Focal loss
  • 第三部分:設計建議和經驗,物體檢測的發展方向

滑動窗口檢測器

自從AlexNet贏得了2012年ILSVRC挑戰賽的冠軍,CNN在圖像分類領域處於主宰地位。物體檢測任務的一個最暴力的方法就是從左到右、從上到下的滑動窗口,在每個窗口做分類任務。為了在不同的視角和距離檢測物體種類,會使用不同尺寸和縱橫比的窗口。

滑動窗口,從左到右,從上到下

我們基於滑動窗口來提取圖片的局部塊。這些局部有可能是扭曲的,因為很多分類器只能處理固定尺寸的圖像。然而,這並不會影響分類準確率,因為分類器在訓練時就會將扭曲的圖像納入訓練集。

將圖像變形為固定尺寸

扭曲的圖像局部塊輸入CNN分類器提取4096維的特徵向量,然後應用SVM分類器用於分類,應用另一個回歸模型用於回歸邊界框。

滑動窗口檢測器的工作流

下面是偽代碼。我們創建了很多窗口來檢測不同位置的不同物體。為了提高性能,一個很直接的方法是減少窗口數量。

for window in windows:
patch = get_patch(image,window)
results = detector(patch)

選擇查找(Selective Search)

不同於暴力方法,我們可以使用一個區域目標方法,即通過創建感興趣區域(ROIs)來做目標檢測。在選擇查找(SS)中,我們開始令每一個像素都是一個組。然後,我們計算每個組的質地,然後將彼此最近的合併為一個組。為了避免一個區域吞噬掉另一個區域,我們優先合併較小的組。我們持續合併組直到所有的組都合併完畢。在下圖第一行,我們展示了區域是如何合併的,第二行展示了合併過程中得到的所有可能的ROIs。

R-CNN

R-CNN通過使用區域提取方法得到了2000個ROIs。這些區域之後扭曲變形為同樣尺寸的圖像單獨輸入到CNN網路中。網路的最後是全連接層,用於分類物體和回歸邊界框。

使用region proposals, CNN以及全連接層來定位物體

下面是系統的流程。

R-CNN工作流

通過更少以及質量更高的ROIs,R-CNN相對於滑動窗口,更加快速和準確。

ROIs = region_proposal(image)
for ROI in ROIs:
patch = get_patch(image, ROI)
results = detector(patch)

邊界框回歸器

區域提取模型的計算複雜度還是很高。為了提高速度,我們通常採用一種更加簡單的區域提取方法來創建ROIs,之後輸入線性回歸器用於回歸邊界框。

利用回歸方法將原始藍色目標框調整為紅色目標框

Fast R-CNN

R-CNN需要很多精確的目標框而且很多區域彼此有重疊。R-CNN在訓練和預測時速度都很慢。如果我們有2000個目標框,每個都單獨輸入CNN做處理,也就是說我們將特徵提取過程重複了2000遍。

為瞭解決這個問題,Fast R-CNN的做法是不在每個目標框上做特徵提取,而是首先對整張圖像做特徵提取。然後在特徵圖上結合此前區域提取方法如SS創建的ROIs得到特徵圖目標框,之後我們使用ROI pooling將目標框處理成固定的尺寸,然後利用全連接層做分類和定位任務。由於只做了一次特徵提取,Fast R-CNN大大地提高了速度。

在特徵圖上應用region proposals,並且利用ROI Pooling得到固定尺寸的局部圖像塊

流程圖如下:

偽代碼如下,沒有了重複特徵提取,速度得到大大提升。Fast R-CNN在訓練時比R-CNN快10倍,在預測時比R-CNN快150倍。

feature_maps = proprocess(image)
ROIS = region_proposal(image)
for ROI in ROIs:
patch = roi_pooling(feature_maps, ROI)
results = detector2(patch)

關於Fast R-CNN最主要的一個點是整個網路可以通過設置多任務損失(分類損失和定位損失)進行端到端的訓練。這可以提高準確率。

ROI Pooling

因為Fast R-CNN使用了全連接層,我們應用ROI Pooing將不同尺寸的ROIs處理為預先定義好的同一尺寸。

我們以一個簡單的例子來說明,特徵圖尺寸是8x8,預定義尺寸是2x2。
  • 下圖左上:我們得到的特徵圖
  • 下圖右上:將目標框(藍色)和特徵圖重疊
  • 下圖左下:我們將目標框分割為目標維度。例如,這裡我們的目標維度是2x2,因此我們將目標框分割成了四個區域,這四個區域有相似或相等的尺寸。
  • 下圖右下:尋找每個區域的最大值作為該區域的值。
左上是輸入特徵圖,右下是輸出特徵圖,右上藍色框是ROI

最終我們在一個ROI上得到了一個2x2的特徵塊,可以後接全連接層進行分類和回歸任務。

Faster R-CNN

Fast R-CNN需要一個附加的區域提取方法如SS。然而,演算法在CPU上的運算速度非常慢。在測試中,Fast R-CNN需要使用2.3秒作出一個預測,其中2秒用於生成2000個ROIs。

feature_maps = proprocess(image)
ROIS = region_proposal(image) #計算消耗很大
for ROI in ROIs:
patch = roi_pooling(feature_maps, ROI)
results = detector2(patch)

Faster R-CNN跟Fast R-CNN基本一致,除了將區域提取方法替換為一個中間深度網路,然後從特徵圖裡提取ROIs。這個新的區域提取網路(RPN)更加高效,生成每張圖像的ROIs只需要10ms。

Faster R-CNN工作流同Fast R-CNN

網路流程圖是類似的,但是區域提取從普通方法替換為卷積網路(RPN)。

用深度網路來實現region proposal

區域提取網路(RPN)

RPN接收第一個卷積網路的特徵圖作為輸入。在這個特徵圖上應用3x3卷積核進行無類別的區域提取,如下面所示的ZF網路。其他的網路如VGG或者ResNet可以用於更加細緻的特徵提取,但是需要以速度為代價。ZF網路輸出256個值,輸入到兩個全連接層中分別預測邊界框和兩個對象性得分。這個對象性用來衡量目標框是否包含物體。我們可以使用一個回歸器來計算一個對象性得分,但是為了簡單起見,Faster R-CNN使用一個分類器得到了兩個可能的類別:一個是「有物體」,另一個是是沒有物體(即背景)。

對於特徵圖中的每一個位置,RPN會做k個假設。因此RPN在每個位置輸出4xk個坐標以及2xk個得分。下圖展示了在8x8特徵圖上應用3x3卷積得到8x8x3個ROIs(其中k=3)。下圖右邊展示的是在單個位置上的3個目標框。

這裡,我們做出了3個假設,並在之後對假設坐修正。由於我們只需要找到一個正確的,沒必要在初始化時做不同尺寸和形狀的假設。因此,Faster R-CNN就沒有隨機假設目標框。相反,她預測相對於一些參考邊界框(叫anchors)的偏移量 delta{x}, delta{y} 。我們對這些便宜值作出限制,因此我們的假設仍然集成了anchors。

為了在每個位置上作出k個預測,我們在每個位置上需要k個anchors。每個預測結果都和一個特定的anchor相關,但是不同位置上的anchor尺寸是一樣的。

這些anchors需要精挑細選以便保持多樣性,並且在不同的尺存和縱橫比上覆蓋真實目標。這可以指導初始訓練得到更好的猜測結果並且允許每個預測得到一個特定形狀的目標框。這使得早期訓練更加穩定和快速。

Faster R-CNN使用了更多的anchors。它使用了9個anchor框:在3種縱橫比以及三種尺度的組合。在每個位置上應用9個anchor,會得到2x9個對象性得分,以及4x9個坐標點。

Anchors也可以叫作先驗或者默認邊界框。

R-CNN模型表現

如下圖所示,Faster R-CNN表現的最好。

基於區域的全卷積神經網路(R-FCN)

假定我們只有一個檢測右眼的特徵圖。我們能用用它來定位一張臉嗎?可以的。由於右眼會出現在人臉圖的左上角,我們可以據此來定位人臉。

如果我們人臉其他部位(如左眼,鼻子,嘴巴)的特徵圖,我們可以結合這些特徵圖獲得人臉的更好定位。

所以我們的困惑在哪兒?在Faster R-CNN中,檢測器需要應用多個全連接網路來作出預測。如果有2000個ROIs,會帶來很大的計算消耗。

feature_maps = process(image)
ROIs = region_proposal(feature_maps)
for ROI in ROIs:
patch = roi_pooling(feature_maps,ROI)
class_scores, box = detector(patch) # Expensive!
class_probabilities = softmax(class_scores)

R-FCN通過減少每個ROI上的工作量來提高速度。基於區域的特徵圖是獨立於ROI的,可以單獨計算。剩下的工作就很簡單了,因此R-FCN比Faster R-CNN更快。

feature_maps = process(image)
ROIs = region_proposal(feature_maps)
score_maps = compute_score_map(feature_maps)
for ROI in ROIs:
V = region_roi_pool(scores_maps, ROI)
class_scores, box = average(V) # Much simpler!
class_probabilities = softmax(class_scores)

考慮一個5x5的特徵圖M,其中有一個藍色方形物體。我們將方形物體均分為3x3的區域。現在,我們創建了一個新的特徵圖只檢測方形的左上角(TL)。新的特徵圖示意如下圖最右。只有黃色的單元格是激活的。

由於我們將這個方形分成了9個部分,我們可以創建9個特徵圖分別用來檢測對應的區域。這些特徵圖叫做位置敏感得分圖,因為每個特徵圖只檢測(輸出得分)物體的一個局部。

我們定義下圖中紅色長方形區域是最終得到的ROI。我們將其劃分成3x3的區域並且計算每個區域包含物體對應部分的概率。例如,左上ROI區域包含左眼的可能性。我們將結果存儲到一個3x3的投票數組中。例如,vote_array[0][0]包含的得分表示我們是否找到了物體的左上部分。

這個將得分圖和ROI映射到投票數組的過程叫做position sensitive ROI-pool。這個過程跟ROI pool極像。我們不做進一步的討論,不過你可以利用擴展閱讀獲得更多的信息。

在計算了所有位置的ROI pool之後,通過取平均得到類別的得分。

假定我們有C類需要檢測。我們可以擴展到C+1個類,因為我們引入了一個背景類。每個類都有一個3x3的得分圖,因此一共有(C+1)x3x3個得分圖。基於這些得分圖我們得到了每個類的得分。之後我們應用一個softmax來計算每個類別上的概率。

下面是數據流。在我們的例子中,令k=3。

回顧

我們從最簡單的滑動窗口演算法開始。

for window in windows:
patch = get_patch(image,window)
results = detector(patch)

然後嘗試減少窗口的數量以及將工作量移到for循環之外。

ROIs = region_proposal(image)
for ROI in ROIs:
patch = get_patch(image, ROI)
results = detector(patch)

在第二部分,我們將完全去掉for循環。單次檢測器不需要像本文中的分步進行目標檢測。

拓展閱讀,關於FPN, R-FCN以及Mask R-CNN

FPN和R-FCN比我們之前描述的要複雜的多,如果有需要,可以參考:

  • Feature Pyramid Networks(FPN) for object detection
  • Region-based Fully Convolutional Networks (R-FCN).
  • Image segmentation with Mask R-CNN

資源

  • Detectron: Facebook Research』s implementation of the Faster R-CNN and Mask R-CNN using Caffe2.
  • The official implementation for the Faster R-CNN in MATLAB.
  • Faster R-CNN implementation in TensorFlow.
  • R-FCN implementation in MXNet.
  • R-FCN implementation in Caffe and MATLAB.
  • R-FCN implementation in TensorFlow.

推薦閱讀:

相關文章