TF笔记:MNIST For ML Beginners
原文链接 https://hlthu.github.io/tensorflow/2017/02/15/tf-learn-mnist-beginners.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。
来源于 tensorflow.org,源码在 这里。这是为 TensorFlow 和机器学习初学者定制的 tutorial。
The MNIST Data
下载与读取数据:
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
数据被分成三个部分: 55,000 个训练数据 (mnist.train
), 10,000 个测试数据 (mnist.test
), and 5,000 个交叉数据集 (mnist.validation
).
每个MNIST数据包括一个图像和一个标注:
We'll call the images "x" and the labels "y".
比如训练数据图片是 mnist.train.images
,训练数据的标注是 mnist.train.labels
. 每一幅图的大小都是 28$$ \times $$28。
可以把图像从二维变成一维,至于怎么降维无所谓,但必须在一个 project 中保持一致,变成一维后即成为了一个 784 维的向量。但是这样做的话会导致图像丢失一些信息,即某像素的邻域信息。比如,训练集会变成一个 55000$$\times$$784 的矩阵,每一行即代表一个图像数据。
至于标签,则变成一个 10 维的向量,只有一个地方为 1,即代表该标签为这个 index。
Softmax 回归
Softmax 回归包括两个步骤;
- 在某些类中加入输入的 evidence。
$$ \text{evidence}i = \sum_j W{i,~ j} x_j + b_i $$
- 将 evidence 转换成归一化的概率分布。 $$ y = \text{softmax}(\text{evidence}) $$
其中 $$W_{i,j}$$ 是权重,$$b_i$$ 是类 $$i$$ 的偏置,$$j$$ 是输入一个数据的维度索引,即 1~784,$$y$$ 就是预测的概率分布。可以这样理解:Softmax 对其输入求幂,然后将其归一化。
$$ \text{softmax}(x)_i = \frac{\exp(x_i)}{\sum_j \exp(x_j)} $$
下图以一个 3 维的输入为例,表示了 Softmax 的计算过程。
写成公式
写成矩阵形式
更简洁的表示
$$ y = \text{softmax}(Wx + b) $$
实现 Regression
先 import tf
import tensorflow as tf
首先定义输入 $x$
x = tf.placeholder(tf.float32, [None, 784])
x
并不是一个特定的值,而是一个占位符(placeholder
),当 run 的时候我们会告诉 TF,因为我们想输入的是 784 维的向量,但是个数不确定,这里 None
表示可以是任何数量。在这里 x
的维度是 $n\times 784$。
同样需要定义权重和偏置,把它们定义成 Variable
,Variable
是可以修改的张量。
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
其中他们都被初始化维0,$$W$$ 是 $784\times 10$,$$b$$ 是 $10$ 维的。
用下面的命令实现这个模型
y = tf.nn.softmax(tf.matmul(x, W) + b)
训练
首先为了训练模型,我们需要定义什么才意味着模型足够好。通常我们定义损失函数(loss)来表示当前模型和预期结果的差距,损失函数越小越好。
通常,交叉熵(cross-entropy)是一个比较好的函数。
$$ H_{y'}(y) = -\sum_i y'_i \log(y_i) $$
其中 $$y$$ 是预测的概率分布,$$y'$$是真实的概率分布(只有一个位置为1)。
为了使用交叉熵,先定义一个 placeholder
作为正确的答案。
y_ = tf.placeholder(tf.float32, [None, 10])
然后是实现交叉熵函数
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
由于 reduction_indices=[1]
,tf.reduce_sum
只在第2维做加法,即大小 10 的那个维度。
在源码中,我们是用的是函数 tf.nn.softmax_cross_entropy_with_logits
。
下面让 TF 开始训练
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
In this case, we ask TensorFlow to minimize cross_entropy using the gradient descent algorithm with a learning rate of 0.5
之后我们还需要定义一个操作来初始化我们定义的变量。
init = tf.global_variables_initializer()
然后就是启动一个 Session
sess = tf.Session()
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})
模型评估
tf.argmax(y,1)
是模型预测出来的结果, tf.argmax(y_,1)
是正确的结果。可以用 tf.equal
来比较是否相等。
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
下面是定义计算精确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
然后就是给出结果
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
一般大约会在 92% 左右。
完整代码
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import argparse
import sys
# Import data
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
FLAGS = None
def main(_):
mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)
# Create the model
x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.matmul(x, W) + b
# Define loss and optimizer
y_ = tf.placeholder(tf.float32, [None, 10])
# The raw formulation of cross-entropy,
#
# tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.nn.softmax(y)),
# reduction_indices=[1]))
#
# can be numerically unstable.
#
# So here we use tf.nn.softmax_cross_entropy_with_logits on the raw
# outputs of 'y', and then average across the batch.
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y, y_))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
sess = tf.InteractiveSession()
# Train
tf.global_variables_initializer().run()
for _ in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
# Test trained model
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(sess.run(accuracy, feed_dict={x: mnist.test.images,
y_: mnist.test.labels}))
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--data_dir', type=str, default='./data',
help='Directory for storing input data')
FLAGS, unparsed = parser.parse_known_args()
tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)