Tensorflow Mnist手写数字识别学习(二)
前言
与手写字体识别(一)相比,本文将定义全连接层的过程封装到函数 中,并增加几层隐藏层,其余无太大变化。
准备工作
%matplotlib inline
import matplotlib.pyplot as plt
import tensorflow as tf
import tensorflow.examples.tutorials.mnist.input_data as input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
由于使用jupyter notebook,若不加入%matplotlib inline
,图片将不会在notebook中显示。
其中read_data_sets("MNIST_data/", one_hot=True)
的第一个参数是数据集保存的位置,第二个参数决定数据是否采用独热编码。因为是分类问题,一般使用独热编码,设置其参数为
。如果此时该目录下没有数据文件,那么将花费几分钟下载后再读取;如果有数据文件,则会自动读取。
定义全连接层函数
def fcn_layer(inputs, outputs_nodes, activate=None):
# 获取输入节点数
inputs_nodes = int(inputs.shape[1])
W = tf.Variable(tf.random_normal([inputs_nodes, outputs_nodes], stddev=0.1),name="W")
b = tf.Variable(tf.zeros([outputs_nodes]),name="b")
Y = tf.matmul(inputs,W) + b
if activate==None:
return Y
else:
return activate(Y)
定义模型
定义占位符
x = tf.placeholder(tf.float32, [None, 784], name="X")
y = tf.placeholder(tf.float32, [None, 10], name="Y")
定义占位的
,最后在
中将数据通过
喂入神经网络。
注:placeholder
是Tensorflow1.x版本中定义占位符的函数,在最新的Tensorflow2.x中失效。
定义神经网络和前向传播过程
# 隐藏层神经元数量
H1_NN = 256
H2_NN = 56
H3_NN = 100
H4_NN = 45
Y1 = fcn_layer(x, H1_NN, tf.nn.relu)
Y2 = fcn_layer(Y1, H2_NN, tf.nn.relu)
Y3 = fcn_layer(Y2, H3_NN, tf.nn.relu)
Y4 = fcn_layer(Y3, H4_NN, tf.nn.relu)
forward = fcn_layer(Y4, 10)
pre = tf.nn.softmax(forward)
即我们最后得到的一个一行十列的向量,用来训练模型或者预测图片上的数字。并且在这里我们定义了四个隐藏层。
损失函数及优化器
# 交叉熵损失函数
loss_fun = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=forward, labels=y))
# 优化器
lr = 0.00001
opt = tf.train.AdamOptimizer(lr).minimize(loss_fun)
由于此问题是一个多元分类问题,所以不能使用逻辑回归中的损失函数
而使用
将逻辑回归延申到多类别。
这里优化器使用的是
优化器,其中参数
是学习率,.minimize(loss_fun)
是将
降低,可以尝试换成别的优化器观察一下结果。
定义准确率
# 检查预测类别tf.argmax(pre, 1)与实际类别tf.argmax(y, 1)的匹配情况
correct_pre = tf.equal(tf.argmax(pre, 1), tf.argmax(y, 1))
# cast将布尔值投射成浮点数
acc = tf.reduce_mean(tf.cast(correct_pre, tf.float32))
函数argmax
用来得到一行或者一列中数值最大的数的位置,若参数设置为1,则得到同一列中的最大值的位置;若设置为0,则得到同一行中最大值的位置。
超参数及参数的设置
# 训练轮数
epochs = 80
# 一次喂入神经网络的个数
batch_size = 80
totle_batch = int(mnist.train.num_examples/batch_size)
# 显示粒度
display_step = 1
Loss = []
Acc = []
每训练
轮即输出当前的轮数,损失和准确率。
Loss用来保存每次验证集测试的损失,并在最后通过画图显示出来。
Acc用来保存每次验证集的正确率,并在最后画图显示。
训练模型
init = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init)
for epoch in range(epochs):
for batch in range(totle_batch):
xs, ys = mnist.train.next_batch(batch_size)
sess.run(opt,feed_dict = {x:xs, y:ys})
loss, accuracy = sess.run([loss_fun, acc],
feed_dict={x:mnist.validation.images, y:mnist.validation.labels})
Loss.append(loss)
Acc.append(accuracy)
if (epoch+1) % display_step == 0:
print("Train Epoch:%02d" % (epoch+1),"Loss=%f" % loss, "Acc=%.4f" % accuracy)
acca = sess.run(acc, feed_dict={x:mnist.test.images, y:mnist.test.labels})
# 结果可视化
plt.plot(Loss)
plt.title('Loss')
plt.show()
plt.plot(Acc)
plt.title('Accuracy')
plt.show()
print("Accuracy=%f" % acca)
print("Train Finished")
训练结果
可见训练80轮后验证集的正确率达到96.8%,测试集上的准确率达到96.44%,正确率算是较高。对比发现没有上一篇只有一层神经网络的正确率高,可能是由于学习率设置过小,训练轮数不够大导致。观察图像可发现正确率还有进一步上升的空间。