有多少人工,就有多少智能

目标检测 Fast RCNN

RCNN存在的问题:

1、一张图像上有大量的重叠框,所以这些候选框送入神经网络时候,提取特征会有冗余!

2、训练的空间需求大。因为RCNN中,独立的分类器和回归器需要很多的特征作为训练。RCNN中提取候选框,提取特征和分类回归是分开的,可独立。

Fast RCNN

针对上诉问题:

Q1:将整张图片归一化送入神经网络,在最后一层再加入候选框信息(这些候选框还是经过 [公式] 提取,再经过一个 [公式] 层统一映射到最后一层特征图上,而RCNN是通过拉伸来归一化尺寸),这样提取特征的前面层就不再需要重复计算。

Q2:损失函数使用了多任务损失函数(multi-task loss),将边框回归直接加入到CNN网络中训练。 网络结构如下:

这篇论文我主要介绍 [公式] 和 [公式] ,这里面的 [公式] 表示 [公式] 。

1、ROI

正文开始之前,先了解一下:SPP空间金字塔池化(Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition) SPP的作用:不管输入的尺寸大小,输出都是固定的。

我们从上面网络结构图可以看出:最右边的不管输入是什么尺寸,每个特征图只输出一个值;中间的是不管输入什么尺寸,将特征图分为2*2个矩阵,每个矩阵取出一个值,一共有4个值;同理,最左边输出有16个值。所以不管输入特征图的大小,每一个特征图经过SPP以后都会产生16维的特征向量。

类似于SPP, [公式] 的作用有两点:

  1. 把图片上 [公式] 选出的候选框映射到特征图上对应的位置,这个映射是根据输入图片缩小的尺寸来的;
  2. 将映射到 [公式] 上面的 [公式] 输出成统一大小的特征,因为这些框的特征区域大小不一样。

所以我们从上测试图和该层作用可以看出:

该 [公式] 的输入是:

1. 提取特征的网络的最后一个特征图层;

2. 一个表示图片中所有ROI的N*5的矩阵,其中N表示 [公式] 的数目。第一列表示图像 [公式],其余四列表示坐标,坐标的参考系不是针对 [公式] 这张图的,而是针对原图的(这边就是映射的坐标和索引号)。四个参数 [公式] 除了尺寸参数 [公式] 外,还有两个位置参数 [公式] 表示RoI的左上角在整个图片中的坐标;

该 [公式] 的输出是: 输出是 [公式] 个vector,其中 [公式] 的值等于 [公式] 的个数,vector的大小为 [公式] ; [公式] 的过程就是将一个个大小不同的box矩形框,在特征图上都池化成大小为 [公式] 的矩形框特征;

具体步骤: ROI pooling具体操作如下:

(1)根据输入image,将ROI映射到feature map对应位置;

(2)将映射后的区域划分为相同大小的sections(sections数量与输出的维度相同); (3)对每个sections进行max pooling操作; 这样我们就可以从不同大小的方框得到固定大小的相应 的feature maps。输出的feature maps的大小不取决于ROI和卷积feature maps大小。因为加入这个神奇的 [公式] 层,对每个 [公式] 都提取一个固定维度的特征表示,再通过正常的 [公式] 进行分类。RCNN的处理流程是先提proposal,然后CNN提取特征,之后用SVM分类器,最后再做 [公式] ,而在Fast-RCNN中,把 [公式] 放进了网络内部,与 [公式] 分类合并成为了一个 [公式] 模型,两个任务能够共享卷积特征,并相互促进。

下面介绍上述具体步骤中的(2)和(3):

假设经过 [公式] 的输出尺寸大小为: [公式] ,层之前输入的特征图尺寸大小为: [公式] ,那么该特征图所需要池化的尺寸大小为: [公式] 。

总结一下:

[公式] 的输入是 [公式] 的坐标和某一层的输出特征, [公式] 目的是提取输出特征图上该 [公式] 坐标所对应的特征。网络得到的 [公式] 坐标是针对输入图像大小的,所以首先需要将 [公式] 坐标缩小到输出特征对应的大小.。

假设输出特征尺寸是输入图像的1/16,那么先将ROI坐标除以16并取整(第一次量化),然后将取整后的ROI划分成 [公式] 个块,因为划分过程得到的块的坐标是浮点值,所以这里还要将块的坐标也做一个量化,具体而言对于左上角坐标采用向下取整,对于右下角坐标采用向上取整,最后采用最大池化操作处理每个块,也就是用每个块中的最大值作为该块的值,每个块都通过这样的方式得到值,最终输出的 [公式] 大小的 [公式] 特征。从这里的介绍可以看出 [公式] 有两次量化操作,这两步量化操作会引入误差。

2、损失函数

这边利用了参数共享,得到这一层的参数,做分类和回归,各不相干!如下面:

# Resnet中的两层
    s = self.L2Norm_out1(out1)
    sources.append(s)
    s = self.L2Norm_out2(out2)
    sources.append(s)

    # 新添加的四层的值
    out3, out4, out5, out6 = self.extras(out2)
    sources.append(out3)   # 添加4个extra层的输出结果
    sources.append(out4)
    sources.append(out5)
    sources.append(out6)

    # apply multibox head to source layers
    for (x, l, c) in zip(sources, self.loc, self.conf):
        loc.append(l(x).permute(0, 2, 3, 1).contiguous())
        conf.append(c(x).permute(0, 2, 3, 1).contiguous())

    loc = torch.cat([o.view(o.size(0), -1) for o in loc], 1)
    conf = torch.cat([o.view(o.size(0), -1) for o in conf], 1)

def multiboxlayer(resnet, num_classes):
    num_anchor = [4, 6, 6, 6, 4, 4]  # number of boxes per feature map location
    in_planes = [128, 512, 512, 512, 512, 512]
    loc_layers = []
    conf_layers = []

    # 取自RESNET的两层
    loc_layers.append(nn.Conv2d(in_planes[0], num_anchor[0] * 4, kernel_size=3, padding=1))
    loc_layers.append(nn.Conv2d(in_planes[1], num_anchor[1] * 4, kernel_size=3, padding=1))
    conf_layers.append(nn.Conv2d(in_planes[0], num_anchor[0] * num_classes, kernel_size=3, padding=1))
    conf_layers.append(nn.Conv2d(in_planes[1], num_anchor[1] * num_classes, kernel_size=3, padding=1))

    # extra_layer中四层
    for k in range(2, 6):     # 因为前面两层是在VGG中用于输出location和confidence,所以从2开始
        loc_layers.append(nn.Conv2d(in_planes[k], num_anchor[k] * 4, kernel_size=3, padding=1))
        conf_layers.append(nn.Conv2d(in_planes[k], num_anchor[k] * num_classes, kernel_size=3, padding=1))
    return resnet, (loc_layers, conf_layers)
 

 

posted @ 2021-04-13 22:07  lvdongjie-avatarx  阅读(100)  评论(0编辑  收藏  举报