TF笔记:MNIST For ML Beginners

2017-02-15 Lu Huang 更多博文 » 博客 » GitHub »

tensorflow tf mnist softmax

原文链接 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。

image

可以把图像从二维变成一维,至于怎么降维无所谓,但必须在一个 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$。

同样需要定义权重和偏置,把它们定义成 VariableVariable是可以修改的张量。

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)

参考