文章與視訊資源多平台更新
微信公衆号|知乎|B站|頭條:AI研習圖書館
深度學習、大資料、IT程式設計知識與資源分享,歡迎關注,共同進步~
一、 引言
文章:SSD: Single Shot MultiBox Detector
代碼:https://github.com/weiliu89/caffe/tree/ssd
來源: ECCV 2016
目标檢測近年來已經取得了很重要的進展,主流的目标算法主要分為兩種類型:
- two-stage方法,如R-CNN系算法,其主要思路是先通過啟發式方法(selective search)或者CNN網絡(RPN)産生一系列稀疏的候選框,然後對這些候選框進行分類與回歸,two-stage方法的優勢是準确度高;
- 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. 參考文獻
- https://handong1587.github.io/deep_learning/2015/10/09/object-detection.html
- SSD: Single Shot MultiBox Detector
- SSD Slide
- caffe-ssd
- SSD TensorFlow
- SSD Pytorch
- leonardoaraujosantos Artificial Inteligence online book
關于算法基于各種架構的實作,連結在參考文獻之中,歡迎交流學習~
您的支援,是我不斷創作的最大動力~
歡迎點贊,關注,留言交流~
深度學習,樂此不疲~