在之前,我们以输入图像的每个像素为中心,生成了多个锚框。 基本而言,这些锚框代表了图像不同区域的样本。 然而,如果为每个像素都生成的锚框,我们最终可能会得到太多需要计算的锚框。 想象一个 561×728 的输入图像,如果以每个像素为中心生成五个形状不同的锚框,就需要在图像上标记和预测超过200万个锚框( 561×728×5 )。
1. 多尺度锚框
减少图像上的锚框数量并不困难。 比如,我们可以在输入图像中均匀采样一小部分像素,并以它们为中心生成锚框。 此外,在不同尺度下,我们可以生成不同数量和不同大小的锚框。 直观地说,比起较大的目标,较小的目标在图像上出现的可能性更多样。 例如, 1×1 、 1×2 和 2×2 的目标可以分别以4、2和1种可能的方式出现在 2×2 图像上。 因此,当使用较小的锚框检测较小的物体时,我们可以采样更多的区域,而对于较大的物体,我们可以采样较少的区域。
为了演示如何在多个尺度下生成锚框,让我们先读取一张图像。 它的高度和宽度分别为561和728像素。
%matplotlib inline
import torch
from d2l import torch as d2l
img = d2l.plt.imread('drive/MyDrive/chapter13/img/catdog.jpg')
h, w = img.shape[:2]
h, w
运行结果:
我们将卷积图层的二维数组输出称为特征图
。 通过定义特征图的形状,我们可以确定任何图像上均匀采样锚框的中心。
display_anchors
函数定义如下。 我们在特征图(fmap)上生成锚框(anchors),每个单位(像素)作为锚框的中心。 由于锚框中的 (𝑥,𝑦) 轴坐标值(anchors)已经被除以特征图(fmap)的宽度和高度,因此这些值介于0和1之间,表示特征图中锚框的相对位置。
由于锚框(anchors)的中心分布于特征图(fmap)上的所有单位,因此这些中心必须根据其相对空间位置在任何输入图像上均匀分布。 更具体地说,给定特征图的宽度和高度fmap_w和fmap_h,以下函数将均匀地对任何输入图像中fmap_h行和fmap_w列中的像素进行采样。 以这些均匀采样的像素为中心,将会生成大小为s(假设列表s的长度为1)且宽高比(ratios)不同的锚框。
# 告诉feature map的高宽以及size大小传入,就能得到所有你要的锚框
def display_anchors(fmap_w, fmap_h, s):
d2l.set_figsize()
# 前两个维度上的值不影响输出
# 生成一个假的feature map,告诉高和宽fmap_h, fmap_w,通道数为10,batch_size=1
# 通道数和batch_size不关心,只关心宽和高
fmap = torch.zeros((1, 10, fmap_h, fmap_w))
# 知道特征图的高和宽就知道了有多少个像素,然后以每个像素为中心生成不同的大小的锚款
# ratios=[1, 2, 0.5]表示1:1的高宽、高是宽的2倍、宽是高的2倍(ratio是宽高比)
# 第一个参数是fmap传入到multibox_prior,这个函数会看宽和高是怎样的,之后的参数是sizes以及ratios
# 返回的结果anchors都是得到0-1之间的数值
anchors = d2l.multibox_prior(fmap, sizes=s, ratios=[1, 2, 0.5])
# bbox_scale真实图片的大小
bbox_scale = torch.tensor((w, h, w, h))
# anchors[0] * bbox_scale:锚框在整个图片的大小
# anchors[0] 取0是因为 batch_size=1
d2l.show_bboxes(d2l.plt.imshow(img).axes,
anchors[0] * bbox_scale)
首先,让我们考虑探测小目标。 为了在显示时更容易分辨,在这里具有不同中心的锚框不会重叠: 锚框的尺度设置为0.15,特征图的高度和宽度设置为4。 我们可以看到,图像上4行和4列的锚框的中心是均匀分布的。
# size取0.15也就是说占锚框图片的0.15x0.15=2.25%的区域
# s应该是占长宽的比例
display_anchors(fmap_w=4, fmap_h=4, s=[0.15])
运行结果:
因为高和宽都是4 ,所以画出来有16个像素。每三个锚框中心点都在一个像素上。因为这是在feature map上生成出来的。feature map是4x4,再映射回去到原来的图片上得到所有锚框。
然后,我们将特征图的高度和宽度减小一半,然后使用较大的锚框来检测较大的目标。 当尺度设置为0.4时,一些锚框将彼此重叠。
display_anchors(fmap_w=2, fmap_h=2, s=[0.4])
运行结果:
最后,我们进一步将特征图的高度和宽度减小一半,然后将锚框的尺度增加到0.8。 此时,锚框的中心即是图像的中心。
# 最后把整个图片缩成一个像素
display_anchors(fmap_w=1, fmap_h=1, s=[0.8])
运行结果: