PriorBox建構源碼
論文連結
實際上PriorBox即default boxes即anchors。本文代碼将要複現的是論文中對于Choosing scales and aspect ratios for default boxes這一節的描述。
default box 設定原理
早先的工作已經反映出淺層能夠擷取更多目标的細節,是以可以提升語義分割的品質。是以SSD借鑒這一特點,同時利用淺層和深層的資訊來提高目标檢測品質,而且還不會對計算增加過多的開銷。

上面這段話的翻譯大緻是在SSD結構中default box不需要和每一層的感受野相對應,特定的特征圖負責處理圖像中特定尺度的物體。什麼意思呢?根據下面的分析和代碼的複現,實際上每個特征圖中預設框的尺度确實沒有與特征圖本身的分辨率或者說單個像素點的感受野有關,而是特征圖尺度的一個小于一的比例。也就是說預設框大小随着特征圖單像素點的感受野的變化而變化。
相關函數
product
先看一下函數定義(已做過适當翻譯):
class product(object):
"""
product(*iterables, repeat=1) --> product object
輸入疊代的笛卡爾積。等價于嵌套的for循環。
例如product(A, B)相當于((x,y) for x in A for y in B)。
注意A在外層循環,B在内層循環。(當然參數還可以大于2個)
如果要單獨計算A的循環,還可以定義repeat,例如
product(A, repeat=4) 等價于 product(A, A, A, A).
具體例子:
product('ab', range(3)) --> ('a',0) ('a',1) ('a',2) ('b',0) ('b',1) ('b',2)
product((0,1), (0,1), (0,1)) --> (0,0,0) (0,0,1) (0,1,0) (0,1,1) (1,0,0) ...
"""
我們再嘗試一下類似于PriorBox代碼中的輸入:
>>>from itertools import product
>>>for i, j in product(range(3), repeat=2):
>>> print(i,j)
>>> 0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
default box 具體設定
尺度的設定
每個特征圖中default box的尺度定義如下:
其中s_min=0.2,s_max=0.9,即分别代表着最低和最高尺度比例,那麼從上面的式子可以看出各個尺度是均勻分布的。
aspect ratios的設定
- 從上面的描述可知,aspect ratios即a_r=w/h,即長寬比(在很多二階論文中也是稱為aspect ratios的),通過a_r和s_k可以計算預設框的w和h;同時w*h即位s_k的平方,是以s_k也可以被了解為面積的開方。
- 特别地,對于aspect ratios=1的情況,還另外增加了一個尺度。
-
同時,作者還定義了每個default box的中心像素位置。
代碼如下:
"""需要用到的參數:
min_dim = 300
"輸入圖最短邊的尺寸"
feature_maps = [38, 19, 10, 5, 3, 1]
steps = [8, 16, 32, 64, 100, 300]
"共有6個特征圖:
feature_maps指的是在某一層特征圖中,周遊一行/列需要的步數
steps指特征圖中兩像素點相距n則在原圖中相距steps[k]*n
由于steps由于網絡結構是以為固定,是以作者應該是由300/steps[k]得到feature_maps"
min_sizes = [30, 60, 111, 162, 213, 264]
max_sizes = [60, 111, 162, 213, 264, 315]
"min_sizes和max_sizes共同使用為用于計算aspect_ratios=1時
rel size: sqrt(s_k * s_(k+1))時所用"
aspect_ratios = [[2], [2, 3], [2, 3], [2, 3], [2], [2]]
"各層除1以外的aspect_ratios,可以看出是各不相同的,
這樣每層特征圖的每個像素點分别有[4,6,6,6,4,4]個default boxes
作者也在原文中提到這個可以根據自己的場景适當調整"
"""
mean = []
#對于每一個特征圖生成box
for k, f in enumerate(feature_maps):
#對特定特征圖的每一個像素點生成适當數量的default boxes
for i, j in product(range(f), repeat=2):
f_k = image_size / steps[k] #f_k 是第k個特征圖的大小
"""每個default box的中心點,從論文以及代碼複現可知0<cx,cy<1
即對應于原圖的一個比例"""
cx = (j + 0.5) / f_k
cy = (i + 0.5) / f_k
#第一種情形:
# aspect_ratio: 1
# rel size: min_size
s_k = min_sizes[k]/image_size
mean += [cx, cy, s_k, s_k]
#第二種情形:
# aspect_ratio: 1
# rel size: sqrt(s_k * s_(k+1))
s_k_prime = sqrt(s_k * (max_sizes[k]/image_size))
mean += [cx, cy, s_k_prime, s_k_prime]
# 剩餘情形
for ar in aspect_ratios[k]:
mean += [cx, cy, s_k*sqrt(ar), s_k/sqrt(ar)]
mean += [cx, cy, s_k/sqrt(ar), s_k*sqrt(ar)]
# back to torch land
output = torch.Tensor(mean).view(-1, 4) #[num_priors,4] (cx,cy,w,h)