感受野越大越好吗(脊髓反射的感受野)
全球人工智能
文章来源:medium
文章投稿:news@top25.cn
感受野(receptive field)作为卷积神经网络(CNN)中最重要的概念之一,我们对它的重视程度是远远不够的。目前所有关于物体识别的算都是围绕这一想法来构建模型。据了解,目前还没有一份完整的指南来介绍如何计算以及可视化CNN的感受野信息。本文介绍了一种新的方法来可视化CNN的特征图,同时提供了一套完整的适用于各种CNN结构的感受野计算方法。此外,作者还通过一个简单的程序来验证文中关于感受野的计算,使得任何人都可以对感受野的计算轻松上手,并进一步加深了对CNN结构的了解。
在阅读本文的过程中,读者需要对CNN的基本概念有一定的了解,特别是卷积(convolution)以及池化(pooling)的操作。
固定尺寸的CNN特征图的可视化
感受野是指CNN结构中某个特征映射到输入空间的区域大小。对于某一特征的感受野,可以通过它的中心位置和它的尺寸大小来描述。图1列举了一些感受野的实例。通过对5×5的输入图做一个核大小k=3×3,填充大小p=1×1,步长s=2×2的卷积运算C,我门能够得到一个大小为3×3的输出特征图(如图1绿色图所示)。对该3×3的特征图继续进行同样的卷积运算,我们将会得到大小为2×2的特征图(如图1橙色图所示)。每个维度的输出特征数可以通过以下公式计算得出,详细解释请参见[1]。
值得注意的是,在本文中,我们均假定CNN结构对称且输入图像为正方形以简化运算,因此所有变量在两个维度上均有相同的值。如果CNN的结构或者输入图像并不对称,则需要为每个维度分别计算特征图的属性。
图1:两种可视化CNN特征图的方式。所有卷积运算均采用的核大小为k=3×3,填充大小为p=1×1,步长为s=2×2。把该卷积应用在一个5×5的输入图,从而得带3×3的绿色特征图,在绿色特征图上继续使用相同的卷积操作,将会得到2×2的橙色特征图。
(左)CNN特征图可视化的常用方式。只看特征图,我们不知道特征在在映射到输入空间的位置(感受野的中心位置)以及区域的大小(感受野的大小)。在deep CNN中很难回溯找到感受野信息。 (右)固定尺寸特征图可视化,其中每个特征图的大小是固定的且特征位于感受野的中心。
图1(左)代表了一种常见的CNN特征图可视化方法。在可视化的过程中,虽然可以通过查看特征图来了解其中包含了多少个特征,但是很难知道每个特征所对应的位置(感受野的中心位置)以及对应区域的大小(感受野的大小)。 图一(右)展示了固定尺寸的CNN特征图可视化,其中所有特征图的大小保持一致,并与输入图大小相同。每一个特征像素均被标记为感受野的中心。因为特征图中的所有特征均具有同样的大小,因此我们可以简单的在某一特征周围划定一个边框来表示其感受野的大小。由于特征图与输入图大小相同,因此我们并不需要将该边框映射到输入层。在图2所提供的另一个实例中,该卷积被应用于更大输入图(7×7)。对于固定尺寸的CNN特征图,我们可以分别通过3D(图2左)或者2D(图2右)的形式来表现。值得注意的是,图2中感受野的大小在第二个特征层中迅速扩大,中央特征的感受野几乎覆盖了整个输入图。这一点在改进deep CNN的设计中起到了至关重要的作用。
图2:固定大小CNN特征图表示实例。相同的卷积C应用于更大的输入图(i = 7×7)上。通过在中心特征周围绘制了感受野边框,并移除填充网格,从而获得更清晰的视图。固定大小的CNN特征图可以分别以3D(左)或2D(右)的形式表现。
感受野的计算
为了计算每一层的感受野,除了每个维度中的特征数n之外,我们还需要提供一些额外的信息。这些信息包括当前感受野的尺寸r,相邻两个特征间的距离(跳跃)j,以及左上角特征(第一个特征)起始的中心坐标。特别要注意的是,正如上文提到的固定大小的CNN特征图,特征的中心坐标即为其感受野的中心坐标。当应用核大小为k,填充大小为p以及步长为s的卷积运算时,输出层的属性可以通过以下公式计算:
公式一基于输入特征数量及卷积的属性计算输出特征数量,这与文献[1]所采用方法相同
公式二计算输出特征图中的跳跃,其等于输入图中的跳跃乘以在应用卷积运算时跳过的输入特征数(即步长)。
公式三计算输出特征图中感受野的大小,其等于由k个输入特征(k-1)* j_in所覆盖的面积加上有输入特征的感受野在边界处所覆盖的额外区域。
公式四计算第一输出特征的感受野中心位置,其等于第一输入特征的中心位置加上从第一输入特征的位置到第一卷积的中心的距离(k- 1)/ 2 * j_in减去填充空间p * j_in。此处需注意,我们需要在两种情况下乘以输入特征图的跳转,以获得实际的距离/空间。
在图3中,我们使用的坐标系中标定输入层第一个特征的中心为0.5。由于第一层是输入层,它始终具有以下属性:n =图像大小,r = 1,j = 1,start = 0.5。通过递归计算上述四个方程,我们可以算出CNN中所有特征图的感受野。图3通过一个实例来说明这些公式如何使用。
图3:将该感受野算法应用于图1实例的过程。第一行列出符号定义以及计算方程,而第二行和第三行展示了该算法在给定输入层信息的条件下计算输出层感受野的过程实例。
同时,作者还写了一个python小程序来计算一个给定CNN结构中所有层的感受野信息。它可以允许通过特征图的名字和特征要素的索引来找到对应的感受野的大小和位置,下图中展示了使用AlexNet时的输出实例,相应代码已经附在文末。
# [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) |
importmath |
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 |
defoutFromIn(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 |
returnn_out, j_out, r_out, start_out |
defprintLayer(layer, layer_name): |
print(layer_name +":") |
print("t n features: %sn t jump: %sn t receptive size: %st 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") |
fori inrange(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)) |
AIJob社是《全球人工智能》旗下专门为AI开发工程师免费服务的求职平台。我们将竭尽全力帮助每一个ai工程师对接自己喜欢的企业,推荐给你喜欢的直接领导,帮你谈一个最好的薪资待遇。
微信咨询:aihr007简历投递:hr@top25.cn企业合作:job@top25.cn
《全球人工智能》招聘5名兼职翻译:图像技术、语音技术、自然语言、机器学习、数据挖掘等专业技术领域,工作内容及待遇请添加工作人员微信:C691993。
热门文章推荐
重磅|全球AI报告:看看谷歌|苹果|Facebook等十几家巨头都收购了哪些牛逼的AI公司?