mnist⼿写数字分类的python实现_TensorFlow的MNIST⼿写
数字分类问题基础篇
本章节的阅读对象是对机器学习和 TensorFlow 都不太了解的新⼿.
就像我们学习编程的第⼀步往往是学习敲出 "Hello World" ⼀样,机器学习的⼊门就要知道 MNIST.
MNIST 是⼀个⼊门级的计算机视觉数据集,它包含各种⼿写数字图⽚:
它也包含每⼀张图⽚对应的标签,告诉我们这个是数字⼏;⽐如,上⾯这四张图⽚的标签分别是 5, 0, 4, 1。
在此教程中,我们将训练⼀个机器学习模型⽤于预测图⽚⾥⾯的数字.
我们的⽬的不是要设计⼀个世界⼀流的复杂模型 —— 尽管我们会在之后给你源代码去实现⼀流的预测模型 —— ⽽是要介绍下如何使⽤TensorFlow 所以,我们这⾥会从⼀个很简单的数学模型开始,它叫做 Softmax Regression.
对应这个教程的实现代码很短,⽽且真正有意思的内容只包含在三⾏代码⾥⾯.但是,去理解包含在这些代
码⾥⾯的设计思想是⾮常重要的:TensorFlow ⼯作流程和机器学习的基本概念.因此,这个教程会很详细地介绍这些代码的实现原理.linux文件句柄满了
MNIST 数据集
MNIST 数据集的官⽹是 Yann LeCun's website 在这⾥,我们提供了⼀份 python 源代码⽤于⾃动下载和安装这个数据集.你可以下载 这份代码,然后⽤下⾯的代码导⼊到你的项⽬⾥⾯,也可以直接复制粘贴到你的代码⽂件⾥⾯.import input_data
mnist = ad_data_sets("MNIST_data/", one_hot=True)
下载下来的数据集被分成两部分:60000 ⾏的训练数据集 (ain) 和 10000 ⾏的测试数据集 (st) 这样的切分很重要,在机器学习模型设计时必须有⼀个单独的测试数据集不⽤于训练⽽是⽤来评估这个模型的性能,从⽽更加容易把设计的模型推⼴到其他数据集上(泛化).
正如前⾯提到的⼀样,每⼀个 MNIST 数据单元有两部分组成:⼀张包含⼿写数字的图⽚和⼀个对应的标签我们把这些图⽚设为“xs”,把这些标签设为“ys”.训练数据集和测试数据集都包含 xs 和 ys, ⽐如训练数据集的图⽚是 ain.images ,训练数据集的标签
是 ain.labels.
每⼀张图⽚包含 28 像素 X28 像素.我们可以⽤⼀个数字数组来表⽰这张图⽚:
我们把这个数组展开成⼀个向量,长度是 28 x 28 = 784.如何展开这个数组(数字间的顺序)不重要,只要保持各个图⽚采⽤相同的⽅式展开.从这个⾓度来看, MNIST 数据集的图⽚就是在 784 维向量空间⾥⾯的点, 并且拥有⽐较 复杂的结构 (提醒: 此类数据的可视化是计算密集型的).
展平图⽚的数字数组会丢失图⽚的⼆维结构信息.这显然是不理想的,最优秀的计算机视觉⽅法会挖掘并利⽤这些结构信息,我们会在后续教程中介绍.但是在这个教程中我们忽略这些结构,所介绍的简单数学模型, softmax 回归 (softmax regression), 不会利⽤这些结构信息.
因此,在 MNIST 训练数据集中,ain.images 是⼀个形状为 [60000, 784] 的张量,第⼀个维度数字⽤来索引图⽚,第⼆个维度数字⽤来索引每张图⽚中的像素点.在此张量⾥的每⼀个元素, 都表⽰某张图⽚⾥的某个像素的强度值,值介于 0 和 1 之间.
相对应的 MNIST 数据集的标签是介于 0 到 9 的数字,⽤来描述给定图⽚⾥表⽰的数字。为了⽤于这个教程,我们使标签数据是"one-hot vectors". ⼀个 one-hot 向量除了某⼀位的数字是1以外其余各维度数字都是 0。所以在此教程中, 数字 n 将表⽰成⼀个只有在第 n 维度(从0 开始)数字为 1 的 10 维向量。⽐如, 标签 0 将表⽰成([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).因此, ain.labels 是⼀个 [60000,
10] 的数字矩阵.
现在,我们准备好可以开始构建我们的模型啦!
Softmax 回归介绍
我们知道 MNIST 的每⼀张图⽚都表⽰⼀个数字, 从 0 到 9。我们希望得到给定图⽚代表每个数字的概率.⽐如说,我们的模型可能推测⼀张包含 9 的图⽚代表数字9的概率是 80% 但是判断它是 8 的概率是 5% (因为 8 和 9 都有上半部分的⼩圆),然后给予它代表其他数字的概率更⼩的值.
这是⼀个使⽤ softmax 回归(softmax regression)模型的经典案例。softmax 模型可以⽤来给不同的对象分配概率.即使在之后, 我们训练更加精细的模型时,最后⼀步也需要⽤ softmax 来分配概率.
softmax 回归(softmax regression)分两步:第⼀步
为了得到⼀张给定图⽚属于某个特定数字类的证据(evidence), 我们对图⽚像素值进⾏加权求和.如果这个像素具有很强的证据说明这张图⽚不属于该类,那么相应的权值为负数,相反如果这个像素拥有有利的证据⽀持这张图⽚属于这个类,那么权值是正数。cgmodel cg模型网
下⾯的图⽚显⽰了⼀个模型学习到的图⽚上每个像素对于特定数字类的权值。红⾊代表负数权值, 蓝⾊代表正数权值。
sql数据库查询讲座我们也需要加⼊⼀个额外的偏置量 (bias), 因为输⼊往往会带有⼀些⽆关的⼲扰量。因此对于给定的输⼊图⽚ x 它代表的是数字 i 的证据可以表⽰为
其中
代表权重,
代表数字 i 类的偏置量, j 代表给定图⽚ x 的像素索引⽤于像素求和.然后⽤ softmax 函数可以把这些证据转换成概率 y:
这⾥的 softmax 可以看成是⼀个激励 (activation) 函数或者链接 (link) 函数,把我们定义的线性函数的输出转换成我们想要的格式, 也就是关于 10 个数字类的概率分布。 因此,给定⼀张图⽚, 它对于每⼀个数字的吻合度可以被 softmax 函数转换成为⼀个概率值。softmax 函数可以定义为:
展开等式右边的⼦式, 可以得到:
但是更多的时候把 softmax 模型函数定义为前⼀种形式:把输⼊值当成幂指数求值,再正则化这些结果值。这个幂运算表⽰, 更⼤的证据对应更⼤的假设模型 (hypothesis) ⾥⾯的乘数权重值。反之,拥有更少的证据意味着在假设模型⾥⾯拥有更⼩的乘数系数.假设模型⾥的权值不可以是 0 值或者负值。Softmax 然后会正则化这些权重值,使它们的总和等于1,以此构造⼀个有效的概率分布(更多的关于
Softmax 函数的信息,可以参考 Michael Nieslen 的书⾥⾯的这个部分,其中有关于 softmax 的可交互式的可视化解释)。
对于 softmax 回归模型可以⽤下⾯的图解释,对于输⼊的 xs 加权求和,再分别加上⼀个偏置量,最后再输⼊到 softmax 函数中:
如果把它写成⼀个等式,我们可以得到:
我们也可以⽤向量表⽰这个计算过程:⽤矩阵乘法和向量相加.这有助于提⾼计算效率.(也是⼀种更有效的思考⽅式)
更进⼀步,可以写成更加紧凑的⽅式:
实现回归模型
为了⽤ python 实现⾼效的数值计算,我们通常会使⽤函数库,⽐如 NumPy,会把类似矩阵乘法这样的复杂运算使⽤其他外部语⾔实现.不幸的是,从外部计算切换回 Python 的每⼀个操作,仍然是⼀个很⼤的开销.如果你⽤ GPU 来进⾏外部计算,这样的开销会更⼤.⽤分布式的计算⽅式,也会花费更多的资源⽤来传输数据.
TensorFlow 也把复杂的计算放在 python 之外完成,但是为了避免前⾯说的那些开销,它做了进⼀步完善。Tensorflow 不单独地运⾏单⼀的复杂计算,⽽是让我们可以先⽤图描述⼀系列可交互的计算操作,然后全部⼀起在 Python 之外运⾏(这样类似的运⾏⽅式,可以在不少的机器学习库中看到)。
使⽤ TensorFlow 之前,⾸先导⼊它:import tensorflow as tf
我们通过操作符号变量来描述这些可交互的操作单元,可以⽤下⾯的⽅式创建⼀个:x = tf.placeholder("float", [None, 784])
svg无功补偿价位x 不是⼀个特定的值,⽽是⼀个占位符 placeholder,我们在 TensorFlow 运⾏计算时输⼊这个值.我们希望能够输⼊任意数量的 MNIST 图像,每⼀张图展平成 784 维的向量。我们⽤ 2 维的浮点数张量来表⽰这些图,这个张量的形状是 [None,784 ] (这⾥的 None 表⽰此张量的第⼀个维度可以是任何长度的)。
我们的模型也需要权重值和偏置量,当然我们可以把它们当做是另外的输⼊(使⽤占位符),但 TensorFlow 有⼀个更好的⽅法来表⽰它们:Variable ⼀个 Variable 代表⼀个可修改的张量,存在在 TensorFlow 的⽤于描述交互性操作的图中。它们可以⽤于计算输⼊值,也可以在计算中被修改。对于各种机器学习应⽤,⼀般都会有模型参数,可以⽤ Variable 表⽰。W = tf.s([784,10]))
b = tf.s([10]))
我们赋予 tf.Variable 不同的初值来创建不同的 Variable:在这⾥,我们都⽤全为零的张量来初始化 W 和 b。因为我们要学习 W 和 b 的值,它们的初值可以随意设置。
注意,W 的维度是 [784,10],因为我们想要⽤ 784 维的图⽚向量乘以它以得到⼀个 10 维的证据值向量,每⼀位对应不同数字类。b 的形状是 [10],所以我们可以直接把它加到输出上⾯。
现在,我们可以实现我们的模型啦。只需要⼀⾏代码!y = tf.nn.softmax(tf.matmul(x,W) + b)
⾸先,我们⽤ tf.matmul(X,W) 表⽰ x 乘以 W,对应之前等式⾥⾯的
,这⾥ x 是⼀个 2 维张量拥有多个输⼊。然后再加上 b,把和输⼊到 tf.nn.softmax 函数⾥⾯。
⾄此,我们先⽤了⼏⾏简短的代码来设置变量,然后只⽤了⼀⾏代码来定义我们的模型。TensorFlow 不仅仅可以使 softmax 回归模型计算变得特别简单,它也⽤这种⾮常灵活的⽅式来描述其他各种数值计算,从机器学习模型对物理学模拟仿真模型。⼀旦被定义好之后,我们的模型就可以在不同的设备上运⾏:计算机的 CPU, GPU, 甚⾄是⼿机!
训练模型
为了训练我们的模型,我们⾸先需要定义⼀个指标来评估这个模型是好的.其实,在机器学习,我们通
常定义指标来表⽰⼀个模型是坏的,这个指标称为成本 (cost) 或损失 (loss),然后尽量最⼩化这个指标。但是,这两种⽅式是相同的。
⼀个⾮常常见的,⾮常漂亮的成本函数是“交叉熵”(cross-entropy)。交叉熵产⽣于信息论⾥⾯的信息压缩编码技术,但是它后来演变成为从博弈论到机器学习等其他领域⾥的重要技术⼿段。它的定义如下:
y 是我们预测的概率分布,y' 是实际的分布(我们输⼊的 one-hot vector)。⽐较粗糙的理解是,交叉熵是⽤来衡量我们的预测⽤于描述真相的低效性。更详细的关于交叉熵的解释超出本教程的范畴,但是你很有必要好好理解它.
为了计算交叉熵,我们⾸先需要添加⼀个新的占位符⽤于输⼊正确值:y_ = tf.placeholder("float", [None,10])
然后我们可以⽤计算交叉熵:cross_entropy = -tf.reduce_sum(y_*tf.log(y))python入门教程 非常详细 pdf
⾸先,⽤ tf.log 计算 y 的每个元素的对数。接下来,我们把 y_ 的每⼀个元素和 tf.log(y_) 的对应元素相乘。最后,⽤ tf.reduce_sum 计算张量的所有元素的总和。(注意,这⾥的交叉熵不仅仅⽤来衡量单⼀的⼀对预测和真实值,⽽是所有 100 幅图⽚的交叉熵的总和。对于 100个数据点的预测表现⽐单⼀数据点的表现能更好地描述我们的模型的性能。
现在我们知道我们需要我们的模型做什么啦,⽤ TensorFlow 来训练它是⾮常容易的。因为 TensorFlow 拥有⼀张描述你各个计算单元的图,它可以⾃动地使⽤反向传播算法(backpropagation algorithm)来有效地确定你的变量是如何影响你想要最⼩化的那个成本值的。然后,TensorFlow 会⽤你选择的优化算法来不断地修改变量以降低成本。train_step =
在这⾥,我们要求 TensorFlow ⽤梯度下降算法(gradient descent algorithm)以 0.01 的学习速率最⼩化交叉熵。梯度下降算法(gradient descent algorithm)是⼀个简单的学习过程,TensorFlow 只需将每个变量⼀点点地往使成本不断降低的⽅向移动。当然TensorFlow 也提供了其他许多优化算法:只要简单地调整⼀⾏代码就可以使⽤其他的算法。
TensorFlow 在这⾥实际上所做的是,它会在后台给描述你的计算的那张图⾥⾯增加⼀系列新的计算操作单元⽤于实现反向传播算法和梯度下降算法。然后,它返回给你的只是⼀个单⼀的操作,当运⾏这个操作时,它⽤梯度下降算法训练你的模型,微调你的变量,不断减少成本。
现在,我们已经设置好了我们的模型。在运⾏计算之前,我们需要添加⼀个操作来初始化我们创建的变量:init =
tf.initialize_all_variables()
现在我们可以在⼀个 Session ⾥⾯启动我们的模型,并且初始化变量:sess = tf.Session()
sess.run(init)
然后开始训练模型,这⾥我们让模型循环训练 1000 次!for i in range(1000):
batch_xs, batch_ys = _batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
该循环的每个步骤中,我们都会随机抓取训练数据中的 100 个批处理数据点,然后我们⽤这些数据点作为参数替换之前的占位符来运⾏train_step。
使⽤⼀⼩部分的随机数据来进⾏训练被称为随机训练 (stochastic training) - 在这⾥更确切的说是随机梯度下降训练。在理想情况下,我们希望⽤我们所有的数据来进⾏每⼀步的训练,因为这能给我们更好的训练结果,但显然这需要很⼤的计算开销。所以,每⼀次训练我们可以使⽤不同的数据⼦集,这样做既可以减少计算开销,⼜可以最⼤化地学习到数据集的总体特性。
评估我们的模型
那么我们的模型性能如何呢?
⾸先,让我们出那些预测正确的标签。tf.argmax 是⼀个⾮常有⽤的函数,它能给出某个 tensor 对象在某⼀维上的其数据最⼤值所在的索引值。由于标签向量是由 0, 1 组成,因此最⼤值 1 所在的索引位置就是类别标签,⽐如 tf.argmax(y,1) 返回的是模型对于任⼀输⼊ x 预测到的标签值,⽽ tf.argmax(y_,1) 代表正确的标签,我们可以⽤ tf.equal 来检测我们的预测是否真实标签匹配(索引位置⼀样表⽰匹配)。correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
这⾏代码会给我们⼀组布尔值。为了确定正确预测项的⽐例,我们可以把布尔值转换成浮点数,然后取平均值。例如,[True, False, True, True] 会变成 [1, 0, 1, 1] ,取平均值后得到 0.75。accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
最后,我们计算所学习到的模型在测试数据集上⾯的正确率。print sess.run(accuracy, feed_dict={x: st.images, y_:
这个最终结果值应该⼤约是 91%。
eclipse中jdk配置这个结果好吗?嗯,并不太好。事实上,这个结果是很差的。这是因为我们仅仅使⽤了⼀个⾮常简单的模型。不过,做⼀些⼩⼩的改进,我们就可以得到 97% 的正确率。最好的模型甚⾄可以获得超过 99.7% 的准确率!(想了解更多信息,可以看看这个关于各种模型的性能对⽐列表)。
⽐结果更重要的是,我们从这个模型中学习到的设计思想。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论