关于感受野 (Receptive field) 你该知道的事
Receptive field 可中译为“感受野”,是卷积神经网络中非常重要的概念之一。
我个人最早看到这个词的描述是在 2012 年 Krizhevsky 的 paper 中就有提到过,当时是各种不明白的,事实上各种网络教学课程也都并没有仔细的讲清楚“感受野”是怎么一回事,有什么用等等。直到我某天看了 UiO 的博士生 Dang Ha The Hien写了一篇非常流传甚广的博文:A guide to receptive field arithmetic for Convolutional Neural Networks,才大彻大悟,世界变得好了,人生都变得有意义了,正如博主自己谈到的写作动机:
This post fills in the gap by introducing a new way to visualize feature maps in a CNN that exposes the receptive field information, accompanied by a complete receptive field calculation that can be used for any CNN architecture.
此文算是上述博文的一个精要版笔记,再加上个人的理解与计算过程。
FYI:读者已经熟悉 CNN 的基本概念,特别是卷积和池化操作。一个非常好的细致概述相关计算细节的 paper 是:A guide to convolution arithmetic for deep learning。
感受野可视化
我们知晓某一层的卷积核大小对应于在上一层输出的“图像”上的“视野”大小。比如,某层有 3x3 的卷积核,那就是一个 3x3 大小的滑动窗口在该层的输入“图像”上去扫描,我们就可以谈相对于上一层,说该层下特征图(feature map)当中任一特征点(feature)的“感受野”大小只有 3x3.(打引号说明术语引用不够严谨)。
- 先看个感受野的较严格定义:
The receptive field is defined as the region in the input space that a particular CNN’s feature is looking at (i.e. be affected by).
一个特征点的感受野可以用其所在的中心点位置(center location)和大小(size)来描述。然而,某卷积特征点所对应的感受野上并不是所有像素都是同等重要的,就好比人的眼睛所在的有限视野范围内,总有要 focus 的焦点。对于感受野来说,距离中心点越近的像素肯定对未来输出特征图的贡献就越大。换句话说,一个特征点在输入图像(Input) 上所关注的特定区域(也就是其对应的感受野)会在该区域的中心处聚焦,并以指数变化向周边扩展(need more explanation)。
废话不多说,我们直接先算起来。
首先假定我们所考虑的 CNN 架构是对称的,并且输入图像也是方形的。这样的话,我们就忽略掉不同长宽所造成的维度不同。
Way1 对应为通常的一种理解感受野的方式。在下方左侧的上图中,是在 5x5 的图像(蓝色)上做一个 3x3 卷积核的卷积计算操作,步长为2,padding 为1,所以输出为 3x3 的特征图(绿色)。那么该特征图上的每个特征(1x1)对应的感受野,就是 3x3。在下方左侧的下图中,是在上述基础上再加了一个完全一样的卷积层。对于经过第二层卷积后其上的一个特征(如红色圈)在上一层特征图上“感受”到 3x3 大小,该 3x3 大小的每个特征再映射回到图像上,就会发现由 7x7 个像素点与之关联,有所贡献。于是,就可以说第二层卷积后的特征其感受野大小是 7x7(需要自己画个图,好好数一数)。Way2 (下方右侧的图像)是另一种理解的方式,主要的区别仅仅是将两层特征图上的特征不进行“合成”,而是保留其在前一层因“步长”而产生的影响。

Way2 的理解方式其实更具有一般性,我们可以无需考虑输入图像的大小对感受野进行计算。如下图:

虽然,图上绘制了输入 9x9 的图像(蓝色),但是它的大小情况是无关紧要的,因为我们现在只关注某“无限”大小图像某一像素点为中心的一块区域进行卷积操作。首先,经过一个 3x3 的卷积层(padding=1,stride=2)后,可以得到特征输出(深绿色)部分。其中深绿色的特征分别表示卷积核扫过输入图像时,卷积核中心点所在的相对位置。此时,每个深绿色特征的感受野是 3x3 (浅绿)。这很好理解,每一个绿色特征值的贡献来源是其周围一个 3x3 面积。再叠加一个 3x3 的卷积层(padding=1,stride=2)后,输出得到 3x3 的特征输出(橙色)。此时的中心点的感受野所对应的是黄色区域 7x7,代表的是输入图像在中心点橙色特征所做的贡献。
这就是为何在 《VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION》 文章中提到:
It is easy to see that a stack of two 3 × 3 conv. layers (without spatial pooling in between) has an effective receptive field of 5 × 5; three such layers have a 7 × 7 effective receptive field.
也就是说两层 3x3 的卷积层直接堆叠后(无池化)可以算的有感受野是 5x5,三层堆叠后的感受野就是 7x7。
感受野计算
直观的感受了感受野之后,究竟该如何定量计算嗯?只要依据 Way2 图像的理解,我们对每一层的特征“顺藤摸瓜”即可。
我们已经发觉到,某一层特征上的感受野大小依赖的要素有:每一层的卷积核大小 k,padding 大小 p,stride s。在推导某层的感受野时,还需要考虑到该层之前各层上特征的的感受野大小 r,以及各层相邻特征之间的距离 j(jump)。
所以对于某一卷积层(卷积核大小 k,padding 大小 p,stride s)上某特征的感受野大小公式为:

- 第一行计算的是,相邻特征之间的距离(jump)。各层里的特征之间的距离显然是严重依赖于 stride 的,并且逐层累积。值得注意的是,输入图像的作为起始像素特征,它的特征距离(jump) 为1。
- 第二行计算的就是某层的特征的感受大小。它依赖于上一层的特征的感受野大小 和特征之间的距离 ,以及该层的卷积核大小 k。输入图像的每个像素作为特征的感受野就是其自身,为1。
- 第三行公式计算的是特征感受野的几何半径。对于处于特征图边缘处的特征来说,这类特征的感受野并不会完整的对应到原输入图像上的区域,都会小一些。初始特征的感受野几何半径为 0.5。

上图中除了公式和说明部分外,有两行分别代表的是第一层卷积和第二层卷积。在每行中,应从左往右观察卷积核计算和操作。
第一层比较简单,最后输出 3x3 绿色的特征图,每个特征有阴影框大小来表示每个特征对应的感受野大小 3x3。其中
表示的 0.5 几何半径,我已经用红色标识出来,对应于阴影面积覆盖到的绿色面积的几何半径。
第二层,由于有一个单位的 padding,所以 3x3 卷积核是按照蓝色箭头标记作为的起始方向开始,在所有的绿色位置上挪动的。最后算得特征的感受野大小为 7x7,亦对应于阴影框和阴影区域部分。其中
是 0.5 也已经用红色标记了出来。

Python Script
这个代码其实很好写,我就直接挪用 Dang Ha The Hien 的 python 脚本了:
# [filter size, stride, padding]
#Assume the two dimensions are the same
#Each kernel requires the following parameters:
# - k_i: kernel size
# - s_i: stride
# - p_i: padding (if padding is uneven, right padding will higher than left padding; "SAME" option in tensorflow)
#
#Each layer i requires the following parameters to be fully represented:
# - n_i: number of feature (data layer has n_1 = imagesize )
# - j_i: distance (projected to image pixel distance) between center of two adjacent features
# - r_i: receptive field of a feature in layer i
# - start_i: position of the first feature's receptive field in layer i (idx start from 0, negative means the center fall into padding) import math
convnet = [[11,4,0],[3,2,0],[5,1,2],[3,2,0],[3,1,1],[3,1,1],[3,1,1],[3,2,0],[6,1,0], [1, 1, 0]]
layer_names = ['conv1','pool1','conv2','pool2','conv3','conv4','conv5','pool5','fc6-conv', 'fc7-conv']
imsize = 227 def outFromIn(conv, layerIn):
n_in = layerIn[0]
j_in = layerIn[1]
r_in = layerIn[2]
start_in = layerIn[3]
k = conv[0]
s = conv[1]
p = conv[2] n_out = math.floor((n_in - k + 2*p)/s) + 1
actualP = (n_out-1)*s - n_in + k
pR = math.ceil(actualP/2)
pL = math.floor(actualP/2) j_out = j_in * s
r_out = r_in + (k - 1)*j_in
start_out = start_in + ((k-1)/2 - pL)*j_in
return n_out, j_out, r_out, start_out def printLayer(layer, layer_name):
print(layer_name + ":")
print("\t n features: %s \n \t jump: %s \n \t receptive size: %s \t start: %s " % (layer[0], layer[1], layer[2], layer[3])) layerInfos = []
if __name__ == '__main__':
#first layer is the data layer (image) with n_0 = image size; j_0 = 1; r_0 = 1; and start_0 = 0.5
print ("-------Net summary------")
currentLayer = [imsize, 1, 1, 0.5]
printLayer(currentLayer, "input image")
for i in range(len(convnet)):
currentLayer = outFromIn(convnet[i], currentLayer)
layerInfos.append(currentLayer)
printLayer(currentLayer, layer_names[i])
print ("------------------------")
layer_name = raw_input ("Layer name where the feature in: ")
layer_idx = layer_names.index(layer_name)
idx_x = int(raw_input ("index of the feature in x dimension (from 0)"))
idx_y = int(raw_input ("index of the feature in y dimension (from 0)")) n = layerInfos[layer_idx][0]
j = layerInfos[layer_idx][1]
r = layerInfos[layer_idx][2]
start = layerInfos[layer_idx][3]
assert(idx_x < n)
assert(idx_y < n) print ("receptive field: (%s, %s)" % (r, r))
print ("center: (%s, %s)" % (start+idx_x*j, start+idx_y*j))
在 AlexNet 网络上的效果如下:

关于感受野 (Receptive field) 你该知道的事的更多相关文章
- 十件你需要知道的事,关于openstack-trove(翻译)
开源数据库即服务OpenStack Trove应该知道的10件事情 作者:Ken Rugg,Tesora首席执行官 Ken Rugg是Tesora的创始人,CEO和董事会成员. Ken的大部分职业都是 ...
- C# 范型约束 new() 你必须要知道的事
C# 范型约束 new() 你必须要知道的事 注意:本文不会讲范型如何使用,关于范型的概念和范型约束的使用请移步谷歌. 本文要讲的是关于范型约束无参构造函数 new 的一些底层细节和注意事项.写这篇文 ...
- 神经网络中的感受野(Receptive Field)
在机器视觉领域的深度神经网络中有一个概念叫做感受野,用来表示网络内部的不同位置的神经元对原图像的感受范围的大小.神经元之所以无法对原始图像的所有信息进行感知,是因为在这些网络结构中普遍使用卷积层和po ...
- 关于Unicode,字符集,字符编码,每个程序员都应该知道的事
关于Unicode,字符集,字符编码,每个程序员都应该知道的事 作者:Jack47 李笑来的文章如何判断一个人是否聪明?中提到: 必要.清晰.且准确的概念,是一切思考的基石.所谓思考,很大程度上,就是 ...
- 学习IOS需要知道的事
什么是iOS iOS是一款由苹果公司开发的操作系统(OS是Operating System的简称),就像平时在电脑上用的Windows XP.Windows 7,都是操作系统 那什么是操作系统呢?操作 ...
- 漫谈ElasticSearch关于ES性能调优几件必须知道的事
lasticSearch是现在技术前沿的大数据引擎,常见的组合有ES+Logstash+Kibana作为一套成熟的日志系统,其中Logstash是ETL工具,Kibana是数据分析展示平台.ES让人惊 ...
- IL命令初学者要知道的事
在一个中间语言程序中,如果某一行以“.”开始,代表这是一个传输给汇编工具的指令:而不是以“.”开始的行是中间语言的代码.上图中.method是方法定义指令,定义了Main方法,参数在“()”中,IL代 ...
- 重写equals方法需要知道的事
重写equals方法 相信在每个人都有过重写过java的equals的方法的经历.这篇博文就从以下几个方面说明重写equals方法的原由,与君共进步. 一 为什么要重写equals方法 首先我们了解e ...
- 苹果强制使用HTTPS传输了怎么办?——关于HTTPS,APP开发者必须知道的事
WeTest 导读 2017年1月1日起,苹果公司将强制使用HTTPS协议传输.本文通过对HTTPS基础原理和通信过程内容的讲解,介绍APP开发者在这个背景下的应对办法. 几周前,我们在<htt ...
随机推荐
- global的使用
对于一个全局变量,你的函数里如果只使用到了它的值,而没有对其赋值(指a = XXX这种写法)的话,就不需要声明global. 相反,如果你对其赋了值的话,那么你就需要声明global.声明global ...
- 树莓派中学TensorFlow
树莓派中默认的虚拟环境为python 2.x,需要用下面的-p参数修改为python3环境.电信wifi和公司网络直接用pip3 install TensorFlow都不好使,用联通手机热点可以安装. ...
- C# 6.0:在catch和finally中使用await
Asyn方法是一个现在很常用的方法,当使用async和await时,你或许曾有这样的经历,就是你想要在catch块或finally块中使用它们,比如当出现一个exception而你希望将日志记在文件或 ...
- WPF 和 百度 eChart 交互
https://blog.csdn.net/defrt4/article/details/52689052
- sqlserver 游标使用
文章来源:https://blog.csdn.net/farmwang/article/details/78661326 --声明一个游标 DECLARE MyCursor CURSOR FOR SE ...
- Linux裸设备管理详解--
裸设备概述 裸设备:也叫裸分区(原始分区),是一种没有经过格式化,不被Unix/Linux通过文件系统来读取的特殊字符设备.裸设备可以绑定一个分区,也可以绑定一个磁盘.字符设备:对字符设备的读写不需要 ...
- tensorflow/threading 用到的一些函数
---恢复内容开始--- import tensorflow as tf 1 tf.squeeze([1,2,3,4]) 删除所有为1的维度 eg shape从(1,2,3,1)到(2,3 ...
- eShopOnContainers 看微服务⑤:消息通信
1.消息通信 传统的单体应用,组件间的调用都是使用代码级的方法函数.比如用户登录自动签到,增加积分.我们可以在登录函数调用积分模块的某个函数,为了解耦我们使用以来注入并放弃new Class()这种方 ...
- update_db_inputs.conf
#!/bin/bash#-------------------------------------------------------------------------------# Name: u ...
- 6.3 基于二分搜索树、链表的实现的集合Set复杂度分析
两种集合类的复杂度分析 在[6.1]节与[6.2]节中分别以二分搜索树和链表作为底层实现了集合Set,在本节就两种集合类的复杂度分析进行分析:测试内容:6.1节与6.2节中使用的书籍.测试方法:测试两 ...