酷播亮新聞
最棒的知識補給站

從RCNN到SSD,這應該是最全的一份目標檢測算法盤點

摘要:目標檢測是很多計算機視覺任務的基礎,不論我們需要實現圖像與文字的交互還是需要識別精細類別,它都提供了可靠的信息。 本文對目標檢測進行了整體回顧,第一部分從RCNN開始介紹基於候選區域的目標檢測器,包括F

目標檢測是很多計算機視覺任務的基礎,不論我們需要實現圖像與文字的交互還是需要識別精細類別,它都提供了可靠的信息。 本文對目標檢測進行了整體回顧,第一部分從RCNN開始介紹基於候選區域的目標檢測器,包括Fast
  R-CNN、Faster R-CNN 和
FPN等。 第二部分則重點討論了包括YOLO、SSD和RetinaNet等在內的單次檢測器,它們都是目前最為優秀的方法。

機器之心之前已經討論過非常多的目標檢測算法,對計算機視覺感興趣的讀者也可以結合以前的文章加強理解。

  • 深度學習目標檢測模型全面綜述:Faster R-CNN、R-FCN和SSD

  • 從零開始PyTorch項目:YOLO v3目標檢測實現

  • 像玩樂高一樣拆解Faster R-CNN:詳解目標檢測的實現過程

  • 後RCNN時代的物體檢測及實例分割進展

  • 物體檢測算法全概述:從傳統檢測方法到深度神經網絡框架

基於候選區域的目標檢測器

滑動窗口檢測器

自從 AlexNet 獲得 ILSVRC 2012 挑戰賽冠軍後,用 CNN 進行分類成為主流。 一種用於目標檢測的暴力方法是從左到右、從上到下滑動窗口,利用分類識別目標。 為了在不同觀察距離處檢測不同的目標類型,我們使用不同大小和寬高比的窗口。

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

我們根據滑動窗口從圖像中剪切圖像塊。 由於很多分類器只取固定大小的圖像,因此這些圖像塊是經過變形轉換的。 但是,這不影響分類準確率,因為分類器可以處理變形後的圖像。

將圖像變形轉換成固定大小的圖像

變形圖像塊被輸入 CNN 分類器中,提取出 4096 個特徵。 之後,我們使用 SVM 分類器識別類別和該邊界框的另一個線性回歸器。

滑動窗口檢測器的系統工作流程圖。

下面是偽代碼。 我們創建很多窗口來檢測不同位置的不同目標。 要提升性能,一個顯而易見的辦法就是減少窗口數量。

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

選擇性搜索

我們不使用暴力方法,而是用候選區域方法(region
  proposal method)創建目標檢測的感興趣區域(ROI)。 在選擇性搜索(selective
search,SS)中,我們首先將每個像素作為一組。 然後,計算每一組的紋理,並將兩個最接近的組結合起來。 但是為了避免單個區域吞噬其他區域,我們首先對較小的組進行分組。 我們繼續合併區域,直到所有區域都結合在一起。 下圖第一行展示瞭如何使區域增長,第二行中的藍色矩形代表合併過程中所有可能的
  ROI。

圖源:van de Sande et al. ICCV’11

R-CNN

R-CNN 利用候選區域方法創建了約 2000 個 ROI。 這些區域被轉換為固定大小的圖像,並分別饋送到卷積神經網絡中。 該網絡架構後面會跟幾個全連接層,以實現目標分類並提煉邊界框。

使用候選區域、CNN、仿射層來定位目標。

以下是 R-CNN 整個系統的流程圖:

通過使用更少且更高質量的 ROI,R-CNN 要比滑動窗口方法更快速、更準確。

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

邊界框回歸器

候選區域方法有非常高的計算複雜度。 為了加速這個過程,我們通常會使用計算量較少的候選區域選擇方法構建 ROI,並在後面使用線性回歸器(使用全連接層)進一步提煉邊界框。

使用回歸方法將藍色的原始邊界框提煉為紅色的。

Fast R-CNN

R-CNN 需要非常多的候選區域以提升準確度,但其實有很多區域是彼此重疊的,因此 R-CNN 的訓練和推斷速度非常慢。 如果我們有 2000 個候選區域,且每一個都需要獨立地饋送到 CNN 中,那麼對於不同的 ROI,我們需要重複提取 2000 次特徵。

此外,CNN 中的特徵圖以一種密集的方式表徵空間特徵,那麼我們能直接使用特徵圖代替原圖來檢測目標嗎?

直接利用特徵圖計算 ROI。

Fast
  R-CNN
使用特徵提取器(CNN)先提取整個圖像的特徵,而不是從頭開始對每個圖像塊提取多次。 然後,我們可以將創建候選區域的方法直接應用到提取到的特徵圖上。 例如,Fast
  R-CNN 選擇了 VGG16 中的捲積層 conv5 來生成
ROI,這些關注區域隨後會結合對應的特徵圖以裁剪為特徵圖塊,並用於目標檢測任務中。 我們使用 ROI
池化將特徵圖塊轉換為固定的大小,並饋送到全連接層進行分類和定位。 因為 Fast-RCNN 不會重複提取特徵,因此它能顯著地減少處理時間。

將候選區域直接應用於特徵圖,並使用 ROI 池化將其轉化為固定大小的特徵圖塊。

以下是 Fast R-CNN 的流程圖:

在下面的偽代碼中,計算量巨大的特徵提取過程從 For 循環中移出來了,因此速度得到顯著提升。 Fast R-CNN 的訓練速度是 R-CNN 的 10 倍,推斷速度是後者的 150 倍。

feature_maps
  = process(image)ROIs = region_proposal(feature_maps)for ROI in ROIs
patch = roi_pooling(feature_maps, ROI) results = detector2(patch)

Fast R-CNN 最重要的一點就是包含特徵提取器、分類器和邊界框回歸器在內的整個網絡能通過多任務損失函數進行端到端的訓練,這種多任務損失即結合了分類損失和定位 損失的方法,大大提升了模型準確度。

ROI 池化

因為 Fast R-CNN 使用全連接層,所以我們應用 ROI 池化將不同大小的 ROI 轉換為固定大小。

為簡潔起見,我們先將 8×8 特徵圖轉換為預定義的 2×2 大小。

  • 下圖左上角:特徵圖。

  • 右上角:將 ROI(藍色區域)與特徵圖重疊。

  • 左下角:將 ROI 拆分為目標維度。 例如,對於 2×2 目標,我們將 ROI 分割為 4 個大小相似或相等的部分。

  • 右下角:找到每個部分的最大值,得到變換後的特徵圖。

輸入特徵圖(左上),輸出特徵圖(右下),ROI (右上,藍色框)。

按上述步驟得到一個 2×2 的特徵圖塊,可以饋送至分類器和邊界框回歸器中。

Faster R-CNN

Fast R-CNN 依賴於外部候選區域方法,如選擇性搜索。 但這些算法在 CPU 上運行且速度很慢。 在測試中,Fast R-CNN 需要 2.3 秒來進行預測,其中 2 秒用於生成 2000 個 ROI。

feature_maps
  = process(image)ROIs = region_proposal(feature_maps) # Expensive!for
ROI in ROIs patch = roi_pooling(feature_maps, ROI) results =
detector2(patch)

Faster R-CNN 採用與 Fast R-CNN 相同的設計,只是它用內部深層網絡代替了候選區域方法。 新的候選區域網絡(RPN)在生成 ROI 時效率更高,並且以每幅圖像 10 毫秒的速度運行。

Faster R-CNN 的流程圖與 Fast R-CNN 相同。

外部候選區域方法代替了內部深層網絡。

候選區域網絡

候選區域網絡(RPN)將第一個卷積網絡的輸出特徵圖作為輸入。 它在特徵圖上滑動一個
  3×3 的捲積核,以使用卷積網絡(如下所示的 ZF 網絡)構建與類別無關的候選區域。 其他深度網絡(如 VGG 或
ResNet)可用於更全面的特徵提取,但這需要以速度為代價。 ZF 網絡最後會輸出 256
個值,它們將饋送到兩個獨立的全連接層,以預測邊界框和兩個 objectness 分數,這兩個 objectness
分數度量了邊界框是否包含目標。 我們其實可以使用回歸器計算單個 objectness 分數,但為簡潔起見,Faster R-CNN
使用只有兩個類別的分類器:即帶有目標的類別和不帶有目標的類別。

對於特徵圖中的每一個位置,RPN
  會做 k 次預測。 因此,RPN 將輸出 4×k 個坐標和每個位置上 2×k 個得分。 下圖展示了 8×8 的特徵圖,且有一個 3×3
的捲積核執行運算,它最後輸出 8×8×3 個 ROI(其中 k=3)。 下圖(右)展示了單個位置的 3 個候選區域。

此處有
  3 種猜想,稍後我們將予以完善。 由於只需要一個正確猜想,因此我們最初的猜想最好涵蓋不同的形狀和大小。 因此,Faster R-CNN
不會創建隨機邊界框。 相反,它會預測一些與左上角名為「錨點」的參考框相關的偏移量(如x、y)。 我們限制這些偏移量的值,因此我們的猜想仍然類似於錨點。

要對每個位置進行 k 個預測,我們需要以每個位置為中心的 k 個錨點。 每個預測與特定錨點相關聯,但不同位置共享相同形狀的錨點。

這些錨點是精心挑選的,因此它們是多樣的,且覆蓋具有不同比例和寬高比的現實目標。 這使得我們可以以更好的猜想來指導初始訓練,並允許每個預測專門用於特定的形狀。 該策略使早期訓練更加穩定和簡便。

Faster R-CNN 使用更多的錨點。 它部署 9 個錨點框:3 個不同寬高比的 3 個不同大小的錨點框。 每一個位置使用 9 個錨點,每個位置會生成 2×9 個 objectness 分數和 4×9 個坐標。

圖源:https://arxiv.org/pdf/1506.01497.pdf

R-CNN 方法的性能

如下圖所示,Faster R-CNN 的速度要快得多。

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

假設我們只有一個特徵圖用來檢測右眼。 那麼我們可以使用它定位人臉嗎? 應該可以。 因為右眼應該在人臉圖像的左上角,所以我們可以利用這一點定位整個人臉。

如果我們還有其他用來檢測左眼、鼻子或嘴巴的特徵圖,那麼我們可以將檢測結果結合起來,更好地定位人臉。

現在我們回顧一下所有問題。 在 Faster R-CNN 中,檢測器使用了多個全連接層進行預測。 如果有 2000 個 ROI,那麼成本非常高。

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 是獨立的,可以在每個 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(score_maps, ROI) class_scores, box = average(V) # Much
simpler! class_probabilities = softmax(class_scores)

現在我們來看一下 5 × 5 的特徵圖 M,內部包含一個藍色方塊。 我們將方塊平均分成 3 × 3 個區域。 現在,我們在 M 中創建了一個新的特徵圖,來檢測方塊的左上角(TL)。 這個新的特徵圖如下圖(右)所示。 只有黃色的網格單元 [2, 2] 處於激活狀態。

在左側創建一個新的特徵圖,用於檢測目標的左上角。

我們將方塊分成 9 個部分,由此創建了 9 個特徵圖,每個用來檢測對應的目標區域。 這些特徵圖叫作位置敏感得分圖(position-sensitive score map),因為每個圖檢測目標的子區域(計算其得分)。

生成 9 個得分圖

下圖中紅色虛線矩形是建議的
  ROI。 我們將其分割成 3 × 3 個區域,並詢問每個區域包含目標對應部分的概率是多少。 例如,左上角 ROI
區域包含左眼的概率。 我們將結果存儲成 3 × 3 vote 數組,如下圖(右)所示。 例如,vote_array[0][0]
包含左上角區域是否包含目標對應部分的得分。

將 ROI 應用到特徵圖上,輸出一個 3 x 3 數組。

將得分圖和 ROI 映射到 vote 數組的過程叫作位置敏感 ROI 池化(position-sensitive ROI-pool)。 該過程與前面討論過的 ROI 池化非常接近。

將 ROI 的一部分疊加到對應的得分圖上,計算 V[i][j]。

在計算出位置敏感 ROI 池化的所有值後,類別得分是其所有元素得分的平均值。

ROI 池化

假如我們有
  C 個類別要檢測。 我們將其擴展為 C + 1 個類別,這樣就為背景(非目標)增加了一個新的類別。 每個類別有 3 × 3 個得分圖,因此一共有
(C+1) × 3 × 3 個得分圖。 使用每個類別的得分圖可以預測出該類別的類別得分。 然後我們對這些得分應用 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)

單次目標檢測器

第二部分,我們將對單次目標檢測器(包括
  SSD、YOLO、YOLOv2、YOLOv3)進行綜述。 我們將分析 FPN
以理解多尺度特徵圖如何提高準確率,特別是小目標的檢測,其在單次檢測器中的檢測效果通常很差。 然後我們將分析 Focal loss 和
RetinaNet,看看它們是如何解決訓練過程中的類別不平衡問題的。

單次檢測器

Faster R-CNN 中,在分類器之後有一個專用的候選區域網絡。

Faster R-CNN 工作流

基於區域的檢測器是很準確的,但需要付出代價。 Faster R-CNN 在 PASCAL VOC 2007 測試集上每秒處理 7 幀的圖像(7 FPS)。 和 R-FCN 類似,研究者通過減少每個 ROI 的工作量來精簡流程。

feature_maps
  = process(image)ROIs = region_proposal(feature_maps)for ROI in ROIs
patch = roi_align(feature_maps, ROI) results = detector2(patch) # Reduce
  the amount of work here!

作為替代,我們是否需要一個分離的候選區域步驟? 我們可以直接在一個步驟內得到邊界框和類別嗎?

feature_maps = process(image)results = detector3(feature_maps) # No more separate step for ROIs

讓我們再看一下滑動窗口檢測器。 我們可以通過在特徵圖上滑動窗口來檢測目標。 對於不同的目標類型,我們使用不同的窗口類型。 以前的滑動窗口方法的致命錯誤在於使用窗口作為最終的邊界框,這就需要非常多的形狀來覆蓋大部分目標。 更有效的方法是將窗口當做初始猜想,這樣我們就得到了從當前滑動窗口同時預測類別和邊界框的檢測器。

基於滑動窗口進行預測

這個概念和 Faster R-CNN 中的錨點很相似。 然而,單次檢測器會同時預測邊界框和類別。 例如,我們有一個 8 × 8 特徵圖,並在每個位置做出 k 個預測,即總共有 8 × 8 × k 個預測結果。

64 個位置

在每個位置,我們有 k 個錨點(錨點是固定的初始邊界框猜想),一個錨點對應一個特定位置。 我們使用相同的 錨點形狀仔細地選擇錨點和每個位置。

使用 4 個錨點在每個位置做出 4 個預測。

以下是 4 個錨點(綠色)和 4 個對應預測(藍色),每個預測對應一個特定錨點。

4 個預測,每個預測對應一個錨點。

在 Faster R-CNN 中,我們使用卷積核來做 5 個參數的預測:4 個參數對應某個錨點的預測邊框,1 個參數對應 objectness 置信度得分。 因此 3× 3× D × 5 卷積核將特徵圖從 8 × 8 × D 轉換為 8 × 8 × 5。

使用 3×3 卷積核計算預測。

在單次檢測器中,卷積核還預測 C 個類別概率以執行分類(每個概率對應一個類別)。 因此我們應用一個 3× 3× D × 25 卷積核將特徵圖從 8 × 8 × D 轉換為 8 × 8 × 25(C=20)。

每個位置做出 k 個預測,每個預測有 25 個參數。

單次檢測器通常需要在準確率和實時處理速度之間進行權衡。 它們在檢測太近距離或太小的目標時容易出現問題。 在下圖中,左下角有 9 個聖誕老人,但某個單次檢測器只檢測出了 5 個。

SSD

SSD 是使用 VGG19 網絡作為特徵提取器(和 Faster R-CNN 中使用的 CNN 一樣)的單次檢測器。 我們在該網絡之後添加自定義卷積層(藍色),並使用卷積核(綠色)執行預測。

同時對類別和位置執行單次預測。

然而,卷積層降低了空間維度和分辨率。 因此上述模型僅可以檢測較大的目標。 為了解決該問題,我們從多個特徵圖上執行獨立的目標檢測。

使用多尺度特徵圖用於檢測。

版權聲明

本文僅代表作者觀點,不代表百度立場。
本文係作者授權百度百家發表,未經許可,不得轉載。

如有侵權請來信告知:酷播亮新聞 » 從RCNN到SSD,這應該是最全的一份目標檢測算法盤點