以前在簡書的文章,搬遷過來 ^-^
先放大神的論文和源碼鎮樓:git
SSD Github: https://github.com/weiliu89/caffe
請選擇分支 SSD
SSD paper: arxiv.org/abs/1512.02…github
對於SSD來講,最有新意的就是它的多尺度特徵,而整個代碼中調整頻度最高的應該是它的Prior_box,咱們就從這些方面來分享一下我本身的理解。windows
##多尺度 先說一下多尺度特徵。在以前的Faster-RCNN中,特徵向量都是從最後一層的Feature Maps上獲得的,對於這種單一的特徵層而言,感覺野是十分有限的,沒有徹底利用好前面幾級的特徵網絡。在SSD中,做者從CONV4_3開始,利用多級Feature Maps的組合做爲分類和迴歸的依據,達到了論文中提到的多尺度的效果。 借用論文中的一張圖來講明,做者是拿YOLO和SSD作的對比:網絡
能夠看出SSD 的特徵是從不一樣的卷積層提取出來(上圖紅線),進行組合再進行迴歸和分類,而YOLO只有一層,在YOLO以後的版本中也借鑑了 SSD的這種多尺度的思想來提升mAp。也就是說,SSD就是Faster-RCNN和YOLO中作了一次的分類和檢測過程放在不一樣的圖像大小上作了屢次。
##Prior_box 知道了SSD的特徵是從不一樣尺度上提取的,那麼論文中所說的8732 BOXES又是怎麼來的呢?用下面這張表來告訴你。數據結構
name | Out_size | Prior_box_num | Total_num |
---|---|---|---|
conv4-3 | 38x38 | 4 | 5776 |
fc7 | 19x19 | 6 | 2166 |
conv5-2 | 10x10 | 6 | 600 |
conv7-2 | 5x5 | 6 | 150 |
conv8-2 | 3x3 | 6 | 36 |
conv9-2 | 1x1 | 4 | 4 |
8732 |
和 Faster-RCNN同樣,SSD也是特徵圖上的每個點對應一組預選框。而後每一層中每個點對應的prior box的個數,是由PriorBox這一層的配置文件決定的。拿conv4-3對應的priorbox來講,caffe的模型配置文件以下: 學習
那麼SSD是怎麼生成對應的四個priorbox的呢? 框的生成過程大概分爲下面三種方式:3d
先以 min_size爲寬高生成一個框。code
若是存在max_size則用sqrt(min_size_ * max_size_),生成一個框。orm
而後根據 aspect_ratio,再去生成。如上面的配置文件,aspect_ratio=2,那麼會自動的再添加一個aspect_ratiod = 1/2,而後根據下面的計算方法: cdn
分別生成兩個框,一個對應 ar = 2 一個對應 ar= 1/2。
直觀點說,就是min_size和max_size會分別生成一個正方形的框,aspect_ratio參數會生成2個長方形的框。因此輸出框的個數 :
prior_box_num = count(min_size)*1+count(max_size)*1+count(aspect_ratio)*2。
PS: min_size是必需要有的參數,不然不會進入對應的框的生成過程。論文跟實際代碼是有一些出入的,Git上也有人在討論這個,基本都選擇無視論文。。。
這裏還有一個比較關鍵的參數,就是step,在conv4-3中設置爲8,這個又是怎麼來的呢?仍是用一個表來看一下:
name | Out_size | Cal_scale | Real_scale |
---|---|---|---|
conv4-3 | 38x38 | 7.8 | 8 |
fc7 | 19x19 | 15.78 | 16 |
conv5-2 | 10x10 | 30 | 32 |
conv7-2 | 5x5 | 60 | 64 |
conv8-2 | 3x3 | 100 | 100 |
conv9-2 | 1x1 | 300 | 300 |
Cal_scale = 300/out_size 實際就是 原圖與特徵圖 大小的比值,好比conv4-3 width = 38 ,輸入的大小爲300,那麼scale=7.8,因此這裏設置的step=8。代碼中實現以下:
這一部分的計算過程能夠在 prior_box_layer.cpp的Forward_cpu中看到。
##特徵的表出形式 若是你看了SSD的網絡結構會發現,每個 convXXXX_mbox_loc 或者 convXXXX_mbox_conf後面都會跟一個permute+flatten layer,以下圖:
這是在幹什麼呢? 使用CAFFE的同窗都知道 ,CAFFE的數據結構是 NCHW的形式(N:樣本個數, C:通道數,H:高,W:寬),而SSD的 XX_conf 和 XX_loc層的輸出,是用通道來保存特徵向量的,因此這裏須要將通道數調整到最後,也就是 permute所作的事情,經過該層後,數據的順序被換成了 NHWC,再經過 flatten拉成一列。
這裏還有仍是要說一下 XX_LOC 和 XX_CONF 層的輸出通道的規則,XX_LOC層是用來回歸框的,因此須要4個座標信息,而XX_CONF是用來作分類的,因此須要class_num個信息,同時每一個點會有多個prior_box ,咱們令 K = count(prior_box),那麼相應的XX_LOC的輸出的通道個數應爲4*K,而XX_CONF的輸出通道個數應爲 class_num*K,做爲驗證,咱們仍是看一下針對於VOC的模型的參數設置,
仍是看conv4_3,這一層對應了4個prior_box ,VOC的分類個數是21(20個分類+1個背景),因此對應的conv4_3_norm_mbox_loc 的num output = 16 = 4*4 ,而 conf的 num_output = 84 = 21*4。因此,若是針對的是本身的訓練集,必定要記着修改 XX_CONF的輸出通道數。
其實簡單點理解,就是SSD的最後幾層的輸出信息都是保存在Channel這一維度的,而一個LOC+CONF+PRIOR的模塊能夠認爲等效於一個 Faster-rcnn的最後的迴歸+分類過程,經過將這些子模塊的特徵拼接起來,獲得一組特徵向量,達到提取多尺度特徵的目的(多個F-RCNN同時工做於同一圖片的不一樣尺度上)。
#####再看一下爲何一個特徵點要對應幾個prior_box。 原圖中的某一個片區域,在通過幾層的提取後,會抽象成特徵圖上的一個點,那麼多對於多個prior_box而言,他們對應的都是同一組信息,那麼多個prior_box的意義是什麼呢?看下圖:
該圖只是示意做用,我假設某一層的特徵輸出中的一個點,在原圖中的感覺野恰好是上圖左上角的區域,能夠看出卡片遮擋了筆的部分特徵(橙色和藍色的框是我標註上去的,2根藍線是示意做用,能夠忽略),若是沒有多個prioro_box的時候,這種場景就沒法正確分類,要麼認爲是卡片,要麼認爲是筆。這時候多個Prior_box的價值就來了,由於多個框都會輸出本身的座標迴歸和分類,它們會去關注本身對應的特徵,而後不一樣的框給出不一樣的分類得分,我的以爲有點相似於一個Attention的結構。
##最後仍是要提一下SSD的數據加強 SSD的數據加強有不少,隨機的剪裁,放縮,亮度,飽和度的調整,等等。參數也基本是見名知意的,因此最好本身跟着代碼看一下比較有效。若是本身須要作數據加強不妨學習一下他的用法。 這裏推薦一個 GIT: https://github.com/eric612/MobileNet-SSD-windows
這個GIT的SSD版本是能夠在 WINDOWS上跑的,這樣就能用宇宙最強IDE——VS一步一步的跟着看圖片的變化了。