w = torch.cat((size_tensor * torch.sqrt(ratio_tensor[0]),
sizes[0] * torch.sqrt(ratio_tensor[1:])))\
* in_height / in_width # 处理矩形输入
h = torch.cat((size_tensor / torch.sqrt(ratio_tensor[0]),
sizes[0] / torch.sqrt(ratio_tensor[1:])))
在这里* in_height / in_width很多人不理解(包括我),经过看其他人的评论和自己测试后我发现,是因为文章中的公式有误,导致大家推导代码感觉没有逻辑性。
缩放比s应该为,宽高比r应该为(所以这里的宽高比不是锚框的宽高比,而是锚框的宽高比与原图的宽高比的比值)。
下面给出公式推导过程:
由得到:
,
对得到的宽高归一化得到:
,
把w和h带到中计算得到 :
,
结合w0、h0、s就能得到:
,
因为w0和h0是归一化过的,再乘以原图宽高就得到文章中计算宽高的公式:
,
把上面推导过程捋清楚后,这里就不能理解* in_height / in_width,是为了与原图等比例缩放,也就是说当r=1时,使得,锚框与原图同形,而不是确定锚框为正方形。对于这一点,只要知道,就很好理解了。
在代码中的测试也验证了我的想法。
img = d2l.plt.imread('../img/catdog.jpg')
h, w = img.shape[:2]
print(h, w)
X = torch.rand(size=(1, 3, h, w))
Y = multibox_prior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])
Y.shape
178 234
# 除以2来获得半高和半宽
anchor_manipulations = torch.stack((-w, -h, w, h)).T.repeat(
in_height * in_width, 1) / 2
# 每个中心点都将有“boxes_per_pixel”个锚框,
# 所以生成含所有锚框中心的网格,重复了“boxes_per_pixel”次
out_grid = torch.stack([shift_x, shift_y, shift_x, shift_y],
dim=1).repeat_interleave(boxes_per_pixel, dim=0)
print(anchor_manipulations[0])
print(out_grid[0])
output = out_grid + anchor_manipulations
print(output[0])
tensor([-0.29, -0.38, 0.29, 0.38])#锚框的半宽与半高
tensor([0.00, 0.00, 0.00, 0.00])#中心坐标
tensor([-0.28, -0.37, 0.29, 0.38])#左上角坐标和右下角坐标
torch.Size([1, 208260, 4])#总锚框数量
torch.set_printoptions(2) # 精简输出精度
#在原文第一个代码块设置了精度为小数点后2位
#0.29/0.38与178/234不完全相等是因为数字精度
所以其实这里代码是没问题的,因为文章中对两个参数的描述不清晰,导致大家不理解。