全连接神经网络和卷积神经网络整体框架是非常相似的,对于卷积神经网络,相邻两层之间只有部分节点相连,为了展示每一层神经元的维度,一般将每层卷积层的节点组织成一个三维矩阵。除了结构相似,卷积网络的输入和输出以及训练流程与全连接神经网络也基本一致。一个卷积神经网络主要由以下5种结构组成:1.输入层 2.卷积层 3.池化层 4.全连接层 5.SoftMax层
卷积层中重要结构-过滤器(filter)或者内核(kernel),过滤器可以将当前层神经网络上的一个子节点矩阵转化为下一层神经网络上的一个单位节点矩阵,单位节点矩阵指的是一个长和宽都为1,但深度不限的节点矩阵。
在一个卷积层中,过滤器处理的节点矩阵的长和宽都是由人工指定的,这个节点矩阵的尺寸也被称之为过滤器尺寸,常用的过滤器尺寸为3×3或5×5,过滤器另外一个需要人工指定的设置是处理得到的单位节点矩阵的深度,这个设置称为过滤器深度。
w(ixyz)来表示对于输出单位节点矩阵中的第i个节点,过滤器输入节点(xyz)的权重,b(i)表示第i个输出节点对应的偏置项参数,a(xyz)为过滤器中节点(xyz)中的取值,f()为激活函数,那么单位矩阵中第i个节点的取值g(i)为:g(i) = f(∑x∑y∑z a(xyz) × w(ixyz) + b(i))。
卷积层结构的前向传播过程就是通过将一个过滤器从神经网络当前层的左上角移动到右下角,并且在移动过程中计算每一个对应的单位矩阵得到的,过滤器每移动一次可以计算得到一个值(深度为k时会计算出k个值),将这些数值拼接成一个新的矩阵,就完成了卷积层的前向传播的过程。
为了避免尺寸的变化,可以在当前层矩阵的边界上加入全0填充(zero-padding),这样可以使得卷积层前向传播结果矩阵大小和当前层矩阵保持一致,除了全0填充,还可以通过设置过滤器移动的步长来调整结果矩阵的大小。
在卷积神经网络中,每一个卷积层中使用的过滤器中的参数是一样的,这是卷积神经网络的一个重要特性。
卷积层的参数个数要远远小于全连神经网络。而且卷积层的参数个数和图片的大小无关,它只和过滤器的尺寸、深度以及当前层节点矩阵的深度有关,这使得卷积神经网络能更好的扩展到更到的图像图像数据上。如果不使用全0填充,步长为1,那么参数个数 = 过滤器尺寸(长乘宽)× 当前层深度 × 过滤器深度 + 偏置项个数(过滤器深度)
下面代码实现的一个卷积层的前向传播过程。
import tensorflow as tf
# 通过get_variable创建过滤器的权重变量和偏置项变量
# [5,5,3,16]前两个代表了过滤器的尺寸,第三个维度表示当前层的深度,第四个维度表示过滤器的深度
filter_weight = tf.get_variable(
'weight', [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))
conv = tf.nn.conv2d(
input, filter_weight, strides=[1, 1, 1, 1], padding='SAME')
bias = tf.nn.bias_add(conv, biases)
# 将计算结果通过激活函数去线性化
actived_conv = tf.nn.relu(bias)
tf.nn.conv2d提供了一个非常方便的函数来实现卷积层的前向传播算法,第一个参数输入为当前层的节点矩阵,注意这个矩阵是一个四维矩阵,后面三个维度对应一个节点矩阵,第一个维度对应输入的batch,比如在输入层,input[0, :, :, :]表示第一张图片,input[1, :, :, :]表示第二张图片以此类推。tf.nn.conv2d第二个参数提供了卷积层的权重,第三个参数为不同维度上的步长,虽然第三个参数提供的是长度为4的数组,但是第一维和最后一维的数字一定是1,这是因为卷积层的步长只对矩阵的长和宽有效,最后一个参数是填充padding,tf提供了SAME和VALID两种选择,SAME表示添加全0填充,VALID表示不添加。
tf.nn.bias_add提供了一个方便的函数来给每一个节点加上偏置项。注意这里不能直接是用加法,因为矩阵上不同位置上的节点都需要加上同样的偏置项。