解讀SSD中的Default box(Prior Box)
1:SSD更具體的框架如下:
2: Prior Box
縮排在SSD中引入了Prior Box,實際上與anchor非常類似,就是一些目標的預選框,後續通過softmax分類+bounding box regression獲得真實目標的位置。SSD按照如下規則生成prior box:
- 以feature map上每個點的中點為中心(offset=0.5),生成一些列同心的prior box(然後中心點的座標會乘以step,相當於從feature map位置映射回原圖位置)
- 正方形prior box最小邊長為
- 每在prototxt設定一個aspect ratio,會生成2個長方形,長寬為: 和
圖4 prior box
- 而每個feature map對應prior box的min_size和max_size由以下公式決定,公式中m是使用feature map的數量(SSD 300中m=6):
第一層feature map對應的min_size=S1,max_size=S2;第二層min_size=S2,max_size=S3;其他類推。在原文中,Smin=0.2,Smax=0.9,但是在SSD 300中prior box設定並不能和paper中上述公式對應:
min_size | max_size | |
---|---|---|
conv4_3 | 30 | 60 |
fc7 | 60 | 111 |
conv6_2 | 111 | 162 |
conv7_2 | 162 | 213 |
conv8_2 | 213 | 264 |
conv9_2 | 264 | 315 |
不過依然可以看出,SSD使用低層feature map檢測小目標,使用高層feature map檢測大目標,這也應該是SSD的突出貢獻了。其中SSD 300在conv4_3生成prior box的conv4_3_norm_priorbox層prototxt定義如下:
[cpp] view plain copy
- layer {
- name: "conv4_3_norm_mbox_priorbox"
- type: "PriorBox"
- bottom: "conv4_3_norm"
- bottom: "data"
- top: "conv4_3_norm_mbox_priorbox"
- prior_box_param {
- min_size: 30.0
- max_size: 60.0
- aspect_ratio: 2
- flip: true
- clip: false
- variance: 0.1
- variance: 0.1
- variance: 0.2
- variance: 0.2
- step: 8
- offset: 0.5
- }
- }
知道了priorbox如何產生,接下來分析prior box如何使用。這裡以conv4_3為例進行分析。
圖5
從圖5可以看到,在conv4_3 feature map網路pipeline分為了3條線路:
- 經過一次batch norm+一次卷積後,生成了[1, num_class*num_priorbox, layer_height, layer_width]大小的feature用於softmax分類目標和非目標(其中num_class是目標類別,SSD 300中num_class = 21)
- 經過一次batch norm+一次卷積後,生成了[1, 4*num_priorbox, layer_height, layer_width]大小的feature用於bounding box regression(即每個點一組[dxmin,dymin,dxmax,dymax],參考Faster RCNN 2.5節)
- 生成了[1, 2, 4*num_priorbox]大小的prior box blob,其中2個channel分別儲存prior box的4個點座標和對應的4個variance
縮排後續通過softmax分類+bounding box regression即可從priox box中預測到目標,熟悉Faster RCNN的讀者應該對上述過程應該並不陌生。其實pribox box的與Faster RCNN中的anchor非常類似,都是目標的預設框,沒有本質的差異。區別是每個位置的prior box一般是4~6個,少於Faster RCNN預設的9個anchor;同時prior box是設定在不同尺度的feature maps上的,而且大小不同。
縮排還有一個細節就是上面prototxt中的4個variance,這實際上是一種bounding regression中的權重。在圖4線路(2)中,網路輸出[dxmin,dymin,dxmax,dymax],即對應下面程式碼中bbox;然後利用如下方法進行鍼對prior box的位置迴歸:
[cpp]
- decode_bbox->set_xmin(
- prior_bbox.xmin() + prior_variance[0] * bbox.xmin() * prior_width);
- decode_bbox->set_ymin(
- prior_bbox.ymin() + prior_variance[1] * bbox.ymin() * prior_height);
- decode_bbox->set_xmax(
- prior_bbox.xmax() + prior_variance[2] * bbox.xmax() * prior_width);
- decode_bbox->set_ymax(
- prior_bbox.ymax() + prior_variance[3] * bbox.ymax() * prior_height);
上述程式碼可以在SSD box_utils.cpp的void DecodeBBox()函式見到