目录
卷积神经网络的基本结构
前面所提到的MNIST是一个相对简单的数据集,而在其他更复杂的图像识别数据集上,卷积神经网络有更好的表现。比如Cifar数据集和ImageNet数据集。Cifar分为Cifar-10和Cifar-100两个问题,都是32*32的彩色图片,Cifar-10问题收集了来自10个不同种类的60000张图片。而ImageNet数据集中的分辨率更高,图像也更加复杂。
在之前所提到的神经网络每两层之间的所有结点都是有边相连的,所以成为全连接神经网络,这种网络的最大问题是参数数量过大。而卷积神经网络与之相比有所差异,相邻两层之间只有部分节点相连,为了展示每一层神经元的维度,一般会将每一层卷积层的节点组织成一个三维矩阵。两种神经网络的训练流程没有任何区别,唯一的区别就在于神经网络中相邻两层的链接方式。
一个卷积网络具体由以下五种结构组成:
- 输入层:输入层一般代表了一个图片的三维矩阵,其中长和宽代表了图像的大小,深度代表了图像的彩色通道。比如黑白图片的深度为1,RGB彩色图片的深度为三。在神经网络种,每一层的三维矩阵都会转化为下一层的三维矩阵,直到最后的全连接层。
- 卷积层:卷积层中每一个节点的输入只是上一层神经网络的小块,常用的大小有5*5或3*3。卷积层试图将神经网络种每一小块进行更加深入的剖析。一般来说,经过卷积层处理过的节点矩阵会变得更深。
- 池化层:该层不会改变三维矩阵的深度,但会缩小矩阵的大小,达到减少整个神经网络的参数的目的。
- 全连接层:卷积神经网络最后一般会是由1到2个全连接层来给出最后的分类结果,通过卷积层和池化层对图像特征的提取,利用全连接层实现对图像的分分类。
- Softmax层:主要用于分类问题,通过该层可以得到当前样例属于不同种类的概率分布。
卷积层
卷积层中最重要的部分成为过滤器或者内核,可以将当前神经网络上的一个子节点矩阵转化为下一层神经网络上的一个单位节点矩阵(长宽为1,深度不限)。过滤器的尺寸一般为3*3或5*5,需要人工指定,成为过滤器尺寸;处理得到的单位节点的深度也需要人工指定,称为为过滤器的深度。在卷积神经网络中,每一个卷积层中使用的过滤器的参数都是一样的。
经过卷积操作的图像一般大小变为:out = (in - kernel_size +1)/stride
在TF中可以实现一个卷积层的前向传播:
import tensorflow as tf
#创建过滤器的权重变量和偏置项变量
#卷积层的参数个数只与过滤器的尺寸、深度以及当前层节点矩阵的深度有关,因此声明的参数变量为四维矩阵
#前两个维度代表了过滤器尺寸,第三个代表当前层的深度,第四个代表过滤器的深度
filter_weight = tf.get_variable('weights', [5, 3, 3, 16], initializar=tf.truncated_normal_initializer(stddev=0.1))
biases = tf.get_variable('biases', [16], initializer=tf.constant_initializer(0.1))
#tf.nn.conv2d可以实现卷积层前向传播的算法
#该函数第一个输入为当前层的节点矩阵,该矩阵为四维矩阵,第一个参数代表第n个图片,后三个代表一个节点矩阵
#第二个输入代表卷积层的权重
#第三个输入为不同维度上的步长从,该矩阵为四维矩阵,但第一个和第四个参数一定为1,中间两个代表在长和宽上的步长
#第四个输入为填充padding的方法,其中SAME表示全0填充,VALID表示不填充
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程序实现了最大池化层的前向传播算法:
#tf.nn.max_pool可以实现最大池化层的前向传播的算法
#该函数第一个输入为卷积层得到的结果
#第二个输入代表过滤器的尺寸ksize,该矩阵为四维矩阵,但第一个和第四个参数一定为1,中间两个代表过滤器的长和宽
#第三个输入为不同维度上的步长从,该矩阵为四维矩阵,但第一个和第四个参数一定为1,中间两个代表在长和宽上的步长
#第四个输入为填充padding的方法,其中SAME表示全0填充,VALID表示不填充
pool = tf.nn.max_pool(actived_conv, ksize=[1, 3, 3, 1], strides=[1,2,2,1], padding='SAME')
#平均池化层
pool = tf.nn.avg_pool(actived_conv, ksize=[1, 3, 3, 1], strides=[1,2,2,1], padding='SAME')
经典卷积网络
LeNet-5模型
LeNet-5模型一共有7层:
- 卷积层。这一层的输入是原始图像像素,模型接受的输入层大小为32*32*1。过滤器尺寸为5*5,深度为6,不使用全0填充,步长为1。输出尺寸为32-5+1=28,深度为6。该卷积层共有5*5*1*6+6=156个参数。
- 池化层。这一层的输入是第一层的输出,是一个28*28*6的节点矩阵。本层过滤器尺寸为2*2,长和宽步长为2,输出矩阵为14*14*6。
- 卷积层。本层输入矩阵尺寸大小为14*14*6。使用过滤器大小为5*5*16,不使用全0填充,步长为1。输出矩阵大小为10*10*16,共有5*5*6*16+16=2416个参数。
- 池化层。输入矩阵10*10*16,过滤器大小2*2,步长2,输出5*5*16。
- 全连接层。输入矩阵5*5*16,过滤器大小5*5,输出长度为120的向量,共有5*5*16*120+120=48120个参数
- 全连接层。输入节点120,输出节点84,总参数120*84+84=10164个。
- 全连接层。输入节点84,输出节点10,总参数120*84+84=10164个。
下面为一个TF程序实现类似该模型的卷积神经网络解决MNIST数字识别问题:
- mnist_cnn_inference.py
import tensorflow as tf
#定义神经网络结构相关的参数
INPUT_NODE = 784
OUTPUT_NODE = 10
IMAGE_SIZE = 28
NUM_CHANNELS = 1
NUM_LABELS = 10
#第一层卷积层滤波器的尺寸和深度
CONV1_DEEP = 32
CONV1_SIZE = 5
#第二层卷积层滤波器的尺寸和深度
CONV2_DEEP = 64
CONV2_SIZE = 5
#全连接层的节点个数
FC_SIZE = 512
#定义卷积神经网络,train用于区分训练过程和测试过程
def inference(input_tensor, train, regularizer):
#声明第一层卷积层,输入28*28*1,输出28*28*32
with tf.variable_scope('layer1-conv1'):
conv1_weights = tf.get_variable('weig