https://zhuanlan.zhihu.com/p/24780433
首发于晓雷机器学习笔记
晓雷
3 个月前
在SPP-net中的难点一曾提到:ROI如何对应到feature map?
这个地方遇到不少坑,看了很多资料都没有太明白,感觉太绕。
最后找到一篇靠谱的文章 卷积神经网络物体检测之感受野大小计算 - 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(长期更新) 里截张图你感受一下:
公式化一下:
卷积神经网络物体检测之感受野大小计算 - 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
【再谈谈感受野上面的坐标映射 (Coordinate Mapping)】
为了完整性直接摘录博客内容了:
通常,我们需要知道网络里面任意两个feature map之间的坐标映射关系(一般是中心点之间的映射),如下图,我们想得到map 3上的点p3映射回map 2所在的位置p2(橙色框的中心点)
计算公式:
最后说一下 前面那张PPT里的公式。
SPP-net 是把原始ROI的左上角和右下角 映射到 feature map上的两个对应点。 有了feature map上的两队角点就确定了 对应的 feature map 区域(下图中橙色)。
如何映射?
个人理解采取这样的策略是因为论文中的映射方法(左上右下映射)会导致feature map上的区域反映射回原始ROI时有多余的区域(下图左边红色框是比蓝色区域大的)
《Spatial Pyramid Pooling in Deep Convolutional Networks for Visual Recognition》