卷积神经网络简介
如图显示了全连接神经网络与卷积神经网络的机构对比图
、
虽然图中显示的全连接神经网络结构和卷积神经网络机构直观上差异比较大,但是实际上它们的整体架构是非常相似的。卷积神经网络也是通过一层一层的节点组织起来的。和全连接神经网络一样,卷积神经网络每一个节点都是一个神经元。在全连接网络中,每相邻两层之间的节点都有边相连,于是一般会将每一层全连接层中的节点组织成一列,这样方便显示连接结构。而对于卷积神经网络,相邻两层之间只有部分节点相连,为了展示每一层神经元的维度,一般会将每一层卷积层的节点组织成一个三维矩阵。
在图像处理中,如果使用全连接神经网络,最大的问题在于参数过多。参数过多除了导致计算速度减慢,还很容易造成过拟合的问题,所以需要一个更合理的神经网络来有效的减少神经网络中的参数个数。卷积神经网络就可以达到这个目的。
在卷积神经网络的前几层中,每一层的节点都被组织成一个三维矩阵,比如图片可以是 长 宽 像素。一个卷积神经网络主要由以下5中结构组成:
(1)输入层。 输入层就是整个神经网络的输入,在处理图像的卷积神经网络中,它一般代表了一张图片的像素矩阵。黑白图片的深度为1,在彩色RGB模式下,深度为 3 。从输入层开始,卷积神经网络通过不同的神经网络结构将上一层的三维矩阵转化为下一层的三维矩阵,直到最后的全连接层。
(2)卷积层。卷积层是卷积神经网络中最为重要的部分。卷积层中每一个节点的输入只是上一层神经网络的一小块,这个小块常有的大小是 3 * 3 或 5 * 5 。卷进层试图将神经网络中的每一小块进行更加深入的分析从而得到抽象程度更高的特征,一般来说,通过卷积层处理过的节点矩阵会变得更深。
(3)池化层。池化层神经网络不会改变三维矩阵的深度,但是它可以缩小矩阵的大小。池化操作可以认为是将一张分辨率较高的图片转化成一张分辨率更低的图片。通过池化层,可以进一步缩小最后全连接层中节点的个数,从而达到减少整个神经网络中参数的目的。
(4)全连接层。在经过多轮卷积层和池化层操作后,在卷积神经的网络最后一般会是由 1 到 2 个全连接层来给出最后的分类结果。
(5)softmax层。跟前面介绍全连接层一样,softmax层主要用于处理分类问题,计算交叉熵。
卷积神经网络常用结构
1.卷积层结构
如图是卷积层神经网络的最重要部分,我们称之为 过滤器
在一个卷积层中,过滤器所处理的节点矩阵的长和宽都是由人工指定的,这个节点矩阵的尺寸也被称为过滤器的尺寸。通常大小有 3 * 3 和 5 * 5 。因为过滤器处理的矩阵深度与当前层神经网络节点的深度是一样的,所以虽然节点矩阵是 3 维的,但过滤器的尺寸只需要指定两个维度。过滤器另外一个需要人工指定的设置是处理得到的单位节点矩阵的深度,这个设置被称为过滤器的深度。注意过滤器的尺寸指的是一个过滤器输入节点矩阵大小,而深度指的是输出单位节点矩阵的深度。
过滤器的前向传播过程就是如图通过左侧小矩阵中的节点计算出右侧单位矩阵中节点的过程。假设左侧为 2 * 2 * 3的节点矩阵,右侧为 1 * 1 * 5 的单位矩阵。则过滤器 总共有 2*2*3*5 + 5 = 65 个参数,其中 + 5 是偏置项参数。用 w 表示左侧节点,b表示偏置项,a表示过滤器,则满足
其中 f 是激活函数,假设用 ReLU 作为激活函数,则g(0) 的计算过程如下
卷积层结构的前向传播过程就是通过将一个过滤器从神经网络当前层的左上角移动到右下角,并且在移动中计算每一个对应的单位矩阵得到的。如图展示了过滤器移动的过程,过滤器每移动一次,可以计算得到一个值(当深度为 K 时就会计算 K 个值),将这些数据拼接成一个新的矩阵,就完成了卷积层的前向传播过程。
当过滤器的大小不为 1 * 1 时,卷积层前向传播得到的矩阵的尺寸要小于当前矩阵的尺寸,如上图所示。当前矩阵为 3 * 3的矩阵,而通过卷积层前向传播算法后,得到的矩阵尺寸为 2 * 2 (右侧所示)。为了避免尺寸的变化,可以在当前层 矩阵的边界上加入全零填充,这样可以使得卷积层前向传播结果矩阵的尺寸和当前层保持一致。如下图是使用了全 0 填充的卷积层传播
除了使用全 0 填充,还可以通过设置过滤器移动的步长来调整结果矩阵的大小。在上述实例中,过滤器每次只移动一格,当移动步长为 2 且使用全 0 填充时,卷积前向传播过程如下
在卷积神经网络中,每一个卷积层中使用的过滤器中的参数都是一样的,这是卷积神经网络一个非常重要的性质。共享每一个卷积层中过滤器中的参数可以巨幅减少神经网络上的参数。假设输入层的维度是 32 * 32 * 3,第一层卷积层使用尺寸为 5 * 5,深度为 16,那么这个卷积层的参数个数为 5 * 5 * 3 * 16 + 16 = 1216 个。而使用 500 个隐藏节点的全连接层将会有 150 万个参数。相比之下,卷积层的参数个数要远远小于全连接层。而且卷积层的参数个数和图片的大小无关,它只和过滤器的尺寸、深度以及当前层节点的深度有关。下图给出了使用全 0 填充,步长为 2 的卷积层前向传播的计算流程
代码实现如下
#通过 tf.get_variable 的方式创建过滤器的权重变量和偏置项变量
#数组前两个维度代表了过滤器的尺寸,第 3 个维度表示当前层的深度,第 4 个维度表示过滤器的深度
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 提供了一个非常方便的函数来实现卷积层前向传播的算法
# 这个函数第一个输入为当前层的节点矩阵,注意这个矩阵是一个 4 维矩阵,后面三维对应一个节点矩阵,第一维对应一个输入 batch
# 第二个输入提供了卷积层的权重,也就是过滤器
# 第三个输入要求一个长度为 4 的数组,但是第一个和第四个要求一定是1 ,第 2 个和第 3 个表示过滤器在长和宽的移动步长
# 最后一个输入 padding 提供 SAME 和 VALID 两种选择,其中 SAME 表示全 0 填充, VALID 表示不添加
conv = tf.nn.conv2d(
input,filter_weight,strides = [1,1,1,1],padding = 'SAME')
# tf.nn.bias_add 提供了一个方便的函数给每一个节点加上偏置项,注意不能跟全连接层一样直接用 +
# 因为不同的深度上需要加不同的偏置项
bias = tf.nn.bias_add(conv,biases)
#将计算结果通过 ReLU 激活函数完成去线性化
actived_conv = tf.nn.relu(bias)
2.池化层结构
在卷积层之间往往会加上一个池化层。池化层可以非常有效的缩小矩阵的尺寸,从而减少最后进入全连接层中的节点数。使用池化层既可以加快计算速度也有防止过拟合的作用。
池化层前向传播过程也是通过移动一个类似过滤器的结构实现的,只不过池化层过滤器中计算的不是节点的加权和,而是采用简单的最大值或平均值计算。使用最大值操作的池化层被称为最大池化层,这是被使用得最多的池化层结构。使用平均值操作的池化层被称为平均池化层。
与卷积层的过滤器类似,池化层的过滤器也是需要人工设定过滤器的尺寸,是否使用全 0 填充以及过滤器移动的步长等设置,而且这些设置的意义也跟卷积层的过滤器是一样的。唯一的区别在于卷积层使用的过滤器是横跨整个深度的,而池化层使用的过滤器只影响一个深度上的节点。所以池化层的过滤器除了在长和宽两个维度移动之外,它还需要在深度这个维度移动。下图展示了一个使用了全 0 填充且步长为 2 的最大池化层前向传播的计算过程:
在图中不同的颜色和不同线段(实线和虚线)代表了不同的池化层过滤器。从图中可以看出,池化层的过滤器除了在长和宽的方向上移动,它还需要在深度的维度上移动(因为无法给出横跨整个深度的参数)。以下是TensorFlow 最大池化层前向传播算法的代码实现。
# tf.nn.max_pool 实现了最大池化层的前向传播过程 类似的平均池化层函数有 tf.nn.avg_pool
# 第一个输入是一个 4 维的矩阵,同卷积层一样,第一维是输入的 batch ,后面三维表示节点矩阵
# 第二个输入 ksize 为过滤器的尺寸,长度为 4 的数组,第1,4个数一定是 1,第2,3 个数代表过滤器尺寸
# ksize 在实际中用的最多的是 [1,2,2,1] 和 [1,3,3,1]
# 第三个输入为步长,同卷积层过滤器一致
# 最后一个参数 padding 表示是否使用全 0 填充,SAME 和 VALID 含义同卷积层一样
pool = tf.nn.max_pool(actived_conv,ksize = [1,3,3,1],
strides = [1,2,2,1], padding = 'SAME')
# actived_conv 就是上面卷积层的前向传播结果