本教程由深度學習中文社區(dl.tustcs.com)發佈,關注我發送私信"YOLO"獲取代碼
前言
從深度學習的最新發展來看,對象檢測是一個非常有用的領域。近年來人們發現了許多用於目標檢測的算法,其中包括YOLO、SSD、Mask-RCNN 和 ValnANET 等等。
在過去的幾個月裡,我一直致力於改進目標檢測的方法。在這一過程我漸漸認識到,學習對象檢測的最佳途徑是從頭開始實現一遍。這正是本教程中所要做的。
我們將使用 PyTorch 來實現基於 YOLO V3 的對象檢測器。
本教程的代碼基於 Python 3.5, 和 PyTorch 0.4。
本教程分為5個部分:
- 第1部分(本文):理解 YOLO 的原理
- 第2部分:創建網絡結構
- 第3部分:實現網絡的前向傳遞
- 第4部分:目標分閾值和非極大值抑制
- 第5部分:網絡的輸入和輸出
背景知識
- 理解卷積神經網絡的原理,包括 Residual Blocks, skip connections, 和 Upsampling。
- 目標檢測的定義、邊界框迴歸、IoU 和非極大值抑制。
- PyTorch 的基本用法。
什麼是 YOLO?
YOLO 的全稱是 You Only Look Once。它是一種基於深度卷積神經網絡的目標檢測器。我們先了解 YOLO 的工作原理。
全卷積神經網絡 FCN
YOLO 僅僅使用卷積層,這種僅適用卷基層的網絡我們稱之為全卷積神經網絡(Fully Convolutional Network)。YOLO 擁有 75 個卷積層,還有 skip connections 和 上採樣 Upsampling 層。它使用步幅為 2 的卷積層對特徵圖進行下采樣,而不是使用池化層,這有助於防止通常由池化導致的低級特徵丟失。
作為 FCN,YOLO 對於輸入圖像的大小並沒有要求。然而,在實踐中,我們可能想要固定輸入的大小,以防止後續一些問題的出現。這其中的一個重要原因是:如果我們希望按 batch 處理圖像(batch 由 GPU 並行處理,這樣可以提升速度),我們就需要固定所有圖像的高度和寬度。這就需要將多個圖像整合進一個大的 batch(將將許多 PyTorch Tensors 合併成一個)。
YOLO 通過 stride(步幅)對圖像進行上採樣。例如,如果網絡的步幅是 32,則大小為 416×416 的輸入圖像將產生 13×13 的輸出。
輸出
一般來講,卷積層所學習的特徵會被傳遞到分類器/迴歸器進行預測(邊界框的座標、類別標籤等)。
在 YOLO 中,預測是通過 1 x 1 的卷積層完成的。
現在要注意的是,我們的輸出都是特徵圖(feature map),因為使用 1 x 1 的卷基層,所以每次輸出的特徵圖都和之前的特徵圖是一樣大小的。在 YOLO v3上,預測圖就是每個可以預測固定數量邊界框的單元格。
對於網絡的深度,我們的特徵圖包含 (B x (5 C)) 個條目, B 代表每個單元可以預測的邊界框數量。根據 YOLO 的論文,這些 B 邊界框中的每一個都可能專門用於檢測某種對象。每個邊界框都有 5 C 個屬性,分別描述每個邊界框的中心座標、維度、objectness 分數和 C 類置信度。YOLO v3 在每個單元中預測 3 個邊界框。
如果對象的中心位於單元格的感受野內,你會希望特徵圖的每個單元格都可以通過其中一個邊界框預測對象。(感受野是輸入圖像對於單元格可見的區域。)
這與 YOLO 是如何訓練的有關,只有一個邊界框負責檢測任意給定對象。首先,我們必須確定這個邊界框屬於哪個單元格。
因此,我們需要切分輸入圖像,把它拆成維度等於最終特徵圖的網格。
讓我們思考下面一個例子,其中輸入圖像大小是 416×416,網絡的步幅是 32。如之前所述,特徵圖的維度會是 13×13。隨後,我們將輸入圖像分為 13×13 個網格。
輸入圖像中包含了真值對象框中心的網格會作為負責預測對象的單元格。在圖像中,它是被標記為紅色的單元格,其中包含了真值框的中心(被標記為黃色)。
現在,紅色單元格是網格中第七行的第七個。我們現在使特徵圖中第七行第七個單元格(特徵圖中的對應單元格)作為檢測狗的單元。
現在,這個單元格可以預測三個邊界框。哪個將會分配給狗的真值標籤?為了理解這一點,我們必須理解錨點的概念。
請注意,我們在這裡討論的單元格是預測特徵圖上的單元格,我們將輸入圖像分隔成網格,以確定預測特徵圖的哪個單元格負責預測對象。
錨點框(Anchor Box)
預測邊界框的寬度和高度看起來非常合理,但在實踐中,訓練會帶來不穩定的梯度。所以,現在大部分目標檢測器都是預測對數空間(log-space)變換,或者預測與預訓練默認邊界框(即錨點)之間的偏移。
然後,這些變換被應用到錨點框來獲得預測。YOLO v3 有三個錨點,所以每個單元格會預測 3 個邊界框。
回到前面的問題,負責檢測狗的邊界框的錨點有最高的 IoU,且有真值框。
預測
下面的公式描述了網絡輸出是如何轉換,以獲得邊界框預測結果的。
中心座標
注意:我們使用 sigmoid 函數進行中心座標預測。這使得輸出值在 0 和 1 之間。原因如下:
正常情況下,YOLO 不會預測邊界框中心的確切座標。它預測:
- 與預測目標的網格單元左上角相關的偏移;
- 使用特徵圖單元的維度(1)進行歸一化的偏移。
以我們的圖像為例。如果中心的預測是 (0.4, 0.7),則中心在 13 x 13 特徵圖上的座標是 (6.4, 6.7)(紅色單元的左上角座標是 (6,6))。
但是,如果預測到的 x,y 座標大於 1,比如 (1.2, 0.7)。那麼中心座標是 (7.2, 6.7)。注意該中心在紅色單元右側的單元中,或第 7 行的第 8 個單元。這打破了 YOLO 背後的理論,因為如果我們假設紅色框負責預測目標狗,那麼狗的中心必須在紅色單元中,不應該在它旁邊的網格單元中。
因此,為了解決這個問題,我們對輸出執行 sigmoid 函數,將輸出壓縮到區間 0 到 1 之間,有效確保中心處於執行預測的網格單元中。
邊界框的維度
我們對輸出執行對數空間變換,然後乘錨點,來預測邊界框的維度。
得出的預測 bw 和 bh 使用圖像的高和寬進行歸一化。即,如果包含目標(狗)的框的預測 bx 和 by 是 (0.3, 0.8),那麼 13 x 13 特徵圖的實際寬和高是 (13 x 0.3, 13 x 0.8)。
Objectness 分數
Object 分數表示目標在邊界框內的概率。紅色網格和相鄰網格的 Object 分數應該接近 1,而角落處的網格的 Object 分數可能接近 0。
objectness 分數的計算也使用 sigmoid 函數,因此它可以被理解為概率。
類別置信度
類別置信度表示檢測到的對象屬於某個類別的概率(如狗、貓、香蕉、汽車等)。在 v3 之前,YOLO 需要對類別分數執行 softmax 函數操作。
但是,YOLO v3 捨棄了這種設計,作者選擇使用 sigmoid 函數。因為對類別分數執行 softmax 操作的前提是類別是互斥的。簡言之,如果對象屬於一個類別,那麼必須確保其不屬於另一個類別。這在我們設置檢測器的 COCO 數據集上是正確的。但是,當出現類別「女性」(Women)和「人」(Person)時,該假設不可行。這就是作者選擇不使用 Softmax 激活函數的原因。
在不同尺度上的預測
YOLO v3 在 3 個不同尺度上進行預測。檢測層用於在三個不同大小的特徵圖上執行預測,特徵圖步幅分別是 32、16、8。這意味著,當輸入圖像大小是 416 x 416 時,我們在尺度 13 x 13、26 x 26 和 52 x 52 上執行檢測。
該網絡在第一個檢測層之前對輸入圖像執行下采樣,檢測層使用步幅為 32 的層的特徵圖執行檢測。隨後在執行因子為 2 的上採樣後,並與前一個層的特徵圖(特徵圖大小相同)拼接。另一個檢測在步幅為 16 的層中執行。重複同樣的上採樣步驟,最後一個檢測在步幅為 8 的層中執行。
在每個尺度上,每個單元使用 3 個錨點預測 3 個邊界框,錨點的總數為 9(不同尺度的錨點不同)。
作者稱這幫助 YOLO v3 在檢測較小目標時取得更好的性能,而這正是 YOLO 之前版本經常被抱怨的地方。上採樣可以幫助該網絡學習細粒度特徵,幫助檢測較小目標。
輸出處理
對於大小為 416 x 416 的圖像,YOLO 預測 ((52 x 52) (26 x 26) 13 x 13)) x 3 = 10647 個邊界框。但是,我們的示例中只有一個對象——一隻狗。那麼我們怎麼才能將檢測次數從 10647 減少到 1 呢?
目標置信度閾值:首先,我們根據它們的 objectness 分數過濾邊界框。通常,分數低於閾值的邊界框會被忽略。
非極大值抑制:非極大值抑制(NMS)可解決對同一個圖像的多次檢測的問題。例如,紅色網格單元的 3 個邊界框可以檢測一個框,或者臨近網格可檢測相同對象。
實現
YOLO 只能檢測出屬於訓練所用數據集中類別的對象。我們的檢測器將使用官方權重文件,這些權重通過在 COCO 數據集上訓練網絡而獲得,因此我們可以檢測 80 個對象類別。
該教程的第一部分到此結束。這部分詳細講解了 YOLO 算法。如果你想深度瞭解 YOLO 的工作原理、訓練過程和與其他檢測器的性能規避,可閱讀原始論文:
YOLO V1: You Only Look Once: Unified, Real-Time Object Detection
YOLO V2: YOLO9000: Better, Faster, Stronger
YOLO V3: An Incremental Improvement
代碼已上傳至GitHub,關注我頭條號發送私信"YOLO"獲取.
閱讀更多 深度學習中文社區 的文章