深度神经网络之MNIST数字识别

这一节将上一节学到的深度神经网络的概念运用起来,通过 tf 来实现 MNIST 手写字识别。

上一节地址: 深度神经网络学习笔记


首先导入 tf 库和训练数据:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)


定义全局初始常量,其中 INPUT_NODE 数为每一张图片 28 * 28 的像素数,OUTPUT_NODE 就是分类的个数 10; LAYER1_NODE 为隐藏层节点数,BATCH_SIZE 为每次训练数据的个数;LEARNING_RATE_BASE 为基础学习率,LEARNING_RATE_DECAY 为学习率的衰减率,REGULARIZATION_RATE 为正则化损失函数的系数,TRAINING_STEPS 为训练的次数,MOVING_AVERAGE_DECAY 为滑动平均衰减率。

INPUT_NODE = 784
OUTPUT_NODE = 10
LAYER1_NODE = 500
BATCH_SIZE = 100
LEARNING_RATE_BASE = 0.8
LEARNING_RATE_DECAY = 0.99
REGULARIZATION_RATE = 0.0001
TRAINING_STEPS = 30000
MOVING_AVERAGE_DECAY = 0.99


定义一个 inference 函数用来计算神经网络的向前传播结果,并且通过 RELU 函数实现了去线性化。avg_class 参数是用来支持测试时使用滑动平均模型,当我们使用了滑动平均模型时,weights 和 biases 值都是从 avg_class 中取出的。

def inference(input_tensor, avg_class, weights1, biases1, weights2, biases2):
    if avg_class is None:
        layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)
        return tf.matmul(layer1, weights2) + biases2
    else:
        layer1 = tf.nn.relu(tf.matmul(input_tensor, avg_class.average(weights1)) + avg_class.average(biases1))
        return tf.matmul(layer1, avg_class.average(weights2)) + avg_class.average(biases2)


定义输入层,生成隐藏层和输出层参数

x = tf.placeholder(tf.float32, [None, INPUT_NODE])
y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE])
weights1 = tf.Variable(tf.truncated_normal([INPUT_NODE, LAYER1_NODE], stddev=0.1))
biases1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE]))
weights2 = tf.Variable(tf.truncated_normal([LAYER1_NODE, OUTPUT_NODE], stddev=0.1))
biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]))


计算当前参数下神经网络向前传播的效果。

y = inference(x, None, weights1, biases1, weights2, biases2)


这里通过滑动平均衰减率和训练次数初始化这个类,用来加快训练早期变量的更新速度;global_step 为动态存储训练次数。

global_step = tf.Variable(0, trainable=False)
variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)


variables_averages_op 这里将所有的神经网络的上参数使用滑动平均,对于指定 trainable=False 的参数不作用。计算使用了滑动平均模型处理的向前传播结果。

variables_averages_op = variable_averages.apply(tf.trainable_variables())
average_y = inference(x, variable_averages, weights1, biases1, weights2, biases2)


计算损失。交叉熵用来刻画预测值与真实值差距的损失函数,我们再通过 softmax 回归将结果变成概率分布。tf 提供了将这两个函数合并使用的函数,第一个参数是向前传播的结果,第二个参数是训练数据的答案。然后计算所有样例的交叉熵平均值。

cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
cross_entropy_mean = tf.reduce_mean(cross_entropy)


这里使用 L2 正则化损失函数,计算模型的正则化损失,计算权重的,不计算偏置。正则化损失函数用来避免过拟合。

regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
regularization = regularizer(weights1) + regularizer(weights2)


最后得出的总损失等于交叉熵损失和正则化损失之和。

loss = cross_entropy_mean + regularization


设置指数衰减的学习率。

learnging_rate = tf.train.exponential_decay(
    LEARNING_RATE_BASE, global_step, mnist.train.num_examples / BATCH_SIZE, LEARNING_RATE_DECAY)


使用优化算法优化总损失。

train_step = tf.train.GradientDescentOptimizer(learnging_rate).minimize(loss, global_step=global_step)


每过一次数据需要更新一下参数。

with tf.control_dependencies([train_step, variables_averages_op]):
    train_op = tf.no_op()


检验使用了滑动平均模型的向前传播结果是否正确。

correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1))


计算平均准确率。

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))


最后开始我们的训练,并验证数据的准确率。

with tf.Session() as sess:
    # 初始化全部变量
    tf.global_variables_initializer().run()
    # 准备验证数据
    validate_feed = {x: mnist.validation.images,
                    y_: mnist.validation.labels}
    # 准备测试数据
    test_feed = {x: mnist.test.images, y_: mnist.test.labels}
    # 迭代
    for i in range(TRAINING_STEPS):
        if i % 1000 == 0:
            # 使用全部的验证数据去做了验证
            validate_acc = sess.run(accuracy, feed_dict=validate_feed)
            print "训练轮数:", i, ",准确率:", validate_acc * 100, "%"
        # 取出一部分训练数据
        xs, ys = mnist.train.next_batch(BATCH_SIZE)
        # 训练
        sess.run(train_op, feed_dict={x: xs, y_: ys})
    # 计算最终的准确率。
    test_acc = sess.run(accuracy, feed_dict=test_feed)
    print "训练轮数:", TRAINING_STEPS, ",准确率:", test_acc * 100, "%"


开始训练的过程,首先初始化所有变量。

tf.global_variables_initializer().run()


MNIST 数据分为训练数据、验证数据和测试数据。我们先准备好验证数据和测试数据,因为数据量不大,可以直接将全部数据用于训练。然后开始我们的迭代训练,训练数据有很多,我们每次训练只取一部分数据进行训练,这样减小计算量,加速神经网络的训练,又不会对结果产生太大影响。

tf 的训练通过 sess.run 函数,第一个参数是最终要计算的,也就是公式的输出,第二个参数 feed 是 placeholder 的输入。

sess.run(train_op, feed_dict={x: xs, y_: ys})


通过一次次的训练,总损失会越来越小,模型的预测越来越准确,到达一个临界点。

完整代码如下:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
# MNIST数据集相关常数,其中输入节点数为每一张图片 28 * 28 的像素数,输出的节点数就是分类的个数 10; LAYER1_NODE 为隐藏层节点数,
# BATCH_SIZE 为每次训练数据的个数;LEARNING_RATE_BASE 为基础学习率,LEARNING_RATE_DECAY 为学习率的衰减率,
# REGULARIZATION_RATE 为正则化损失函数的系数,TRAINING_STEPS 为训练的次数,MOVING_AVERAGE_DECAY 为滑动平均衰减率
INPUT_NODE = 784
OUTPUT_NODE = 10
LAYER1_NODE = 500
BATCH_SIZE = 100
LEARNING_RATE_BASE = 0.8
LEARNING_RATE_DECAY = 0.99
REGULARIZATION_RATE = 0.0001
TRAINING_STEPS = 30000
MOVING_AVERAGE_DECAY = 0.99
# 这个函数用来计算神经网络的向前传播结果,并且通过 RELU 函数实现了去线性化。avg_class 参数是用来支持测试时使用滑动平均模型。
def inference(input_tensor, avg_class, weights1, biases1, weights2, biases2):
    if avg_class is None:
        layer1 = tf.nn.relu(tf.matmul(input_tensor, weights1) + biases1)
        return tf.matmul(layer1, weights2) + biases2
    else:
        layer1 = tf.nn.relu(tf.matmul(input_tensor, avg_class.average(weights1)) + avg_class.average(biases1))
        return tf.matmul(layer1, avg_class.average(weights2)) + avg_class.average(biases2)
# 输入层
x = tf.placeholder(tf.float32, [None, INPUT_NODE])
y_ = tf.placeholder(tf.float32, [None, OUTPUT_NODE])
# 生成隐藏层参数
weights1 = tf.Variable(tf.truncated_normal([INPUT_NODE, LAYER1_NODE], stddev=0.1))
biases1 = tf.Variable(tf.constant(0.1, shape=[LAYER1_NODE]))
# 生成输出层参数
weights2 = tf.Variable(tf.truncated_normal([LAYER1_NODE, OUTPUT_NODE], stddev=0.1))
biases2 = tf.Variable(tf.constant(0.1, shape=[OUTPUT_NODE]))
# 计算当前参数下神经网络向前传播的效果。
y = inference(x, None, weights1, biases1, weights2, biases2)
# 这个变量用来存储当前训练的次数。
global_step = tf.Variable(0, trainable=False)
# 这里通过滑动平均衰减率和训练次数初始化这个类,用来加快训练早期变量的更新速度。
variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
# 这里将所有的神经网络的上参数使用滑动平均,对于指定 trainable=False 的参数不作用。
variables_averages_op = variable_averages.apply(tf.trainable_variables())
# 计算使用了滑动平均模型处理的向前传播结果。
average_y = inference(x, variable_averages, weights1, biases1, weights2, biases2)
# 计算交叉熵,用来刻画预测值与真实值差距的损失函数,第一个参数是向前传播的结果,第二个是训练数据的答案。
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
# 计算所有样例的交叉熵平均值。
cross_entropy_mean = tf.reduce_mean(cross_entropy)
# 计算 L2 正则化损失函数
regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
# 计算模型的正则化损失,计算权重的,不计算偏置。
regularization = regularizer(weights1) + regularizer(weights2)
# 总损失等于交叉熵损失和正则化损失之和。
loss = cross_entropy_mean + regularization
# 设置指数衰减的学习率。
learnging_rate = tf.train.exponential_decay(
    LEARNING_RATE_BASE, global_step, mnist.train.num_examples / BATCH_SIZE, LEARNING_RATE_DECAY)
# 使用优化算法优化总损失。
train_step = tf.train.GradientDescentOptimizer(learnging_rate).minimize(loss, global_step=global_step)
# 每过一次数据需要更新一下参数。
with tf.control_dependencies([train_step, variables_averages_op]):
    train_op = tf.no_op()
# 检验使用了滑动平均模型的向前传播结果是否正确。
correct_prediction = tf.equal(tf.argmax(average_y, 1), tf.argmax(y_, 1))
# 计算平均准确率。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
if __name__ == "__main__":
    with tf.Session() as sess:
        # 初始化全部变量
        tf.global_variables_initializer().run()
        # 准备验证数据
        validate_feed = {x: mnist.validation.images,
                        y_: mnist.validation.labels}
        # 准备测试数据
        test_feed = {x: mnist.test.images, y_: mnist.test.labels}
        # 迭代
        for i in range(TRAINING_STEPS):
            if i % 1000 == 0:
                # 使用全部的验证数据去做了验证
                validate_acc = sess.run(accuracy, feed_dict=validate_feed)
                print "训练轮数:", i, ",准确率:", validate_acc * 100, "%"
            # 取出一部分训练数据
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            # 训练
            sess.run(train_op, feed_dict={x: xs, y_: ys})
        # 计算最终的准确率。
        test_acc = sess.run(accuracy, feed_dict=test_feed)
        print "训练轮数:", TRAINING_STEPS, ",准确率:", test_acc * 100, "%"
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 %

笔记结束,如有错误还望帮忙指正。下一节总结 准确率、交叉熵平均值、总损失、学习率、平均绝对梯度 的变化趋势。


最后,欢迎大家关注我的专栏 『知一周曝』,我会继续给大家分享开发生涯中的学习总结和生活感悟,一起探讨提高~~
我的个人学习笔记地址: 『Noogel's notes』,这里会先发布我平时的学习笔记,整理后会发到我的专栏。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值