42 锚框【动手学深度学习v2】

边框的加入使得图像处理任务变得复杂了许多
边缘框表示的是物体的真实位置。
锚框则是算法对物体位置的猜测。具体步骤见下:

计算两个框的相似度方法:IoU-交并比
运算方法是两框交集除以两框并集

我的理解应该是拿框住的范围与真实物体框的范围求雅可比值,再设置一个雅可比值,小于则负类(背景)大于(关联)

例子:一个图片中含有4个边缘框(对应下图中列数)和9个锚框(对应下图中行数)。则矩阵中的每个值就是该边缘框与锚框的IoU值。
1、找出该矩阵中的最高值,即相似度最高的一对边缘框和锚框,并将该数值所在的行与列中的其他数值删掉。
2、寻找剩余数值中的最大值。
3、直到所有边缘框都找到了对应的锚框,则剩下的锚框都为负类(背景)。
注:一个锚框就是一个训练样本

非极大值抑制:将多个相似的框进行合并
具体操作方法:找到非背景类的最大预测值,去除与它相似度较高的其他框


代码实现
%matplotlib inline import torch from d2l import torch as d2l torch.set_printoptions(2) # 精简输出精度
锚框的生成:以一个像素为中心生成多个高宽不同的框

#@save def multibox_prior(data, sizes, ratios): """生成以每个像素为中心具有不同形状的锚框""" in_height, in_width = data.shape[-2:] device, num_sizes, num_ratios = data.device, len(sizes), len(ratios) boxes_per_pixel = (num_sizes + num_ratios - 1) size_tensor = torch.tensor(sizes, device=device) ratio_tensor = torch.tensor(ratios, device=device) # 为了将锚点移动到像素的中心,需要设置偏移量。 # 因为一个像素的高为1且宽为1,我们选择偏移我们的中心0.5 offset_h, offset_w = 0.5, 0.5 steps_h = 1.0 / in_height # 在y轴上缩放步长 steps_w = 1.0 / in_width # 在x轴上缩放步长 # 生成锚框的所有中心点 center_h = (torch.arange(in_height, device=device) + offset_h) * steps_h center_w = (torch.arange(in_width, device=device) + offset_w) * steps_w shift_y, shift_x = torch.meshgrid(center_h, center_w, indexing='ij') shift_y, shift_x = shift_y.reshape(-1), shift_x.reshape(-1) # 生成“boxes_per_pixel”个高和宽, # 之后用于创建锚框的四角坐标(xmin,xmax,ymin,ymax) 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:]))) # 除以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) output = out_grid + anchor_manipulations return output.unsqueeze(0)
可以看到返回的锚框变量Y
的形状是(批量大小,锚框的数量,4)。
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
561 728 torch.Size([1, 2042040, 4])
2042040是锚框数
def show_bboxes(axes, bboxes, labels=None, colors=None): """显示所有边界框""" def _make_list(obj, default_values=None): if obj is None: obj = default_values elif not isinstance(obj, (list, tuple)): obj = [obj] return obj labels = _make_list(labels) colors = _make_list(colors, ['b', 'g', 'r', 'm', 'c']) for i, bbox in enumerate(bboxes): color = colors[i % len(colors)] rect = d2l.bbox_to_rect(bbox.detach().numpy(), color) axes.add_patch(rect) if labels and len(labels) > i: text_color = 'k' if color == 'w' else 'w' axes.text(rect.xy[0], rect.xy[1], labels[i], va='center', ha='center', fontsize=9, color=text_color, bbox=dict(facecolor=color, lw=0))
d2l.set_figsize() bbox_scale = torch.tensor((w, h, w, h)) fig = d2l.plt.imshow(img) show_bboxes(fig.axes, boxes[250, 250, :, :] * bbox_scale, ['s=0.75, r=1', 's=0.5, r=1', 's=0.25, r=1', 's=0.75, r=2', 's=0.75, r=0.5'])
知识补充:
一个锚框只能对应一个真实框
锚框是以像素为中心,变换高度和宽度生成的