【TensorFlow】神经网络MNIST手写识别

来源:互联网 发布:锦尚中国的源码怎么样 编辑:程序博客网 时间:2024/05/18 23:14

项目稍有停歇,终于有时间来玩一下TensorFlow和DL了。看了官网入门教程就先来说说神经网络吧。

1.MNIST数据集

MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片,如下图:官网在此
MNIST例图
MNIST包含四个部分:一个训练图片集,一个训练标签集,一个测试图片集,一个测试标签集。下载下来后解压四个文件都是二进制文件,需要转换才能看到真实的图片。
每一个MNIST数据单元有两部分组成:一张包含手写数字的图片和一个对应的标签,每一张图片包含28X28个像素点。

2.神经网络

神经网络其实是一种算法,能够提供给我们一种复杂的非线性模型Hw,b(x),并以此来拟合我们的数据。又因为它的构造和处理信息的模式有点像人类,这让神经网络更显得神奇。

  • 基本结构
    先从最简单的说起,只有一个神经元的神经网络。
    这里写图片描述
    这就是一个简单的神经网络,图中的圆圈圈就是一个神经元。对于一个复杂的,多层的神经网络来说,一个神经元可以有多个输入和一个输出;每个神经元的输入即可以是其他神经元的输出,也可以是整个神经网络的输入。所谓的神经网络结构就是指不同神经元之间的连接结构。神经元结构的输出就是所有输入的加权和,不同输入的权重就是神经元的参数。
    一个多层的神经网络

  • 基本流程
    数据从输入层输入,在隐藏层进行加权变换,最后在输出层进行输出。神经网络的优化过程就是优化神经元中参数取值的过程。
    每个神经元都可以代表一种特定的输出函数,例如上面的h(x)=Wx+b。我们也称之为激励函数(Activation Function),又由于每次输入多多少少会带点噪声,那么我们则需要在后面上一个偏置(bias)。本文的激励函数我们选用softmax。

流程图

  • softmax回归模型
    softmax模型是logistic回归模型在多分类问题上的推广,在多分类问题中,类标签 y可以取两个以上的值。 由于MNIST是要辨识10个数字,所以该模型非常适合处理这个问题。值得一提的是,softmax是有监督。在Softmax回归中将 x 分类为类别 j 的概率为:这里写图片描述 使得所有概率之和为 1 。

3.TensorFlow变量

神经网络中的参数weight和bias是实现分类和回归问题中重要的部分。在TensorFlow中,tf.Variable的作用就是保存和更新神经网络中的参数。下面来看下TensorFlow中是如何生成和初始化变量的。
例子:

weight = tf.Variable(tf.random_normal([2, 3], 1, stddev=2, seed=1, name='weight'))

这段代码就会产生一个2x3的矩阵,矩阵中的元素是均值为1,标准差为2,随机种子为1,别名叫’weight’的随机数。通过正态分布的随机数来初始化神经网络中的参数一个非常常用的方法。还有一些其他的随机数生成器。

函数名称 随机数分布 主要参数 tf.random_normal 正态分布 平均值,标准差,取值类型 tf.truncated_normal 正态分布,当如果随机出来的值偏离平均值超过2个标准差,那么这个数将被重新随机 平均值,标准差,取值类型 tf.random_uniform 平均分布 最小,最大取值,取值类型 tf.random_gamma Gamma分布 形状参数Alpha,尺度参数beta,取值类型

TensorFlow也支持通过常数来初始化变量

函数名称 功能 例子 tf.zeros 产生全0数组 tf.zeros([2,3],int32)==>[[0,0,0],[0,0,0]] tf.ones 产生全1数组 tf.ones([2,3],int32)==>[[1,1,1],[1,1,1]] tf.fill 产生一个全为给定数字的数组 tf.fill([2,3],3)==>[[3,3,3,],[3,3,3]] tf.constant 产生一个给定常量 tf.constant([1,2,3])==>[1,2,3]

当声明好变量后必须调用初始化语句,并运行

init = tf.global_variables_initializer()sess = tf.Session()sess.run(init)

4.MNIST识别

第一步:导入数据,初始化参数

import tensorflow.examples.tutorials.mnist.input_data as input_datamnist = input_data.read_data_sets("MNIST_data/", one_hot=True)# x 不是一个特定的值,而是一个占位符 placeholder ,我们在TensorFlow运行计算时输入这个值x = tf.placeholder(tf.float32, [None, 784])  y_ = tf.placeholder(tf.float32, shape=[None, 10])  # 用于输入标签真正的值W = tf.Variable(tf.zeros([784, 10]))  # 初始化权值Wb = tf.Variable(tf.zeros([10]))  # 初始化偏置项b

第二步:实现回归模型(使用前向传播法获取预测值)

# tf.matmul(X,W) 表示 x 乘以 W ,对应之前等式里面的Wx+b;这里x是一个2维张量拥有多个输入。然后再加上b,把和输入到 tf.nn.softmax 函数里面。y = tf.nn.softmax(tf.matmul(x, W) + b)

第三步:训练模型(使用反向传播更新参数)
为了训练我们的模型,我们首先需要定义一个指标来评估这个模型的好坏,它与实际值之间的差异,也可以理解为预测的准不准。这个指标可以由一个成本函数得出,这里选用交叉熵(cross-entropy)作为成本函数。交叉熵越大说明准确度不够,反之说明准备度比较准。公式如下:
这里写图片描述
代码如下:

cross_entropy = -tf.reduce_sum(y_ * tf.log(y)  # 求交叉熵

使用梯度下降法来反向传播更新参数,使交叉熵越来越小

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)  # 用梯度下降法使得交叉熵最小

第四步:评估模型

# argmax 给出某个tensor对象在某一维上的其数据最大值所在的索引值。由于标签向量是由0,1组成,因此最大值1所在的索引位置就是类别标签correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))  #检测我们的预测是否真实标签匹配(索引位置一样表示匹配)accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))  # 确定正确预测项的比例,我们可以把布尔值转换成浮点数,然后取平均值。

完整代码:

import tensorflow as tfimport tensorflow.examples.tutorials.mnist.input_data as input_datamnist = input_data.read_data_sets("MNIST_data/", one_hot=True)x = tf.placeholder(tf.float32, [None, 784])  # x 不是一个特定的值,而是一个占位符 placeholder ,我们在TensorFlow运行计算时输入这个值y_ = tf.placeholder(tf.float32, shape=[None, 10])  # 用于输入正确值W = tf.Variable(tf.zeros([784, 10]))  # 初始化权值Wb = tf.Variable(tf.zeros([10]))  # 初始化偏置项b# tf.matmul(X,W) 表示 x 乘以 W ,对应之前等式里面的Wx+b;这里 x 是一个2维张量拥有多个输入。然后再加上 b ,把和输入到 tf.nn.softmax 函数里面。y = tf.nn.softmax(tf.matmul(x, W) + b)cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))  # 求交叉熵train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)  # 用梯度下降法使得交叉熵最小# argmax 给出某个tensor对象在某一维上的其数据最大值所在的索引值。由于标签向量是由0,1组成,因此最大值1所在的索引位置就是类别标签correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))  # 检测我们的预测是否真实标签匹配(索引位置一样表示匹配)accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))  # 确定正确预测项的比例,我们可以把布尔值转换成浮点数,然后取平均值。print(accuracy)init = tf.global_variables_initializer()with tf.Session() as sess:    sess.run(init)    for i in range(10000):  # 训练阶段,迭代1000次        batch_xs, batch_ys = mnist.train.next_batch(100)  # 按批次训练,每批100行数据        sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})  # 执行训练        if (i % 50 == 0):  # 每训练100次,测试一次            print("accuracy:", sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))

5.小结

上面的程序实现了MNIST手写识别,虽然是最基本的神经网络,但是也基本上囊括了训练神经网络的过程,总结一下:
1.定义神经网络结构和前向传播的输出结果
2.定义成本函数以及选择反向传播的优化算法
3.生成Session并且在训练集上反复运行反向传播优化算法
无论神经网络结构怎么变,这3个步骤是不会变的!

0 0
原创粉丝点击