14.5. 多尺度目标检测¶ 在 SageMaker Studio Lab 中打开 Notebook
在 14.4节中,我们以输入图像的每个像素为中心生成了多个锚框。这些锚框本质上是图像不同区域的样本。然而,如果为*每个*像素都生成锚框,我们将最终得到过多的锚框用于计算。想象一个\(561 \times 728\)的输入图像,如果以每个像素为中心,生成5个不同形状的锚框,那么在图像上需要标注和预测的锚框数量将超过200万个(\(561 \times 728 \times 5\))。
14.5.1. 多尺度锚框¶
你可能意识到,减少图像上的锚框数量并不难。例如,我们可以在输入图像上均匀采样一小部分像素,并以它们为中心生成锚框。此外,在不同的尺度下,我们可以生成不同数量和不同大小的锚框。直观地说,较小的物体比较大的物体更有可能出现在图像中。例如,在\(2 \times 2\)的图像上,\(1 \times 1\)、\(1 \times 2\)和\(2 \times 2\)的物体分别可能以4、2和1种方式出现。因此,当使用较小的锚框检测较小的物体时,我们可以采样更多的区域,而对于较大的物体,我们可以采样较少的区域。
为了演示如何在多个尺度下生成锚框,让我们读取一张图像。它的高度和宽度分别为561和728像素。
%matplotlib inline
import torch
from d2l import torch as d2l
img = d2l.plt.imread('../img/catdog.jpg')
h, w = img.shape[:2]
h, w
(561, 728)
%matplotlib inline
from mxnet import image, np, npx
from d2l import mxnet as d2l
npx.set_np()
img = image.imread('../img/catdog.jpg')
h, w = img.shape[:2]
h, w
[22:09:30] ../src/storage/storage.cc:196: Using Pooled (Naive) StorageManager for CPU
(561, 728)
回想一下,在7.2节中,我们将卷积层的二维数组输出称为特征图。通过定义特征图的形状,我们可以在任何图像上确定均匀采样锚框的中心。
下面定义了display_anchors
函数。我们在特征图(fmap
)上生成锚框(anchors
),每个单元(像素)作为锚框的中心。由于锚框(anchors
)中的\((x, y)\)轴坐标值已被特征图(fmap
)的宽度和高度相除,因此这些值介于0和1之间,表示锚框在特征图中的相对位置。
由于锚框(anchors
)的中心分布在特征图(fmap
)上的所有单元上,因此这些中心必须在任何输入图像上根据其相对空间位置*均匀*分布。更具体地说,给定特征图的宽度和高度fmap_w
和fmap_h
,以下函数将在任何输入图像上*均匀*采样fmap_h
行和fmap_w
列中的像素。以这些均匀采样的像素为中心,将生成尺度为s
(假设列表s
的长度为1)和不同宽高比(ratios
)的锚框。
def display_anchors(fmap_w, fmap_h, s):
d2l.set_figsize()
# Values on the first two dimensions do not affect the output
fmap = torch.zeros((1, 10, fmap_h, fmap_w))
anchors = d2l.multibox_prior(fmap, sizes=s, ratios=[1, 2, 0.5])
bbox_scale = torch.tensor((w, h, w, h))
d2l.show_bboxes(d2l.plt.imshow(img).axes,
anchors[0] * bbox_scale)
def display_anchors(fmap_w, fmap_h, s):
d2l.set_figsize()
# Values on the first two dimensions do not affect the output
fmap = np.zeros((1, 10, fmap_h, fmap_w))
anchors = npx.multibox_prior(fmap, sizes=s, ratios=[1, 2, 0.5])
bbox_scale = np.array((w, h, w, h))
d2l.show_bboxes(d2l.plt.imshow(img.asnumpy()).axes,
anchors[0] * bbox_scale)
首先,让我们考虑检测小物体。为了在显示时更容易区分,这里不同中心的锚框不会重叠:锚框尺度设置为0.15,特征图的高度和宽度设置为4。我们可以看到,图像上4行4列的锚框中心是均匀分布的。
display_anchors(fmap_w=4, fmap_h=4, s=[0.15])
display_anchors(fmap_w=4, fmap_h=4, s=[0.15])
接下来,我们将特征图的高度和宽度减半,并使用更大的锚框来检测更大的物体。当尺度设置为0.4时,一些锚框会相互重叠。
display_anchors(fmap_w=2, fmap_h=2, s=[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])
display_anchors(fmap_w=1, fmap_h=1, s=[0.8])
14.5.2. 多尺度检测¶
既然我们已经生成了多尺度锚框,我们将使用它们来检测不同尺度的各种大小的物体。下面我们介绍一种基于CNN的多尺度目标检测方法,我们将在14.7节中实现它。
在某个尺度上,假设我们有\(c\)个形状为\(h \times w\)的特征图。使用14.5.1节中的方法,我们生成\(hw\)组锚框,其中每组有\(a\)个具有相同中心的锚框。例如,在14.5.1节的实验的第一个尺度上,给定十个(通道数)\(4 \times 4\)的特征图,我们生成了16组锚框,其中每组包含3个具有相同中心的锚框。接下来,根据真实边界框为每个锚框标注类别和偏移量。在当前尺度下,目标检测模型需要预测输入图像上\(hw\)组锚框的类别和偏移量,其中不同的组具有不同的中心。
假设这里的\(c\)个特征图是CNN基于输入图像进行前向传播得到的中间输出。由于每个特征图上有\(hw\)个不同的空间位置,因此可以认为同一空间位置上有\(c\)个单元。根据7.2节中感受野的定义,特征图上同一空间位置的这\(c\)个单元在输入图像上具有相同的感受野:它们表示同一感受野中的输入图像信息。因此,我们可以将同一空间位置的特征图的\(c\)个单元转换为使用该空间位置生成的\(a\)个锚框的类别和偏移量。本质上,我们使用某个感受野内的输入图像信息来预测输入图像上与该感受野接近的锚框的类别和偏移量。
当不同层的特征图在输入图像上具有不同大小的感受野时,它们可以用来检测不同大小的物体。例如,我们可以设计一个神经网络,其中靠近输出层的特征图的单元具有更宽的感受野,因此它们可以从输入图像中检测到更大的物体。
简而言之,我们可以利用深度神经网络在多个层级上对图像的分层表示来进行多尺度目标检测。我们将在14.7节中通过一个具体的例子来展示这是如何工作的。
14.5.3. 小结¶
在多个尺度上,我们可以生成不同大小的锚框来检测不同大小的物体。
通过定义特征图的形状,我们可以确定在任何图像上均匀采样锚框的中心。
我们使用某个感受野内的输入图像信息来预测输入图像上与该感受野接近的锚框的类别和偏移量。
通过深度学习,我们可以利用其在多个层级上对图像的分层表示来进行多尺度目标检测。