深度学习Anchor Boxes原理与实战技术

目标检测算法通常对输入图像中的大量区域进行采样,判断这些区域是否包含感兴趣的目标,并调整这些区域的边缘,以便更准确地预测目标的地面真实边界框。不同的模型可能使用不同的区域采样方法。在这里,我们介绍一种这样的方法:它生成多个大小和纵横比不同的边框,同时以每个像素为中心。这些边界框称为锚框。我们将在下面几节中练习基于锚盒的对象检测。

首先,导入本文所需的包或模块。在这里,我们修改了NumPy的打印精度。因为打印张量实际上调用了NumPy的print函数,所以本文打印的张量中的浮点数更简洁。

%matplotlib inline

from d2l import mxnet as d2l

from mxnet import gluon, image, np, npx

np.set_printoptions(2)

npx.set_np()

1. Generating Multiple Anchor Boxes

假设输入图像的高度为\(h\),宽度为\(w\)。我们生成以图像的每个像素为中心的不同形状的锚框。假设大小为\(s\in (0, 1]\),纵横比为\(r>0\),锚框的宽度和高度分别为\(ws\sqrt{r}\)和\(hs/\sqrt{r}\)。当中心位置给定时,确定一个已知宽度和高度的锚箱。

下面我们设置了一组大小\(s_1,\ldots,s\u n\)和一组纵横比\(r\u 1,\ldots,r\u m\)。如果我们使用以每个像素为中心的所有尺寸和纵横比的组合,输入图像将有总共\(whnm\)个锚框。虽然这些锚盒可以覆盖所有的地面真实边界盒,但计算复杂度往往过高。因此,我们通常只对包含\(s_1\) 或 \(r_1\)大小和纵横比的组合感兴趣,即:

\[(s_1, r_1), (s_1, r_2), \ldots, (s_1, r_m), (s_2, r_1), (s_3, r_1), \ldots, (s_n, r_1).\]

也就是说,以同一像素为中心的锚框数量为\(n+m-1\)。对于整个输入图像,我们将生成总共\(wh(n+m-1)\)个锚框。

上述锚箱生成方法已在multibox_prior函数中实现。我们指定输入、一组大小和一组纵横比,此函数将返回输入的所有锚框。

img = image.imread('../img/catdog.jpg').asnumpy()

h, w = img.shape[0:2]

print(h, w)

X = np.random.uniform(size=(1, 3, h, w))  # Construct input data

Y = npx.multibox_prior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])

Y.shape

561 728

(1, 2042040, 4)

我们可以看到返回的锚框变量y的形状是(批大小,锚框数量,4)。将锚框变量y的形状更改为(图像高度、图像宽度、以同一像素为中心的锚框数量,4)后,我们可以获得所有以指定像素位置为中心的锚定框。在下面的示例中,我们访问位于(250,250)中心的第一个锚定框。它有四个元素:锚框左上角的\(x,y\)轴坐标和右下角的\(x,y\)轴坐标。\(x\)和\(y\)轴的坐标值分别除以图像的宽度和高度,因此值范围在0和1之间。

boxes = Y.reshape(h, w, 5, 4)

boxes[250, 250, 0, :]

array([0.06, 0.07, 0.63, 0.82])

为了描述图像中所有以一个像素为中心的锚框,我们首先定义show_bboxes函数来绘制图像上的多个边界框。

#@save

def show_bboxes(axes, bboxes, labels=None, colors=None):

"""Show bounding boxes."""

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.asnumpy(), 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))

正如我们看到的,在x轴和y轴的值除以坐标。在绘制图像时,我们需要恢复锚定框的原始坐标值,从而定义变量bbox_scale。现在,我们可以在图像中以(250,250)为中心绘制所有的锚框。如您所见,蓝色锚框大小为0.75,纵横比为1,很好地覆盖了图像中的狗。

d2l.set_figsize((3.5, 2.5))

bbox_scale = np.array((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'])

2. Intersection over Union

我们刚刚提到了锚盒很好地覆盖了图像中的狗。如果已知目标的地面真实边界框,这里的“井”如何量化?一种直观的方法是测量锚盒与地面真实边界盒之间的相似度。我们知道Jaccard索引可以度量两个集合之间的相似性。给定集合\(\mathcal{A}\)和\(\mathcal{B}\),它们的Jaccard索引是它们的交集大小除以它们的并集大小:

\[J(\mathcal{A},\mathcal{B}) = \frac{\left|\mathcal{A} \cap \mathcal{B}\right|}{\left| \mathcal{A} \cup \mathcal{B}\right|}.\]

实际上,我们可以将边界框的像素区域视为像素集合。这样,我们就可以通过像素集的Jaccard索引来度量两个边界框的相似度。当我们测量两个边界框的相似性时,我们通常将Jaccard索引称为intersection over union(IoU),即两个边界框的相交面积与并集面积的比值,如图13.4.1所示。IoU的值范围在0到1之间:0表示两个边界框之间没有重叠的像素,而1表示两个边界框相等。

Fig. 1.  IoU is the ratio of the intersecting area to the union area of two bounding boxes.

将使用IoU来测量锚定框和地面真实边界框之间以及不同锚定框之间的相似性。

3. Labeling Training Set Anchor Boxes

在训练集中,我们将每个锚盒视为一个训练示例。为了训练目标检测模型,我们需要为每个锚框标记两种类型的标签:第一种是锚框中包含的目标的类别(类别),第二种是地面真相边界框相对于锚定框的偏移量(offset)。在目标检测中,首先生成多个锚框,预测每个锚框的类别和偏移量,根据预测的偏移量调整锚定框的位置,得到用于预测的边界框,最后过滤出需要输出的预测边界框。

我们知道,在目标检测训练集中,每幅图像都标有地面真实边界框的位置和所包含目标的类别。锚盒生成后,我们主要根据与锚盒相似的地面真实边界框的位置和类别信息对锚盒进行标记。那么,我们如何将地面真实边界框指定给与它们类似的锚框呢?

Fig 2.  Assign ground-truth bounding boxes to anchor boxes.

ground_truth = np.array([[0, 0.1, 0.08, 0.52, 0.92],

[1, 0.55, 0.2, 0.9, 0.88]])

anchors = np.array([[0, 0.1, 0.2, 0.3], [0.15, 0.2, 0.4, 0.4],

[0.63, 0.05, 0.88, 0.98], [0.66, 0.45, 0.8, 0.8],

[0.57, 0.3, 0.92, 0.9]])

fig = d2l.plt.imshow(img)

show_bboxes(fig.axes, ground_truth[:, 1:] * bbox_scale, ['dog', 'cat'], 'k')

show_bboxes(fig.axes, anchors * bbox_scale, ['0', '1', '2', '3', '4']);

我们可以使用multibox_target函数标记锚定框的类别和偏移量。此函数用于将背景类别设置为0,并将目标类别的整数索引从零递增1(1表示dog,2表示cat)。我们在锚定框和底真值边界框中添加实例维数,并使用expand_dims函数构造形状为(batch size批次大小、类别数包括背景、锚框数量)的随机预测结果。

labels = npx.multibox_target(np.expand_dims(anchors, axis=0),

np.expand_dims(ground_truth, axis=0),

np.zeros((1, 3, 5)))

返回的结果中有三项,都是张量格式。第三项由标记为锚定框的类别表示。

labels[2]

array([[0., 1., 2., 0., 2.]])

我们根据锚框和地面真实边界框在图像中的位置来分析这些标记类别。首先,在所有的“锚框-地面真实边界框”对中,锚框\(A_4\)到cat的地面真相边界框的IoU最大,因此锚框(A_4\)的类别被标记为cat。

返回值的第二项是一个mask变量,其形状为(批大小,锚框数量的四倍)。mask变量中的元素与每个定位框的四个偏移值一一对应。因为我们不关心背景检测,所以负类的偏移量不应该影响目标函数。通过乘以元素,mask变量中的0可以在计算目标函数之前过滤掉负的类偏移量。

labels[1]

array([[0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0.,

1., 1., 1., 1.]])

返回的第一项是为每个定位框标记的四个偏移量值,负类定位框的偏移量标记为0。

labels[0]

array([[ 0.00e+00,  0.00e+00,  0.00e+00,  0.00e+00,  1.40e+00,  1.00e+01,

2.59e+00,  7.18e+00, -1.20e+00,  2.69e-01,  1.68e+00, -1.57e+00,

0.00e+00,  0.00e+00,  0.00e+00,  0.00e+00, -5.71e-01, -1.00e+00,

-8.94e-07,  6.26e-01]])

4. Bounding Boxes for Prediction

在模型预测阶段,我们首先为图像生成多个锚框,然后逐个预测这些锚框的类别和偏移量。然后,基于锚定框及其预测偏移量得到预测边界框。当有多个锚盒时,同一个目标可以输出许多相似的预测边界框。为了简化结果,我们可以去掉类似的预测边界框。通常称为非最大值抑制(NMS)。

接下来,我们将看一个详细的例子。首先,建造四个锚箱。为了简单起见,我们假设预测的偏移量都为0。这意味着预测边界框是锚定框。最后,我们为每个类别构造一个预测概率。

anchors = np.array([[0.1, 0.08, 0.52, 0.92], [0.08, 0.2, 0.56, 0.95],

[0.15, 0.3, 0.62, 0.91], [0.55, 0.2, 0.9, 0.88]])

offset_preds = np.array([0] * anchors.size)

cls_probs = np.array([[0] * 4,  # Predicted probability for background

[0.9, 0.8, 0.7, 0.1],  # Predicted probability for dog

[0.1, 0.2, 0.3, 0.9]])  # Predicted probability for cat

在图像上打印预测边界框及其置信级别。

fig = d2l.plt.imshow(img)

show_bboxes(fig.axes, anchors * bbox_scale,

['dog=0.9', 'dog=0.8', 'dog=0.7', 'cat=0.9'])

我们使用multibox_detection函数来执行NMS,并将阈值设置为0.5。这将向张量输入添加一个示例维度。我们可以看到返回结果的形状是(批量大小,锚框数量,6)。每行的6个元素表示同一预测边界框的输出信息。第一个元素是预测的类别索引,从0开始(0表示dog,1表示cat)。值-1表示NMS中的背景或删除。第二个元素是预测边界框的置信度。其余四个元素是预测边界框左上角的\(x,y\)轴坐标和右下角的\(x,y\)轴坐标(值范围在0到1之间)。

output = npx.multibox_detection(

np.expand_dims(cls_probs, axis=0),

np.expand_dims(offset_preds, axis=0),

np.expand_dims(anchors, axis=0),

nms_threshold=0.5)

output

array([[[ 0.  ,  0.9 ,  0.1 ,  0.08,  0.52,  0.92],

[ 1.  ,  0.9 ,  0.55,  0.2 ,  0.9 ,  0.88],

[-1.  ,  0.8 ,  0.08,  0.2 ,  0.56,  0.95],

[-1.  ,  0.7 ,  0.15,  0.3 ,  0.62,  0.91]]])

我们移除了类别1的预测边界框,并将NMS保留的结果可视化。

fig = d2l.plt.imshow(img)

for i in output[0].asnumpy():

if i[0] == -1:

continue

label = ('dog=', 'cat=')[int(i[0])] + str(i[1])

show_bboxes(fig.axes, [np.array(i[2:]) * bbox_scale], label)

在实际应用中,我们可以在执行NMS之前移除置信水平较低的预测边界框,从而减少NMS的计算量。我们还可以过滤NMS的输出,例如,只保留具有较高置信水平的结果作为最终输出。

5. Summary

我们以每个像素为中心,生成具有不同大小和纵横比的多个锚框。

IoU,也称为Jaccard索引,测量两个边界框的相似性。它是两个边界框的相交面积与并集面积之比。

在训练集中,我们为每个锚盒标记两种类型的标签:一种是锚盒中包含的目标类别,另一种是ground-truth真实边界框相对于锚盒的偏移量。

在预测时,我们可以使用非最大值抑制(NMS)去除相似的预测边界框,从而简化预测结果。

深度学习Anchor Boxes原理与实战技术的更多相关文章

  1. 2020年12月18号--21号 人工智能(深度学习DeepLearning)python、TensorFlow技术实战

    深度学习DeepLearning(Python)实战培训班 时间地点: 2020 年 12 月 18 日-2020 年 12 月 21日 (第一天报到 授课三天:提前环境部署 电脑测试) 一.培训方式 ...

  2. 深度学习中Dropout原理解析

    1. Dropout简介 1.1 Dropout出现的原因 在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象. 在训练神经网络的时候经常会遇到过拟合的问题 ...

  3. 深度学习anchor的理解

    摘抄与某乎 anchor 让网络学习到的是一种推断的能力.网络不会认为它拿到的这一小块 feature map 具有七十二变的能力,能同时从 9 种不同的 anchor 区域得到.拥有 anchor ...

  4. Hebye 深度学习中Dropout原理解析

    1. Dropout简介 1.1 Dropout出现的原因 在机器学习的模型中,如果模型的参数太多,而训练样本又太少,训练出来的模型很容易产生过拟合的现象. 在训练神经网络的时候经常会遇到过拟合的问题 ...

  5. 深度学习RNN实现股票预测实战(附数据、代码)

    背景知识 最近再看一些量化交易相关的材料,偶然在网上看到了一个关于用RNN实现股票预测的文章,出于好奇心把文章中介绍的代码在本地跑了一遍,发现可以work.于是就花了两个晚上的时间学习了下代码,顺便把 ...

  6. 2021年1月15日【深度学习DeepLearning(python)实战班】

    深度学习网络课程QQ群群号: 1057802989(加群备注:杨春娇邀请) 强化学习QQ交流群群号: 872395038(加群备注:杨春娇邀请)

  7. 深度学习框架Keras介绍及实战

    Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlow, CNTK, 或者 Theano 作为后端运行.Keras 的开发重点是支持快速的实验.能够以最小的时延 ...

  8. 深度学习笔记——PCA原理与数学推倒详解

    PCA目的:这里举个例子,如果假设我有m个点,{x(1),...,x(m)},那么我要将它们存在我的内存中,或者要对着m个点进行一次机器学习,但是这m个点的维度太大了,如果要进行机器学习的话参数太多, ...

  9. 漫谈深度学习时代点击率预估技术进展 &&深度学习在推荐系统上的发展

    转载:https://www.infoq.cn/article/XA055tpFrprUy*0UBdCb https://www.zhihu.com/question/20830906/answer/ ...

随机推荐

  1. 【手打】coredns单台使用

    目录: coredns介绍 coredns安装 corendns配置 coredns介绍 CoreDNS 其实就是一个 DNS 服务,而 DNS 作为一种常见的服务发现手段,所以很多开源项目以及工程师 ...

  2. Windows PE 第一章开发环境和基本工具使用

    第一章 Windows PE 基本工具 1.1开发语言MASM32 1.1.1设置开发环境 这个不细说了,我在整理Intel汇编的时候详细的说了环境搭建以及细节.地址是:http://blog.csd ...

  3. (Py练习)日期格式转换

    #将日期转换为易读的格式 #使用dateuti包 from dateutil import parser dt = parser.parse("Mar 6 2019 12:00AM" ...

  4. Maven不扫描java文件夹下的配置文件解决办法

    <build> <resources> <resource> <directory>src/main/java</directory> &l ...

  5. NumPy之:理解广播

    目录 简介 基础广播 广播规则 简介 广播描述的是NumPy如何计算不同形状的数组之间的运算.如果是较大的矩阵和较小的矩阵进行运算的话,较小的矩阵就会被广播,从而保证运算的正确进行. 本文将会以具体的 ...

  6. 使用FastDFS进行文件管理

    使用FastDFS进行文件管理 FastDFS简介 FastDFS: FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等, ...

  7. Redis 存储对象信息是用 Hash 还是 String

    Redis 内部使用一个 RedisObject 对象来表示所有的 key 和 value,RedisObject 中的 type,则是代表一个 value 对象具体是何种数据类型,它包含字符串(St ...

  8. 10.Debug

    1.Debug模式 1.1 什么是Debug模式 是供程序员使用的程序调试工具,它可以用于查看程序的执行流程,也可以用于追踪程序执行过程来调试程序. 1.2 Debug介绍与操作流程 Debug调式, ...

  9. 怎么用CMD命令进入D盘

    怎么用CMD命令进入D盘 太平洋电脑网 ​ 已认证的官方帐号 6 人赞同了该文章 大家都知道win操作系统想要打开D盘,直接点我的电脑就能进d盘了,有时候只能使用dos的情况下也利用系统自带的cmd命 ...

  10. shell基础之exit,break,continue

    exit代码: 1 #!/bin/bash 2 echo "Is it morning? Please answer yes or no." 3 read YES_OR_NO 4 ...