TensorFlow学习笔记【二】 手写数字识别入门

〇、

文章总是改来改去,其实也是各个地方找到,看到的东西拿过来拼拼凑凑,主要还是给自己看的吧。
第一部分 主要的算法解读
第二部分 Python 代码的实现
第三部分 对代码和细节的解读

一、模型构建

softmax 函数(归一化指数函数),能将任意一个含有任意实数的 K 维向量 z 投射到另一个 K 维实向量 σ(z) 中,使得每一个元素的范围都在 (0, 1) 之间,并且所有元素的和为1。

$$
\sigma(\mathbf{z})j = \frac{e^{z_j}}{\sum{k=1}^{K}e^{z_k}},\quad j=1,\dots,K
$$

MNIST中的每一张 28*28 的图片都表示一个手写数字,从0到9,为了得到给定图片代表每个数字的概率,我们使用 softmax 回归(softmax regression),为每个不同的对象(数字)分配概率。

对图片像素值进行加权求和。如果这个像素具有很强的证据说明这张图片不属于该类,那么相应的权值为负数,相反如果这个像素拥有有利的证据支持这张图片属于这个类,那么权值是正数。

图为,对每个数字图片上的像素点进行学习,得到每个像素对于特定数字类的权值。红色代表负数权值,蓝色代表正数权值。

此外,还要添加一个偏置量(bias),b,来排除输入数据中的干扰量。

$$
evidence_i = \sum_j \mathbf{W}_{i,j}x_j+b_i
$$

然后用 softmax 函数将其转换为概率:

$$
y = softmax(evidence)
$$

二、Python实现

作为数据集数据文件本身没有使用标准的图片格式存储,因此需要使用输入数据的代码(在这里下载)来手动解压。

训练和验证的 python 代码如下(TensorFlow中文社区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import input_data
import tensorflow as tf

# 自动下载 MNIST 数据集, 表示为 one_hot 向量
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 任意数量的展平的图像张量作为输入值
x = tf.placeholder("float", [None, 784])

# weight 和 bias 的 Variable 对象,用来存储模型参数,在每轮迭代时被更新,初始化为 0,
# (在这个简单方法中初始值不太重要)
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

# 建立 softmax 回归模型
y = tf.nn.softmax(tf.matmul(x,W) + b)

# 计算交叉熵的输入值
y_ = tf.placeholder("float", [None, 10])

# 计算交叉熵
cross_entropy = -tf.reduce_sum(y_*tf.log(y))

# 反向传播算法 (backpropagation algorithm)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)


# 执行运行计算
init = tf.global_variables_initializer()

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

# 评估模型的正确率
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}))


三、一点解读

从公式到 Tensorflow 的“翻译”:
loss function,Loss 越小表示模型行的分类结果与真实值的偏差越小,即模型越精准。这里使用了交叉熵 Cross-entropy 作为 loss function,其公式如下。

\begin{equation}
H_{y’}(y)=- \sum_iy’_i log(y_i)
\end{equation}

这里的 y’ 是输入的真实 label,在代码中定义一个 placeholder,label 是用 one-hot 编码的,因此我们将检查输入数据的格式是否为“[None, 10]”,10 维向量。求和为 tf.reduce_sum,“翻译”成 Python 代码为:

1
2
# 计算交叉熵
cross_entropy = -tf.reduce_sum(y_*tf.log(y))

定义优化算法,使用随机梯度下降 SGD(Stochastic Gradient Descent),此时,前面构建的公式自动构成了计算图,tensorflow根据此计算图进行自动求导,通过反向传播算法(back propagation)进行训练,通过减少 loss 来更新模型的参数。

1
2
# 反向传播算法 (backpropagation algorithm)
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

最后迭代的执行训练操作 train_step。此处用从训练集抽取的 100 条样本构成 batch,feed 给前面预留的输入 placeholder,进行训练。此方法可以减少计算量,避免不容易跳出局部最优的现象,收敛速度也比全样本训练要快很多。

1
2
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

完成训练,对模型的准确率进行验证,使用 tf.argmax() ,它的第一个参数是 tensor,第二个参数是 axis,即“寻找的方向”,一维向量则为0。此函数在这里的作用是寻找 tensor 中最大值的索引号,对于 y 来说,就是预测的结果中可能性最大的那个分类结果。然后用 tf.equal 来判断是否和正确的类型相同。以此来评价算法的准确率。
(argmax(f(x)) 函数的含义是使 f(x) 取得最大值的自变量 x 的值。)

回忆一下上面的步骤,利用 Tensorflow 实现机器学习算法的一般步骤如下:
(1)定义算法公式;
(2)定义 loss function,选择优化器,指定优化器来优化 loss;
(3)迭代地对数据进行训练;
(4)在测试集或验证集上对准确率进行评价。