TensorFlow识别MNIST数字

MNIST数据集

  MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片:
在这里插入图片描述
它也包含每一张图片对应的标签,告诉我们这个是数字几。例如上面这四张图片的标签分别是5041
  MNIST数据集的官网是http://yann.lecun.com/exdb/mnist/。以下的python源代码用于自动下载和安装这个数据集:

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

下载下来的数据集被分成两部分:60000行的训练数据集(mnist.train)和10000行的测试数据集(mnist.test)。这样的切分很重要,在机器学习模型设计时,必须有一个单独的测试数据集不用于训练,而是用来评估这个模型的性能,从而更加容易把设计的模型推广到其他数据集上。
  每一个MNIST数据单元由两部分组成:一张包含手写数字的图片和一个对应的标签。我们把这些图片设为xs,把这些标签设为ys。训练数据集和测试数据集都包含xsys,比如训练数据集的图片是mnist.train.images,训练数据集的标签是mnist.train.labels

print(mnist.train.images.shape, mnist.train.labels.shape)
print(mnist.test.images.shape, mnist.test.labels.shape)
print(mnist.validation.images.shape, mnist.validation.labels.shape)

  每一张图片包含28 * 28个像素点。我们可以用一个数字数组来表示这张图片:
在这里插入图片描述
把这个数组展开成一个向量,长度是28 * 28 = 784。如何展开这个数组不重要,只要保持各个图片采用相同的方式展开。
  展平图片的数字数组会丢失图片的二维结构信息,这显然是不理想的,最优秀的计算机视觉方法会挖掘并利用这些结构信息。但是在这个教程中,我们忽略这些结构,所介绍的简单数学模型softmax回归不会利用这些结构信息。
  因此,在MNIST训练数据集中,mnist.train.images是一个形状为[60000, 784]的张量,第一个维度数字用来索引图片,第二个维度数字用来索引每张图片中的像素点。在此张量里的每一个元素,都表示某张图片里的某个像素的强度值,值介于01之间。
在这里插入图片描述
  MNIST数据集的标签是介于09之间的数字,用来描述给定图片里表示的数字。我们使标签数据是one-hot向量,一个one-hot向量除了某一位的数字是1以外,其余各维度数字都是0。所以在此教程中,数字n将表示成一个只有在第n维度(从0开始)数字为110维向量。比如,标签0将表示成[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]。因此,mnist.train.labels是一个[60000, 10]的数字矩阵。
在这里插入图片描述

Softmax回归介绍

  MNIST的每一张图片都表示一个数字,我们希望得到给定图片代表每个数字的概率。例如,模型可能推测一张包含9的图片代表数字9的概率是80%,它是8的概率是5%,然后给予它代表其他数字的概率更小的值。
  这是一个使用softmax回归模型的经典案例,softmax模型可以用来给不同的对象分配概率。即使以后需要训练更加精细的模型,最后一步也需要用softmax来分配概率。
  为了得到一张给定图片属于某个特定数字类的证据evidence,我们对图片像素值进行加权求和。如果这个像素具有很强的evidence说明这张图片不属于该类,那么相应的权值为负数;相反,如果这个像素拥有有利的evidence支持这张图片属于这个类,那么权值是正数。下面的图片显示了一个模型学习到的图片上每个像素对于特定数字类的权值,红色代表负数权值,蓝色代表正数权值:

在这里插入图片描述

  我们也需要加入一个额外的偏置量bias,因为输入往往会带有一些无关的干扰量。因此对于给定的输入图片 x x x,它代表的是数字 i i i的证据可以表示为:

e v i d e n c e i = ∑ j W i , j x j + b i evidence_{i} = \sum_{j}W_{i,j}x_{j} + b_{i} evidencei=jWi,jxj+bi

其中 W i W_{i} Wi代表权重, b i b_{i} bi代表数字i类的偏置量, j j j代表给定图片 x x x的像素索引用于像素求和。然后用softmax函数可以把这些证据转换成概率 y y y

y = s o f t m a x ( e v i d e n c e ) y = softmax(evidence) y=softmax(evidence)

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

s o f t m a x ( x ) i = e x p ( x i ) ∑ j e x p ( x j ) softmax(x)_{i} = \frac{exp(x_{i})}{\sum_{j}exp(x_{j})} softmax(x)i=jexp(xj)exp(xi)

  对于softmax回归模型,可以用下面的图解释,对于输入的 x s x_{s} xs加权求和,再分别加上一个偏置量,最后再输入到softmax函数中:
在这里插入图片描述

如果把它写成一个等式,我们可以得到:
在这里插入图片描述
我们也可以用向量表示这个计算过程:用矩阵乘法和向量相加,这有助于提高计算效率:
在这里插入图片描述
更进一步,可以写成更加紧凑的方式:

y = s o f t m a x ( W x + b ) y = softmax(Wx + b) y=softmax(Wx+b)

实现回归模型

  首先载入TensorFlow库,并创建一个新的InteractiveSession,使用这个命令会将这个session注册为默认的session,之后的运算也默认跑在这个session里,不同session之间的数据和运算应该都是相互独立的。接下来创建一个placeholder,即输入数据的地方,其第一个参数是数据类型,第二个参数[None, 784]代表tensorshape,也就是数据的尺寸,这里的None代表不限条数的输入(None表示此张量的第一个维度可以是任何长度的),784代表每条输入是一个784维的向量。

import tensorflow as tf
sess = tf.InteractiveSession()
x = tf.placeholder(tf.float32, [None, 784])

接下来要为softmax模型中的权重值weights和偏置量biases创建VariableVariable用来存储模型参数。我们把weightsbiases全部初始化为0,因为模型训练时会自动学习适合的值,所以对这个简单模型来说初始值并不重要。不过对于复杂的卷积网络、循环网络或比较深的全连接网络,初始化的方法可以说至关重要。注意这里Wshape[784, 10]784是特征的维数,10代表有10类(因为我们想要用784维的图片向量乘以它,以得到一个10维的证据值向量),因为labelone-hot编码后是10维的向量。

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

接下来要实现softmax算法:

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

首先,我们用tf.matmul(x, W)表示x乘以W,对应之前等式里面的 W x Wx Wx,然后再加上 b b b,把和输入到tf.nn.softmax函数里面。

训练模型

  为了训练我们的模型,首先需要定义一个指标来评估这个模型是好的。在机器学习中,我们通常定义指标来表示一个模型是坏的,这个指标称为成本cost或损失loss,然后尽量最小化这个指标,这两种方式是相同的。
  一个非常常见且漂亮的成本函数是交叉熵(cross-entropy)。交叉熵产生于信息论里面的信息压缩编码技术,但是它后来演变成为从博弈论到机器学习等其他领域里的重要技术手段,其定义如下:

H y ′ ( y ) = − ∑ i y i ′ l o g ( y i ) H_{y'}(y) = -\sum_{i}y'_{i}log(y_{i}) Hy(y)=iyilog(yi)

y y y是我们预测的概率分布, y ′ y' y是实际的分布(我们输入的one-hot向量)。
  为了计算交叉熵,我们首先需要添加一个新的占位符用于输入正确值:

y_ = tf.placeholder(tf.float32, [None, 10])

然后计算交叉熵:

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

首先用tf.log计算y的每个元素的对数,接下来把y_的每一个元素和tf.log(y)的对应元素相乘,最后用tf.reduce_sum计算张量的所有元素的总和。注意,这里的交叉熵不仅仅用来衡量单一的一对预测和真实值,而是所有100幅图片的交叉熵的总和(100指的是下面的mini-batch的大小)。对于100个数据点的预测表现,比单一数据点的表现能更好地描述我们的模型的性能。
  现在有了算法softmax的定义,又有了损失函数cross-entropy的定义,只需要再定义一个优化算法即可开始训练,常见采用随机梯度下降SGD。定义好优化算法后,TensorFlow就可以根据我们定义的整个计算图自动求导,并根据反向传播算法(backpropagation algorithm)进行训练,每一轮迭代时更新参数来减小loss。我们直接调用tf.train.GradientDescentOptimizer,并设置学习速率为0.5,优化目标设定为cross-entropy,得到进行训练的操作train_step

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

梯度下降算法gradient descent algorithm是一个简单的学习过程,TensorFlow只是将每个变量一点点地往使成本不断降低的方向移动。当然TensorFlow也提供了其他许多优化算法,只要简单地调整一行代码就可以使用其他的算法。TensorFlow在这里实际上所做的是:它会在后台给描述你的计算的那张图里面增加一系列新的计算操作单元,用于实现反向传播算法和梯度下降算法,然后返回给你的只是一个单一的操作。当运行这个操作时,它用梯度下降算法训练你的模型,微调你的变量,不断减少成本。
  下一步使用TensorFlow的全局参数初始化器tf.global_variables_initializer

sess.run(tf.global_variables_initializer())

最后一步,我们开始迭代地执行训练操作train_step。这里每次都随机从训练集中抽取100条样本构成一个mini-batch,并feedplaceholder

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

  我们已经完成了训练,接下来就对模型的准确率进行验证。tf.argmax是一个非常有用的函数,它能给出某个tensor对象在某一维上的其数据最大值所在的索引值。由于标签向量是由01组成,因此最大值1所在的索引位置就是类别标签,比如tf.argmax(y, 1)返回的是模型对于任一输入x预测到的标签值,而tf.argmax(y_, 1)代表正确的标签。而tf.equal来判断预测的数字是否就是正确的类别(索引位置一样表示匹配),最后返回计算分类是否正确的操作correct_prediction

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

这行代码会输出一组布尔值,为了确定正确预测项的比例,我们可以把布尔值转换成浮点数,然后取平均值。例如[True, False, True, True]会变成[1, 0, 1, 1],取平均值后得到0.75。我们统计全部样本预测的accuracy,这里需要先用tf.cast将之前correct_prediction输出的bool值转换为float32,再求平均:

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

我们将测试数据的特征和label输入评测流程accuracy,计算模型在测试集上的准确率,再将结果打印出来:

print(accuracy.eval({x: mnist.test.images, y_: mnist.test.labels}))

以上是一个没有隐含层的最浅的神经网络,整个步骤分为4个部分:

  1. 定义算法公式,也就是神经网络forward时的计算。
  2. 定义loss,选定优化器,并指定优化器优化loss
  3. 迭代地对数据进行训练。
  4. 在测试集或验证集对准确率进行评测。

  补充说明:如果最后的结果为0.098,则修改文件./tensorflow/contrib/learn/python/learn/datasets/mnist.py,将SOURCE_URLhttps://storage.googleapis.com/cvdf-datasets/mnist/改为http://yann.lecun.com/exdb/mnist/就可以了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值