import numpy as np
import math
def ssd_anchor_one_layer(img_shape,feat_shape,sizes,ratios,step,offset=0.5,dtype=np.float32):
"""Computer SSD default anchor boxes for one feature layer.
Determine the relative position grid of the centers, and the relative
width and height.
Arguments:
feat_shape: Feature shape, used for computing relative position grids;
size: Absolute reference sizes;
ratios: Ratios to use on these features;
img_shape: Image shape, used for computing height, width relatively to the
former;
offset: Grid offset.
Return:
y, x, h, w: Relative x and y grids, and height and width.
"""
# Compute the position grid: simple way.
# y, x = np.mgrid[0:feat_shape[0], 0:feat_shape[1]]
# y = (y.astype(dtype) + offset) / feat_shape[0]
# x = (x.astype(dtype) + offset) / feat_shape[1]
# Weird SSD-Caffe computation using steps values...
#對於第一個特征圖(block4:38x38);y=[[0,0,……0],[1,1,……1],……[37,37,……,37]];
# 而x=[[0,1,2……,37],[0,1,2……,37],……[0,1,2……,37]]
y, x = np.mgrid[0:feat_shape[0], 0:feat_shape[1]]
# 可以得到在原圖上,相對原圖比例大小的每個錨點中心坐標x,y
# 將38個cell對應錨點框的x,y坐標偏移至每個cell中心,然后乘以相對原圖縮放的比例,再除以原圖
y = (y.astype(dtype) + offset) * step / img_shape[0]
x = (x.astype(dtype) + offset) * step / img_shape[1]
# Expand dims to support easy broadcasting.
# 對於第一個特征圖,y的shape=38x38x1;x的shape=38x38x1
y = np.expand_dims(y, axis=-1)
x = np.expand_dims(x, axis=-1)
# Compute relative height and width.
# Tries to follow the original implementation of SSD for the order.
# 該特征圖上每個點對應的錨點框數量;如:對於第一個特征圖每個點預測4個錨點框(block4:38x38),
#num_anchors :2+2=4
num_anchors = len(sizes) + len(ratios)
# 對於第一個特征圖,h的shape=4x;w的shape=4x
h = np.zeros((num_anchors, ), dtype=dtype)
w = np.zeros((num_anchors, ), dtype=dtype)
# Add first anchor boxes with ratio=1.
# 第一個錨點框的高h[0]=起始錨點的高/原圖大小的高;例如:h[0]=21/300
h[0] = sizes[0] / img_shape[0]
# 第一個錨點框的寬w[0]=起始錨點的寬/原圖大小的寬;例如:w[0]=21/300
w[0] = sizes[0] / img_shape[1]
di = 1 #錨點寬個數偏移
if len(sizes) > 1:
# 第二個錨點框的高h[1]=sqrt(起始錨點的高*起始錨點的寬)/原圖大小的高;例如:h[1]=sqrt(21*45)/300
h[1] = math.sqrt(sizes[0] * sizes[1]) / img_shape[0]
# 第二個錨點框的高w[1]=sqrt(起始錨點的高*起始錨點的寬)/原圖大小的寬;例如:w[1]=sqrt(21*45)/300
w[1] = math.sqrt(sizes[0] * sizes[1]) / img_shape[1]
di += 1
for i, r in enumerate(ratios):
# 遍歷長寬比例,第一個特征圖,r只有兩個,2和0.5;共四個錨點寬size(h[0]~h[3])
# 例如:對於第一個特征圖,h[0+2]=h[2]=21/300/sqrt(2);w[0+2]=w[2]=45/300*sqrt(2)
# 例如:對於第一個特征圖,h[1+2]=h[3]=21/300/sqrt(0.5);w[1+2]=w[3]=45/300*sqrt(0.5)
# 返回沒有歸一化前的錨點坐標和尺寸
h[i+di] = sizes[0] / img_shape[0] / math.sqrt(r)
w[i+di] = sizes[0] / img_shape[1] * math.sqrt(r)
return y, x, h, w
y, x, h, w = ssd_anchor_one_layer((300,300),(38,38),(21., 45.),[2, .5],8)
print(h)
print(w)
[0.07 0.10246951 0.04949747 0.09899495]
[0.07 0.10246951 0.09899495 0.04949747]
其中第一個38*38的特征圖,每個點產生4個anchor,分別為0.07和0.102的正方形兩個,寬高分別為0.049、0.098的長方形兩個。
Loss函數計算
SSD的Loss函數包含兩項:(1)預測類別損失(2)預測位置偏移量損失:
Loss中的N代表着被挑選出來的默認框正樣本個數,L(los)即位置偏移量損失是Smooth L1 loss(是默認框與GTbox之間的位置偏移與網絡預測出的位置偏移量之間的損失),L(conf)即預測類別損失是多類別softmax loss,α的值設置為1. Smooth L1 loss定義為:
L(los)損失函數的定義為:
根據函數定義我們可以看到L(los)損失函數主要有四部分:中心坐標cx的偏移量損失,中心點坐標cy的偏移損失,寬度w的縮放損失以及高度h的縮放損失。式中的l表示的是預測的坐標偏移量,g表示的是默認框與之匹配的GTbox的坐標偏移量。

L(conf)多類別softmax loss損失定義為:

根據函數定義我們可以看到L(conf)損失由兩部分組成:正樣本(Pos)損失和負樣本(Neg)損失。

參考:https://blog.csdn.net/u010712012/article/details/86555814


