《TensorFlow:实战Google深度学习框架》——6.3 卷积神经网络常用结构

1、卷积层

图6-8显示了卷积层神经网络结构中重要的部分:滤波器(filter)或者内核(kernel)。

过滤器可以将当前层神经网络上的一个子节点矩阵转化为下一层神经网络上的一个单位节点矩阵 。 单位节点矩阵指的是一个长和宽都为1,但深度不限的节点矩阵 。

在一个卷积层巾,过滤器所处理的节点矩阵的长和宽都是由人工指定的,这个节点矩阵的尺寸也被称之为过滤器的尺寸。常用的过滤器尺寸有 3 × 3 或 5 × 5
过滤器的尺寸指的是一个过滤器输入节点矩阵的大小(长和宽),而深度指的是输出单位节点矩阵的深度。如图 6-8 所示,左侧小矩阵的尺寸为过滤器的尺寸,而右侧单位矩阵的深度为过滤器的深度。


下边通过一个样例来说明卷积运算及前向传播过程。样例中将展示如何通过过滤器将一个 2 × 2 × 3 的节点矩阵变化为一个
1 × 1× 5 的单位节点矩阵 。

假设使用w_{x,y,z}^{i}来表示对于输出单位节点矩阵中的第i个节点,过滤器输入节点(x,y,z)的权重,使用b^{i}表示第i个输出节点对应的偏置项参数,那么单位矩阵中的第i个节点的取值g(i)为:

其中,a_{x,y,z}为过滤器中节点(x, y, z)的取值,f为激活函数。图6-9展示了再给定a,w^{0}b^{0}的情况下,使用ReLU作为激活函数时g(0)的计算过程。

在图6-9的左侧给出了 a 和 w^{0}的取值,这里通过 3 个二维矩阵来表示一个三维矩阵的取值,其中每一个二维矩阵表示三维矩阵在某一个深度上的取值 。点(·)符号表示点积,也就是矩阵中对应元素乘积的和。图 6-9 的右侧显示了g(0)的计算过程。如果给出 w^{1}w^{4}b^{1}b^{4}, 那么也可以类似地计算出 g(1)到 g(4)的取值。

6-9 使用过滤器计算g(0)取值的过程示意图

为了更好的可视化过滤器的移动过程,图6-10展示了在 3 × 3 矩阵上使用 2 × 2过滤器卷积层结构前向传播的过程,这里节点深度为1。

在这个过程中,首先将这个过滤器用于左上角子矩阵,然后移动到右上角矩阵,再到左下角矩阵,最后到右下角矩阵。过滤器每移动一次,可以计算得到一个值(当深度为k时会计算出 k个值) 。将这些数值拼接成一个新的矩阵,就完成了卷积层前向传播的过程。图 6-10的右侧显示了过滤器在移动过程中计算得到的结果与新矩阵中节点的对应关系 。

当过滤器的大小不为 1 × 1时,卷积层前向传播得到的矩阵的尺寸要小于当前层矩阵的尺寸 ,一般是n-k+1,n为矩阵的大小,k为过滤器的大小。6-10 所示,当前层矩阵的大小为 3 × 3 (图 6-10 左侧矩阵〉,而通过卷积层前向传播算法之后,得到的矩阵大小为 2 × 2(图 6-10 右侧矩阵)。为了避免尺寸的变化,可以在当前层矩阵的边界上加入全 0 填充( zero-padding)。这样可以使得卷积层前向传播结果矩阵的大小和 当前层矩阵保持一致。 图 6- 11显示 了使用全0填充后卷积层前向传播过程示意图。

除了使用全 0 填充,还可以通过设置过滤器移动的步长来调整结果矩阵的大小。在图 10 和图 6-11 中,过滤器每次都只移动一格。图 6-12 中显示了当移动步长为 2 且使用全 0 填充时,卷积层前向传播的过程。

从图 6-12上可以看出,当长和宽的步长均为 2 时,过滤器每隔 2 步计算一次结果,所以得到的结果矩阵的长和宽也就都只有原来的一半。以下公式给出了在同时使用全 0 填充时结果矩阵的大小 。

其中out_{length}表示输出层矩阵的长度,它等于输入层矩阵长度除以长度方向上的步长向上取整数out_{width}表示输出层矩阵的宽度,它等于输入层矩阵宽度除以宽度方向上的步长向上取整值

如果不使用全 0 填充,以下公式给出了结果矩阵的大小 。


在卷积神经网络中,每一个卷积层中使用的过滤器中的参数都是一样(参数共享)的。这是卷积神经网络一个非常重要的性质。从直观上理解,共享过滤器的参数可以使得图像上的内容不受位置的影响,同时也可以减少神经网络上的参数。

卷积层的参数个数和图片的大小无关,它只和过滤器的尺寸、深度以及当前层节点矩阵的深度有关。这使得卷积神经网络可以很好地扩展到更大的图像数据上 。

结合过滤器的使用方法和参数共享的机制,图 6-13 给出了使用了全 0 填充、步长为 2的卷积层前向传播的计算流程 。
 

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

图 6-13 给出了过滤器上权重的取值以及偏置项的取值,通过图 6-9 中所示的计算方法,可以得到每一个格子的具体取值 。 以下公式给出了左上角格子取值的计算方法,其他格子可以依次类推。


TensorFlow实现卷积计算前向传播:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tensorflow as tf

# 通过 tf.get_variable 的方式创建过滤器的权重变量和偏置项变量。
# 上面介绍了卷积层的参数个数只和滤波器的尺寸、深度以及当前层节点矩阵的深度有关,所以这里声明的参数变量是一个四维矩阵,
# 前面两个维度代表了过滤器的尺寸,第三个维度表示当前层的深度,第四个维度表示过滤器的深度。
filter_weights = tf.get_variable('weights', [5, 5, 3, 16], initialzer=tf.truncated_normal_initializer(seed=0.1))

# 和卷积层的权重类似,当前层矩阵上不同位置的偏置项也是共辜的,所以总共有下个深度个不
# 同的偏E项。本样例代码中 16 为过滤器的深度,也是神经网络中下一层节点矩阵的深度 。
biases = tf.get_variable('biases', [16], initializer=tf.constant_initializer(0.1))

# tf.nn.conv2d 提供了一个非常方便的函数来实现卷积层前向传播的算法。这个函数的第一个输入为当前层的节点矩阵。
# 注意这个矩阵是一个四维矩阵,后面三个维度对应一个节点矩阵,第一维对应一个输入batch。
# 比如在输入层,input[O , :, :, :]表示第一张图片, input[l, :, :, :]表示第二张图片,以此类推。
# tf.nn.conv2d 第二个参数提供了卷积层的权重,第三个参数为不同维度上的步长。
# 虽然第三个参数提供的是一个长度为 4 的数组,但是第一维和最后一维的数字要求一定是 l 。
# 这是因为卷积层的步长只对矩阵的长和宽有效。最后一个参数是填充(padding)的方法,
# TensorFlow中提供SAME或是VALID两种选择。其中SAME但表示添加全0填充,“VALID”表示不添加
conv = tf.nn.conv2d(input, filter_weights, strides=[1, 1, 1, 1], padding='SAME')

# tf.nn.bias_add提供了一个方便的函数给每一个节点加上偏置项。注意这里不能直接使用加法!!1
# 因为知阵上不同位置上的节点都需要加上同样的偏置项。
bias = tf.nn.bias_add(conv, biases)

# 将计算结果通过ReLU激活函数完成去线性化
actived_conv = tf.nn.relu(bias)

猜你喜欢

转载自blog.csdn.net/Sophia_11/article/details/84573714