TensorFlow中的MINST分类代码解析

关于tensorflow的第一堂课,课程只是一小半,更重要的是课后作业,如果你对课后有任何想法,可以将你的代码和尝试发邮件到guoruidong517@126.com。

要想学好深度学习界最最火的tensor-flow就要从这个名字讲起。而本教程的目的就是通过一行一行的讲解MINST代码,让你了解tensor-flow的基本构成。短短十几行代码,就可以实现深度学习,是不是很期待。

**Tensor-flow是围绕着图构建出来的,**不然这个名字中的flow怎么解释。要想了解tensor-flow,就要将这些代码想象成画图的构成,先选好纸,搭好想画的图的骨架,然后上色,最后将图拿去给懂行的人去评价。

我们要看的例子是熟悉机器学习的人都会遇到的手写数字识别,专业一点的叫法是MINST数据集。(放MINST数据集的介绍图片)这份数据集包括55000行训练用点数据集(mnist.train),10000行测试数据集(mnist.test),以及5000行验证数据集(mnist.validation),每一张图片包含28*28像素.我们可以用一个数字数组来表示这张图片,每一个MNIST数据单元有两部分组成:一张包含手写数字的图片和一个对应的标签.我们把这些图片设为“xs”,把这些标签设为“ys”.训练数据集和测试数据集都包含xs和ys,比如训练数据集的图片是mnist.train.images,训练数据集的标签是mnist.train.labels.(这里可以有代码,语速可以快一点)

importinput_data
2mnist = input_data.read_data_sets(“MNIST_data/”, one_hot=True)

这两行代码是用来自动下载MINST数据集,不必深究。

import tensorflow as tf

这行代码是用来导入tensorflow模块的,相当于找了一张画纸

下来我们要做的给我们的画搭好骨架,就是告诉程序要做哪些准备工作

x = tf.placeholder(“float”, [None, 784])

这里的占位符(placeholder)是tensor-flow中最常用的一个概念,这句话告诉程序,x这个变量是一个类型为浮点数的一个向量,长度为784,为啥是784了,那是因为我们的数据是28像素*28的图,而28*28就是784.我们的神经网络,要将每一个像素变成一个输入。

那这里x又是为啥叫x,x是未知数的意思,而对于tensor-flow来说,未知的也就是原始的数据集,即输入的MINST数据。那None又是什么意思了,没有,那就是不知道了,所以这里的None指的是这里申请的矩阵长度不确定,宽为784.

W = tf.Variable(tf.zeros([784,10]))
b = tf.Variable(tf.zeros([10]))

如果你要的是可以变化的值,那么在设置tensor-flow的时候,就需要设置为变量variable,这里变量的命名是有学问的,w是weight的缩写,b是bias的缩写,我觉得要想代码可读,命名最好要写完整点的。

你也许会问,这里784我懂,那10又是为啥了?这里的10指代的是从784个像素中选取10个特征值,每一位对应不同数字类。

接下来的一步是画龙点睛的一步,也就是告诉tensor-flow上面定义好的到底要怎么连接起来

y = tf.nn.softmax(tf.matmul(x,W) + b)

这句有点复杂,我们先从括号最里面看起,tf.matmul(X,W)表示x乘以W,matmul分开就是matrix multiplication的意思,再将这一步得到的特征值加上bias,作为softmax函数的输入。

这里的softmax可以看成是一个激励(activation)函数或是链接(link)函数,把我们定义的线性函数的输出转换成我们想要的格式,也就是关于10个数字类的概率分布.因此,给定一张图片,它对于每一个数字的吻合度可以被softmax函数转换成为一个概率值.softmax函数可以定义为:

softmax(x) = normalize(exp(x))

Normalize,翻译出来就是标准化,就是保证各个softmax的值加起来为一,而要做到这个,就需要除以各个值指数化后的加和。

这些都搞不懂,那没关系,tensor-flow会给你搞定,而且不管是用CPU还是GPU,你都不用操心,tensor-flow作为一门高级语言,可以以灵活的方式来描述其他各种数值计算,一旦被定义好之后,我们的模型就可以在不同的设备上运行。

下面要确定的是该怎么定义要优化的值,也就是神经网络要学习的是什么,这里要引入交叉熵的概念,比较粗糙的理解是,交叉熵是用来衡量我们的预测用于描述真相的低效性.要想学好深度学习,最好要深入理解交叉熵,这个我们会在之后的课程中详细来讲这个概念。

y = tf.placeholder(“float”, [None,10])

这里新定义的占位符长度位置,宽度为10,是我们要是我们预测的概率分布,下一句有点复杂

cross_entropy = tf.reduce_sum(y_*tf.log(y))

还是从括号最里面来看,这里y_*tf.log(y)中后一项是tensor-flow计算出的概率分布,前一项是实际的上各个图形属于那个数字的概率分布。而这就是交叉熵公式中Sum中的部分。将其作为reduce_sum的输入,这个函数计算(tensor)张量的所有元素的总和。

值得强调的是,值得注意的是,这里的交叉熵不仅仅用来衡量单一的一对预测和真实值,而是所有100幅图片的交叉熵的总和.对于100个数据点的预测表现比单一数据点的表现能更好地描述我们的模型的性能。这也是为啥定义占位符y时将其长度设为None, 未知的原因。

现在我们知道我们需要我们的模型做什么啦,用TensorFlow来训练它是非常容易的.因为TensorFlow拥有一张描述你各个计算单元的图,它可以自动地使用反向传播算法(backpropagation algorithm)来有效地确定你的变量是如何影响你想要最小化的那个成本值,也就是我们之前说的交叉熵.然后,TensorFlow会用你选择的优化算法来不断地修改变量以降低成本.

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(

cross_entropy)

这里给定要用的优化算法是最常见的梯度下降。这是一个简单的学习过程,TensorFlow只需将每个变量一点点地往使成本不断降低的方向移动.当然TensorFlow也提供了其他许多优化算法:只要简单地调整一行代码就可以使用其他的算法.

TensorFlow在这里实际上所做的是,它会在后台给描述你的计算的那张图里面增加一系列新的计算操作单元用于实现反向传播算法和梯度下降算法。当运行这个操作时,它用梯度下降算法训练你的模型,微调你的变量,也就是要学习的weight和bias,以达到不断减少交叉熵的目的,最终提高判断的准确度。

现在,我们已经设置好了我们的模型.在运行计算之前,我们需要添加一个操作来初始化我们创建的变量:就是这一句了

init = tf.initialize_all_variables()

图的框架画完了,找一个session,相当于将画装裱起来,然后run起来,tensor flow就帮你实现例如反向传播算法,梯度下降等的细节了。

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

开始训练模型,这里我们让模型循环训练1000次!随机抓取训练数据中的100个批处理数据点,然后我们用这些数据点作为参数替换之前的占位符来运行train_step
foriin range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

我们的模型性能如何呢?

correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

tf.argmax(y,1)是模型认为每个输入最有可能对应的那些标签,而tf.argmax(y_,1)代表正确的标签.我们可以用tf.equal来检测我们的预测是否真实标签匹配.

accuracy = tf.reduce_mean(tf.cast(correct_prediction, “float”))

这一行将上一行得出的类似[True, False, True, True]会变成[1,0,1,1],取平均值后得到0.75 .

最后,我们计算所学习到的模型在测试数据集上面的正确率.

print sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.

test.labels})

最终结果值应该大约是91%。

总结一下,TensorFlow是一个以图(graphs)来表示计算的编程系统,图中的节点被称之为op (operation 的缩写).一个op获得零或多个张量(tensors)执行计算,产生零或多个张量。 张量是一个按类型划分的多维数组。

TensorFlow编程可按两个阶段组织起来:构建阶段和执行阶段;前者用于组

织计算图,而后者利用session中执行计算图中的op操作。

构建过程完成后就可运行执行过程。为了载入之前所构建的图,必须先创建一个

会话对象(Session object)。会话构建器在未指明参数时会载入默认的图。

TensorFlow事实上通过一个“翻译”过程,将定义的图转化为不同的可用计算资源间实现分布计算的操作,如CPU或是显卡GPU。

课后作业

难度1星

利用python的函数,按照图的构建,图的参数设置,图的执行,以及效果评价,将上面提到的程序改成由4个函数组成的程序。

难度2星

改变训练集的个数,将训练集,测试集,验证集的个数等比例缩小为之前的25%,50%,75%,在其他条件不变的情况下,记录程序所消耗的时间以及预测准确度,给出相应的折现图。

难度3星

我们将0 4 6 8 9 这5个数字定义为有封闭空间的数字, 将 1 2 3 5 7定义为没有封闭空间的数字,修过程序,做出尽可能少的改变,让你的神经网络能够学习到数字是否包含封闭空间这个概念,并给出预测的准确度。

扩展阅读

神经网络的跨学科盛宴

循环神经网络RNN打开手册

呆呆2017-03-07 21:58:22

学好深度学习,好赞!其实我很懵逼/糗大了/糗大了

大胡子2017-03-07 23:06:49

写的不错,加油,一直关注!

志2017-03-08 11:06:19

tf.initialize_all_variables() 这个api已经不建议使用了

王诗君2017-03-07 19:52:34

MNIST名字打错了喂…

作者

好吧,是的

0IIIIIII0 大佳2017-03-07 19:37:41

解释的不错,赞

天下大共和2017-03-07 19:33:03

沙发!