算法实现过程的详细介绍

之前在Tensorflow实战一种实现完整的Softmax Regression(没有隐含层),并在MNIST数据集种取得了大概92%的准确率。现在我们要给神经网络加上隐藏层,并使用减轻过拟合的Dropout,自适应学习速率的Adagrad,以及可以解决梯度弥散问题的激活函数ReLU。

  1. 首先载入Tensorflow并加载MNIST数据集。创建一个Tensorflow默认的Interactive Session,这样后面的操作就不需要指定Session了。
#MLP多层感知机
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
sess = tf.InteractiveSession()
  1. 接下来我们要给隐含层的参数设置Variable并进行初始化,这里in_units是输入节点,h1_units是隐含层的输出节点设为300,W1,b1是隐含层的权重和偏置,我们将偏置全部赋值为0,并将权重初始化为截断的正太分布,其标准差为0.1,这一步可以通过tf.truncated_normal方便得实现。因为模型使用了ReLU,所以需要正态分布给参数加一点噪声来打破完全对称和避免0梯度(dead relu),不过在这里的作用不太明显。而对最后输出层的Softmax,直接将权重W2和偏置b2全部初始化为0即可。
#设置隐藏层参数及初始化
in_units = 784
h1_units = 300
w1 = tf.Variable(tf.truncated_normal([in_units, h1_units], stddev=0.1))
b1 = tf.Variable(tf.zeros([h1_units]))
w2 = tf.Variable(tf.zeros([h1_units, 10]))
b2 = tf.Variable(tf.zeros([10]))
  1. 定义输入x的placeholder。另外,因为在训练和预测时,Dropout的比率keep_prob(即保留节点的概率)是不一样的,通常在训练时小于1,而预测时则等于1,所以也把Dropout的比率作为计算图的输入,申请一个placeholder。
x = tf.placeholder(tf.float32, [None, in_units])
keep_prob = tf.placeholder(tf.float32)
  1. 下面定义模型结构。首先需要一个隐含层,命名为hidden1,可以通过tf.nn.relu(tf.matmul(x, W1)+b1)来实现一个激活函数为ReLU的隐含层,这个隐含层的计算公式就是 y = r e l u ( W 1 x + b 1 ) y=relu(W_1x+b_1) y=relu(W1x+b1),接下来调用tf.nn.dropout实现Dropout的功能,即随机的将一部分节点置为0,这里的keep_prob参数即为保留数据而不置0的比例,在训练时应该是小于1的,用于制造随机性,防止过拟合。在预测是等于1,使用全部特征来预测样本的类别。最后是输出层,即是Softmax,这一行代码的功能和实战1中是一致的。
#定义模型结构
hidden1 = tf.nn.relu(tf.matmul(x, w1) + b1)
hidden1_drop = tf.nn.dropout(hidden1, keep_prob)
y = tf.nn.softmax(tf.matmul(hidden1_drop, w2) + b2)
  1. 定义损失函数和优化器,这里损失函数还是使用交叉熵损失函数,优化器选择自适应的Adagrad,并把学习率设置为0.3,这里直接调用tf.train.AdagradOptimizer就可以了。
#定义损失函数和选择优化器
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
train_step = tf.train.AdagradOptimizer(0.3).minimize(cross_entropy)
  1. 开始训练,训练的时候keep_prob设置为0.75,因为加入了隐含层,我们需要更多的训练迭代来优化模型参数以达到一个较好的效果。这里一共采用了3000个batch,每个batch包含100个样本,一共30万的样本,相当于对全数据集进行了5轮(epoch)迭代。
#训练
tf.global_variables_initializer().run()
for i in range(3000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    train_step.run({x: batch_xs, y_:batch_ys, keep_prob: 0.75})
  1. 计算准确率,这里把kee_prob直接设置为1即可。
#计算准确率
correct_prediction = tf.equal(tf.arg_max(y, 1), tf.arg_max(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval({x:mnist.test.images, y_:mnist.test.labels, keep_prob:1.0}))
  1. 最终我们再测试集上可以达到98%的准确率,相比于Softmax,我们的误差由8%降到了2%。

算法完整代码

#coding=utf-8
#MLP多层感知机
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
sess = tf.InteractiveSession()
#设置隐藏层参数及初始化
in_units = 784
h1_units = 300
w1 = tf.Variable(tf.truncated_normal([in_units, h1_units], stddev=0.1))
b1 = tf.Variable(tf.zeros([h1_units]))
w2 = tf.Variable(tf.zeros([h1_units, 10]))
b2 = tf.Variable(tf.zeros([10]))

x = tf.placeholder(tf.float32, [None, in_units])
keep_prob = tf.placeholder(tf.float32)
#定义模型结构
hidden1 = tf.nn.relu(tf.matmul(x, w1) + b1)
hidden1_drop = tf.nn.dropout(hidden1, keep_prob)
y = tf.nn.softmax(tf.matmul(hidden1_drop, w2) + b2)
#定义损失函数和选择优化器
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
train_step = tf.train.AdagradOptimizer(0.3).minimize(cross_entropy)
#训练
tf.global_variables_initializer().run()
for i in range(3000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    train_step.run({x: batch_xs, y_:batch_ys, keep_prob: 0.75})
#计算准确率
correct_prediction = tf.equal(tf.arg_max(y, 1), tf.arg_max(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
print(accuracy.eval({x:mnist.test.images, y_:mnist.test.labels, keep_prob:1.0}))