目標檢測-SSD算法詳細總結

一、 引言

文章:SSD: Single Shot MultiBox Detector
代碼:https://github.com/weiliu89/caffe/tree/ssd
來源: ECCV 2016

目標檢測近年來已經取得了很重要的進展,主流的目標算法主要分爲兩種類型:

  1. two-stage方法,如R-CNN系算法,其主要思路是先通過啓發式方法(selective search)或者CNN網絡(RPN)產生一系列稀疏的候選框,然後對這些候選框進行分類與迴歸,two-stage方法的優勢是準確度高;
  2. one-stage方法,如Yolo和SSD,其主要思路是均勻地在圖片的不同位置進行密集抽樣,抽樣時可以採用不同尺度和長寬比,然後利用CNN提取特徵後直接進行分類與迴歸,整個過程只需要一步,所以其優勢是速度快,但是均勻的密集採樣的一個重要缺點是訓練比較困難,這主要是因爲正樣本與負樣本(背景)極其不均衡(參見Focal Loss),導致模型準確度稍低。

不同算法的性能如圖所示,可以看到兩類方法在準確度和速度上的差異。
在這裏插入圖片描述

二、 算法解析

本文講解的是SSD算法,其英文全名是Single Shot MultiBox Detector,Single shot指明瞭SSD算法屬於one-stage方法,MultiBox指明瞭SSD是多框預測。SSD算法在準確度和速度(除了SSD512)上都比Yolo要好很多。下圖2給出了不同算法的基本框架圖,對於Faster R-CNN,其先通過CNN得到候選框,然後再進行分類與迴歸,而Yolo與SSD可以一步到位完成檢測。

相比Yolo,SSD採用CNN來直接進行檢測,而不是像Yolo那樣在全連接層之後做檢測。其實採用卷積直接做檢測只是SSD相比Yolo的其中一個不同點,另外還有兩個重要的改變。

  • 一是SSD提取了不同尺度的特徵圖來做檢測,大尺度特徵圖(較靠前的特徵圖)可以用來檢測小物體,而小尺度特徵圖(較靠後的特徵圖)用來檢測大物體;
  • 二是SSD採用了不同尺度和長寬比的先驗框(Prior boxes, Default boxes,在Faster R-CNN中叫做錨,Anchors)。Yolo算法缺點是難以檢測小目標,而且定位不準,但是這幾點重要改進使得SSD在一定程度上克服這些缺點。

下面我們來詳細講解SSD算法的原理。

在這裏插入圖片描述

1. 設計理念

SSD和Yolo一樣都是採用一個CNN網絡來進行檢測,但是卻採用了多尺度的特徵圖,其基本架構如圖3所示。下面將SSD核心設計理念總結爲以下三點:
在這裏插入圖片描述
(1)採用多尺度特徵圖用於檢測

所謂多尺度採用大小不同的特徵圖,CNN網絡一般前面的特徵圖比較大,後面會逐漸採用stride=2的卷積或者pool來降低特徵圖大小,這正如圖3所示,一個比較大的特徵圖和一個比較小的特徵圖,它們都用來做檢測。這樣做的好處是比較大的特徵圖來用來檢測相對較小的目標,而小的特徵圖負責檢測大目標,如圖4所示,8x8的特徵圖可以劃分更多的單元,但是其每個單元的先驗框尺度比較小。

(2)採用卷積進行檢測

與Yolo最後採用全連接層不同,SSD直接採用卷積對不同的特徵圖來進行提取檢測結果。對於形狀爲m×n×pm×n×p的特徵圖,只需要採用3×3×p3×3×p這樣比較小的卷積核得到檢測值。

(3)設置先驗框

在Yolo中,每個單元預測多個邊界框,但是其都是相對這個單元本身(正方塊),但是真實目標的形狀是多變的,Yolo需要在訓練過程中自適應目標的形狀。而SSD借鑑了Faster R-CNN中anchor的理念,每個單元設置尺度或者長寬比不同的先驗框,預測的邊界框(bounding boxes)是以這些先驗框爲基準的,在一定程度上減少訓練難度。一般情況下,每個單元會設置多個先驗框,其尺度和長寬比存在差異,如圖5所示,可以看到每個單元使用了4個不同的先驗框,圖片中貓和狗分別採用最適合它們形狀的先驗框來進行訓練,後面會詳細講解訓練過程中的先驗框匹配原則。
在這裏插入圖片描述
SSD的檢測值也與Yolo不太一樣。對於每個單元的每個先驗框,其都輸出一套獨立的檢測值,對應一個邊界框,主要分爲兩個部分。第一部分是各個類別的置信度或者評分,值得注意的是SSD將背景也當做了一個特殊的類別,如果檢測目標共有c個類別,SSD其實需要預測c+1個置信度值,其中第一個置信度指的是不含目標或者屬於背景的評分。後面當我們說cc個類別置信度時,請記住裏面包含背景那個特殊的類別,即真實的檢測類別只有c−1個。

在預測過程中,置信度最高的那個類別就是邊界框所屬的類別,特別地,當第一個置信度值最高時,表示邊界框中並不包含目標。第二部分就是邊界框的location,包含4個值(cx,cy,w,h),分別表示邊界框的中心座標以及寬高。但是真實預測值其實只是邊界框相對於先驗框的轉換值(paper裏面說是offset,但是覺得transformation更合適,參見R-CNN)。先驗框位置用d=(dcx,dcy,dw,dh)表示,其對應邊界框用b=(bcx,bcy,bw,bh)b表示,那麼邊界框的預測值ll其實是b相對於d的轉換值:
在這裏插入圖片描述
習慣上,我們稱上面這個過程爲邊界框的編碼(encode),預測時,你需要反向這個過程,即進行解碼(decode),從預測值l中得到邊界框的真實位置b:
在這裏插入圖片描述
然而,在SSD的Caffe源碼實現中還有trick,那就是設置variance超參數來調整檢測值,通過bool參數variance_encoded_in_target來控制兩種模式,當其爲True時,表示variance被包含在預測值中,就是上面那種情況。但是如果是Fasle(大部分採用這種方式,訓練更容易?),就需要手動設置超參數variance,用來對ll的4個值進行放縮,此時邊界框需要這樣解碼:

在這裏插入圖片描述
綜上所述,對於一個大小m×n的特徵圖,共有mn個單元,每個單元設置的先驗框數目記爲k,那麼每個單元共需要(c+4)k個預測值,所有的單元共需要(c+4)kmn個預測值,由於SSD採用卷積做檢測,所以就需要(c+4)k個卷積核完成這個特徵圖的檢測過程。

2. 網絡結構

SSD採用VGG16作爲基礎模型,然後在VGG16的基礎上新增了卷積層來獲得更多的特徵圖以用於檢測。

SSD的網絡結構如下圖所示。上面是SSD模型,下面是Yolo模型,可以明顯看到SSD利用了多尺度的特徵圖做檢測。模型的輸入圖片大小是300×300(還可以是512×512,其與前者網絡結構沒有差別,只是最後新增一個卷積層,本文不再討論)。
在這裏插入圖片描述
在這裏插入圖片描述
採用VGG16做基礎模型,首先VGG16是在ILSVRC CLS-LOC數據集預訓練。然後借鑑了DeepLab-LargeFOV,分別將VGG16的全連接層fc6和fc7轉換成3×3卷積層conv6和1×1卷積層conv7,同時將池化層pool5由原來的2×2−s2變成3×3−s1(猜想是不想reduce特徵圖大小),爲了配合這種變化,採用了一種Atrous Algorithm,其實就是conv6採用擴展卷積或帶孔卷積(Dilation Conv),其在不增加參數與模型複雜度的條件下指數級擴大卷積的視野,其使用擴張率(dilation rate)參數,來表示擴張的大小,如下圖所示,(a)是普通的3×3卷積,其視野就是3×3,(b)是擴張率爲2,此時視野變成7×7,©擴張率爲4時,視野擴大爲15×15,但是視野的特徵更稀疏了。Conv6採用3×3大小但dilation rate=6的擴展卷積。
在這裏插入圖片描述
在這裏插入圖片描述
作者採用了atrous algorithm 的技術,這裏所謂的 atrous algorithm,我查閱了資料,就是 hole filling algorithm。
在 DeepLab 的主頁上:http://liangchiehchen.com/projects/DeepLab.html,有一張如下的圖:
在這裏插入圖片描述
博客 1:http://www.cnblogs.com/jianyingzhou/p/5386222.html

最早用的就是 deeplab 的文章了,Semantic Image Segmentation with Deep
Convolutional Nets and Fully Connected CRFS 這篇文章和 fcn 不同的是,在最後產生 score
map 時,不是進行upsampling,而是採用了 hole algorithm,就是在 pool4 和 pool 5層,步長由 2 變成
1,必然輸出的 score map 變大了,但是 receptive field 也變小了,爲了不降低 receptive
field,怎麼做呢?利用 hole algorithm,將卷積 weights 膨脹擴大,即原來卷積核是 3x3,膨脹後,可能變成 7x7
了,這樣 receptive field 變大了,而 score map 也很大,即輸出變成 dense 的了。

這麼做的好處是,輸出的 score map 變大了,即是 dense 的輸出了,而且 receptive field
不會變小,而且可以變大。這對做分割、檢測等工作非常重要。

博客 2:http://blog.csdn.net/tangwei2014/article/details/50453334

既想利用已經訓練好的模型進行 fine-tuning,又想改變網絡結構得到更加 dense 的 score map.

這個解決辦法就是採用 Hole 算法。如下圖 (a) (b) 所示,在以往的卷積或者 pooling 中,一個 filter
中相鄰的權重作用在 feature map 上的位置都是物理上連續的。如下圖 © 所示,爲了保證感受野不發生變化,某一層的 stride
由 2 變爲 1 以後,後面的層需要採用 hole 算法,具體來講就是將連續的連接關係是根據 hole size 大小變成 skip
連接的(圖 © 爲了顯示方便直接畫在本層上了)。不要被 © 中的 padding 爲 2 嚇着了,其實 2 個 padding
不會同時和一個 filter 相連。

pool4 的 stride 由 2 變爲 1,則緊接着的 conv5_1, conv5_2 和 conv5_3 中 hole size 爲
2。接着 pool5 由 2 變爲 1 , 則後面的 fc6 中 hole size 爲 4。
在這裏插入圖片描述

本文還將 fully convolutional reduced (atrous) VGGNet 中的所有的 dropout layers、fc8 layer 移除掉了。

本文在 fine-tuning 預訓練的 VGG model 時,初始 learning rate 爲 10−3,momentum 爲 0.9,weight decay 爲 0.0005,batch size 爲 32,learning rate decay 的策略隨數據集的不同而變化。

其中VGG16中的Conv4_3層將作爲用於檢測的第一個特徵圖。conv4_3層特徵圖大小是38×38,但是該層比較靠前,其norm較大,所以在其後面增加了一個L2 Normalization層(參見ParseNet),以保證和後面的檢測層差異不是很大,這個和Batch Normalization層不太一樣,其僅僅是對每個像素點在channle維度做歸一化,而Batch Normalization層是在[batch_size, width, height]三個維度上做歸一化。歸一化後一般設置一個可訓練的放縮變量gamma,使用TF可以這樣簡單實現:

# l2norm (not bacth norm, spatial normalization)
def l2norm(x, scale, trainable=True, scope="L2Normalization"):
    n_channels = x.get_shape().as_list()[-1]
    l2_norm = tf.nn.l2_normalize(x, [3], epsilon=1e-12)
    with tf.variable_scope(scope):
        gamma = tf.get_variable("gamma", shape=[n_channels, ], dtype=tf.float32,
                                initializer=tf.constant_initializer(scale),
                                trainable=trainable)
        return l2_norm * gamma

從後面新增的卷積層中提取Conv7,Conv8_2,Conv9_2,Conv10_2,Conv11_2作爲檢測所用的特徵圖,加上Conv4_3層,共提取了6個特徵圖,其大小分別是(38,38),(19,19),(10,10),(5,5),(3,3),(1,1),但是不同特徵圖設置的先驗框數目不同(同一個特徵圖上每個單元設置的先驗框是相同的,這裏的數目指的是一個單元的先驗框數目)。先驗框的設置,包括尺度(或者說大小)和長寬比兩個方面。對於先驗框的尺度,其遵守一個線性遞增規則:隨着特徵圖大小降低,先驗框尺度線性增加:

在這裏插入圖片描述
其中m指的特徵圖個數,但卻是5,因爲第一層(Conv4_3層)是單獨設置的,sk表示先驗框大小相對於圖片的比例,而smin和smax表示比例的最小值與最大值,paper裏面取0.2和0.9。對於第一個特徵圖,其先驗框的尺度比例一般設置爲smin/2=0.1,那麼尺度爲300×0.1=30。對於後面的特徵圖,先驗框尺度按照上面公式線性增加,但是先將尺度比例先擴大100倍,此時增長步長爲在這裏插入圖片描述,這樣各個特徵圖的sk爲20,37,54,71,88,將這些比例除以100,然後再乘以圖片大小,可以得到各個特徵圖的尺度爲60,111,162,213,264,這種計算方式是參考SSD的Caffe源碼。

綜上,可以得到各個特徵圖的先驗框尺度30,60,111,162,213,264。對於長寬比,一般選取ar∈{1,2,3,1/2,1/3},對於特定的長寬比,按如下公式計算先驗框的寬度與高度(後面的sk均指的是先驗框實際尺度,而不是尺度比例):
在這裏插入圖片描述
默認情況下,每個特徵圖會有一個ar =1,且尺度爲 sk的先驗框,除此之外,還會設置一個尺度爲在這裏插入圖片描述
的先驗框,這樣每個特徵圖都設置了兩個長寬比爲1但大小不同的正方形先驗框。注意最後一個特徵圖需要參考一個虛擬 sm+1=300×105/100=315來計算 s′m。因此,每個特徵圖一共有 6 個先驗框 {1,2,3,1/2,1/3,1′},但是在實現時,Conv4_3,Conv10_2和Conv11_2層僅使用4個先驗框,它們不使用長寬比爲 3,1/3,的先驗框。每個單元的先驗框的中心點分佈在各個單元的中心,即
在這裏插入圖片描述
得到了特徵圖之後,需要對特徵圖進行卷積得到檢測結果,下圖給出了一個 5×5大小的特徵圖的檢測過程。其中Priorbox是得到先驗框,前面已經介紹了生成規則。檢測值包含兩個部分:類別置信度和邊界框位置,各採用一次 3×3卷積來進行完成。令 n_k 爲該特徵圖所採用的先驗框數目,那麼類別置信度需要的卷積核數量爲 nk×c ,而邊界框位置需要的卷積核數量爲 nk×4 。由於每個先驗框都會預測一個邊界框,所以SSD300一共可以預測 38×38×4+19×19×6+10×10×6+5×5×6+3×3×4+1×1×4=8732 個邊界框,這是一個相當龐大的數字,所以說SSD本質上是密集採樣。

在這裏插入圖片描述

3. 訓練過程

(1)先驗框匹配

在訓練過程中,首先要確定訓練圖片中的ground truth(真實目標)與哪個先驗框來進行匹配,與之匹配的先驗框所對應的邊界框將負責預測它。在Yolo中,ground truth的中心落在哪個單元格,該單元格中與其IOU最大的邊界框負責預測它。

但是在SSD中卻完全不一樣,SSD的先驗框與ground truth的匹配原則主要有兩點

首先,對於圖片中每個ground truth,找到與其IOU最大的先驗框,該先驗框與其匹配,這樣,可以保證每個ground truth一定與某個先驗框匹配。通常稱與ground truth匹配的先驗框爲正樣本,反之,若一個先驗框沒有與任何ground truth進行匹配,那麼該先驗框只能與背景匹配,就是負樣本。一個圖片中ground truth是非常少的, 而先驗框卻很多,如果僅按第一個原則匹配,很多先驗框會是負樣本,正負樣本極其不平衡,所以需要第二個原則。

第二個原則是:對於剩餘的未匹配先驗框,若某個ground truth的IOU大於某個閾值(一般是0.5),那麼該先驗框也與這個ground truth進行匹配。這意味着某個ground truth可能與多個先驗框匹配,這是可以的。但是反過來卻不可以,因爲一個先驗框只能匹配一個ground truth,如果多個ground truth與某個先驗框IOU大於閾值,那麼先驗框只與IOU最大的那個先驗框進行匹配。

第二個原則一定在第一個原則之後進行,仔細考慮一下這種情況,如果某個ground truth所對應最大IOU小於閾值,並且所匹配的先驗框卻與另外一個ground truth的IOU大於閾值,那麼該先驗框應該匹配誰,答案應該是前者,首先要確保某個ground truth一定有一個先驗框與之匹配。但是,這種情況我覺得基本上是不存在的。由於先驗框很多,某個ground truth的最大IOU肯定大於閾值,所以可能只實施第二個原則既可以了,這裏的TensorFlow版本就是隻實施了第二個原則,但是這裏的Pytorch兩個原則都實施了。下圖爲一個匹配示意圖,其中綠色的GT是ground truth,紅色爲先驗框,FP表示負樣本,TP表示正樣本。

在這裏插入圖片描述
儘管一個ground truth可以與多個先驗框匹配,但是ground truth相對先驗框還是太少了,所以負樣本相對正樣本會很多。爲了保證正負樣本儘量平衡,SSD採用了hard negative mining,就是對負樣本進行抽樣,抽樣時按照置信度誤差(預測背景的置信度越小,誤差越大)進行降序排列,選取誤差的較大的top-k作爲訓練的負樣本,以保證正負樣本比例接近1:3。

(2)損失函數

訓練樣本確定了,然後就是損失函數了。損失函數定義爲位置誤差(locatization loss, loc)與置信度誤差(confidence loss, conf)的加權和:
在這裏插入圖片描述
其中N是先驗框的正樣本數量。
在這裏插入圖片描述
並且ground truth的類別爲p。c爲類別置信度預測值。L爲先驗框的所對應邊界框的位置預測值,而g是ground truth的位置參數。對於位置誤差,其採用Smooth L1 loss,定義如下

在這裏插入圖片描述
(3)數據擴增

採用數據擴增(Data Augmentation)可以提升SSD的性能,主要採用的技術有水平翻轉(horizontal flip),隨機裁剪加顏色扭曲(random crop & color distortion),隨機採集塊域(Randomly sample a patch)(獲取小目標訓練樣本),如下圖所示:
在這裏插入圖片描述
在這裏插入圖片描述
其它的訓練細節如學習速率的選擇詳見論文,這裏不再贅述。

4. 預測過程

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

5. 算法特點

1 SSD結合了YOLO中的迴歸思想和Faster-RCNN中的Anchor機制,使用全圖各個位置的多尺度區域特徵進行迴歸,既保持了YOLO速度快的特性,也保證了窗口預測的跟Faster-RCNN一樣比較精準。

2 SSD的核心是在特徵圖上採用卷積核來預測一系列Default Bounding Boxes的類別、座標偏移。爲了提高檢測準確率,SSD在不同尺度的特徵圖上進行預測。

6. 算法要點

一、模型結構

1 多尺度特徵圖(Mult-scale Feature Map For Detection)

在圖像Base Network基礎上,將Fc6,Fc7變爲了Conv6,Conv7兩個卷積層,添加了一些卷積層(Conv8,Conv9,Conv10,Conv11),這些層的大小逐漸減小,可以進行多尺度預測。

2 卷積預測器(Convolutional Predictors For Detection)

每個新添加的卷積層和之前的部分卷積層,使用一系列的卷積核進行預測。對於一個大小爲m * n大小,p通道的卷積層,使用3 * 3的p通道卷積核作爲基礎預測元素進行預測,在某個位置上預測出一個值,該值可以是某一類別的得分,也可以是相對於Default Bounding Boxes的偏移量,並且在圖像的每個位置都將產生一個值。

3 默認框和比例(Default Boxes And Aspect Ratio)

在特徵圖的每個位置預測K個Box。對於每個Box,預測C個類別得分,以及相對於Default Bounding Box的4個偏移值,這樣需要(C+4) * k個預測器,在m*n的特徵圖上將產生(C+4) * k * m * n個預測值。這裏,Default Bounding Box類似於Faster-RCNN中Anchors,如下圖所示。
在這裏插入圖片描述
二、模型訓練

1 監督學習的訓練關鍵是人工標註的label。對於包含Default Box(在Faster R-CNN中叫做Anchor)的網絡模型(如:YOLO,Faster R-CNN, MultiBox)關鍵點就是如何把 標註信息(Ground True Box,Ground True Category)映射到(Default Box上)。

2 給定輸入圖像以及每個物體的Ground Truth,首先找到每個Ground True Box對應的Default Box中IOU最大的作爲正樣本。然後,在剩下的Default Box中找到那些與任意一個Ground Truth Box的IOU大於0.5的Default Box作爲正樣本。其他的作爲負樣本(每個Default Box要麼是正樣本Box要麼是負樣本Box)。如上圖中,兩個Default Box與貓匹配,一個與狗匹配。在訓練過程中,採用Hard Negative Mining 的策略(根據Confidence Loss對所有的Box進行排序,使正負例的比例保持在1:3) 來平衡正負樣本的比率。

3 損失函數

與Faster-RCNN中的RPN是一樣的,不過RPN是預測Box裏面有Object或者沒有,沒有分類,SSD直接用的Softmax分類。Location的損失,還是一樣,都是用Predict box和Default Box/Anchor的差 與Ground Truth Box和Default Box/Anchor的差進行對比,求損失。
在這裏插入圖片描述

7. 性能評估

首先整體看一下SSD在VOC2007,VOC2012及COCO數據集上的性能。相比之下,SSD512的性能會更好一些。加*的表示使用了image expansion data augmentation(通過zoom out來創造小的訓練樣本)技巧來提升SSD在小目標上的檢測效果,所以性能會有所提升。
在這裏插入圖片描述
檢測結果展示:
在這裏插入圖片描述

8. 參考文獻

  1. https://handong1587.github.io/deep_learning/2015/10/09/object-detection.html
  2. SSD: Single Shot MultiBox Detector
  3. SSD Slide
  4. caffe-ssd
  5. SSD TensorFlow
  6. SSD Pytorch
  7. leonardoaraujosantos Artificial Inteligence online book

關於算法基於各種框架的實現,鏈接在參考文獻之中,歡迎交流學習~

發佈了82 篇原創文章 · 獲贊 50 · 訪問量 4039
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章