Tensorflow Mnist手写数字识别学习(二)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_44547562/article/details/102699372

前言

与手写字体识别(一)相比,本文将定义全连接层的过程封装到函数 f c n _ l a y e r fcn\_layer 中,并增加几层隐藏层,其余无太大变化。

准备工作

%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)的第一个参数是数据集保存的位置,第二个参数决定数据是否采用独热编码。因为是分类问题,一般使用独热编码,设置其参数为 T r u e 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")

定义占位的 x , y x,y ,最后在 S e s s i o n Session 中将数据通过 f e e d _ d i c t feed\_dict 喂入神经网络。
注: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)

p r e pre 即我们最后得到的一个一行十列的向量,用来训练模型或者预测图片上的数字。并且在这里我们定义了四个隐藏层。

损失函数及优化器

# 交叉熵损失函数
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)

由于此问题是一个多元分类问题,所以不能使用逻辑回归中的损失函数
J ( W , b ) = ( x , y ) D ( y log ( y ) ( 1 y ) log ( 1 y ) ) J(W,b) = \sum_{(x,y) \in D}(-y\log(y')-(1-y)\log(1-y'))
而使用 s o f t m a x softmax 将逻辑回归延申到多类别。
这里优化器使用的是 A d a m Adam 优化器,其中参数 l r lr 是学习率,.minimize(loss_fun)是将 l o s s _ f u n 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 = []

每训练 d i s p l a y _ s t e p display\_step 轮即输出当前的轮数,损失和准确率。
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%,正确率算是较高。对比发现没有上一篇只有一层神经网络的正确率高,可能是由于学习率设置过小,训练轮数不够大导致。观察图像可发现正确率还有进一步上升的空间。

猜你喜欢

转载自blog.csdn.net/weixin_44547562/article/details/102699372