ROI中feature map特征映射到perceptive fields难点解析

来源:互联网 发布:知乎等级 编辑:程序博客网 时间:2024/05/21 19:35

RCNN首次将CNN这一目标分类的王牌使用到了目标检测之中(虽然使用的过程中仍然将CNN当成是一个分类器),初代的R-CNN精度并不高,因此后续出现了诸如SPPNet, Fast R-CNN, Faster R-CNN等的一系列改进,最终实现了端对端的学习,同时带来了速度和精度上的提升。

SPP-Net和Fast R-CNN本质上解决问题的思路都是一样的,也就是如何将候选框只用进行一次卷积得到feature map同时实现全连接网路尺度的控制。

首先,我们来看一下将所有ROI特征直接在feature map上提取的难点:

  1. 原始图像的ROI如何映射到特征图(一系列卷积层的最后输出)
  2. ROI在特征图上的对应特征区域的维度不满足全连接层的输入要求如何处理(不能像在原始ROI图像上那样进行截取和缩放)

原始图像ROI向特征图的映射

感受野概念及其计算

该问题也就是计算最后一层的神经元在原始图片上的感受野(某一层输出结果的一个元素对应于输入层的区域大小)。

我们知道后一层感受野H与前一层感受野W之间的关系是H = (W - K + 2P)/ S + 1。那么反过来已知后一层的感受野要得到前一层的感受野翻解计算即可,可以得到W = SH + K - 2P - S。

使用VGG16以及AlexNet ZF5的感受野大小代码:

# -*- coding: UTF-8 –*-import numpy as np#!/usr/bin/env pythonnet_struct = {'alexnet': {'net':[[11,4,0],[3,2,0],[5,1,2],[3,2,0],[3,1,1],[3,1,1],[3,1,1],[3,2,0]],                   'name':['conv1','pool1','conv2','pool2','conv3','conv4','conv5','pool5']},       'vgg16': {'net':[[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],                        [2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0],[3,1,1],[3,1,1],[3,1,1],[2,2,0]],                 'name':['conv1_1','conv1_2','pool1','conv2_1','conv2_2','pool2','conv3_1','conv3_2',                         'conv3_3', 'pool3','conv4_1','conv4_2','conv4_3','pool4','conv5_1','conv5_2','conv5_3','pool5']},       'zf-5':{'net': [[7,2,3],[3,2,1],[5,2,2],[3,2,1],[3,1,1],[3,1,1],[3,1,1]],               'name': ['conv1','pool1','conv2','pool2','conv3','conv4','conv5']}}imsize = 224def outFromIn(isz, net, layernum):    totstride = 1    insize = isz    for layer in range(layernum):        fsize, stride, pad = net[layer]        outsize = (insize - fsize + 2*pad) / stride + 1        insize = outsize        totstride = totstride * stride    return outsize, totstridedef inFromOut(net, layernum):    RF = 1    for layer in reversed(range(layernum)):        fsize, stride, pad = net[layer]        RF = ((RF -1)* stride) + fsize    return RFif __name__ == '__main__':    print "layer output sizes given image = %dx%d" % (imsize, imsize)    for net in net_struct.keys():        print '************net structrue name is %s**************'% net        for i in range(len(net_struct[net]['net'])):            p = outFromIn(imsize,net_struct[net]['net'], i+1)            rf = inFromOut(net_struct[net]['net'], i+1)            print "Layer Name = %s, Output size = %3d, Stride = % 3d, RF size = %3d" % (net_struct[net]['name'][i], p[0], p[1], rf)

得到的结果为:
感受野计算

感受野坐标映射

通常,如果想要知道任意两个feature map之间的坐标映射关系(一般是中心点之间的映射),如下图所示,如果我们想得到map 3上的点映射回map 2所在的位置p2的话,对于卷积层,使用的公式是在上述感受野计算基础之上将所有感受野的大小乘以2,也就是 W = SH - P + (K - S) / 2。

如图所示:

通过上述公式可以轻松得到感受野的大小。也即 p1 = 6 × p3 + 7。

SPP-Net的ROI映射

SPP-Net使用的是脚点映射,也就是如图所示的映射:

映射的基本方式是将左上角的点(x,y)映射到feature map上的(x’, y’), 使得(x’,y’)在原始图上感受野(绿色框的中点)与(x,y)尽可能相近。

对应的映射公式也就是之前公式每层都填充padding/2 之后的简化结果: pi = si × p(i+1)。通过级联便可以得到上文中的公式。

特征图输出与全连接层输入的匹配

对于问题二我们分析的话,该问题涉及的流程主要是:图像输入->卷积层1->池化1->…->卷积层n->池化n->全连接层。而引发上述问题的关键原因在于全连接层的输入维度是固定死的,导致池化n的输出必须与之匹配,继而导致图像输入的尺寸必须固定。

显然,将卷积层的最后输出与全连接层的输入维度相匹配的话,至少有如下两种方法:

  1. 想办法让不同尺寸的图像也可以使池化n产生固定的输出维度;
  2. 想办法让全连接层可以接受非固定的输入维度

上述第一种解决方法就是SPPNet的思想,它将池化n进行了空间金字塔池化, 使得不同尺寸的图像也可以使池化n产生固定的输出维度;

第二种方法的解决思想就是讲全连接转变为全卷积,作用的效果等效于在原始图像上做滑窗,多个窗口并行处理。

接下来分别对上述问题进行分析以及提供当前的解决方案。

空间金字塔池化

空间金字塔的实现方式是沿着金字塔的低端向顶端一层一层地进行池化。

金字塔池化层

假设原图输入是224x224,对于conv5出来后的输出是13x13x256的,可以理解成有256个这样的filter,每个filter对应一张13x13的reponse map。如果像上图那样将reponse map分成1x1(金字塔底座),2x2(金字塔中间),4x4(金字塔顶座)三张子图,分别做max pooling后,出来的特征就是(16+4+1)x256 维度。如果原图的输入不是224x224,出来的特征依然是(16+4+1)x256维度。不是太懂为何无论图像尺寸是什么,池化n始终输出为(16+4+1)x256维度的原因,后续弄明白后进行补充。

SPP-Net将conv5的池化层改为空间金字塔池化之后,就不用把每一个ROI都找到来给CNN做卷积了,整张图像做一次卷积即可。

相对于RCNN,SPP-Net的流程表示为:

这里写图片描述

全卷积网络(FCN)

全卷积网络的核心思想是将传统CNN中的全连接层转化成一个个的卷积层。在传统的CNN结构中,前5层是卷积层,第6层和第7层分别是一个长度为4096的一维向量,第8层是长度为1000的一维向量,分别对应1000个类别的概率。FCN将这3层表示为卷积层,卷积核的大小(通道数,宽,高)分别为(4096,1,1)、(4096,1,1)、(1000,1,1)。所有的层都是卷积层,故称为全卷积网络。

通过这种方式可以很好的解决图像尺度的问题。

关于更多全卷积网络的内容细节,会在后续的博客中具体展开。

以上便是讲feature map特征映射到perspective fields的难点以及当前该问题的解决现状。

The End.

阅读全文
1 0
原创粉丝点击