深度學習 SSD的理解和細節分析

以前在簡書的文章,搬遷過來 ^-^
先放大神的論文和源碼鎮樓: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作的對比:網絡

1.jpg

能夠看出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

  1. 先以 min_size爲寬高生成一個框。code

  2. 若是存在max_size則用sqrt(min_size_ * max_size_),生成一個框。orm

  3. 而後根據 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一步一步的跟着看圖片的變化了。

相關文章
相關標籤/搜索