基于Tensorflow的MNIST机器学习

来源:互联网 发布:软件订阅模式 编辑:程序博客网 时间:2024/05/17 20:31

程序其实不难,这篇文章我主要基于这个demo本身进行讲解,先不扯Tensorflow这个工具,也不讲这个demo对机器学习怎么怎么入门。很多人包括我一开始,对这个简单的demo本身还没理解,更别说机器学习和Tensorflow了。

我分以下3部分讲:

一、demo要做什么,此处用到的数据源是什么样的以及怎样获取

二、模型分析

三、运用Tensorflow处理该模型

一、demo要做什么,此处用到的数据源是什么样的以及怎样获取

我们要做的是训练一个数字图片识别模型,有点像破解验证码的程序:给定含有0–9的数字手写图片(目前不能上传自己的图片,只能用数据源提供的图片,因为训练样本有限,是28*28像素的图片集),然后能够用这个模型去识别图片中的数字是什么,比如能识别下图数字为5,0,4,1

这里写图片描述

这4张图片都来自于一个叫MNIST的数据集,不要在意MNIST是什么,只要知道可以通过input_data.py下载我们要的数据就好,在主程序中是这么引入它的:

from tensorflow.examples.tutorials.mnist import input_datamnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

这样可以把图片数据读到mnist变量中,该数据包含60000行的训练数据(train*)和10000行的测试数据(t10k*),如下图所示:

这里写图片描述

训练数据和测试数据又各自分为一一对应的图片数据和标签数据,图片是28*28的象素点,标签是0–9的数字,图片和标签相互对应着,这就是别人采集好的MNIST数据集,如上图所示。可以看到,标签数据文件大小明显比图片文件要小很多,而且(train*)文件也明显比(t10k*)小得多,因为测试数据只有10000行,而训练数据60000行。测试数据是当模型训练好之后,供测试模型训准确率之用,这也是为啥不要我们自己再提供图片来测试,因为它们模型都是基于28*28像素的图片训练出来的,如果要支持第三方图片识别,需做额外复杂的处理,不在本文讨论范畴。
Note:如果训练过程中出现如下报错,请先在Mnist官网下载此数据集导入本地文件夹后再重新开始训练

URLError: <urlopen error [WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。>

二、模型分析

模型主要还是围绕象素点来进行研究,把训练数据集的图片数据和标签数据分开,每张图片是28*28的象素点,可以用784长度的数组来存,于是训练数据的图片可以用60000*784的二维数组表示,60000代表图片的张数。因为每张代表一个数字,所以标签数据集可以用长度为10的数组表示,例如数字0表示为[1,0,0,0,0,0,0,0,0],5表示为[0,0,0,0,1,0,0,0,0],专业术语叫one-hot向量,于是标签数据集可以用60000*10的二维数组表示。

784个像素点构成一张图片,每张图片表示0–9的数字,我们要建立的模型就是从最小单元像素为出发点,印射到0–9的数字,有点高中所学的点动成线线动成面的意思。所以如果不考虑象素点之间的干扰,可以粗糙的建立一个模型:0–9每个数字,对应784个权值,分别代表该数字印射到各个象素点的权重,比如6这张图片对应的784个权重,分别对应着该数字到各个象素点的映射,可以理解为数字是由象素点构成的,此处印射只是对”构成“这个动作的量化,于是权W可以写成10*784的二维数组。也可以对”构成“这个动作进一步抽取,得到某种函数对应关系,如下:

这里写图片描述
其中evidence(i)代表该图片是数字i的可能性,0<=i<=9,或者说是证据,j从1到784的象素点进行求和,0 < j <784,Wi,j代表数字i对应象素点j的权值,考虑到某些数字图片输入的偏差,b(i)代表数字i对应的偏置量,我个人理解b(i)是针对诸如数字0和8,数字6和9等等这些个别数字有自己的一个特性,所以需要加入一个偏置量。接着用如下公式对上述证据值做一个概率拟合。

这里写图片描述

softmax函数
softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,可以看成概率来理解,从而来进行多分类!形象的如下图表示:

这里写图片描述

softmax直白来说就是将原来输出是3,1,-3通过softmax函数一作用,就映射成为(0,1)的值,而这些值的累和为1(满足概率的性质),那么我们就可以将它理解成概率,在最后选取输出结点的时候,我们就可以选取概率最大(也就是值对应最大的)结点,作为我们的预测目标!

举一个例子:比如有10个输出神经元,那么就有10个动作,1动作,2动作,3动作…一直到10动作。(根据每个状态(输入),来预测动作(得到概率最大的输出),最终得到的一系列动作序列就可以完成任务),比如在一次的输出过程中输出结点的值是如下:

[0.2,0.1,0.05,0.1,0.2,0.02,0.08,0.01,0.01,0.23]

那么我们就知道这次我选取的动作是动作10,因为0.23是这次概率最大的,那么怎么理解多分类呢?很容易,如果你想选取俩个动作,那么就找概率最大的俩个值即可~(这里只是简单的告诉大家softmax在实际问题中一般怎么应用)

切回正题,反映一张图片对应0–9的概率分布Y值如下:
这里写图片描述

进一步可以写成如下公式(满足矩阵相乘规则):

这里写图片描述

简记如下:
这里写图片描述

这个one-hot向量Y,代表对该图片预测出来的数字。如果已知该图片的真实数字y,那我们要做的是“尽可能让Y等于y”。利用交叉熵知识,我们可以把“尽可能让Y等于y”抽取出数学表达式,如下:

这里写图片描述

即“尽可能让Y等于y”就是要上述公式的值Hy(Y)尽可能的小。

总结如下:

我们训练的目的就是求W和B,W一共有10*784个值,B一共有10个值,使得交叉熵Hy(Y)的值越来越小。

做法如下:

我们把W和B的值都初始化为0,然后用训练数据集的图片去训练,对单张训练图片而言,转化为数学问题就是:已知该图片的象素点集合X,套用上述一系列公式,可以计算得到一个代表0–9数字的one-hot向量Y,再配合已知该图片实际代表的数字0–9的向量y(比如0表示为[1,0,0,0,0,0,0,0,0]),把Y和y代入上述交叉熵的公式,得到值Hy(Y),通过不断调整W和B的值,使得Hy(Y)最小化。

三、运用Tensorflow处理该模型

如果没听说过Tensorflow,建议去网上了解下,然后花5分钟快速阅读下基本用法…5分钟过去了…假设你终于知道Tensorflow是干啥的了,比如知道啥叫节点、预设定、Feed和session.run()。然后我们来建立上述模型。Tensorflow通俗的说就是先预设定好变量、公式和要达到的目的,把这些统统程序化,等一切准备就绪后,输入参数启动整个训练程序。

1、x = tf.placeholder("float", [None, 784])理解为一个拥有N张图片,每张图片拥有784个象素点的的变量,等下模型跑起来,作为输入变量。

2、W = tf.Variable(tf.zeros([784,10])) 这是需要调整的权值W,它包含10*784个值,因为0–9每个数字到784个象素点之间都有一个权分量,该值在对多张训练图片进行训练后得到交叉熵Hy(Y),通过该值大小,反过来对W不断进行调整。

3、b = tf.Variable(tf.zeros([10]))0–9每个数字都有一个偏置量,跟W一样,也需要不断反馈调整,该值容易理解,第一段已作过解释。

4、Y = tf.nn.softmax(tf.matmul(x,W) + b) 设定该公式,通过初始化的W和B,以及每次循环的训练图片集,预测数该图片属于0–9哪个数字。

5、y = tf.placeholder("float", [None,10]) 给定图片真实代表0–9哪个数字,等下模型跑起来,作为输入变量。(公式和代码的Y,y感觉颠倒了,不要在意细节,知道就好)

6、cross_entropy = -tf.reduce_sum(y*tf.log(Y)) 设定该公式,求交叉熵。

7、train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) 设定该公式,表示整个训练过程采用梯度下降算法来使上述交叉熵值最小。0.01为学习速率,个人认为可以理解为步长,即导数中的自变量移动大小。

8、init = tf.initialize_all_variables()sess.run(init)初始化设定好的程式。

接下来启动训练:

for i in range(1000):batch_xs, batch_ys = mnist.train.next_batch(100)sess.run(train_step, feed_dict={x: batch_xs, y: batch_ys})

这里训练了1000次,每次从mnst库中拿取100张图片来训练,把这100张图片的象素点存在batch_xs变量,把图片代表的0–9数字存在batch_ys变量,然后作为输入启动程式。

最后运用下面3句,用测试数据集测试该模型的准确率:

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(Y,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))print sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})

我本地训练10次,每次的准确率如下图,准确率基本在91%左右:

这里写图片描述