原始图片中的ROI如何映射到到feature map?(转)

链接:https://zhuanlan.zhihu.com/p/24780433
链接:https://www.cnblogs.com/objectDetect/p/5947169.html

在SPP-net中的难点一曾提到:ROI如何对应到feature map?

这个地方遇到不少坑,看了很多资料都没有太明白,感觉太绕。

先数数遇到的坑:

  • 《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》原文是这样写的,一脸懵逼。

<img src="https://pic1.zhimg.com/v2-807eae8ad5e065b0c148cdf86a7b9c74_b.png" data-rawwidth="855" data-rawheight="328" class="origin_image zh-lightbox-thumb" width="855" data-original="https://pic1.zhimg.com/v2-807eae8ad5e065b0c148cdf86a7b9c74_r.jpg"/>
  • 找了张图是这样画的:有那么点意思,好像是从前向后推出各个层的感受野,可是还是不懂为啥这样。

<img src="https://pic4.zhimg.com/v2-21797891b633ceabfaa1eee4145cf87f_b.png" data-rawwidth="702" data-rawheight="394" class="origin_image zh-lightbox-thumb" width="702" data-original="https://pic4.zhimg.com/v2-21797891b633ceabfaa1eee4145cf87f_r.jpg"/>
  • 这两张图,看的有点摸不着头脑
<img src="https://pic3.zhimg.com/v2-fe10f568d661a542b7eafc68b6b53b52_b.png" data-rawwidth="723" data-rawheight="634" class="origin_image zh-lightbox-thumb" width="723" data-original="https://pic3.zhimg.com/v2-fe10f568d661a542b7eafc68b6b53b52_r.jpg"/>
<img src="https://pic2.zhimg.com/v2-3d3dbf2366717b55baccea3e55900e7d_b.png" data-rawwidth="757" data-rawheight="575" class="origin_image zh-lightbox-thumb" width="757" data-original="https://pic2.zhimg.com/v2-3d3dbf2366717b55baccea3e55900e7d_r.jpg"/>


<img src="https://pic2.zhimg.com/v2-1ea44cae8805cef752c52437b4895899_b.png" data-rawwidth="845" data-rawheight="433" class="origin_image zh-lightbox-thumb" width="845" data-original="https://pic2.zhimg.com/v2-1ea44cae8805cef752c52437b4895899_r.jpg"/>

回归正题

最后找到一篇靠谱的文章 卷积神经网络物体检测之感受野大小计算 - machineLearning - 博客园,它给出了一个不错的启发,还附带了代码,最关键的是它给出了参考链接。 于是我终于在参考链接找到了这篇 Concepts and Tricks In CNN(长期更新) 最佳博文,不仅清晰易懂,而且公式详细。(不过感觉略有不足,所以下面就详细介绍一下这个大坑)

【先说说感受野的计算】

回忆一下我之前在 卷积神经网络(CNN)简介 里就曾经画图推导过的一个公式(这个公式很常见,可是竟然很少有人去讲它怎么来的,当时我在写 CNN简介就顺便画图推导了一下,没细看的同学可以回头看看)

原文里提到:隐藏层边长(输出的边长) = (W - K + 2P)/S + 1
(其中 W是输入特征的大小,K是卷积核大小,P是填充大小,S是步长(stride))

为了理解方便我就把公式先用英文写一下:

output field size = ( input field size - kernel size + 2*padding ) / stride + 1

(output field size 是卷积层的输出,input field size 是卷积层的输入)


反过来问你: 卷积层的输入(也即前一层的感受野) = ?

答案必然是: input field size = (output field size - 1)* stride - 2*padding + kernel size

再重申一下:卷积神经网络CNN中,某一层输出结果中一个元素所对应的输入层的区域大小,被称作感受野receptive field。感受野的大小是由kernel size,stride,padding , outputsize 一起决定的。

Concepts and Tricks In CNN(长期更新) 里截张图你感受一下:


<img src="https://pic1.zhimg.com/v2-49a0afeabcd1e9a195e47e6ccebb416c_b.png" data-rawwidth="720" data-rawheight="497" class="origin_image zh-lightbox-thumb" width="720" data-original="https://pic1.zhimg.com/v2-49a0afeabcd1e9a195e47e6ccebb416c_r.jpg"/>
公式化一下:

  • 对于Convolution/Pooling layer(博文作者忘了加上padding本文在这里补上):[公式]

  • 对于 Neuronlayer(ReLU/Sigmoid/..) :[公式] (显然如此)


上面只是给出了 前一层在后一层的感受野,如何计算最后一层在原始图片上的感受野呢? 从后向前级联一下就可以了(先计算最后一层到倒数第二层的感受野,再计算倒数第二层到倒数第三层的感受野,依次从后往前推导就可以了)

卷积神经网络物体检测之感受野大小计算 - machineLearning - 博客园 中用如下核心代码计算了 Alexnet zf-5和VGG16网络每层输出feature map的感受野大小。

net_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 = 224

def 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, totstride

def inFromOut(net, layernum):#从后向前算感受野 返回该层元素在原始图片中的感受野
RF = 1
for layer in reversed(range(layernum)):
fsize, stride, pad = net[layer]
RF = ((RF -1)* stride) + fsize
return RF

<img src=“ https://pic2.zhimg.com/v2-594a9e66ea950f0effe662fb4015965d_b.png” data-rawwidth=“548” data-rawheight=“603” class=“origin_image zh-lightbox-thumb” width=“548” data-original=“ https://pic2.zhimg.com/v2-594a9e66ea950f0effe662fb4015965d_r.jpg”/>

【再谈谈感受野上面的坐标映射 (Coordinate Mapping)】

为了完整性直接摘录博客内容了:

通常,我们需要知道网络里面任意两个feature map之间的坐标映射关系(一般是中心点之间的映射),如下图,我们想得到map 3上的点p3映射回map 2所在的位置p2(橙色框的中心点)

<img src=“ https://pic3.zhimg.com/v2-1d44fc450846b22e0adc0ec658d804aa_b.png” data-rawwidth=“702” data-rawheight=“401” class=“origin_image zh-lightbox-thumb” width=“702” data-original=“ https://pic3.zhimg.com/v2-1d44fc450846b22e0adc0ec658d804aa_r.jpg”/>

计算公式:
  • 对于 Convolution/Pooling layer: [公式]
  • 对于Neuronlayer(ReLU/Sigmoid/…) : [公式]

上面是计算任意一个layer输入输出的坐标映射关系,如果是计算任意feature map之间的关系,只需要用简单的组合就可以得到,下图是一个简单的例子:

<img src=“ https://pic2.zhimg.com/v2-c1ce5a16dbd75553be1a9ea8921f3c35_b.png” data-rawwidth=“697” data-rawheight=“199” class=“origin_image zh-lightbox-thumb” width=“697” data-original=“ https://pic2.zhimg.com/v2-c1ce5a16dbd75553be1a9ea8921f3c35_r.jpg”/>


最后说一下 前面那张PPT里的公式。

<img src=“ https://pic2.zhimg.com/v2-1ea44cae8805cef752c52437b4895899_b.png” class=“content_image”/>

  • 对于上面 A simple solution:其实也是何凯明在SPP-net中采用的方法。其实就是巧妙的化简一下公式 [公式] 令每一层的padding都为 [公式]
    • [公式] 为奇数 [公式] 所以 [公式]
    • [公式] 为偶数 [公式] 所以 [公式]
    • [公式] 是坐标值,不可能取小数 所以基本上可以认为 [公式] 。公式得到了化简:感受野中心点的坐标[公式]只跟前一层 [公式] 有关。
  • 对于上面的 A general solution: 其实就是把 公式 [公式] 级联消去整合一下而已。
    <img src=“ https://pic4.zhimg.com/v2-7e30f0972bfb5399436844952f3990b3_b.png” data-rawwidth=“279” data-rawheight=“72” class=“content_image” width=“279”/>



SPP-net的ROI映射做法详解

SPP-net 是把原始ROI的左上角和右下角 映射到 feature map上的两个对应点。 有了feature map上的两队角点就确定了 对应的 feature map 区域(下图中橙色)。

<img src=“ https://pic3.zhimg.com/v2-d65a3df8b9dfbefc29712e8a5b99527a_b.png” data-rawwidth=“838” data-rawheight=“465” class=“origin_image zh-lightbox-thumb” width=“838” data-original=“ https://pic3.zhimg.com/v2-d65a3df8b9dfbefc29712e8a5b99527a_r.jpg”/>

如何映射?

左上角的点(x,y)映射到 feature map上的[公式] : 使得 [公式] 在原始图上感受野(上图绿色框)的中心点 与(x,y)尽可能接近。

对应点之间的映射公式是啥?

  • 就是前面每层都填充padding/2 得到的简化公式 : [公式]
  • 需要把上面公式进行级联得到 [公式] 其中 [公式]
  • 对于feature map 上的 [公式] 它在原始图的对应点为 [公式]
  • 论文中的最后做法:把原始图片中的ROI映射为 feature map中的映射区域(上图橙色区域)其中 左上角取:[公式], ;右下角的点取: 界取y’的x值:[公式]。 下图可见 [公式] , [公式] 的作用效果分别是增加和减少。也就是 左上角要向右下偏移,右下角要想要向左上偏移。个人理解采取这样的策略是因为论文中的映射方法(左上右下映射)会导致feature map上的区域反映射回原始ROI时有多余的区域(下图左边红色框是比蓝色区域大的)
    <img src=“ https://pic4.zhimg.com/v2-09c3f5fbb3eeccc6af58d5a5bf8e00c3_b.png” data-rawwidth=“927” data-rawheight=“186” class=“origin_image zh-lightbox-thumb” width=“927” data-original=“ https://pic4.zhimg.com/v2-09c3f5fbb3eeccc6af58d5a5bf8e00c3_r.jpg”/>

<img src=“ https://pic4.zhimg.com/v2-1cf8175e6bd122ee93cde1b8c4e497c3_b.png” data-rawwidth=“612” data-rawheight=“304” class=“origin_image zh-lightbox-thumb” width=“612” data-original=“ https://pic4.zhimg.com/v2-1cf8175e6bd122ee93cde1b8c4e497c3_r.jpg”/>

<img src=“ https://pic2.zhimg.com/v2-d35879cf759c673bc2c534f295e88f69_b.png” data-rawwidth=“408” data-rawheight=“80” class=“content_image” width=“408”/>


参考:

《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》

Concepts and Tricks In CNN(长期更新)

卷积神经网络物体检测之感受野大小计算 - machineLearning - 博客

iccv2015_tutorial_convolutional_feature_maps_kaiminghe.

卷积神经网络(CNN)简介

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值