Tensorflow 是 Google 的一个开源机器学习学习框架,基于 数据流图 进行计算,里面包含了一些封装好的算法,例如 SGD(随机梯度下降)、CNN、RNN 等,用起来还是很方便的。走进Tensorflow系列文章计划从Mnist数据集开始,逐步入门 Tensorflow 。由于我也是刚刚接触 Tensorflow,文章里有什么不正确的地方,希望大家能多多指正。
Mnist 数据集
Mnist 是一个手写数字图片的数据库,里面包含了 60000 张训练数据集、10000 张测试数据集,数据集里有图片和对应的 label(标签),并且所有手写数字图片都是 28x28 尺寸的灰度图,Mnist 包含下面四部分:
train-images-idx3-ubyte.gz : training set images (9912422 bytes)
train-labels-idx1-ubyte.gz : training set labels (28881 bytes)
t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)
t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)
手写字体长这个样子
点击Mnist数据集下载就可以进入Mnist数据集网站下载,如果下载有困难的话可以私信我。
但是你下载下来的这四个压缩包并不是这种图片,而是描述图像的二进制数据,有关 Mnist 数据集的解析,这里不做重点,下面会用 Tensorflow 提供的函数进行解析。
Tensorflow 解析 Mnist 数据集
Tensorflow 的安装就不多说了,这个是官方的安装教程。
安装完成后,导入 Tensorflow 的 「python」包(当然,官方还提供了其他编程语言的API),像下面这样:
就说明 Tensorflow 安装成功了,下面开始解析 Mnist 数据集:
from tensorflow.examples.tutorials.mnist import input_data
file = "/data_public/mnist/" #你存放 Mnist 数据集的路径
mnist = input_data.read_data_sets(file, one_hot=True)
解析后分为两部分, mnist.train 和 mnist.test,分别代表训练集和测试集。
利用 Tensorflow 识别 Mnist 中的手写字
首先用比较简单的训练模型 Softmax 回归,关于 Softmax 回归的知识,以后会单独拿出来细讲,这里只做简单说明。一张手写字图片代表的数字有 0~9 十种可能性,Softmax 回归可以推测出该手写字图片分别为 0~9 的可能性,即一张为 6 的手写字图片,经 Softmax 推测后后,得到改图片中数字为 6 的概率为 80% ,为 5 的概率为10%,为其他数字的概率为更小的值。
Tensorflow中提供了 Softmax 回归的函数,下面开始构建 Tensorflow 的计算图。
首先导入 Tensorflow 模块。
import tensorflow as tf
然后设置一个 占位符 用来输入图像 x .
x = tf.placeholder(tf.float32,shape=[None,784],name='x')
这里输入数据的 shape 为什么是[None,784],None 代表数据的第一维,即列所在维度可以是任意长度,784 代表一张 28x28 的图片铺展为一行,去除了维度方面的信息。
同理,还需要设置一个 占位符 用来输入图像的标签(label).
y_ = tf.placeholder(tf.float32,shape=[None,10],name='y_')
前面说过,每张手写体图片的代表的数字有 10 种可能性,所以 y_ 的 shape 为[None,10]
除了这些输入数据,还需要设置模型的权重 w 和偏置 b 。对于这两个可变的参数,就不用占位符来设置了,而是用 tf.Variable 来表示它们。
w = tf.Variable(tf.zeros[784,10])
b = tf.Variable(tf.zeros[10])
可能有人会问,为什么 w 的 shape 是[784,10] ,因为每张手写体图片的代表的数字有 10 种可能性,每张 28x28 的图片被铺展为一行 784 个像素,将 w 的shape设置为 [784,10] ,目的是计算出每张图片在每种可能性上表现出来的证据值。
下面直接使用 Softmax 函数。
y = tf.nn.softmax(tf.matmul(w,x) + b)
tf.matmul(w,x) 代表的是 w 和 x 做矩阵乘。
这样,我们就定义好了我们的模型,但是还缺一个损失函数,模型训练就是通过最小化损失函数来求模型的权重 w 和偏置 b 的。这里用的是交叉熵(cross-entropy)损失函数,函数形式如下。
yi 是预测的概率分布, y' 是实际的概率分布。
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
为了最小化损失函数,需要用到反向传播 思想,这里用的是 SGD (随机梯度下降)算法来最小化损失函数。
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
这里的 0.01 指的是学习率。
这样,我们的计算图就构建好了,下面开始运行我们的计算图。首先初始化一下变量。
init = tf.initialize_all_variables()
然后在一个 Session 里运行。
sess = tf.Session()
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})
mini_batch 为 100 ,即每次往里送 100 张图片,一共送 1000 次结束。
为了评估我们的模型,需要计算出模型的准确率。
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print (sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
tf.argmax(y,1) 是返回第二维(行方向)上最大值的索引,tf.equal() 是比较两个值是否相等,返回一个 bool 值(True or False),tf.cast() 是将bool 值转换为 1.0 or 0.0 的浮点类型,tf.reduce_mean() 是计算平均值。
到此为止,实现了一个简单的 Tensorflow 识别手写字模型的训练。下一节,用 CNN 实现手写字的识别。