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)