前面两讲我们使用全连接神经网络对Mnist数据集进行了训练,我们已经学会使用数据集训练模型,并让训练好的模型输出识别结果了。 我们之前的模型之所以叫全连接神经网络,是因为每一个神经元和前后相邻层的每一个神经元都有连接关系。前面,我们把原始图像的所有像素点以一维数组的形式输入全连接神经网络;全连接网络会计算分类评估值,也就是,识别出的结果。 在全连接神经网络中,每一层参数w的个数等于前一层神经元的个数乘以后一层神经元的个数。每一层参数b的个数等于后一层神经元的个数。这样,待优化的总参数就是各层的参数w和b的总和。比如,上节课的两层神经网络,第一层需要784*500+500,第二层需要500*10+10个。一共有近40万个待优化的参数。这还只是分辨率为28*28的黑白图像。
如果换成现实生活中的高分辨率彩色图像,不仅像素点增加,还从灰度图的单通道信息变成红绿蓝的三通道信息。待优化的参数过多,很容易导致模型过拟合。
为了避免过拟合现象的发生,我们在实际应用时,往往不会将原始图片直接喂入全连接神经网络,会先对原始图片进行特征提取,把提取到的特征喂给全连接神经网络。再让全连接神经网络按照前两次课的方法,计算出分类评估值。 比如,先把左边这张图片进行多次特征提取,再把提取后的计算机可以读懂的特征喂给全连接神经网络。
卷积便是一种有效提取图片特征的方法。一般会用一个正方形的卷积核,遍历图片上的每一个像素点。图片与卷积核重合区域内,相对应的每一个像素点乘以相对应点的权重,求和,再加上偏置后,得到输出图片的一个像素值。 比如,有这样一张5*5*1的灰度图片,1表示单通道,5*5表示分辨率。如果用一个3*3*1的卷积核对5*5*1的图片进行卷积,实际上就是让卷积核在图片上滑动。卷积核每滑动一次,会计算得到输出图片中的一个值。
输出图片变成的计算公式如下:
此图因为用了一个卷积核,所以输出的深度是1。输出是3*3*1的图片。
有时候会在输入图片周围进行全零填充,这样可以保证输出图片的尺寸和输入图片一致。比如刚才的5*5*1的图片,周围进行了全0填充,使得输出图片仍然保持5*5*1的维度,这个全0填充的过程叫做padding。
这个公式给出了使用padding和不使用padding的输出维度。使用padding时,输出的边长等于输入的边长除以步长,如果不整除需要向上取整数,比如2.4取作3。如果不使用padding,输出图片的边长等于输出图片的边长减去核长加上1,再除以步长,如果不能整除,同样需要向上取整数。
在TensorFlow框架中,使用全零填充表示为padding=‘SAME’,不使用全零填充表示为padding='VALID'。比如刚才的5*5*1的图片,使用全0填充输出为5*5*1,不使用全0填充输出为3*3*1。
TensorFlow给出了计算卷积的函数,用tf.nn.conv2d()表示。函数中要给出4个信息,分别是对输入图片的描述、对卷积核的描述、对卷积核滑动步长的描述、是否使用padding。 在输入描述中,用batch给出一次喂入多少张图片。每张图片的分辨率大小,比如5行5列。这些图片包含了几个通道的信息,如果是灰度图,是单通道,这里写1;如果彩色图,是红绿蓝3通道,这里写3。 在核描述中,要给出卷积核的行分辨率,列分辨率,通道数,用了几个卷积核。比如[3,3,1,16]表示卷积核是3行3列,是1通道,一共有16个这样的卷积核。卷积核的通道数是由输入图片的通道数决定的。卷积核的通道数,应该等于输入图片的通道数,所以也是1。一共有16个这样的卷积核,说明卷积操作后,输出图片的深度是16,也就是输出是16通道。 在卷积核的步长描述中,第2个参数表示横向滑动步长,第3个参数表示纵向滑动步长。第1个参数和第4个参数都固定是1。 padding选项这里用的是'VALID',注意'VALID'是以字符串的形式给出。
刚才是对单通道的灰度图片求卷积,在大多数情况下,输入的图片是RGB三个颜色组成的彩色图。输入图片包含了红绿蓝三层信息。卷积核的深度应该等于图片的通道数。所以使用了3*3*3的卷积核,最后一个3表示匹配输入图像的3个通道数。这样,这个卷积核有3层。每层会随机生成9个待优化的参数。一共有27个待优化的参数w和一个偏置b。对于彩色图,按层分解开,可以直观表示成左边的图,三个分量。卷积计算方法和单层卷积计算方法相似,卷积核为了匹配红绿蓝,也是三层。把三层的卷积核套在三成的彩色图片上。重合的27个像素点进行对应点的乘加运算,最后加上偏置b,求得输出图片中的一个值。
对于这一幅彩色图片,用conv2d()函数实现,可以表示为:
一次输入batch张图片,输入图片的分辨率是5*5,是3通道的。卷积核是3*3分辨率,3通道,一共有16个卷积核,这样输出的深度是16。核滑动的步长是1。padding选择使用。
通过卷积特征提取,得到的特征,仍然数量巨大。池化可以减少特征数量。池化的主要方法有:最大池化、均值池化。最大池化可以提取图片的纹理,均值池化可以保留背景特征。 如果用2*2的核对输入图片以2为步长进行池化,输出图片变为输入图片的四分之一大小。
TensorFlow给出了计算池化的函数,最大池化用tf.nn.max_pool()函数,平均池化用tf.nn.avg_pool()函数。函数中也要给出四个信息:对输入的描述、对池化核的描述、对池化核滑动步长的描述、是否使用padding。 在输入的描述中,给出一次输入batch张图片,行、列分辨率,输入通道的个数。 池化核只描述行分辨率、列分辨率,第一个和最后一个参数固定是1。 池化的滑动步长只描述横向的滑动步长和纵向的滑动步长,第一个和最后一个参数同样固定是1。 padding可以是使用0填充'SAME'或者不使用0填充'VALID'。
在神经网络的训练过程中,为了减少过多的参数,常使用Dropout的方法,将一部分神经元按照一定概率从神经网路中舍弃。这种舍弃是临时性的,仅在训练时舍弃一定概率的神经元,在使用神经网络时,会把所有的神经元恢复到神经网络中。比如下图,在训练时,一些神经元不参与神经网络计算了。 dropout可以有效减少过拟合。TensorFlow提供了Dropout函数,用tf.nn.dropout(),第一个参数是上一层的输出,第二个参数给出神经元舍弃的概率。在实际应用中,常常在前向传播构建神经网络时,使用dropout来减小过拟合,加快模型的训练速度。 dropout一般会放在全连接网络中,如果在训练参数的过程中,输出等于tf.nn.dropout(上层输出,暂时舍弃的概率),这样就指定概率的神经元被随机置0,置0的神经元不参加当前轮的参数优化。
其实,卷积神经网络就是借助卷积操作,对输入图片进行特征提取,再把提取到的特征喂入全连接网络,所以卷积神经网络可以认为是由两部分组成。第一部分是是对输入图片的特征提取,第二部分是前面讲过的全连接网络。只不过喂入全连接网络的不再是原始图片,而是经过若干次卷积、激活和池化后的特征信息。
卷积神经网络从诞生到现在,已经出现了许多经典网路结构,比如Lenet-5,AlexNex,VGGNet,GoogleNet,ResNet等,每一种网络结构都是以上面的四种操作为基础进行的扩展。Lenet-5是最早出现的卷积神经网络,由LeCun团队首次提出,有效解决了手写数字的识别问题。接下来,我们会用Lenet-5为例,介绍卷积神经网络的结构,和用TensorFlow编码实现。
|