深度学习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. poj1509最小表示法

    题意:       给你一个循环串,然后找到一个位置,使得从这个位置开始的整个串字典序最小. 思路:       最小表示法的建档应用,最小表示法很好理解,就点贪心的意思,一开始我们枚举两个起点i,j ...

  2. Linux-鸟菜-2-主机规划与磁盘分区

    Linux-鸟菜-2-主机规划与磁盘分区 开机流程: 1. BIOS:開機主動執行的韌體,會認識第一個可開機的裝置: 2. MBR:第一個可開機裝置的第一個磁區內的主要開機記錄區塊,內含開機管理程式: ...

  3. 改善c++程序的150个建议(读后总结)-------0-9

    0. 不要让main 函数返回 void 入口函数main()返回类型应该为 int, 即程序结束时return 0 表示程序正常返回,函数结束时 return -1 值表示程序异常返回, 如果不显式 ...

  4. CLS的探索:Python如何让日志免费云化

    前言 日志服务(Cloud Log Service,CLS)是腾讯云提供的一站式日志服务平台,提供了从日志采集.日志存储到日志检索,图表分析.监控告警.日志投递等多项服务,协助用户通过日志来解决业务运 ...

  5. WTM Blazor,Blazor开发利器

    Blazor从诞生到现在也有一段时间了,之前一直在观望,从dotnet5中Blazor的进步以及即将到来的dotnet6中的规划来看,Blazor的前途还是光明的,所以WtmBlazor来了! Bla ...

  6. JS数组的操作方法汇总

    数组的增删 push():添加到最后 pop():取出最后一个 shift():取出第一个 unshift():添加到第一个 splice() : 返回删除的数组,如果没有则为空数组,会改变原数组.可 ...

  7. .Net 中的 string、String、StringBuffer 内存处理性能 和 应用场景

    body { font-family: Segoe UI, SegoeUI, Helvetica Neue, Helvetica, Arial, sans-serif } code { color: ...

  8. Docker镜像的仓库及底层依赖的核心技术(3)

    一.docker镜像的仓库 仓库分为公共仓库和私有仓库 DockerHub的官方仓库:https://hub.docker.com DockerPool社区仓库:https://dl.dockerpo ...

  9. IDEA 全局搜索 Jar 包中源码内容

    引言 项目开发过程中,经常遇到需要在依赖的 Jar 包查看源码,查找类方法和属性,介绍两种在 IDEA 中搜索 Jar 包内容的方式 方式一:双击 SHIFT 快捷键 输入需要查询的类名或方法名 方式 ...

  10. LTC4020

    今天凯哥说他之前有一块电池放电低于20V了 然后接上4020后 会先浮充   涓流充 大约200ma  充过了20V后又是4A了