目標檢測SSD: Single Shot MultiBox Detector


一、前言

1.1 什么是目標檢測

目標檢測問題可以分為以下兩個問題:

  • 分類:所有類別的概率
  • 定位: 4個值(中心位置x,y,寬w,高h)
    在這里插入圖片描述
    目標檢測近年來已經取得了很重要的進展,主流的算法主要分為兩個類型(參考RefineDet):(1)two-stage方法,如R-CNN系算法,其主要思路是先通過啟發式方法(selective search)或者CNN網絡(RPN)產生一系列稀疏的候選框,然后對這些候選框進行分類與回歸,two-stage方法的優勢是准確度高;(2)one-stage方法,如Yolo和SSD,其主要思路是均勻地在圖片的不同位置進行密集抽樣,抽樣時可以采用不同尺度和長寬比,然后利用CNN提取特征后直接進行分類與回歸,整個過程只需要一步,所以其優勢是速度快,但是均勻的密集采樣的一個重要缺點是訓練比較困難,這主要是因為正樣本與負樣本(背景)極其不均衡(參見Focal Loss),導致模型准確度稍低。不同算法的性能如下圖所示,可以看到兩類方法在准確度和速度上的差異。
    在這里插入圖片描述

1.2 Single-shot V.S. R-CNN家族

● R-CNN家族基於候選區域做預測.預測分為兩步:

  1. 使用Selective Search或者Region-Proposal-Network
    選出候選區域.候選區域的數量不大,減少了后續的
    計算量。
  2. 使用分類器和回歸器在候選區域上面做分類和邊
    界預測

● Single-shot家族不做候選區域選擇,直接對所有可能的區域預測類別和邊界.
在這里插入圖片描述

1.3 SDD的優點

  1. 比Faster R-CNN更快,比YOLO更准確。
  2. 根據預定義的anchor,使用卷積層的輸出,預測anchor對應區域包含的物體類別,邊界位置和大小。
  3. 使用不同的卷積層的輸出預測不同尺寸的物體,為不同的長寬比的物體單獨做預測
  4. 端到端的訓練,訓練方便

二、SSD的設計理念

SSD和Yolo一樣都是采用CNN網絡來進行檢測,但是卻采用了多尺度的特征圖,其基本架構如下圖所示:
在這里插入圖片描述

2.1 采用多尺度特征圖用於檢測

所謂多尺度采用大小不同的特征圖,CNN網絡一般前面的特征圖比較大,后面會逐漸采用stride=2的卷積或者pool來降低特征圖大小,這正如下圖所示,一個比較大的特征圖和一個比較小的特征圖,它們都用來做檢測。這樣做的好處是比較大的特征圖來用來檢測相對較小的目標,而小的特征圖負責檢測大目標
在這里插入圖片描述

2.2 采用卷積進行檢測

與Yolo最后采用全連接層不同,SSD直接采用卷積對不同的特征圖來進行提取檢測結果。對於形狀為 m×n×p的特征圖,只需要采用 3×3×p這樣比較小的卷積核做卷積,可以預測每一個位置對於的4個位置信息中的一個,或者所有類別概率中的一個值以conv102為例:
在這里插入圖片描述為每一個anchor,需要使用(4 +類別總數)個卷積核做卷積
在這里插入圖片描述

2.3 設置先驗框(anchor)

SSD借鑒了Faster R-CNN中anchor的理念,每個單元設置尺度或者長寬比不同的先驗框,預測的邊界框(bounding boxes)是以這些先驗框為基准的,在一定程度上減少訓練難度。一般情況下,每個單元會設置多個先驗框,其尺度和長寬比存在差異,如下圖所示,可以看到每個單元使用了4個不同的先驗框,圖片中貓和狗分別采用最適合它們形狀的先驗框來進行訓練。
在這里插入圖片描述
在這里插入圖片描述

三、SSD的定位原理

SSD的檢測值也與Yolo不太一樣。對於每個單元的每個先驗框,其都輸出一套獨立的檢測值,對應一個邊界框,主要分為兩個部分。第一部分是各個類別的置信度或者評分,值得注意的是SSD將背景也當做了一個特殊的類別,如果檢測目標共有 c 個類別,SSD其實需要預測 c+1 個置信度值,其中第一個置信度指的是不含目標或者屬於背景的評分。在預測過程中,置信度最高的那個類別就是邊界框所屬的類別,特別地,當第一個置信度值最高時,表示邊界框中並不包含目標。第二部分就是邊界框的location,包含4個值 \(l=(c x, c y, w, h)\) ,分別表示邊界框的中心坐標以及寬高。但是真實預測值其實只是邊界框相對於先驗框的轉換值(paper里面說是offset,但是覺得transformation更合適,參見R-CNN)。先驗框位置用 \(d=\left(d^{c x}, d^{c y}, d^{w}, d^{h}\right)\) 表示,其對應真實邊界框用 \(b=\left(b^{c x}, b^{c y}, b^{w}, b^{h}\right)\)表示,那么邊界框的預測值 \(l\) 其實是 \(b\) 相對於\(d\) 的轉換值:

\(l^{c x}=\left(b^{c x}-d^{c x}\right) / d^{w}, l^{c y}=\left(b^{c y}-d^{c y}\right) / d^{h}\)
\(l^{w}=\log \left(b^{w} / d^{w}\right), l^{h}=\log \left(b^{h} / d^{h}\right)\)

習慣上,我們稱上面這個過程為邊界框的編碼(encode),預測時,你需要反向這個過程,即進行解碼(decode),從預測值\(l\) 中得到邊界框的真實位置 \(b\)

\(b^{c x}=d^{w} l^{c x}+d^{c x}, b^{c y}=d^{y} l^{c y}+d^{c y}\)
\(b^{w}=d^{w} \exp \left(l^{w}\right), b^{h}=d^{h} \exp \left(l^{h}\right)\)

然而,在SSD的Caffe源碼實現中還有trick,那就是設置variance超參數來調整檢測值,通過bool參數variance_encoded_in_target來控制兩種模式,當其為True時,表示variance被包含在預測值中,就是上面那種情況。但是如果是False(大部分采用這種方式,訓練更容易?),就需要手動設置超參數variance,用來對 \(l\) 的4個值進行放縮,此時邊界框需要這樣解碼:

\(b^{c x}=d^{w}\left(\text { variance }[0] * l^{c x}\right)+d^{c x}, b^{c y}=d^{y}\left(\text { variance }[1] * l^{c y}\right)+d^{c y}\)
\(b^{w}=d^{w} \exp \left(\text {variance}[2] * l^{w}\right), b^{h}=d^{h} \exp \left(\text {variance}[3] * l^{h}\right)\)

綜上所述, 對於一個大小 \(m \times n\) 的特征圖, 共有 \(m\times n\) 個單元, 每個單元設置的先驗框數目記為\(k\) ,那么每個單元共需要 \((c+4) k\) 個預測值, 所有的單元共需要 \((c+4) k m n\) 個預測值, 由於SSD采用卷積做檢測, 所以就需要 \((c+4) k\) 個卷積核完成這個特征圖的檢測過程。

四、SSD的網絡結構

SSD采用VGG16作為基礎模型,然后在VGG16的基礎上新增了卷積層來獲得更多的特征圖以用於檢測。SSD的網絡結構如下圖所示。可以明顯看到SSD利用了多尺度的特征圖做檢測。模型的輸入圖片大小是 300 × 300 (還可以是 512 × 512 ,其與前者網絡結構沒有差別,只是最后新增一個卷積層。)
在這里插入圖片描述
采用VGG16做基礎模型,首先VGG16是在ILSVRC CLS-LOC數據集預訓練。然后借鑒了DeepLab-LargeFOV,分別將VGG16的全連接層fc6和fc7轉換成 3 × 3 卷積層 conv6和 1 × 1卷積層conv7,同時將池化層pool5由原來的stride=2的2 × 2變成stride=1的 3 × 3(猜想是不想reduce特征圖大小),為了配合這種變化,采用了一種Atrous Algorithm,其實就是conv6采用擴展卷積或帶孔卷積(Dilation Conv),其在不增加參數與模型復雜度的條件下指數級擴大卷積的視野,其使用擴張率(dilation rate)參數,來表示擴張的大小,如下圖所示,(a)是普通的 3 × 3 卷積,其視野就是 3 × 3 ,(b)是擴張率為2,此時視野變成 7 × 7,(c)擴張率為4時,視野擴大為 15 × 15 ,但是視野的特征更稀疏了。Conv6采用 3 × 3 大小但dilation rate=6的擴展卷積。
在這里插入圖片描述然后移除dropout層和fc8層,並新增一系列卷積層,在檢測數據集上做finetuing。
在這里插入圖片描述

其中VGG16中的Conv4_3層將作為用於檢測的第一個特征圖。conv4_3層特征圖大小是 38 × 38,但是該層比較靠前,其norm較大,所以在其后面增加了一個L2 Normalization層(參見ParseNet),以保證和后面的檢測層差異不是很大,這個和Batch Normalization層不太一樣,其僅僅是對每個像素點在channle維度做歸一化,而Batch Normalization層是在[batch_size, width, height]三個維度上做歸一化。

從后面新增的卷積提取Conv7,Conv8_2,Conv9_2,Conv10_2,Conv11_2作為檢測所用的特征圖,加上Conv4_3層,共提取了6個特征圖,其大小分別是(38,38),(19,19),(10,10),(5,5),(3,3),(1,1),
得到了特征圖之后,需要對特征圖進行卷積得到檢測結果,下圖給出了一個 5 × 5 大小的特征圖 的檢測過程。其中Priorbox是得到先驗框。檢測值包含兩個部分:類別置信度和邊界框位置,各采用一次 3 × 3 卷積來進行完成。令 \(n_{k}\) 為該特征圖所采用的先驗框數
目,那么類別置信度需要的卷積核數量為 \(n_{k} \times c,\) 而邊界框位置需要的卷積核數量為 \(n_{k} \times 4\) 由於每個先驗框都會預測一個邊界框,所以SSD300一共可以預測 \(38 \times 38 \times 4+19 \times 19 \times 6+10 \times 10 \times 6+5 \times 5 \times 6+3 \times 3 \times 4+1 \times 1 \times 4=8732\)
個邊界框, 這是一個相當龐大的數字,所以說SSD本質上是密集采樣。
在這里插入圖片描述

五、先驗框的選擇原則

但是不同特征圖設置的先驗框數目不同(同一個特征圖上每個單元設置的先驗框是相同的,這里的數目指的是一個單元的先驗框數目)。先驗框的設置,包括尺度(或者說大小)和長寬比兩個方面。對於先驗框的尺度,其遵守一個線性遞增規則:隨着特征圖大小降低,先驗框尺度線性增加

5.1 確定先驗框的尺寸

在這里插入圖片描述其中 \(m\) 指的特征圖個數,但卻是 5,因為第一層 (Conv4_3層) 是單獨設置的, \(s_{k}\) 表示先驗框大小相對於圖片的比例,而 \(s_{m i n}\)\(s_{m a x}\) 表示比例的最小值與最大值, paper里面取0.2和 0.9。對於第一個特征圖,其先驗框的尺度比例一般設置為 \(s_{m i n} / 2=0.1,\) 那么尺度為 \(300 \times 0.1=30\) 。對於后面的特征圖, 先驗框尺度按照上面公式線性增加,但是先將尺度比例先 擴大100倍, 此時增長步長為 \(\left\lfloor\frac{\left\lfloor s_{\max } \times 100\right\rfloor-\left\lfloor s_{\min } \times 100\right\rfloor}{m-1}\right\rfloor=17,\) 這樣各個特征圖的\(s_{k}\)\(20,37,54,71,88,\) 將這些比例除以100,然后再乘以圖片大小,可以得到各個特征圖的 尺度為 60,111,162,213,264,這種計算方式是參考SSD的Caffe源碼。綜上,可以得到各個特 征圖的先驗框尺度 30,60,111,162,213,264 。

5.2 確定先驗框的長寬比

一般選取 \(a_{r} \in\left\{1,2,3, \frac{1}{2}, \frac{1}{3}\right\}\),對於特定的長寬比, 按如下公式計算先驗框的寬度與高度 (后面的 \(s_{k}\) 均指的是先驗框實際尺 度, 而不是尺度比例):

\(w_{k}^{a}=s_{k} \sqrt{a_{r}}, h_{k}^{a}=s_{k} / \sqrt{a_{r}}\)

默認情況下,每個特征圖會有一個 \(a_{r}=1\) 具尺度為 \(s_{k}\) 的先驗框, 除此之外, 還會設置一個尺 度為 \(s_{k}^{\prime}=\sqrt{s_{k} s_{k+1}}\)\(a_{r}=1\) 的先驗框, 這樣每個特征圖都設置了兩個長寬比為1但大小不同 的正方形先驗框。注意最后一個特征圖需要參考一個虛擬 \(s_{m+1}=300 \times 105 / 100=315\) 來計 算 \(s_{m}^{\prime} 。\) 因此, 每個特征圖一共有 6 個先驗框 \(\left\{1,2,3, \frac{1}{2}, \frac{1}{3}, 1^{\prime}\right\},\) 但是在實現時,Conv4_3, Conv10_2和Conv11_2層僅使用4個先驗框,它們不使用長寬比為 3, \(\frac{1}{3}\) 的先驗框。每個單元的先驗框的中心點分布在各個單元的中心, 即 \(\left(\frac{i+0.5}{\left|f_{k}\right|}, \frac{j+0.5}{\left|f_{k}\right|}\right), i, j \in\left[0,\left|f_{k}\right|\right)\)其中 \(\left|f_{k}\right|\) 為特征圖的大小。

5.3 確定先驗框的位置

\(\left(x_{\ell}^{i}, y_{\ell}^{j}\right)=\left(\frac{i+0.5}{m} W, \frac{j+0.5}{n} H\right)\)
\(i=0,1, \ldots, m-1\)
\(j=0,1, \ldots, n-1\)
W:輸入圖像的寬度 H: 輸入圖像的高度

六、先驗框匹配

在訓練過程中,首先要確定訓練圖片中的ground truth(真實目標)與哪個先驗框來進行匹配,與之匹配的先驗框所對應的邊界框將負責預測它。在Yolo中,ground truth的中心落在哪個單元格,該單元格中與其IOU最大的邊界框負責預測它。但是在SSD中卻完全不一樣,SSD的先驗框與ground truth的匹配原則主要有兩點:

  • 首先,對於圖片中每個ground truth,找到與其IOU最大的先驗框,該先驗框與其匹配,這樣,可以保證每個ground truth一定與某個先驗框匹配。通常稱與ground truth匹配的先驗框為正樣本(其實應該是先驗框對應的預測box,不過由於是一一對應的就這樣稱呼了),反之,若一個先驗框沒有與任何ground truth進行匹配,那么該先驗框只能與背景匹配,就是負樣本。一個圖片中ground truth是非常少的, 而先驗框卻很多,如果僅按第一個原則匹配,很多先驗框會是負樣本,正負樣本極其不平衡,所以需要第二個原則。
  • 第二個原則是:對於剩余的未匹配先驗框,若某個ground truth的 IOU 大於某個閾值(一般是0.5),那么該先驗框也與這個ground truth進行匹配。這意味着某個ground truth可能與多個先驗框匹配,這是可以的。但是反過來卻不可以,因為一個先驗框只能匹配一個ground truth,如果多個ground truth與某個先驗框 IOU大於閾值,那么先驗框只與IOU最大的那個ground truth進行匹配。

第二個原則一定在第一個原則之后進行,仔細考慮一下這種情況,如果某個ground truth所對應最大IOU 小於閾值,並且所匹配的先驗框卻與另外一個ground truth的 IOU 大於閾值,那么該先驗框應該匹配誰,答案應該是前者,首先要確保某個ground truth一定有一個先驗框與之匹配。但是,這種情況我覺得基本上是不存在的。由於先驗框很多,某個ground truth的最大 IOU 肯定大於閾值,所以可能只實施第二個原則就可以了。下圖為一個匹配示意圖,其中綠色的GT是ground truth,紅色為先驗框,FP表示負樣本,TP表示正樣本。
在這里插入圖片描述
盡管一個ground truth可以與多個先驗框匹配,但是ground truth相對先驗框還是太少了,所以負樣本相對正樣本會很多。為了保證正負樣本盡量平衡,SSD采用了hard negative mining,就是對負樣本進行抽樣,抽樣時按照置信度誤差(預測背景的置信度越小,誤差越大)進行降序排列,選取誤差的較大的top-k作為訓練的負樣本,以保證正負樣本比例接近1:3。

							IOU定義如下:

在這里插入圖片描述

七、損失函數

損失函數定義為位置誤差(locatization loss, loc)與置信度誤差(confidence loss, conf)的加權和:

\(L(x, c, l, g)=\frac{1}{N}\left(L_{c o n f}(x, c)+\alpha L_{l o c}(x, l, g)\right)\)

  • N:與真實邊界框配對的anchor的數量,即為選定的正樣本和負樣本的數量之和。
  • \(\alpha\) 用於平衡分類損失和定位損失, 可以和通過交叉驗證cross validation選定.
  • x: 這里 \(x_{i j}^{p} \in\{1,0\}\) 為一個指示參數, 當 \(x_{i j}^{p}=1\) 時表示第 \(i\) 個先驗框與第 j 個ground truth匹配,並且ground truth的類別為 \(p\)
  • c: 真實物體的預測值
  • I: 預測的邊界框中心位置和長, 寬
  • g: 真實的邊界框中心位置和長, 寬

對於位置誤差,其采用Smooth L1 loss,定義如下:

\(L_{l o c}(x, l, g)=\sum_{i \in P o s}^{N} \sum_{m \in\{c x, c y, w, h\}} x_{i j}^{k} \operatorname{smooth}_{\mathrm{L} 1}\left(l_{i}^{m}-\hat{g}_{j}^{m}\right)\)

\(\hat{g}_{j}^{c x}=\left(g_{j}^{c x}-d_{i}^{c x}\right) / d_{i}^{w} \quad \hat{g}_{j}^{c y}=\left(g_{j}^{c y}-d_{i}^{c y}\right) / d_{i}^{h}\)

\(\hat{g}_{j}^{w}=\log \left(\frac{g_{j}^{w}}{d_{i}^{w}}\right) \quad \hat{g}_{j}^{h}=\log \left(\frac{g_{j}^{h}}{d_{i}^{h}}\right)\)

\(\operatorname{smooth}_{L_{1}}(x)=\left\{\begin{array}{ll}0.5 x^{2} & \text { if }|x|<1 \\ |x|-0.5 & \text { otherwise }\end{array}\right.\)
在這里插入圖片描述
由於 \(x_{i j}^{p}\) 的存在, 所以位置誤差僅針對正樣本進行計算。值得注意的是, 要先對ground truth的 \(g\) 進行編碼得到 \(\hat{g},\) 因為預測值 \(l\) 也是編碼值, 若設置variance_encoded_in_target=True, 編碼時要加上variance:

\(\hat{g}_{j}^{c x}=\left(g_{j}^{c x}-d_{i}^{c x}\right) / d_{i}^{w} /\operatorname{variance}[0]\)

\(\hat{g}_{j}^{c y}=\left(g_{j}^{c y}-d_{i}^{c y}\right) / d_{i}^{h} /\operatorname{variance}[1]\)

\(\hat{g}_{j}^{w}=\log \left(g_{j}^{w} / d_{i}^{w}\right) / \operatorname{variance}[2]\)

\(\hat{g}_{j}^{h}=\log \left(g_{j}^{h} / d_{i}^{h}\right) / \operatorname{variance}[3]\)

對於置信度誤差, 其采用softmax loss:

\(L_{c o n f}(x, c)=-\sum_{i \in P o s}^{N} x_{i j}^{p} \log \left(\hat{c}_{i}^{p}\right)-\sum_{i \in N e g} \log \left(\hat{c}_{i}^{0}\right) \quad\)

where \(\quad \hat{c}_{i}^{p}=\frac{\exp \left(c_{i}^{p}\right)}{\sum_{p} \exp \left(c_{i}^{p}\right)}\)

權重系數 \(\alpha\) 通過交叉驗證設置為1。

八、數據增強

采用數據擴增(Data Augmentation)可以提升SSD的性能,主要采用的技術有水平翻轉(horizontal flip),隨機裁剪加顏色扭曲(random crop & color distortion),隨機采集塊域(Randomly sample a patch)(獲取小目標訓練樣本)。
在這里插入圖片描述

九、非極大值抑制(Non-max suppression)

我們可能會以不同的大小和長寬比檢測到同一目標, 為了避免對同一目標的多次檢測而使用Non-max suppression.

  1. 按照檢測到目標的輸出概率排序
  2. 丟棄概率太低的預測位置
  3. 重復:
  • 選中概率最大的預測位置, 如果和另外一個預測位置有重疊(例如, 重疊率 IOU大於0.5), 保留概率最大的預測位置, 丟棄另外一個.

在這里插入圖片描述

十、預測過程

預測過程比較簡單,對於每個預測框,首先根據類別置信度確定其類別(置信度最大者)與置信度值,並過濾掉屬於背景的預測框。然后根據置信度閾值(如0.5)過濾掉閾值較低的預測框。對於留下的預測框進行解碼,根據先驗框得到其真實的位置參數(解碼后一般還需要做clip,防止預測框位置超出圖片)。解碼之后,一般需要根據置信度進行降序排列,然后僅保留top-k(如400)個預測框。最后就是進行NMS算法,過濾掉那些重疊度較大的預測框。最后剩余的預測框就是檢測結果了。

參考資料

參考鏈接:

https://legacy.gitbook.com/@leonardoaraujosantos
https://zhuanlan.zhihu.com/p/33544892

參考文獻:

論文: https://arxiv.org/abs/1512.02325
代碼: https://github.com/weiliu89/caffe/tree/ssd

多種框架實現

SSD Caffe:https://github.com/weiliu89/caffe/tree/ssd
SSD TensorFlow:https://github.com/balancap/SSD-Tensorflow
SSD Pytorch:https://github.com/amdegroot/ssd.pytorch

打賞

如果對您有幫助,就打賞一下吧O(∩_∩)O


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM