Softmax 识别手写数字

TensorFlow 入门(二):Softmax 识别手写数字

MNIST是一个非常简单的机器视觉数据集,如下图所示,它由几万张28像素x28像素的手写数字组成,这些图片只包含灰度值信息。我们的任务就是对这些手写数字的图片进行分类,转成0~9一共十类。

基本步骤

引包侠

from tensorflow.examples.tutorials.mnist import input_data

加载数据

mnist = input_data.read_data_sets('MNIST_data/', one_hot = True)

注意:若提示你的主机中的软件中止了一个已建立的连接,请关闭杀毒软件,以防误报。

你也可以直接从这里下载数据集,并在根目录下建立MNIST_data文件夹。再运行上述代码即可。

数据集探查

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)

# 输出
(55000, 784) (55000, 10)
(10000, 784) (10000, 10)
(5000, 784) (5000, 10)

可以看到训练集有55000个样本,测试集有10000个样本,同时验证集有5000个样本。每一个样本都有对应的标注信息,即label。我们将在训练集上训练模型,在验证集上检验效果并决定何时完成训练,最后我们在测试集评测模型的效果(可通过准确率,召回率,F1-score等评测。)

每一张图片包含28像素X28像素。我们可以用一个数字数组来表示这张图片:

我们把这个数组展开成一个向量,长度是 28x28 = 784。如何展开这个数组(数字间的顺序)不重要,只要保持各个图片采用相同的方式展开。从这个角度来看,MNIST数据集的图片就是在784维向量空间里面的点, 并且拥有比较复杂的结构 (提醒: 此类数据的可视化是计算密集型的)。

这里手写数字识别为多分类问题,因此我们采用Softmax Regression模型来处理。关于Softmax,可以参看这里。你也可以认为它是二分类问题Sigmoid函数的推广。具体形式如下:

yi=ezi∑Kj=1ezjyi=ezi∑j=1Kezj

y_i = \frac{e^{z_i}}{\sum_{j = 1}^K{e^{z_j}}}

表示第i类模型预测的概率(总共有K类),zjzjz^j表示上一层的输出,可以是任意实数。Softmax的好处在于可以把每个类归一化到[0, 1]之间,且所有类的概率之和为1,这样我们可以从中选择最大概率的jjj,来表示模型的输出类别。

关于Softmax的推导可以参看这里。符号不是很严格,但基本能看明白。

咱们继续

我们第一层采用Logistic Regression,一张图片总共有(28 x 28)784个特征,每个特征与一个参数相乘,代表这个特征在此类别上的贡献,可以参看上图。

所以有

zj=∑i=1784wjixi+bjzj=∑i=1784wjixi+bj

z_j =\sum_{i = 1}^{784}w_{ji} x_i + b_j

定义输入向量和会话 首先载入TensorFlow库,并创建一个新的InteractiveSession,使用这个命令将这个session注册为默认的session,之后的运算也默认跑在这个session里,不同session之间的数据和运算应该都是相互独立的。接下来创建一个Placeholder,即输入数据的地方。Placeholder的第一个参数是数据类型,第二个参数[None, 784]代表tensor的shape,也就是数据的尺寸,这里None代表不限条数的输入,784代表每条输入是一个784维的向量。

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

创建变量 定义Sotfmax Regression模型中的weights和biases对象,注意这里的变量是全局性质的,所以使用TensorFlow中的Variable对象。

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

实现Sotfmax Regression算法

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

定义损失函数 采用交叉信息熵,公式如下:

Loss=−∑iy′ilog(yi)Loss=−∑iyi′log⁡(yi)

Loss = -\sum_{i} y'_i \log(y_i) 其中y′iyi′y'_i表示真实值,yiyiy_i表示预测的概率。

y_ = tf.placeholder(tf.float32, [None, 10])
loss = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices = [1]))

先定义一个placeholder,输入真实的label,用来计算cross entropy。tf.reduce_sum也就是求和的∑∑\sum, 而tf.reduce_mean则用来对每个batch数据结果求平均。

定义优化算法 类似与梯度下降算法,此处我们采用随机梯度下降SGD,能够更快的收敛,且容易跳出局部最优解。

# 学习速率为0.5
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss)

运行

tf.global_variables_initializer().run()

一切准备就绪,喂数据

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

模型验证

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval({x : mnist.test.images, y_ : mnist.test.labels}))

# 输出
0.922

注意:前两行都只是定义,还未真正的执行,最后eval才是执行的代码。0.922的准确率,对于只有一层的Logistic Regression多分类已经不错了。

总结

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券