深度学习系列第三篇 — MNIST数字识别
这一节将上一节学到的深度神经网络的概念运用起来,通过 tf 来实现 MNIST 手写字识别。
首先导入 tf 库和训练数据:
1 | import tensorflow as tf |
定义全局初始常量,其中 INPUT_NODE 数为每一张图片 28 * 28 的像素数,OUTPUT_NODE 就是分类的个数 10; LAYER1_NODE 为隐藏层节点数,BATCH_SIZE 为每次训练数据的个数;LEARNING_RATE_BASE 为基础学习率,LEARNING_RATE_DECAY 为学习率的衰减率,REGULARIZATION_RATE 为正则化损失函数的系数,TRAINING_STEPS 为训练的次数,MOVING_AVERAGE_DECAY 为滑动平均衰减率。
1 | INPUT_NODE = 784 |
定义一个 inference 函数用来计算神经网络的向前传播结果,并且通过 RELU 函数实现了去线性化。avg_class 参数是用来支持测试时使用滑动平均模型,当我们使用了滑动平均模型时,weights 和 biases 值都是从 avg_class 中取出的。
1 | def inference(input_tensor, avg_class, weights1, biases1, weights2, biases2): |
定义输入层,生成隐藏层和输出层参数
1 | x = tf.placeholder(tf.float32, [None, INPUT_NODE]) |
计算当前参数下神经网络向前传播的效果。
1 | y = inference(x, None, weights1, biases1, weights2, biases2) |
这里通过滑动平均衰减率和训练次数初始化这个类,用来加快训练早期变量的更新速度;global_step 为动态存储训练次数。
1 | global_step = tf.Variable(0, trainable=False) |
variables_averages_op 这里将所有的神经网络的上参数使用滑动平均,对于指定 trainable=False 的参数不作用。计算使用了滑动平均模型处理的向前传播结果。
1 | variables_averages_op = variable_averages.apply(tf.trainable_variables()) |
计算损失。交叉熵用来刻画预测值与真实值差距的损失函数,我们再通过 softmax 回归将结果变成概率分布。tf 提供了将这两个函数合并使用的函数,第一个参数是向前传播的结果,第二个参数是训练数据的答案。然后计算所有样例的交叉熵平均值。
1 | cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1)) |
这里使用 L2 正则化损失函数,计算模型的正则化损失,计算权重的,不计算偏置。正则化损失函数用来避免过拟合。
1 | regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE) |
最后得出的总损失等于交叉熵损失和正则化损失之和。
1 | loss = cross_entropy_mean + regularization |
设置指数衰减的学习率。
1 | learnging_rate = tf.train.exponential_decay( |
使用优化算法优化总损失。
1 | train_step = tf.train.GradientDescentOptimizer(learnging_rate).minimize(loss, global_step=global_step) |
每过一次数据需要更新一下参数。
1 | with tf.control_dependencies([train_step, variables_averages_op]): |
检验使用了滑动平均模型的向前传播结果是否正确。
1 | correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1)) |
计算平均准确率。
1 | accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) |
最后开始我们的训练,并验证数据的准确率。
1 | with tf.Session() as sess: |
开始训练的过程,首先初始化所有变量。
1 | tf.global_variables_initializer().run() |
MNIST 数据分为训练数据、验证数据和测试数据。我们先准备好验证数据和测试数据,因为数据量不大,可以直接将全部数据用于训练。然后开始我们的迭代训练,训练数据有很多,我们每次训练只取一部分数据进行训练,这样减小计算量,加速神经网络的训练,又不会对结果产生太大影响。
tf 的训练通过 sess.run 函数,第一个参数是最终要计算的,也就是公式的输出,第二个参数 feed 是 placeholder 的输入。
1 | sess.run(train_op, feed_dict={x: xs, y_: ys}) |
通过一次次的训练,总损失会越来越小,模型的预测越来越准确,到达一个临界点。
完整代码如下:
1 | import tensorflow as tf |
Extracting MNIST_data/train-images-idx3-ubyte.gz
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
训练轮数: 0 ,准确率: 9.20000001788 %
训练轮数: 1000 ,准确率: 97.619998455 %
训练轮数: 2000 ,准确率: 98.0799973011 %
训练轮数: 3000 ,准确率: 98.2599973679 %
训练轮数: 4000 ,准确率: 98.1999993324 %
训练轮数: 5000 ,准确率: 98.1800019741 %
训练轮数: 6000 ,准确率: 98.2400000095 %
训练轮数: 7000 ,准确率: 98.2200026512 %
训练轮数: 8000 ,准确率: 98.1999993324 %
训练轮数: 9000 ,准确率: 98.2599973679 %
训练轮数: 10000 ,准确率: 98.2400000095 %
训练轮数: 11000 ,准确率: 98.2400000095 %
训练轮数: 12000 ,准确率: 98.1599986553 %
训练轮数: 13000 ,准确率: 98.2599973679 %
训练轮数: 14000 ,准确率: 98.299998045 %
训练轮数: 15000 ,准确率: 98.4200000763 %
训练轮数: 16000 ,准确率: 98.2800006866 %
训练轮数: 17000 ,准确率: 98.3799993992 %
训练轮数: 18000 ,准确率: 98.3600020409 %
训练轮数: 19000 ,准确率: 98.3200013638 %
训练轮数: 20000 ,准确率: 98.3399987221 %
训练轮数: 21000 ,准确率: 98.3799993992 %
训练轮数: 22000 ,准确率: 98.400002718 %
训练轮数: 23000 ,准确率: 98.400002718 %
训练轮数: 24000 ,准确率: 98.4200000763 %
训练轮数: 25000 ,准确率: 98.3200013638 %
训练轮数: 26000 ,准确率: 98.4200000763 %
训练轮数: 27000 ,准确率: 98.3799993992 %
训练轮数: 28000 ,准确率: 98.400002718 %
训练轮数: 29000 ,准确率: 98.3200013638 %
训练轮数: 30000 ,准确率: 98.3900010586 %
下一节总结 准确率、交叉熵平均值、总损失、学习率、平均绝对梯度 的变化趋势。