Tensorflow官方文档学习理解 (三)-MNIST

MNIST机器学习入门

MNIST是一个入门级的计算机视觉数据集,它包含各种手写数字图片:

它也包含每一张图片对应的标签,告诉我们这个是数字几。在开始之前,我们需要下载数据集:链接:https://pan.baidu.com/s/1J6p8wo5xyymhLhoSyP_X4Q 密码:wzrn

下载来的数据集被分为两个部分,6000行的训练数据集(mnist.train)和1000行的测试数据集(mnist.test)。这样切分是为了让训练的模型能够有更好的泛化能力。MNIST数据集有两部分组成,一张包含手写体的图片,和手写体图片对应的标签。每一张图片是由[28 * 28]个像素点组成的,我们可以用数字数组来将其表示,如下图所示:

这样来看的话,这张图片就是28*28=784维的数据点。如果我们将其展开为一维数据的话,我们就会丢失其中二维结构中的信息,但是以前传统的做法没有利用这些二维的信息,我们先从一维的说起,之后再说如何利用其中的二维信息(卷积神经网络)。

因此6000行的训练数据集可以表示为[6000,784]维的张量,第一个维度的数据用来索引图片,第二个维度的数据用来索引每张图片的像素点。相对应的MNIST数据集的标签是介于0-9的数字,用来描述给定图片里表示的数字。为了适应这个教程,我们使用的标签数据是‘one hot’,形式。一个one hot向量,除了某一位的数字是1以外,其余各维度数字都是0。比如数字0的标签表示为【1 0 0 0 0 0 0 0 0 0】,因此mnist.train.labels是一个【6000 * 10】的数字矩阵。

为了得到一张给定图片属于某个特定数字类型的证据(evidence),我们对图片像素值进行加权求和,如果这个像素具有很强的证据,说明这张图片不属于该类,那么相应的权值为负数,相反,如果这个像素拥有有利证据支持这张图片属于这个类,那么权值是正数。我们也需要增加一些额外的偏置,因为输入往往会带有一些无关的干扰量。

当我们给定输入图片x它代表的数字i的证据可以表示为:

evidence_{i}=\sum W_{i,j}x_{j}+b_{i}

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

y = softmax(evidence)

这里的softmax可以看成是一个激励(activation)函数或者链接(link)函数,把我们定义的线性函数的输出转换成我们想要的格式,也就是关于10个数字类的概率分布。

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

展开等式右边的子式,可以得到:

softmax(x)_{i}=\frac{exp(x_{i})}{\sum _{j}exp(x_{j})}

因此整个流程框图的表示形式如下图所示:

更近一步表示起来的话就是:

y=softmax(Wx+b)

实现回归模型

首先我们需要导入tensorflow:

import tensorflow as tf

接下来我们创建一个占位符,相当于给输入的图片先在会话图中占一个位置:

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

这个张量的形状是[None,784],这里的None表示此张量的第一个维度可以是任意长度的。

我们的模型需要参数,我们当然也可以通过tf.placeholder的方法来将参数传入进去。但是tensorflow有更加方便的方法来处理他们:Variable。一个Variable代表一个可修改的张量,存在在tensorflow用于描述交互性操作的图中。它们可以计算输入值,也可以在计算中被修改。在这里我们定义参数的权重和偏置:

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

在这里我们初始化的时候将权重和偏置全初始化为0,W的维度是[784 10],因为我们想要用784维的图片向量乘以它得到一个10维的向量,每一位对应不同的数字。b的形状是[10],所以我们可以直接把它经过softmax后加到输出上面去。所以我们的输出为:

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

接下来我们就要想怎么来训练我们的模型,使得我们模型的参数能够更加优化,在实现模型的参数更新之前,我们需要定义一个指标来衡量我们模型的好坏,这样的话我们才会有优化的目标。在机器学习中,我们通常定义指标来表示一个模型是坏的,这个指标称为(cost)或损失(loss),然后尽量最小化这个指标。一个非常常见的,非常漂亮的loss函数是“交叉熵”。交叉熵产生于信息论里面的信息压缩编码技术,但是后来演变成为博弈论到机器学习等其他领域里的重要技术手段。

H_{y^{'}}(y)=-\sum y^{'}_{i}log(y_{i})

y是我们预测的概率分布,y^{'}是实际的分布。为了计算交叉熵,我们首先需要添加一个新的占位符用于输入正确值:

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

然后我们可以用- \sum y^{'}log(y),计算交叉熵。

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

tf.reduce_sum是计算张量所有元素的总和。(注意,这里的交叉熵不仅仅用来衡量单一的一对预测和真实值,而是所有100幅图片的交叉熵的总和。对于100个数据点的预测表现比单一数据点的表现能更好地描述我们的模型的性能。)

有了优化目标之后,接下来我们就需要选择优化算法来对其进行优化,在tensorflow中提供了很好地优化算法封装库,这里我们选择其中的梯度下降算法,以0.01的学习率最小化交叉熵:

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

到此为止的话我们已经设置好了我们的模型,接下来我们需要初始化我们的模型

init = tf.global_variables_initializer()

启动我们的模型:

with tf.Session() as sess:
    sess.run(init)

然后开始训练模型,这里我们让模型循环训练1000次!

    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})

在该循环的每个步骤中,我们随机抓取100个数据将其扔入模型中进行训练,这些数据就是通过之前的占位符传入会话图中。

在训练完成之后,我们还希望看一下我们的模型到底训练地怎么样,它的泛化能力好不好。首先我们找出那些预测正确的标签,tf.argmax能给你在一个张量里沿着某条轴的最高条目的索引值。tf.argmax(y, 1)是模型认为每个输入最有可能对应的那些标签,而tf.argmax(y_,1)代表正确的标签。我们可以用tf.equal来检测我们的预测是否与真实标签匹配。

correct_prediction = tf.equal(tf.arg_max(y, 1), tf.arg_max(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:mnist.test.images, y_:mnist.test.labels}))

到此为止我们的所有代码都写完了,准确率大概在91%左右,效果不是很好,之后我们会分享一下卷积神经网络处理手写体的识别,准确率能够达到将近97%。附上完整的代码:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)
import tensorflow as tf
x = tf.placeholder("float", [None, 784])
w = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, w) + b)
y_ = tf.placeholder("float", [None, 10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.global_variables_initializer()
correct_prediction = tf.equal(tf.arg_max(y, 1), tf.arg_max(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
with tf.Session() as sess:
    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})
    print(sess.run(accuracy, feed_dict={x:mnist.test.images, y_:mnist.test.labels}))

猜你喜欢

转载自blog.csdn.net/weixin_39059031/article/details/82827946
今日推荐