使用Tensorflow实现CNN进行手写数字识别

传统的机器学习需要使用不同的特征提取算法获取特征,深度卷积神经网络为图像分类提供了统一的解决方案。

一、卷积神经网络

   卷积神经网络CNN是多层神经网络的一个变种,传统的多层神经网络,当隐层数变多时,节点数目过多时就会造成参数个数过多,训练难度极大。它充分利用了图片中相邻区域的信息,通过稀疏连接和共享权值的方式大大减少参数矩阵的规模,也提高了训练速度。

1、卷积神经网络的核心概念

为了减少参数的个数,提出了以下三个概念
   (1)稀疏连接(sparse connectivity ):通过对数据中的局部区域进行建模,发现局部的一些特性。第m层结点的输入为第m-1层神经元的一个子集,被选择的子集的大小称为感受野。每组感受野中,其参数是相互共享的,也就是权值共享。
   (2)共享权值(Shared weights):简化计算过程,使得需要优化的参数减少。如感受野大小为3时,此时包含三个参数w1,w2,w3,这样极大缩减需要学习的参数数量。
   (3)池化(Pooling):也就是子采样,目的是解决图像中的平移不变性,达到要识别的内容和其位置无关。采用最大池化max-pooling,将输入图像划分为一系列不重叠的正方形区域,对每个子区域输出其中的最大值,通过消除非最大值,进一步降低计算量。

2、CNN基本原理

2.1、卷积的数学意义

使用Tensorflow实现CNN进行手写数字识别_第1张图片

2.2、卷积滤波

   卷积其实是图像处理中一种常用的线性滤波方法,使用卷积可是降噪,蜕化等。是对图片中每一个像素点,计算它的邻域像素和卷积核滤波器矩阵的对应位置元素的乘积,然后将乘积累加。
   卷积核:是一个权值矩阵,表示如何处理单个像素与其周围像素之间的关系。卷积核每个元素越接近,则越模糊降噪;相差大,则锐化。一般比较小,因为和计算量有关。每个卷积核就是一个特征提取器,n个就提取n个特征。

2.3、卷积层

   将卷积操作和反向传播结合,诞生卷积神经网络,通过大量图片让程序自己训练学习卷积核参数就可以。
   卷积层节点和全连接层节点有三个不同
   1、局部感知域(稀疏连接):对于每个计算单元,只考虑其像素位置附近的输入,也就是只取上一层输入的一个子集。这些局部信息组合形成图像。10X10的卷积核进行卷积操作的话,每个节点100个输入,对应100个参数。而且同层的卷积核共享权值,大大减少了参数。
   2、权值共享:对图片进行卷积时,会让卷积核逐一划过每个像素,这样处理每个像素的参数都是相同的。
   3、多核卷积:以多核的方式来充分提取特征。每个卷积核生成一幅新图像,这些图像称为特征图,这是比像素更高级的特征。可以理解为经过滤波后的不同通道。

2.4、池化

   得到了更高级别的特征后,可以交给分类器进行训练分类了。但是在这之前,需要池化操作进行降维。
   池化:将图像按窗口大小划分为不重叠的区域,然后对每一个区域内的元素进行聚合。一般采用2x2窗口大小,聚合方法:取各个元素最大值;取平均值。采用2x2的池化操作,处理完的图像长和宽都是原图的一般,变为1/4。既达到降维的目的,也使得特征提取有了“平移不变性(有几个像素的位移的情况下,依然可以获得稳定的特征集合)”。我们只关心那些特征可以代表物体。

2.5、ReLU函数

   通过该激活函数,将特征空间的向量非线性变换映射到另一个空间,然后实现线性可分。不用sigmoid的原因是,它可用于拟合概率,会产生梯度消失,收敛速度慢。
   f(x) = max(0,x)
   取值范围[0,无穷],这样可以将取值映射到所有正数域。分类效果好,收敛快,计算快。

2.6、多层卷积

   整个网络由多个特征提取阶段构成。每个阶段三个操作:卷积,池化和非线性激活函数。能逼近复杂的非线性模型函数,又能以较简单的方式训练。
   浅层:提取细节特征,如眼角,嘴唇之类的。
   深层:将细节组合,提取更完整,抽象的特征,如鼻子等。
   全连接层:按照最抽象的特征进行分类。

2.7、Dropout

   抵消过拟合:AlexNet将Dropout应用在网络中的前两个全连接层。Dropout是在每一轮训练中,随机让隐层结点失效一部分,改变网络结构,但每个节点的权值被保留。在最终预测时打开全部隐层结点,使用完整的网络。

2.8、经典的AlexNet

使用Tensorflow实现CNN进行手写数字识别_第2张图片

二、卷积神经网络求解

   CNN中最重要的就是卷积层(Convolution Layer),下采样层(也就是池化,Sub-Sampling),和全连接层(Full-Connected Layer)。分别对应CNN三个重要操作:卷积,最大池化,和全连接的MLP。

1、卷积层操作

   卷积操作为f(x)g(x)在重合区域的积分。
   一维卷积:输入向量与权值向量乘积之和就是卷积后的下一层神经元的值。
   二维卷积:与一维不同的是,其权重组成的是矩阵,不是向量。所以通过原始数据矩阵与权重矩阵的点积,得到卷积后的结果。输入为矩阵,不是向量。
   三维卷积:是二维卷积的推广形式,如RGB图片,对应了三个通道,每个通道进行二维数据的卷积操作,将三个通道的值累加,就得到最终的卷积结果。
   求解卷积操作中的权重值:与BP神经网络的求解类似,基本过程还是信号的正向传播和误差的反向传播。
   权值求解过程:给出误差矩阵d,权重矩阵的梯度是输入矩阵和误差矩阵卷积操作。

2、下采样层

   卷积层后,就是下采样层(池化),用一个特征来表达一个局部特征,起到降维作用。

3、全连接层

   是一个包含隐层的神经网络模型,CNN中,卷积层和下采样层交替叠加得到特征的高层抽象特征,对该高层抽象进行全连接映射,如softmax,最终对其进行分类。

三、Tensorflow简介

   磨刀不误砍柴工,实际运用之前先了解一下Tensorflow内部的设计原理和运行机制。

3.1、Tensorflow

   它是一款基于数据流图的数值计算开源软件库。数据流图是对计算过程的抽象表示,它是有向图,图中的点表示各种数学计算操作,边表示操作与操作之间传递的高维数组数据(称为tensor)。内核使用C++编写。

3.2、Tensorflow基础概念

3.2.1、计算图(也叫数据流图)

   Tensorflow是基于计算图的数值计算系统。保证了各种算法实现的灵活性。
   计算图的执行:看做数据tensor按照图的拓扑顺序,从输入节点逐步流过所有中间节点,最后流出输出节点的过程。
   图节点operations,图中的节点代表数字计算操作的算子。它是参与计算的基本单位,每个算子对应一种运算,tensorflow内置了很多算子,各种数值,数组,矩阵,状态操作,神经网络的各个操作,存档啊,队列,同步啊,控制流等。
   连接边tensor,节点之间的连接边代表参与计算的高维数组数据。它代表多维数组,对应的是神经网络的高维参数矩阵。tensor可以是任意维度,每维可以是任意长度,其中的元素可以是任意内置类型。4维tensor可以表示一个mini-batch的图片,四个维度分别是批大小,像素行数,像素列数,通道数。
   变量:Variable,来存储参数值,表示了图的状态。可以与tensor一样参与各种运算,区别是tensor的值每次计算后丢弃,Variable的值会不断更新。

3.2.2、Session会话

   Session:是驱动Tensorflow系统执行计算交互的入口。负责完成多计算设备或集群分布式的节点布置和数据传输节点的添加,将子图分配给相应的执行器单元。

3.3、Tensorflow系统架构

   Tensorflow是拥有“client—>master—>worker”架构的分布式系统。
   一般的执行流程:客户端通过会话tf.Session接口与master进行通信,向master提交触发执行请求,master将执行任务分配到一个或多个worker进程上,执行的结果通过master返回客户端。可见worker是最终负责计算的角色,每一个worker进程都会管理和使用计算机上的 硬件设备资源来处理计算子图的运算过程。

四、利用TensorFlow实现CNN进行手写数字识别

   构建卷积神经网络类,使用MNIST手写体识别的数据集对其进行训练和测试。

4.1、首先定义四个函数

   (1)权值函数:w_variable(shape),返回自定义的权值。用到tf.truncated_normal(shape, mean, stddev) :shape表示生成张量的维度,mean是均值,stddev是标准差。这个函数产生正态分布,均值和标准差自己设定。这是一个截断的产生正态分布的函数,就是说产生正态分布的值如果与均值的差值大于两倍的标准差,那就重新生成。
   :卷积核的shape为:[length, high, in_channel, out_channel],全连接层、softmax和drop out的shape为:[length, high]。
   (2)偏置函数:b_variable(shape),返回偏置向量,在卷积过程中,它是shape=out_channel,在全连接层和softmax层中shape=high。
   (3)卷积函数:conv2d(x, W),返回输入图片在经过卷积后值。tf.nn.conv2d(input, filter, strides, padding)。
   参数说明
   input : 输入的要做卷积的图片,要求为一个张量,shape为 [ batch, in_height, in_weight, in_channel ],其中batch为图片的数量,in_height 为图片高度,in_weight 为图片宽度,in_channel 为图片的通道数,灰度图该值为1,彩色图为3。
   filter: 卷积核,要求也是一个张量,shape为 [ filter_height, filter_weight, in_channel, out_channels ],其中 filter_height 为卷积核高度,filter_weight 为卷积核宽度,in_channel 是图像通道数 ,和 input 的 in_channel 要保持一致,out_channel 是卷积核数量。
   strides: 卷积时在图像每一维的步长,这是一个一维的向量,[ 1, strides, strides, 1],第一位和最后一位固定必须是1
   padding: string类型,值为“SAME” 和 “VALID”,表示的是卷积的形式,是否考虑边界。"SAME"是考虑边界,不足的时候用0去填充周围,"VALID"则不考虑
   (4)池化函数:max_pool_2x2(x),tf.nn.max_pool(value, ksize, strides, padding, name=None)
   参数说明
   value:需要池化的输入,一般池化层接在卷积层后面,所以输入通常是feature map,依然是[batch, height, width, channels]这样的shape。
   ksize:池化窗口的大小,取一个四维向量,一般是[1, height, width, 1],因为我们不想在batch和channels上做池化,所以这两个维度设为了1。
   strides:和卷积类似,窗口在每一个维度上滑动的步长,一般也是[1, stride,stride, 1]
   padding:和卷积类似,可以取’VALID’ 或者’SAME’

import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

def w_variable(shape):
	init=tf.truncated_normal(shape, stddev=0.1)
	return tf.Variable(init)
def b_variable(shape):
	init=tf.constant(0.1, shape=shape)
	return tf.Variable(init)
def conv2d(x, W): #x input, W filter
	return tf.nn.conv2d(x, W, strides=[1,1,1,1], padding='SAME') #size W=[length, high, in_channel, out_channel]
def max_pool_2x2(x):
	return tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')

4.2、构建CNN网络。

   结构:整个网络由两个卷积层(包含激活层和池化层),一个全连接层,一个dropout层和一个softmax层组成。

#下载数据
mnist= input_data.read_data_sets('MNIST_data',one_hot=True)
x= tf.placeholder("float", shape=[None, 784])
y_= tf.placeholder("float", shape=[None, 10])
x_image= tf.reshape(x, [-1,28,28,1]) #size [num, length, high, channel]
# 第一个卷积层
W_covn1= w_variable([5,5,1,32])  #the covn core W
b_covn1= b_variable([32])
h_conv1= tf.nn.relu(conv2d(x_image, W_covn1)+ b_covn1)
h_pool1= max_pool_2x2(h_conv1)
# 第二个卷积层
W_covn2= w_variable([5,5,32,64])
b_covn2= b_variable([64])
h_conv2= tf.nn.relu(conv2d(h_pool1, W_covn2)+ b_covn2)
h_pool2= max_pool_2x2(h_conv2)
# 全连接层
W_fc1= w_variable([7*7*64, 1024])
b_fc1= b_variable([1024])
h_pool2_flat= tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1= tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1)+ b_fc1)
# drop out层
keep_prob=tf.placeholder("float")
h_pool2_flat= tf.nn.dropout(h_fc1, keep_prob)
#输出softmax层
W_fc2= w_variable([1024, 10])
b_fc2= b_variable([10])
h_fc2= tf.nn.softmax(tf.matmul(h_pool2_flat, W_fc2)+ b_fc2)

4.3、开始训练

   训练过程:定义fit函数对CNN训练,包含了两个卷积层、池化层。将预测值和真实值的交叉熵作为最终的损失函数,求损失函数中的最小值。利用优化方法求解损失函数,得到CNN模型的值。

# 定义损失函数(交叉熵)
cross_entropy= -tf.reduce_sum(y_*tf.log(h_fc2))
# 训练
train_step= tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#性能指标:准确率
correct_prediction= tf.equal(tf.argmax(y_, 1), tf.argmax(h_fc2, 1))
acc= tf.reduce_mean(tf.cast(correct_prediction, "float"))
# 初始化
init=tf.global_variables_initializer()
#运行
sess=tf.Session()
sess.run(init)
for i in range(20000):
	batch= mnist.train.next_batch(50)
	#sess.run(train_step, feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
	sess.run(train_step, feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})
	if i%100 == 0:
		acc_train= sess.run(acc, feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})
		print("step:", i)
		print("acc_train:", acc_train)
print("acc_pre",sess.run(acc, feed_dict={y_: mnist.test.images, h_fc2: mnist.test.labels, keep_prob: 1.0}))
sess.close()

解释
   tf.placeholder(dtype, shape=None, name=None),此函数可以理解为形参,用于定义过程,在执行的时候再赋具体的值,先占位。也是用于存储数据,但是主要用于feed_dict的配合,接收输入数据用于训练模型等。placeholder值在训练过程中会不断地被赋予新的值,用于批训练,基本上其值是不会轻易进行加减操作。手写数字图像是28x28的,分类为10类,所以tf.placeholder(“float”, [None,28,28, 1]), tf.placeholder(“float”, [None,10])。None为样本数,10表示10列。
   tf.Variable(initializer,name),参数initializer是初始化参数,name是可自定义的变量名称。主要是用于给出训练变量的。比如我们经常使用的网络权重,偏置。 值得注意的是Variable在声明是必须赋予初始值。在训练过程中该值很可能会进行不断的加减操作变化。 名称的真实含义,在于变量,也即在真实训练时,其值是会改变的,自然事先需要指定初始值;
   dropout设定:dropout是深度学习中避免过拟合的手段之一,经典网路结构中,dropout都被放到全连接层之后,鲜有放到卷积层之后。这是因为实验证明卷积层后的dropout层对网络泛化能力的改进微乎其微。但是还要设定其在各层的概率。
Dropout就是在不同的训练过程中随机扔掉一部分神经元。也就是让某个神经元的激活值以一定的概率p,让其停止工作,这次训练过程中不更新权值,也不参加神经网络的计算。但是它的权重得保留下来(只是暂时不更新而已),因为下次样本输入时它可能又得工作了。

你可能感兴趣的:(深度学习,神经网络,tensorflow,深度学习)