TensorFlow实战系列11--卷积层网络结构

 图 4 中显示了卷积层神经网络结构中最重要的部分,这个部分被称之为过滤器(filter)或者内核(kernel)。因为 TensorFlow 文档中将这个结构称之为过滤器(filter),所以我们将统称这个结构为过滤器。如图 4 所示,过滤器可以将当前层神经网络上的一个子节点

矩阵转化为下一层神经网络上的一个单位节点矩阵。单位节点矩阵指的是一个长和宽都为 1,但深度不限的节点矩阵。

                                              

       图 4 卷积层过滤器结构示意图

 在一个卷积层中,过滤器所处理的节点矩阵的长和宽都是由人工指定的,这个节点矩阵的尺寸也被称之为过滤器的尺寸。常用的过滤器尺寸有3×3 或 5×5。因为过滤器处理的矩阵深度和当前层神经网络节点矩阵的深度是一致的,所以虽然节点矩阵是三维的,但过滤器的尺寸只需要指定两个维度。过滤器中另外一个需要人工指定的设置是处理得到的单位节点矩阵的深度,这个设置称为过滤器的深度。注意过滤器的尺寸指的是一个过滤器输入节点矩阵的大小,而深度指的是输出单位节点矩阵的深度。如图 4 所示,左侧小矩阵的尺寸为过滤器的尺寸,而右侧单位矩阵的深度为过滤器的深度。

 如图 4 所示,过滤器的前向传播过程就是通过左侧小矩阵中的节点计算出右侧单位矩阵中节点的过程。为了直观地解释过滤器的前向传播过程,在下面的篇幅中将给出一个具体的样例。在这个样例中将展示如何通过过滤器将一个 2×2×3 的节点矩阵变化为一个 1×1×5 的单位节点矩阵。一个过滤器的前向传播过程和全连接层相似,它总共需要 2×2×3×5+5=65个参数,其中最后的 +5 为偏置项参数的个数。假设使用 w (x,y,z)i 来表示对于输出单位节点矩阵中的第 i 个节点,过滤器输入节点 (x,y,z) 的权重,使用 b i 表示第 i 个输出节点对应的偏置项参数,那么单位矩阵中的第 i 个节点的取值 g(i) 为:

 其中 a (x,y,z) 为过滤器中节点 (x,y,z) 的取值,f 为激活函数。如果将 a 和w i 组织成两个向量,那么一个过滤器的计算过程完全可以通过向量乘法来完成。卷积层结构的前向传播过程就是通过将一个过滤器从神经网络当前层的左上角移动到右下角,并且在移动中计算每一个对应的单位矩阵得到的。图 5 展示了卷积层结构前向传播的过程。为了更好地可视化过滤器的移动过程,图 5 中使用的节点矩阵深度都为 1。在图 5 中,展示了在 3×3矩阵上使用 2×2 过滤器的卷积层前向传播过程。在这个过程中,首先将这个过滤器用于左上角子矩阵,然后移动到左下角矩阵,再到右上角矩阵,最后到右下角矩阵。过滤器每移动一次,可以计算得到一个值(当深度为k 时会计算出 k 个值)。将这些数值拼接成一个新的矩阵,就完成了卷积层前向传播的过程。图 5 的右侧显示了过滤器在移动过程中计算得到的结果与新矩阵中节点的对应关系。

 在图 5 中,只讲解了移动过滤器的方式,没有涉及到过滤器中的参数如何设定。在卷积神经网络中,每一个卷积层中使用的过滤器中的参数都是一样的。这是卷积神经网络一个非常重要的性质。从直观上理解,共享过滤器的参数可以使得图像上的内容不受位置的影响。以 MNIST 手写体数字识别为例,无论数字“1”出现在左上角还是右下角,图片的种类都是不变的。因为在左上角和右下角使用的过滤器参数相同,所以通过卷积层之后无论数字在图像上的哪个位置,得到的结果都一样。

  

       图5 卷积层前向传播过程示意图

 共享每一个卷积层中过滤器中的参数可以巨幅减少神经网络上的参数。以 Cifar-10 问题为例,输入层矩阵的维度是 32×32×3。假设第一层卷积层使用尺寸为 5×5,深度为 16 的过滤器,那么这个卷积层的参数个数为 5×5×3×16+16=1216 个。上文提到过,使用 500 个隐藏节点的全连接层将有 150 万个参数。相比之下,卷积层的参数个数要远远小于全连接层。而且卷积层的参数个数和图片的大小无关,它只和过滤器的尺寸、深度以及当前层节点矩阵的深度有关。这使得卷积神经网络可以很好地扩展
到更大的图像数据上。

     

       图6 卷积层前向传播过程样例图

 结合过滤器的使用方法和参数共享的机制,图 6 给出了使用了全 0 填充、移动步长为 2 的卷积层前向传播的计算流程。下面的公式给出了左上角格子取值的计算方法,其他格子可以依次类推。

ReLu(0×1+0×(-1)+0×0+1×2+1)=ReLu(3)=3
 TensorFlow 对卷积神经网络提供了非常好的支持,下面的程序实现了一个卷积层的前向传播过程。从以下代码可以看出,通过 TensorFlow 实现卷积层是非常方便的。

# 通过tf.get_variable的方式创建过滤器的权重变量和偏置项变量。上面介绍了卷积层
# 的参数个数只和过滤器的尺寸、深度以及当前层节点矩阵的深度有关,所以这里声明的参数变
# 量是一个四维矩阵,前面两个维度代表了过滤器的尺寸,第三个维度表示当前层的深度,第四
# 个维度表示过滤器的深度。
filter_weight = tf.get_variable(
 'weights', [5, 5, 3, 16],
initializer=tf.truncated_normal_initializer(stddev=0.1))
# 和卷积层的权重类似,当前层矩阵上不同位置的偏置项也是共享的,所以总共有下一层深度个不
# 同的偏置项。本样例代码中16为过滤器的深度,也是神经网络中下一层节点矩阵的深度。
biases = tf.get_variable(
 'biases', [16], initializer=tf.constant_initializer(0.1))
# tf.nn.conv2d提供了一个非常方便的函数来实现卷积层前向传播的算法。这个函数的第一个输
# 入为当前层的节点矩阵。注意这个矩阵是一个四维矩阵,后面三个维度对应一个节点矩阵,第一
# 维对应一个输入batch。比如在输入层,input[0,:,:,:]表示第一张图片,input[1,:,:,:]
# 表示第二张图片,以此类推。tf.nn.conv2d第二个参数提供了卷积层的权重,第三个参数为不
# 同维度上的步长。虽然第三个参数提供的是一个长度为4的数组,但是第一维和最后一维的数字
# 要求一定是1。这是因为卷积层的步长只对矩阵的长和宽有效。最后一个参数是填充(padding)
# 的方法,TensorFlow中提供SAME或是VALID两种选择。其中SAME表示添加全0填充,
# “VALID”表示不添加。
conv = tf.nn.conv2d(
 input, filter_weight, strides=[1, 1, 1, 1], padding='SAME')
# tf.nn.bias_add提供了一个方便的函数给每一个节点加上偏置项。注意这里不能直接使用加
# 法,因为矩阵上不同位置上的节点都需要加上同样的偏置项。虽然下一层神经网络的大小为
# 2×2,但是偏置项只有一个数(因为深度为1),而2×2矩阵中的每一个值都需要加上这个
# 偏置项。
bias = tf.nn.bias_add(conv, biases)
# 将计算结果通过ReLU激活函数完成去线性化。
actived_conv = tf.nn.relu(bias)
















 

猜你喜欢

转载自blog.csdn.net/tian_qing_lei/article/details/79270201