博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于CNN中感受野的理解和计算方法
阅读量:2185 次
发布时间:2019-05-02

本文共 3904 字,大约阅读时间需要 13 分钟。

1.感受野的理解

CNN中的感受野是CNN中的一个很重要的概念,关于其解释网上有许多版本,如

  • 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).
  • 在卷积神经网络中,感受野的定义是 卷积神经网络每一层输出的特征图(feature map)上的像素点在原始图像上映射的区域大小。
  • 在机器视觉领域的深度神经网络中有一个概念叫做感受野,用来表示网络内部的不同位置的神经元对原图像的感受范围的大小。

大意都是指CNN中处在某一层的神经元(或者说特征图上的某一点)在输入图像中所对应的感受区域大小,这一概念其实正是从生物学上的感受野类比过来的。

2. 感受野的计算方法

在网上主要找到了两种计算感受野的方法,一种是,另一种是,前者理解起来比较快,方便手算;后者理解起来可能要花点时间但比较系统且可以顺次计算出各层的感受野,方便编程实现。

2.1 自顶向下的计算方式

在这里插入图片描述

以卷积核尺寸k=5,步长s=2为例,计算示例图如下:
在这里插入图片描述
上式表示的是相邻输入输出层感受区域对应关系,由于感受野是相对于输入图像的,因此要利用上式进行多次迭代计算才能求出最终的感受野大小。如下图经过两次卷积后,右图中的一个像素点对应中图的区域是3*3,而中图的3*3又对应左图的7*7感受区域,所以右图一个像素点的感受野是7*7。
在这里插入图片描述
当上式中m为输出特征图的尺寸 w o u t w_{out} wout时,其对应的输入感受野n还可以表示成 n = w i n + w p a d n=w_{in}+w_{pad} n=win+wpad,这样就有 w i n + w p a d = k + s ( w o u t − 1 ) w_{in}+w_{pad}=k+s(w_{out}-1) win+wpad=k+s(wout1),简单整理一下就可以得到输出特征图尺寸的计算公式:
w o u t = w i n + w p a d − k s − 1 w_{out} = \frac{w_{in}+w_{pad}-k}{s}-1 wout=swin+wpadk1
以上图片和公式来源:

2.2 自底向上的计算方式

计算方法如下图所示:

这里写图片描述
图中已经解释的比较清楚,第一个式子就是常用的根据输入尺寸计算卷积输出特征图尺寸的公式,相信熟悉CNN的童鞋一定不陌生;第三个式子可以这样理解,对于 r i n r_{in} rin所在层第一个k*k卷积区域(其对应的感受野也即下一层的一个神经元对应的感受野 r o u t r_{out} rout),卷积区域的第一个位置对应的感受野就是 r i n r_{in} rin,剩下的(横向或纵向)k-1个位置中每个位置产生的感受野增量就是上一层的特征间隔 j i n j_{in} jin;最后一个式子则是在第三个式子的基础上把padding的影响考虑进来了,根据 s t a r t o u t = r o u t − 2 ∗ p ∗ j i n 2 start_{out}=\frac{r_{out}-2*p*j_{in}}{2} startout=2rout2pjin(不难从下图中得出),再将第三个式子带入即可得到 s t a r t o u t = r i n / 2 + ( k − 1 2 − p ) ∗ j i n start_{out}=r_{in}/2+(\frac{k-1}{2}-p)*j_{in} startout=rin/2+(2k1p)jin,对于Layer0而言, s t a r t i n = r i n / 2 start_{in}=r_{in}/2 startin=rin/2,即第四个式子。

另外,由上面的第二个和第三个式子可以推出关于感受野计算的一个简化公式:

式中 l k l_k lk表示第k层对应的感受野尺寸,注意 f k − 1 f_{k}-1 fk1乘以的因子是前k-1层的步长累乘的结果(当前层的步长不参与当前层感受野的计算)

3.代码实现

自底向上的感受野计算方式的python3代码如下

# coding:utf-8net_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']}}def calc_receptive_field(network, input_size):    """Calculate receptive field according to name of network and input_size.    Assume input image is square"""    if network is None or input_size is None:        return None    assert network in net_struct.keys(), "unknown net"    layer_sizes, feat_gaps, RF_sizes = [], [], []    net_list = net_struct[network]['net']    name_list = net_struct[network]['name']    assert len(net_list) == len(name_list), "unmatched between length of layers and number of names"    n_in = input_size    j_in = 1    RF_in = 1    for i in range(len(net_list)):        kernel, stride, pad = net_list[i]        n_out = (n_in + 2*pad - kernel)//stride + 1        j_out = stride * j_in        RF_out = RF_in + (kernel-1)*j_in        layer_sizes.append(n_out)        feat_gaps.append(j_in)        n_in, j_in, RF_in = n_out, j_out, RF_out        print("Layer Name:{}, Output size:{}, Stride:{}, RF size:{}".format(name_list[i], n_out, j_out, RF_out))    result = zip(name_list, layer_sizes, feat_gaps, RF_sizes)    return resultif __name__ == "__main__":    input_size = 224    print("input size: 224*224")    for network in net_struct.keys():        print("-----------------network name: %s--------------" % network)        calc_receptive_field(network, input_size)

程序输出结果:

这里写图片描述
最后推荐一个网页版的,输入各卷积层参数配置即可计算出最后的感受野大小。
参考资料:

你可能感兴趣的文章
ORACLE表空间扩张
查看>>
orcal 循环执行sql
查看>>
web.xml配置监听器,加载数据库信息配置文件ServletContextListener
查看>>
结构型模式之桥接模式(Bridge)
查看>>
行为型模式之状态模式(State)
查看>>
行为型模式之策略模式(Strategy)
查看>>
行为型模式之模板方法模式(TemplateMethod)
查看>>
行为型模式之访问者模式(Visitor)
查看>>
大小端详解
查看>>
source insight使用方法简介
查看>>
<stdarg.h>头文件的使用
查看>>
C++/C 宏定义(define)中# ## 的含义 宏拼接
查看>>
Git安装配置
查看>>
linux中fork()函数详解
查看>>
C语言字符、字符串操作偏僻函数总结
查看>>
Git的Patch功能
查看>>
分析C语言的声明
查看>>
TCP为什么是三次握手,为什么不是两次或者四次 && TCP四次挥手
查看>>
C结构体、C++结构体、C++类的区别
查看>>
进程和线程的概念、区别和联系
查看>>