学习RCNN系列论文时, 出现了感受野(receptive field)的名词, 感受野的尺寸大小是如何计算的,在网上没有搜到特别详细的介绍, 为了加深印象,记录下自己对这一感念的理解,希望对理解基于CNN的物体检测过程有所帮助。
1 感受野的概念
在卷积神经网络中,感受野的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小。
RCNN论文中有一段描述,Alexnet网络pool5输出的特征图上的像素在输入图像上有很大的感受野(have very large receptive fields (195 × 195 pixels))和步长(strides (32×32 pixels) ), 这两个变量的数值是如何得出的呢?
2 感受野大小的计算
感受野计算时有下面的几个情况需要说明:
(1)第一层卷积层的输出特征图像素的感受野的大小等于滤波器的大小
(2)深层卷积层的感受野大小和它之前所有层的滤波器大小和步长有关系
(3)计算感受野大小时,忽略了图像边缘的影响,即不考虑padding的大小,关于这个疑惑大家可以阅读一下参考文章2的解答进行理解
这里的每一个卷积层还有一个strides的概念,这个strides是之前所有层stride的乘积。
即strides(i) = stride(1) * stride(2) * ...* stride(i-1)
关于感受野大小的计算采用top to down的方式, 即先计算最深层在前一层上的感受野,然后逐渐传递到第一层,使用的公式可以表示如下:
RF = 1 #待计算的feature map上的感受野大小
for layer in (top layer To down layer):
RF = ((RF -1)* stride) + fsize
stride 表示卷积的步长; fsize表示卷积层滤波器的大小
用python实现了计算VGG16网络每层输出feature map的感受野大小,实现代码:
#!/usr/bin/env python
net = {'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']}
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 # 最后一层相对前一层的感受野是1
for layer in reversed(range(layernum)): # 从最后一层往前数
t = RF
fsize, stride, pad = net[layer] # 得到这一层的fsize,stride,pad
RF = ((RF - 1) * stride) + fsize # 最后
# print(t,stride, fsize, RF)
return RF
if __name__ == '__main__':
for i in range(len(net['net'])): # 逐层进行处理
p = outFromIn(imsize, net['net'], i + 1) # 得到当前层的输出信息
# print(p[0], p[1])
# if i != 5:
# continue
rf = inFromOut(net['net'], i + 1)
# print(rf, '**')
print("Layer Name = %s, Output size = %3d, Stride = % 3d, RF size = %3d" % (
net['name'][i], p[0], p[1], rf))
假如要计算第N层的感受野,总的计算过程就是:从后往前计算,也就是第N层相对前面层的感受野(即第N-1层到第1层)。