TensorFlow入门教程(五):MNIST手写数字识别加强版

一、  代价函数

  • 上一节中,我们采用的代价函数为:
    loss = tf.reduce_mean(tf.square(y - prediction))  # 求预测平均误差

如果,将代价函数改为交叉熵代价函数,其训练速度,精度,将更快。(详情百度数学原理)

loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))  # 交叉熵

二、优化器

在网络修改权值时,训练函数的选择是一个重要的因素,决定着训练的快慢和准确度,由下图,不同优化器到大最终点的路径如图所示,所以,采用不同的优化器函数可得到不同的效果

TensorFlow入门教程(五):MNIST手写数字识别加强版

 

三、  Dropout

  • 在数据训练中,长出现以下三种数据拟合情况:

TensorFlow入门教程(五):MNIST手写数字识别加强版

为了防止数据过拟合,在神经网络中,可以引入dropout层进行训练。dropout基本思想就是训练时,让一部分神经元工作,一部分不工作,从而避免了过拟合。

TensorFlow入门教程(五):MNIST手写数字识别加强版

四、  学习率

学习率,即每次修改权值的大小,就像跑步的大步子和小步子。动态的改变学习率,训练前期,使用较大的学习率,可以迅速到达目标的大概位置,后期,使用较小的学习率,可以使得到达时位置更加精确。

五、  代码

本节代码与上节大同小异,只是针对上述提出的内容进行了修改,并且增加了网络的层数。

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data", one_hot=True)  # 载入数据
batch_size = 100  # 每个批次大小
n_batch = mnist.train.num_examples // batch_size  # 批次数目

x = tf.placeholder(tf.float32, [None, 784])
y = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)

# 创建神经网络
lr = tf.Variable(0.001, dtype=tf.float32)
w1 = tf.Variable(tf.truncated_normal([784, 500], stddev=0.1))
b1 = tf.Variable(tf.zeros([500])+0.1)
L1 = tf.nn.tanh(tf.matmul(x, w1)+b1)
L1_drop = tf.nn.dropout(L1, keep_prob)

w2 = tf.Variable(tf.truncated_normal([500, 300], stddev=0.1))
b2 = tf.Variable(tf.zeros([300])+0.1)
L2 = tf.nn.tanh(tf.matmul(L1_drop, w2)+b2)
L2_drop = tf.nn.dropout(L2, keep_prob)

w3 = tf.Variable(tf.truncated_normal([300, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10])+0.1)
prediction = tf.nn.softmax(tf.matmul(L2_drop, w3)+b3)

# 交叉熵代价函数
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=y, logits=prediction))  # 交叉熵

train_step = tf.train.AdamOptimizer(lr).minimize(loss)
init = tf.global_variables_initializer()

# 将结果存放在一个布尔型列表中
correct_prediction = tf.equal(tf.arg_max(y, 1), tf.arg_max(prediction, 1))
# arg_max返回一维张量中最大值所在位置,equal进行是否相等判断,结果为True False
accuary = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# cast将correct_prediction中数据转化为float型,并求均值,计算精确度
with tf.Session() as sess:
    sess.run(init)
    for epoch in range(20):  # 共训练20次
        sess.run(tf.assign(lr, 0.001 * (0.95 ** epoch)))  # 学习率初值为0.001,以后每次训练,学习率都乘以0.95
        for batch in range(n_batch):  # 每次训练完,需要进行多少次
            batch_x, batch_y = mnist.train.next_batch(batch_size)
            sess.run(train_step, feed_dict={x: batch_x, y: batch_y, keep_prob: 0.7})  # keep_prob=0.7,即有70%的神经元工作
            
        learn_rate = sess.run(lr)
        Test_acc = sess.run(accuary, feed_dict={x: mnist.test.images, y: mnist.test.labels, keep_prob: 1})
        print("Iter" + str(epoch) + ",Test_acc" + str(Test_acc) + ",learn_rate" + str(learn_rate))

运行结果:

Iter0,Test_acc0.9374,learn_rate0.001
Iter1,Test_acc0.9491,learn_rate0.00095
Iter2,Test_acc0.9566,learn_rate0.0009025
Iter3,Test_acc0.9591,learn_rate0.000857375
Iter4,Test_acc0.965,learn_rate0.00081450626
Iter5,Test_acc0.9671,learn_rate0.0007737809
Iter6,Test_acc0.9665,learn_rate0.0007350919
Iter7,Test_acc0.9698,learn_rate0.0006983373
Iter8,Test_acc0.9707,learn_rate0.0006634204
Iter9,Test_acc0.9719,learn_rate0.0006302494
Iter10,Test_acc0.9712,learn_rate0.0005987369
Iter11,Test_acc0.9716,learn_rate0.0005688001
Iter12,Test_acc0.9738,learn_rate0.0005403601
Iter13,Test_acc0.9744,learn_rate0.0005133421
Iter14,Test_acc0.9751,learn_rate0.000487675
Iter15,Test_acc0.9755,learn_rate0.00046329122
Iter16,Test_acc0.9751,learn_rate0.00044012666
Iter17,Test_acc0.975,learn_rate0.00041812033
Iter18,Test_acc0.9763,learn_rate0.00039721432
Iter19,Test_acc0.9758,learn_rate0.0003773536

由结果可知,第一次训练,其精确到就达到了93.74%,经过20次训练后,精度为97.5%,比上一节训练结果有了很大提高。