2018-05-27

(轉(zhuǎn)自知乎)目標(biāo)檢測(cè)近年來(lái)已經(jīng)取得了很重要的進(jìn)展侨赡,主流的算法主要分為兩個(gè)類型(參考RefineDet):(1)two-stage方法模她,如R-CNN系算法咐蝇,其主要思路是先通過(guò)啟發(fā)式方法(selective search)或者CNN網(wǎng)絡(luò)(RPN)產(chǎn)生一系列稀疏的候選框授帕,然后對(duì)這些候選框進(jìn)行分類與回歸特姐,two-stage方法的優(yōu)勢(shì)是準(zhǔn)確度高晶丘;(2)one-stage方法,如Yolo和SSD,其主要思路是均勻地在圖片的不同位置進(jìn)行密集抽樣浅浮,抽樣時(shí)可以采用不同尺度和長(zhǎng)寬比沫浆,然后利用CNN提取特征后直接進(jìn)行分類與回歸,整個(gè)過(guò)程只需要一步滚秩,所以其優(yōu)勢(shì)是速度快专执,但是均勻的密集采樣的一個(gè)重要缺點(diǎn)是訓(xùn)練比較困難柔滔,這主要是因?yàn)檎龢颖九c負(fù)樣本(背景)極其不均衡(參見(jiàn)Focal Loss)血崭,導(dǎo)致模型準(zhǔn)確度稍低。不同算法的性能如圖1所示丽涩,可以看到兩類方法在準(zhǔn)確度和速度上的差異桐腌。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖1 不同檢測(cè)算法的性能對(duì)比</figcaption>

</figure>

本文講解的是SSD算法拄显,其英文全名是Single Shot MultiBox Detector,名字取得不錯(cuò)哩掺,Single shot指明了SSD算法屬于one-stage方法凿叠,MultiBox指明了SSD是多框預(yù)測(cè)。在上一篇文章中我們已經(jīng)講了Yolo算法嚼吞,從圖1也可以看到盒件,SSD算法在準(zhǔn)確度和速度(除了SSD512)上都比Yolo要好很多。圖2給出了不同算法的基本框架圖舱禽,對(duì)于Faster R-CNN炒刁,其先通過(guò)CNN得到候選框,然后再進(jìn)行分類與回歸誊稚,而Yolo與SSD可以一步到位完成檢測(cè)翔始。相比Yolo,SSD采用CNN來(lái)直接進(jìn)行檢測(cè)里伯,而不是像Yolo那樣在全連接層之后做檢測(cè)城瞎。其實(shí)采用卷積直接做檢測(cè)只是SSD相比Yolo的其中一個(gè)不同點(diǎn),另外還有兩個(gè)重要的改變疾瓮,一是SSD提取了不同尺度的特征圖來(lái)做檢測(cè)脖镀,大尺度特征圖(較靠前的特征圖)可以用來(lái)檢測(cè)小物體,而小尺度特征圖(較靠后的特征圖)用來(lái)檢測(cè)大物體狼电;二是SSD采用了不同尺度和長(zhǎng)寬比的先驗(yàn)框(Prior boxes, Default boxes蜒灰,在Faster R-CNN中叫做錨,Anchors)肩碟。Yolo算法缺點(diǎn)是難以檢測(cè)小目標(biāo)强窖,而且定位不準(zhǔn),但是這幾點(diǎn)重要改進(jìn)使得SSD在一定程度上克服這些缺點(diǎn)削祈。下面我們?cè)敿?xì)講解SDD算法的原理翅溺,并最后給出如何用TensorFlow實(shí)現(xiàn)SSD算法。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖2 不同算法的基本框架圖</figcaption>

</figure>

設(shè)計(jì)理念

SSD和Yolo一樣都是采用一個(gè)CNN網(wǎng)絡(luò)來(lái)進(jìn)行檢測(cè),但是卻采用了多尺度的特征圖未巫,其基本架構(gòu)如圖3所示窿撬。下面將SSD核心設(shè)計(jì)理念總結(jié)為以下三點(diǎn):

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖3 SSD基本框架</figcaption>

</figure>

(1)采用多尺度特征圖用于檢測(cè)

所謂多尺度采用大小不同的特征圖,CNN網(wǎng)絡(luò)一般前面的特征圖比較大叙凡,后面會(huì)逐漸采用stride=2的卷積或者pool來(lái)降低特征圖大小劈伴,這正如圖3所示,一個(gè)比較大的特征圖和一個(gè)比較小的特征圖握爷,它們都用來(lái)做檢測(cè)跛璧。這樣做的好處是比較大的特征圖來(lái)用來(lái)檢測(cè)相對(duì)較小的目標(biāo),而小的特征圖負(fù)責(zé)檢測(cè)大目標(biāo)新啼,如圖4所示追城,8x8的特征圖可以劃分更多的單元,但是其每個(gè)單元的先驗(yàn)框尺度比較小燥撞。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖4 不同尺度的特征圖</figcaption>

</figure>

(2)采用卷積進(jìn)行檢測(cè)

與Yolo最后采用全連接層不同座柱,SSD直接采用卷積對(duì)不同的特征圖來(lái)進(jìn)行提取檢測(cè)結(jié)果。對(duì)于形狀為 [圖片上傳失敗...(image-aa9462-1527406250790)]

的特征圖物舒,只需要采用 [圖片上傳失敗...(image-c432aa-1527406250790)]

這樣比較小的卷積核得到檢測(cè)值色洞。

(3)設(shè)置先驗(yàn)框

在Yolo中,每個(gè)單元預(yù)測(cè)多個(gè)邊界框冠胯,但是其都是相對(duì)這個(gè)單元本身(正方塊)火诸,但是真實(shí)目標(biāo)的形狀是多變的,Yolo需要在訓(xùn)練過(guò)程中自適應(yīng)目標(biāo)的形狀荠察。而SSD借鑒了Faster R-CNN中anchor的理念置蜀,每個(gè)單元設(shè)置尺度或者長(zhǎng)寬比不同的先驗(yàn)框,預(yù)測(cè)的邊界框(bounding boxes)是以這些先驗(yàn)框?yàn)榛鶞?zhǔn)的悉盆,在一定程度上減少訓(xùn)練難度盯荤。一般情況下,每個(gè)單元會(huì)設(shè)置多個(gè)先驗(yàn)框焕盟,其尺度和長(zhǎng)寬比存在差異廷雅,如圖5所示,可以看到每個(gè)單元使用了4個(gè)不同的先驗(yàn)框京髓,圖片中貓和狗分別采用最適合它們形狀的先驗(yàn)框來(lái)進(jìn)行訓(xùn)練,后面會(huì)詳細(xì)講解訓(xùn)練過(guò)程中的先驗(yàn)框匹配原則商架。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖5 SSD的先驗(yàn)框</figcaption>

</figure>

SSD的檢測(cè)值也與Yolo不太一樣堰怨。對(duì)于每個(gè)單元的每個(gè)先驗(yàn)框,其都輸出一套獨(dú)立的檢測(cè)值蛇摸,對(duì)應(yīng)一個(gè)邊界框备图,主要分為兩個(gè)部分。第一部分是各個(gè)類別的置信度或者評(píng)分,值得注意的是SSD將背景也當(dāng)做了一個(gè)特殊的類別揽涮,如果檢測(cè)目標(biāo)共有 [圖片上傳失敗...(image-4d05d7-1527406250790)]

個(gè)類別抠藕,SSD其實(shí)需要預(yù)測(cè) [圖片上傳失敗...(image-980aae-1527406250790)]

個(gè)置信度值,其中第一個(gè)置信度指的是不含目標(biāo)或者屬于背景的評(píng)分蒋困。后面當(dāng)我們說(shuō) [圖片上傳失敗...(image-a181c-1527406250790)]

個(gè)類別置信度時(shí)盾似,請(qǐng)記住里面包含背景那個(gè)特殊的類別,即真實(shí)的檢測(cè)類別只有 [圖片上傳失敗...(image-f138b5-1527406250790)]

個(gè)雪标。在預(yù)測(cè)過(guò)程中零院,置信度最高的那個(gè)類別就是邊界框所屬的類別,特別地村刨,當(dāng)?shù)谝粋€(gè)置信度值最高時(shí)告抄,表示邊界框中并不包含目標(biāo)。第二部分就是邊界框的location嵌牺,包含4個(gè)值 [圖片上傳失敗...(image-ecaf3c-1527406250790)]

打洼,分別表示邊界框的中心坐標(biāo)以及寬高。但是真實(shí)預(yù)測(cè)值其實(shí)只是邊界框相對(duì)于先驗(yàn)框的轉(zhuǎn)換值(paper里面說(shuō)是offset逆粹,但是覺(jué)得transformation更合適募疮,參見(jiàn)R-CNN)。先驗(yàn)框位置用 [圖片上傳失敗...(image-bc7778-1527406250790)]

表示枯饿,其對(duì)應(yīng)邊界框用 [圖片上傳失敗...(image-6d2e14-1527406250790)]

$表示酝锅,那么邊界框的預(yù)測(cè)值 [圖片上傳失敗...(image-be18e9-1527406250790)]

其實(shí)是 [圖片上傳失敗...(image-878765-1527406250790)]

相對(duì)于 [圖片上傳失敗...(image-bcd2fa-1527406250790)]

的轉(zhuǎn)換值:

[圖片上傳失敗...(image-3e4186-1527406250790)]

[圖片上傳失敗...(image-c8847b-1527406250790)]

習(xí)慣上,我們稱上面這個(gè)過(guò)程為邊界框的編碼(encode)奢方,預(yù)測(cè)時(shí)搔扁,你需要反向這個(gè)過(guò)程,即進(jìn)行解碼(decode)蟋字,從預(yù)測(cè)值 [圖片上傳失敗...(image-eb29a-1527406250790)]

中得到邊界框的真實(shí)位置 [圖片上傳失敗...(image-74146e-1527406250790)]

[圖片上傳失敗...(image-f9bb2d-1527406250790)]

[圖片上傳失敗...(image-91f8f-1527406250790)]

然而稿蹲,在SSD的Caffe源碼實(shí)現(xiàn)中還有trick,那就是設(shè)置variance超參數(shù)來(lái)調(diào)整檢測(cè)值鹊奖,通過(guò)bool參數(shù)variance_encoded_in_target來(lái)控制兩種模式苛聘,當(dāng)其為T(mén)rue時(shí),表示variance被包含在預(yù)測(cè)值中忠聚,就是上面那種情況设哗。但是如果是False(大部分采用這種方式,訓(xùn)練更容易两蟀?)网梢,就需要手動(dòng)設(shè)置超參數(shù)variance,用來(lái)對(duì) [圖片上傳失敗...(image-256fb8-1527406250790)]

的4個(gè)值進(jìn)行放縮赂毯,此時(shí)邊界框需要這樣解碼:

[圖片上傳失敗...(image-9f704e-1527406250790)]

[圖片上傳失敗...(image-7424e6-1527406250790)]

綜上所述战虏,對(duì)于一個(gè)大小 [圖片上傳失敗...(image-98ea8e-1527406250790)]

的特征圖拣宰,共有 [圖片上傳失敗...(image-deafa3-1527406250790)]

個(gè)單元,每個(gè)單元設(shè)置的先驗(yàn)框數(shù)目記為 [圖片上傳失敗...(image-59fca0-1527406250790)]

烦感,那么每個(gè)單元共需要 [圖片上傳失敗...(image-5a072f-1527406250790)]

個(gè)預(yù)測(cè)值巡社,所有的單元共需要 [圖片上傳失敗...(image-2c23bf-1527406250790)]

個(gè)預(yù)測(cè)值,由于SSD采用卷積做檢測(cè)手趣,所以就需要 [圖片上傳失敗...(image-313e3-1527406250790)]

個(gè)卷積核完成這個(gè)特征圖的檢測(cè)過(guò)程晌该。

網(wǎng)絡(luò)結(jié)構(gòu)

SSD采用VGG16作為基礎(chǔ)模型,然后在VGG16的基礎(chǔ)上新增了卷積層來(lái)獲得更多的特征圖以用于檢測(cè)回懦。SSD的網(wǎng)絡(luò)結(jié)構(gòu)如圖5所示气笙。上面是SSD模型,下面是Yolo模型怯晕,可以明顯看到SSD利用了多尺度的特征圖做檢測(cè)潜圃。模型的輸入圖片大小是 [圖片上傳失敗...(image-2ce82c-1527406250790)]

(還可以是 [圖片上傳失敗...(image-f0281c-1527406250789)]

,其與前者網(wǎng)絡(luò)結(jié)構(gòu)沒(méi)有差別舟茶,只是最后新增一個(gè)卷積層谭期,本文不再討論)。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖5 SSD網(wǎng)絡(luò)結(jié)構(gòu)</figcaption>

</figure>

采用VGG16做基礎(chǔ)模型吧凉,首先VGG16是在ILSVRC CLS-LOC數(shù)據(jù)集預(yù)訓(xùn)練隧出。然后借鑒了DeepLab-LargeFOV,分別將VGG16的全連接層fc6和fc7轉(zhuǎn)換成 [圖片上傳失敗...(image-2f49cf-1527406250789)]

卷積層 conv6和 [圖片上傳失敗...(image-8516df-1527406250789)]

卷積層conv7阀捅,同時(shí)將池化層pool5由原來(lái)的變成(猜想是不想reduce特征圖大姓偷伞),為了配合這種變化饲鄙,采用了一種Atrous Algorithm凄诞,其實(shí)就是conv6采用擴(kuò)展卷積或帶孔卷積(<u style="text-decoration: none; border-bottom: 1px dashed gray;">Dilation Conv</u>),其在不增加參數(shù)與模型復(fù)雜度的條件下指數(shù)級(jí)擴(kuò)大卷積的視野忍级,其使用擴(kuò)張率(dilation rate)參數(shù)帆谍,來(lái)表示擴(kuò)張的大小,如下圖6所示轴咱,(a)是普通的 [圖片上傳失敗...(image-822235-1527406250789)]

卷積汛蝙,其視野就是 [圖片上傳失敗...(image-2b542f-1527406250789)]

,(b)是擴(kuò)張率為1朴肺,此時(shí)視野變成 [圖片上傳失敗...(image-d1fb78-1527406250789)]

窖剑,(c)擴(kuò)張率為3時(shí),視野擴(kuò)大為 [圖片上傳失敗...(image-7941e9-1527406250789)]

戈稿,但是視野的特征更稀疏了苛吱。Conv6采用 [圖片上傳失敗...(image-62841c-1527406250789)]

大小但dilation rate=6的擴(kuò)展卷積。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖6 擴(kuò)展卷積</figcaption>

</figure>

然后移除dropout層和fc8層器瘪,并新增一系列卷積層翠储,在檢測(cè)數(shù)據(jù)集上做finetuing。

其中VGG16中的Conv4_3層將作為用于檢測(cè)的第一個(gè)特征圖橡疼。conv4_3層特征圖大小是 [圖片上傳失敗...(image-23587e-1527406250789)]

援所,但是該層比較靠前,其norm較大欣除,所以在其后面增加了一個(gè)L2 Normalization層(參見(jiàn)ParseNet)住拭,以保證和后面的檢測(cè)層差異不是很大,這個(gè)和Batch Normalization層不太一樣历帚,其僅僅是對(duì)每個(gè)像素點(diǎn)在channle維度做歸一化滔岳,而B(niǎo)atch Normalization層是在[batch_size, width, height]三個(gè)維度上做歸一化。歸一化后一般設(shè)置一個(gè)可訓(xùn)練的放縮變量gamma挽牢,使用TF可以這樣簡(jiǎn)單實(shí)現(xiàn):

# 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作為檢測(cè)所用的特征圖,加上Conv4_3層睹栖,共提取了6個(gè)特征圖硫惕,其大小分別是 [圖片上傳失敗...(image-b7c182-1527406250789)]

,但是不同特征圖設(shè)置的先驗(yàn)框數(shù)目不同(同一個(gè)特征圖上每個(gè)單元設(shè)置的先驗(yàn)框是相同的野来,這里的數(shù)目指的是一個(gè)單元的先驗(yàn)框數(shù)目)恼除。先驗(yàn)框的設(shè)置,包括尺度(或者說(shuō)大新铡)和長(zhǎng)寬比兩個(gè)方面豁辉。對(duì)于先驗(yàn)框的尺度,其遵守一個(gè)線性遞增規(guī)則:隨著特征圖大小降低搪锣,先驗(yàn)框尺度線性增加:

[圖片上傳失敗...(image-527c7d-1527406250789)]

其中 [圖片上傳失敗...(image-d25b43-1527406250789)]

指的特征圖個(gè)數(shù)秋忙,但卻是 [圖片上傳失敗...(image-27557c-1527406250789)]

,因?yàn)榈谝粚樱–onv4_3層)是單獨(dú)設(shè)置的构舟, [圖片上傳失敗...(image-ef0706-1527406250789)]

表示先驗(yàn)框大小相對(duì)于圖片的比例灰追,而 [圖片上傳失敗...(image-74686d-1527406250789)]

和 [圖片上傳失敗...(image-9682dc-1527406250789)]

表示比例的最小值與最大值,paper里面取0.2和0.9狗超。對(duì)于第一個(gè)特征圖弹澎,其先驗(yàn)框的尺度比例一般設(shè)置為 [圖片上傳失敗...(image-22c7b4-1527406250789)]

,那么尺度為 [圖片上傳失敗...(image-16049c-1527406250789)]

努咐。對(duì)于后面的特征圖苦蒿,先驗(yàn)框尺度按照上面公式線性增加,但是先將尺度比例先擴(kuò)大100倍渗稍,此時(shí)增長(zhǎng)步長(zhǎng)為 [圖片上傳失敗...(image-d23106-1527406250789)]

佩迟,這樣各個(gè)特征圖的 [圖片上傳失敗...(image-e84517-1527406250789)]

為 [圖片上傳失敗...(image-1cb4af-1527406250789)]

团滥,將這些比例除以100,然后再乘以圖片大小报强,可以得到各個(gè)特征圖的尺度為 [圖片上傳失敗...(image-dc0526-1527406250789)]

灸姊,這種計(jì)算方式是參考SSD的Caffe源碼。綜上秉溉,可以得到各個(gè)特征圖的先驗(yàn)框尺度 [圖片上傳失敗...(image-4ef710-1527406250789)]

力惯。對(duì)于長(zhǎng)寬比,一般選取 [圖片上傳失敗...(image-9e4f1c-1527406250789)]

召嘶,對(duì)于特定的長(zhǎng)寬比父晶,按如下公式計(jì)算先驗(yàn)框的寬度與高度(后面的 [圖片上傳失敗...(image-b8e70c-1527406250789)]

均指的是先驗(yàn)框?qū)嶋H尺度,而不是尺度比例):

[圖片上傳失敗...(image-5cba55-1527406250789)]

默認(rèn)情況下弄跌,每個(gè)特征圖會(huì)有一個(gè) [圖片上傳失敗...(image-8677e7-1527406250789)]

且尺度為 [圖片上傳失敗...(image-56a126-1527406250789)]

的先驗(yàn)框甲喝,除此之外,還會(huì)設(shè)置一個(gè)尺度為 [圖片上傳失敗...(image-c1d015-1527406250789)]

且 [圖片上傳失敗...(image-b8481d-1527406250789)]

的先驗(yàn)框碟绑,這樣每個(gè)特征圖都設(shè)置了兩個(gè)長(zhǎng)寬比為1但大小不同的正方形先驗(yàn)框俺猿。注意最后一個(gè)特征圖需要參考一個(gè)虛擬 [圖片上傳失敗...(image-f82bb3-1527406250789)]

來(lái)計(jì)算 [圖片上傳失敗...(image-8be899-1527406250789)]

。因此格仲,每個(gè)特征圖一共有 [圖片上傳失敗...(image-be7fa-1527406250789)]

個(gè)先驗(yàn)框 [圖片上傳失敗...(image-b6c666-1527406250789)]

押袍,但是在實(shí)現(xiàn)時(shí),Conv4_3凯肋,Conv10_2和Conv11_2層僅使用4個(gè)先驗(yàn)框谊惭,它們不使用長(zhǎng)寬比為 [圖片上傳失敗...(image-41dc14-1527406250789)]

的先驗(yàn)框。每個(gè)單元的先驗(yàn)框的中心點(diǎn)分布在各個(gè)單元的中心侮东,即 [圖片上傳失敗...(image-7adf38-1527406250789)]

圈盔,其中 [圖片上傳失敗...(image-f11095-1527406250789)]

為特征圖的大小。

得到了特征圖之后悄雅,需要對(duì)特征圖進(jìn)行卷積得到檢測(cè)結(jié)果驱敲,圖7給出了一個(gè) [圖片上傳失敗...(image-3183e4-1527406250789)]

大小的特征圖的檢測(cè)過(guò)程。其中Priorbox是得到先驗(yàn)框宽闲,前面已經(jīng)介紹了生成規(guī)則众眨。檢測(cè)值包含兩個(gè)部分:類別置信度和邊界框位置,各采用一次 [圖片上傳失敗...(image-3cf413-1527406250789)]

卷積來(lái)進(jìn)行完成容诬。令 [圖片上傳失敗...(image-7e788b-1527406250789)]

為該特征圖所采用的先驗(yàn)框數(shù)目娩梨,那么類別置信度需要的卷積核數(shù)量為 [圖片上傳失敗...(image-6fc028-1527406250789)]

,而邊界框位置需要的卷積核數(shù)量為 [圖片上傳失敗...(image-77a566-1527406250789)]

览徒。由于每個(gè)先驗(yàn)框都會(huì)預(yù)測(cè)一個(gè)邊界框狈定,所以SSD300一共可以預(yù)測(cè) [圖片上傳失敗...(image-ab29fe-1527406250789)]

個(gè)邊界框,這是一個(gè)相當(dāng)龐大的數(shù)字习蓬,所以說(shuō)SSD本質(zhì)上是密集采樣纽什。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖7 基于卷積得到檢測(cè)結(jié)果</figcaption>

</figure>

訓(xùn)練過(guò)程

(1)先驗(yàn)框匹配
在訓(xùn)練過(guò)程中措嵌,首先要確定訓(xùn)練圖片中的ground truth(真實(shí)目標(biāo))與哪個(gè)先驗(yàn)框來(lái)進(jìn)行匹配,與之匹配的先驗(yàn)框所對(duì)應(yīng)的邊界框?qū)⒇?fù)責(zé)預(yù)測(cè)它芦缰。在Yolo中铅匹,ground truth的中心落在哪個(gè)單元格,該單元格中與其IOU最大的邊界框負(fù)責(zé)預(yù)測(cè)它饺藤。但是在SSD中卻完全不一樣,SSD的先驗(yàn)框與ground truth的匹配原則主要有兩點(diǎn)流礁。首先涕俗,對(duì)于圖片中每個(gè)ground truth,找到與其IOU最大的先驗(yàn)框神帅,該先驗(yàn)框與其匹配再姑,這樣,可以保證每個(gè)ground truth一定與某個(gè)先驗(yàn)框匹配找御。通常稱與ground truth匹配的先驗(yàn)框?yàn)檎龢颖荆ㄆ鋵?shí)應(yīng)該是先驗(yàn)框?qū)?yīng)的預(yù)測(cè)box元镀,不過(guò)由于是一一對(duì)應(yīng)的就這樣稱呼了),反之霎桅,若一個(gè)先驗(yàn)框沒(méi)有與任何ground truth進(jìn)行匹配栖疑,那么該先驗(yàn)框只能與背景匹配,就是負(fù)樣本滔驶。一個(gè)圖片中g(shù)round truth是非常少的遇革, 而先驗(yàn)框卻很多,如果僅按第一個(gè)原則匹配揭糕,很多先驗(yàn)框會(huì)是負(fù)樣本萝快,正負(fù)樣本極其不平衡,所以需要第二個(gè)原則著角。第二個(gè)原則是:對(duì)于剩余的未匹配先驗(yàn)框揪漩,若某個(gè)ground truth的 [圖片上傳失敗...(image-620469-1527406250789)]

大于某個(gè)閾值(一般是0.5),那么該先驗(yàn)框也與這個(gè)ground truth進(jìn)行匹配吏口。這意味著某個(gè)ground truth可能與多個(gè)先驗(yàn)框匹配奄容,這是可以的。但是反過(guò)來(lái)卻不可以锨侯,因?yàn)橐粋€(gè)先驗(yàn)框只能匹配一個(gè)ground truth嫩海,如果多個(gè)ground truth與某個(gè)先驗(yàn)框 [圖片上傳失敗...(image-9becd4-1527406250789)]

大于閾值,那么先驗(yàn)框只與IOU最大的那個(gè)先驗(yàn)框進(jìn)行匹配囚痴。第二個(gè)原則一定在第一個(gè)原則之后進(jìn)行叁怪,仔細(xì)考慮一下這種情況,如果某個(gè)ground truth所對(duì)應(yīng)最大 [圖片上傳失敗...(image-1eb66-1527406250789)]

小于閾值深滚,并且所匹配的先驗(yàn)框卻與另外一個(gè)ground truth的 [圖片上傳失敗...(image-e30d4c-1527406250789)]

大于閾值奕谭,那么該先驗(yàn)框應(yīng)該匹配誰(shuí)涣觉,答案應(yīng)該是前者,首先要確保某個(gè)ground truth一定有一個(gè)先驗(yàn)框與之匹配血柳。但是官册,這種情況我覺(jué)得基本上是不存在的。由于先驗(yàn)框很多难捌,某個(gè)ground truth的最大 [圖片上傳失敗...(image-32118b-1527406250789)]

肯定大于閾值膝宁,所以可能只實(shí)施第二個(gè)原則既可以了,這里的TensorFlow版本就是只實(shí)施了第二個(gè)原則根吁,但是這里的Pytorch兩個(gè)原則都實(shí)施了员淫。圖8為一個(gè)匹配示意圖,其中綠色的GT是ground truth击敌,紅色為先驗(yàn)框介返,F(xiàn)P表示負(fù)樣本,TP表示正樣本沃斤。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖8 先驗(yàn)框匹配示意圖</figcaption>

</figure>

盡管一個(gè)ground truth可以與多個(gè)先驗(yàn)框匹配圣蝎,但是ground truth相對(duì)先驗(yàn)框還是太少了,所以負(fù)樣本相對(duì)正樣本會(huì)很多衡瓶。為了保證正負(fù)樣本盡量平衡徘公,SSD采用了hard negative mining,就是對(duì)負(fù)樣本進(jìn)行抽樣鞍陨,抽樣時(shí)按照置信度誤差(預(yù)測(cè)背景的置信度越小步淹,誤差越大)進(jìn)行降序排列,選取誤差的較大的top-k作為訓(xùn)練的負(fù)樣本诚撵,以保證正負(fù)樣本比例接近1:3缭裆。

(2)損失函數(shù)
訓(xùn)練樣本確定了,然后就是損失函數(shù)了寿烟。損失函數(shù)定義為位置誤差(locatization loss澈驼, loc)與置信度誤差(confidence loss, conf)的加權(quán)和:

[圖片上傳失敗...(image-87add8-1527406250789)]

其中 [圖片上傳失敗...(image-c0426a-1527406250789)]

是先驗(yàn)框的正樣本數(shù)量。這里 [圖片上傳失敗...(image-333887-1527406250789)]

為一個(gè)指示參數(shù)筛武,當(dāng) [圖片上傳失敗...(image-25f788-1527406250789)]

時(shí)表示第 [圖片上傳失敗...(image-11e50f-1527406250789)]

個(gè)先驗(yàn)框與第 [圖片上傳失敗...(image-9b6c5a-1527406250789)]

個(gè)ground truth匹配缝其,并且ground truth的類別為 [圖片上傳失敗...(image-2b8389-1527406250789)]

。 [圖片上傳失敗...(image-8a2760-1527406250789)]

為類別置信度預(yù)測(cè)值徘六。 [圖片上傳失敗...(image-6a341b-1527406250789)]

為先驗(yàn)框的所對(duì)應(yīng)邊界框的位置預(yù)測(cè)值内边,而 [圖片上傳失敗...(image-631625-1527406250789)]

是ground truth的位置參數(shù)。對(duì)于位置誤差待锈,其采用Smooth L1 loss漠其,定義如下:

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

</figure>

<figure style="margin: 1.6em 0px 1em; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

</figure>

由于 [圖片上傳失敗...(image-cb6729-1527406250789)]

的存在,所以位置誤差僅針對(duì)正樣本進(jìn)行計(jì)算。值得注意的是和屎,要先對(duì)ground truth的 [圖片上傳失敗...(image-f3f8b1-1527406250789)]

進(jìn)行編碼得到 [圖片上傳失敗...(image-5d4f77-1527406250789)]

拴驮,因?yàn)轭A(yù)測(cè)值 [圖片上傳失敗...(image-3a1001-1527406250789)]

也是編碼值,若設(shè)置variance_encoded_in_target=True柴信,編碼時(shí)要加上variance:

[圖片上傳失敗...(image-19a70e-1527406250789)]

[圖片上傳失敗...(image-6b1a6-1527406250789)]

對(duì)于置信度誤差套啤,其采用softmax loss:

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

</figure>

權(quán)重系數(shù) [圖片上傳失敗...(image-1698e8-1527406250789)]

通過(guò)交叉驗(yàn)證設(shè)置為1。

(3)數(shù)據(jù)擴(kuò)增

采用數(shù)據(jù)擴(kuò)增(Data Augmentation)可以提升SSD的性能随常,主要采用的技術(shù)有水平翻轉(zhuǎn)(horizontal flip)潜沦,隨機(jī)裁剪加顏色扭曲(random crop & color distortion),隨機(jī)采集塊域(Randomly sample a patch)(獲取小目標(biāo)訓(xùn)練樣本)绪氛,如下圖所示:

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

</figure>

<figure style="margin: 1.6em 0px 1em; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">圖9 數(shù)據(jù)擴(kuò)增方案</figcaption>

</figure>

其它的訓(xùn)練細(xì)節(jié)如學(xué)習(xí)速率的選擇詳見(jiàn)論文止潮,這里不再贅述。

預(yù)測(cè)過(guò)程

預(yù)測(cè)過(guò)程比較簡(jiǎn)單钞楼,對(duì)于每個(gè)預(yù)測(cè)框,首先根據(jù)類別置信度確定其類別(置信度最大者)與置信度值袄琳,并過(guò)濾掉屬于背景的預(yù)測(cè)框询件。然后根據(jù)置信度閾值(如0.5)過(guò)濾掉閾值較低的預(yù)測(cè)框。對(duì)于留下的預(yù)測(cè)框進(jìn)行解碼唆樊,根據(jù)先驗(yàn)框得到其真實(shí)的位置參數(shù)(解碼后一般還需要做clip宛琅,防止預(yù)測(cè)框位置超出圖片)。解碼之后逗旁,一般需要根據(jù)置信度進(jìn)行降序排列嘿辟,然后僅保留top-k(如400)個(gè)預(yù)測(cè)框。最后就是進(jìn)行NMS算法片效,過(guò)濾掉那些重疊度較大的預(yù)測(cè)框红伦。最后剩余的預(yù)測(cè)框就是檢測(cè)結(jié)果了。

性能評(píng)估

首先整體看一下SSD在VOC2007淀衣,VOC2012及COCO數(shù)據(jù)集上的性能昙读,如表1所示。相比之下膨桥,SSD512的性能會(huì)更好一些蛮浑。加*的表示使用了image expansion data augmentation(通過(guò)zoom out來(lái)創(chuàng)造小的訓(xùn)練樣本)技巧來(lái)提升SSD在小目標(biāo)上的檢測(cè)效果,所以性能會(huì)有所提升只嚣。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">表1 SSD在不同數(shù)據(jù)集上的性能</figcaption>

</figure>

SSD與其它檢測(cè)算法的對(duì)比結(jié)果(在VOC2007數(shù)據(jù)集)如表2所示沮稚,基本可以看到,SSD與Faster R-CNN有同樣的準(zhǔn)確度册舞,并且與Yolo具有同樣較快地檢測(cè)速度蕴掏。

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">表2 SSD與其它檢測(cè)算法的對(duì)比結(jié)果(在VOC2007數(shù)據(jù)集)</figcaption>

</figure>

文章還對(duì)SSD的各個(gè)trick做了更為細(xì)致的分析,表3為不同的trick組合對(duì)SSD的性能影響,從表中可以得出如下結(jié)論:

  • 數(shù)據(jù)擴(kuò)增技術(shù)很重要囚似,對(duì)于mAP的提升很大剩拢;
  • 使用不同長(zhǎng)寬比的先驗(yàn)框可以得到更好的結(jié)果;

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">表3 不同的trick組合對(duì)SSD的性能影響</figcaption>

</figure>

同樣的饶唤,采用多尺度的特征圖用于檢測(cè)也是至關(guān)重要的徐伐,這可以從表4中看出:

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

<figcaption style="margin-top: 0.35556em; font-size: 0.9em; line-height: 1.5; text-align: center; color: rgb(153, 153, 153);">表4 多尺度特征圖對(duì)SSD的影響</figcaption>

</figure>

TensorFlow上的實(shí)現(xiàn)

SSD在很多框架上都有了開(kāi)源的實(shí)現(xiàn),這里基于balancap的TensorFlow版本來(lái)實(shí)現(xiàn)SSD的Inference過(guò)程募狂。這里實(shí)現(xiàn)的是SSD300办素,與paper里面不同的是,這里采用 [圖片上傳失敗...(image-8a3cbe-1527406250789)]

祸穷。首先定義SSD的參數(shù):

self.ssd_params = SSDParams(img_shape=(300, 300),   # 輸入圖片大小
                                    num_classes=21,     # 類別數(shù)+背景
                                    no_annotation_label=21,
                                    feat_layers=["block4", "block7", "block8", "block9", "block10", "block11"],   # 要進(jìn)行檢測(cè)的特征圖name
                                    feat_shapes=[(38, 38), (19, 19), (10, 10), (5, 5), (3, 3), (1, 1)],  # 特征圖大小
                                    anchor_size_bounds=[0.15, 0.90],  # 特征圖尺度范圍
                                    anchor_sizes=[(21., 45.),
                                                  (45., 99.),
                                                  (99., 153.),
                                                  (153., 207.),
                                                  (207., 261.),
                                                  (261., 315.)],  # 不同特征圖的先驗(yàn)框尺度(第一個(gè)值是s_k性穿,第2個(gè)值是s_k+1)
                                    anchor_ratios=[[2, .5],
                                                   [2, .5, 3, 1. / 3],
                                                   [2, .5, 3, 1. / 3],
                                                   [2, .5, 3, 1. / 3],
                                                   [2, .5],
                                                   [2, .5]], # 特征圖先驗(yàn)框所采用的長(zhǎng)寬比(每個(gè)特征圖都有2個(gè)正方形先驗(yàn)框)
                                    anchor_steps=[8, 16, 32, 64, 100, 300],  # 特征圖的單元大小
                                    anchor_offset=0.5,                       # 偏移值,確定先驗(yàn)框中心
                                    normalizations=[20, -1, -1, -1, -1, -1],  # l2 norm
                                    prior_scaling=[0.1, 0.1, 0.2, 0.2]       # variance
                                    )

然后構(gòu)建整個(gè)網(wǎng)絡(luò)雷滚,注意對(duì)于stride=2的conv不要使用TF自帶的padding="same"需曾,而是手動(dòng)pad,這是為了與Caffe一致:

def _built_net(self):
        """Construct the SSD net"""
        self.end_points = {}  # record the detection layers output
        self._images = tf.placeholder(tf.float32, shape=[None, self.ssd_params.img_shape[0],
                                                        self.ssd_params.img_shape[1], 3])
        with tf.variable_scope("ssd_300_vgg"):
            # original vgg layers
            # block 1
            net = conv2d(self._images, 64, 3, scope="conv1_1")
            net = conv2d(net, 64, 3, scope="conv1_2")
            self.end_points["block1"] = net
            net = max_pool2d(net, 2, scope="pool1")
            # block 2
            net = conv2d(net, 128, 3, scope="conv2_1")
            net = conv2d(net, 128, 3, scope="conv2_2")
            self.end_points["block2"] = net
            net = max_pool2d(net, 2, scope="pool2")
            # block 3
            net = conv2d(net, 256, 3, scope="conv3_1")
            net = conv2d(net, 256, 3, scope="conv3_2")
            net = conv2d(net, 256, 3, scope="conv3_3")
            self.end_points["block3"] = net
            net = max_pool2d(net, 2, scope="pool3")
            # block 4
            net = conv2d(net, 512, 3, scope="conv4_1")
            net = conv2d(net, 512, 3, scope="conv4_2")
            net = conv2d(net, 512, 3, scope="conv4_3")
            self.end_points["block4"] = net
            net = max_pool2d(net, 2, scope="pool4")
            # block 5
            net = conv2d(net, 512, 3, scope="conv5_1")
            net = conv2d(net, 512, 3, scope="conv5_2")
            net = conv2d(net, 512, 3, scope="conv5_3")
            self.end_points["block5"] = net
            print(net)
            net = max_pool2d(net, 3, stride=1, scope="pool5")
            print(net)

            # additional SSD layers
            # block 6: use dilate conv
            net = conv2d(net, 1024, 3, dilation_rate=6, scope="conv6")
            self.end_points["block6"] = net
            #net = dropout(net, is_training=self.is_training)
            # block 7
            net = conv2d(net, 1024, 1, scope="conv7")
            self.end_points["block7"] = net
            # block 8
            net = conv2d(net, 256, 1, scope="conv8_1x1")
            net = conv2d(pad2d(net, 1), 512, 3, stride=2, scope="conv8_3x3",
                         padding="valid")
            self.end_points["block8"] = net
            # block 9
            net = conv2d(net, 128, 1, scope="conv9_1x1")
            net = conv2d(pad2d(net, 1), 256, 3, stride=2, scope="conv9_3x3",
                         padding="valid")
            self.end_points["block9"] = net
            # block 10
            net = conv2d(net, 128, 1, scope="conv10_1x1")
            net = conv2d(net, 256, 3, scope="conv10_3x3", padding="valid")
            self.end_points["block10"] = net
            # block 11
            net = conv2d(net, 128, 1, scope="conv11_1x1")
            net = conv2d(net, 256, 3, scope="conv11_3x3", padding="valid")
            self.end_points["block11"] = net

            # class and location predictions
            predictions = []
            logits = []
            locations = []
            for i, layer in enumerate(self.ssd_params.feat_layers):
                cls, loc = ssd_multibox_layer(self.end_points[layer], self.ssd_params.num_classes,
                                              self.ssd_params.anchor_sizes[i],
                                              self.ssd_params.anchor_ratios[i],
                                              self.ssd_params.normalizations[i], scope=layer+"_box")
                predictions.append(tf.nn.softmax(cls))
                logits.append(cls)
                locations.append(loc)
            return predictions, logits, locations

對(duì)于特征圖的檢測(cè)祈远,這里單獨(dú)定義了一個(gè)組合層ssd_multibox_layer呆万,其主要是對(duì)特征圖進(jìn)行兩次卷積,分別得到類別置信度與邊界框位置:

# multibox layer: get class and location predicitions from detection layer
    def ssd_multibox_layer(x, num_classes, sizes, ratios, normalization=-1, scope="multibox"):
        pre_shape = x.get_shape().as_list()[1:-1]
        pre_shape = [-1] + pre_shape
        with tf.variable_scope(scope):
            # l2 norm
            if normalization > 0:
                x = l2norm(x, normalization)
                print(x)
            # numbers of anchors
            n_anchors = len(sizes) + len(ratios)
            # location predictions
            loc_pred = conv2d(x, n_anchors*4, 3, activation=None, scope="conv_loc")
            loc_pred = tf.reshape(loc_pred, pre_shape + [n_anchors, 4])
            # class prediction
            cls_pred = conv2d(x, n_anchors*num_classes, 3, activation=None, scope="conv_cls")
            cls_pred = tf.reshape(cls_pred, pre_shape + [n_anchors, num_classes])
            return cls_pred, loc_pred

對(duì)于先驗(yàn)框车份,可以基于numpy生成谋减,定義在ssd_anchors.py文件中,結(jié)合先驗(yàn)框與檢測(cè)值扫沼,對(duì)邊界框進(jìn)行過(guò)濾與解碼:

classes, scores, bboxes = self._bboxes_select(predictions, locations)

這里將得到過(guò)濾得到的邊界框出爹,其中classes, scores, bboxes分別表示類別,置信度值以及邊界框位置缎除。

基于訓(xùn)練好的權(quán)重文件在這里下載严就,這里對(duì)SSD進(jìn)行測(cè)試:

ssd_net = SSD()
classes, scores, bboxes = ssd_net.detections()
images = ssd_net.images()

sess = tf.Session()
# Restore SSD model.
ckpt_filename = './ssd_checkpoints/ssd_vgg_300_weights.ckpt'
sess.run(tf.global_variables_initializer())
saver = tf.train.Saver()
saver.restore(sess, ckpt_filename)

img = cv2.imread('./demo/dog.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img_prepocessed = preprocess_image(img)   # 預(yù)處理圖片,主要是歸一化和resize
rclasses, rscores, rbboxes = sess.run([classes, scores, bboxes],
                                      feed_dict={images: img_prepocessed})
rclasses, rscores, rbboxes = process_bboxes(rclasses, rscores, rbboxes)  # 處理預(yù)測(cè)框器罐,包括clip,sort,nms

plt_bboxes(img, rclasses, rscores, rbboxes)  # 繪制檢測(cè)結(jié)果

詳細(xì)的代碼放在GitHub上了盈蛮,然后看一下一個(gè)自然圖片的檢測(cè)效果:

<figure style="margin: 1em 0px; color: rgb(26, 26, 26); font-family: -apple-system, system-ui, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
image

</figure>

如果你想實(shí)現(xiàn)SSD的train過(guò)程,你可以參考附錄里面的Caffe,TensorFlow以及Pytorch實(shí)現(xiàn)技矮。

小結(jié)

SSD在Yolo的基礎(chǔ)上主要改進(jìn)了三點(diǎn):多尺度特征圖抖誉,利用卷積進(jìn)行檢測(cè),設(shè)置先驗(yàn)框衰倦。這使得SSD在準(zhǔn)確度上比Yolo更好袒炉,而且對(duì)于小目標(biāo)檢測(cè)效果也相對(duì)好一點(diǎn)。由于很多實(shí)現(xiàn)細(xì)節(jié)都包含在源碼里面樊零,文中有描述不準(zhǔn)或者錯(cuò)誤的地方在所難免我磁,歡迎交流指正孽文。

參考文獻(xiàn)

  1. SSD: Single Shot MultiBox Detector
  2. SSD Slide
  3. SSD Caffe
  4. SSD TensorFlow
  5. SSD Pytorch
  6. leonardoaraujosantos Artificial Inteligence online book
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市夺艰,隨后出現(xiàn)的幾起案子芋哭,更是在濱河造成了極大的恐慌,老刑警劉巖郁副,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滋尉,死亡現(xiàn)場(chǎng)離奇詭異律歼,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)牡拇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)冈敛,“玉大人遭铺,你說(shuō)我怎么就攤上這事搀绣。” “怎么了恰聘?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵句各,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我晴叨,道長(zhǎng)诫钓,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任篙螟,我火速辦了婚禮,結(jié)果婚禮上问拘,老公的妹妹穿的比我還像新娘遍略。我一直安慰自己,他們只是感情好骤坐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布绪杏。 她就那樣靜靜地躺著,像睡著了一般纽绍。 火紅的嫁衣襯著肌膚如雪蕾久。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,031評(píng)論 1 285
  • 那天拌夏,我揣著相機(jī)與錄音僧著,去河邊找鬼。 笑死障簿,一個(gè)胖子當(dāng)著我的面吹牛盹愚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播站故,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼皆怕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼毅舆!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起愈腾,我...
    開(kāi)封第一講書(shū)人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤憋活,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后虱黄,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體悦即,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年礁鲁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了盐欺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡仅醇,死狀恐怖冗美,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情析二,我是刑警寧澤粉洼,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站叶摄,受9級(jí)特大地震影響属韧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蛤吓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一宵喂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧会傲,春花似錦锅棕、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至泼疑,卻和暖如春德绿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背退渗。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工移稳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人会油。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓秒裕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親钞啸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子几蜻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容