概述
在TensorFlow实现手写数字的识别这篇博客中,介绍了通过TensorFlow构造一个神经网络来实现手写数字的识别,最后通过MNIST数据集,最后在测试集的识别率大约为91%左右。这篇博客主要对这个程序训练的模型进行优化和准确率的提升。在原来的基础上,增加了指数衰减学习率、L2正则化以及滑动平均模型的应用,关于这三种方式在之前的博客已经介绍过了。
一、TensorFlow相关函数
sparse_softmax_cross_entropy_with_logits(_sentinel=None,labels=None, logits=None, name=None)
功能:计算稀疏的softmax交叉熵通过logits和labels参数,计算离散分类任务的错误的可能性,被分类的类别都是互相独立的。
参数:
labels:tensor,类型是int32、int64,它代表每一个正确类别的下标。如,下面的例子中,对于每一个图片都会有一个10维的向量,如[1,0,0,0,0,0,0,0,0,0]这个就代表这张图片对应的数字是0,也就是这个向量为1的下标。
logits:神经网络的前向传播结果,不包括softmax层。
返回值:tensor,与labels的大小相同,与logits的数据类型相同,是一个softmax的交叉熵损失值。
reduce_mean(input_tensor,axis=None,keep_dims=False,name=None,reduction_indices=None)
功能:根据张量的维度来计算张量的平均值。
参数:
input_tensor:需要计算平均值的输入tensor(张量),是一个数字类型的。
axis:默认是None是对所有的元素求平均值,如果设置为0则是对列求平均值,如果为1则是对行求平均值。
1、对张量的所有值求平均值
a = tf.Variable(tf.constant([1.,2.,3.,4.,5.,6.],shape=[2,3]),dtype=tf.float32)
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)
result = tf.reduce_mean(a)
print(a.eval(session=sess))
'''
[[ 1. 2. 3.]
[ 4. 5. 6.]]
'''
print(result.eval(session=sess))
#3.5
2、对张量的列求平均值
a = tf.Variable(tf.constant([1.,2.,3.,4.,5.,6.],shape=[2,3]),dtype=tf.float32)
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)
result = tf.reduce_mean(a,0)
print(a.eval(session=sess))
'''
[[ 1. 2. 3.]
[ 4. 5. 6.]]
'''
print(result.eval(session=sess))
#[ 2.5 3.5 4.5]
3、对张量的行求平均值
a = tf.Variable(tf.constant([1.,2.,3.,4.,5.,6.],shape=[2,3]),dtype=tf.float32)
sess = tf.Session()
init = tf.initialize_all_variables()
sess.run(init)
result = tf.reduce_mean(a,1)
print(a.eval(session=sess))
'''
[[ 1. 2. 3.]
[ 4. 5. 6.]]
'''
print(result.eval(session=sess))
#[ 2. 5.]
二、神经网络结构介绍
1、在之前写的使用神经网络实现手写数字的识别,之前的神经网络是由两层网络组成,第一层是线性层,一共由784*10=7840个权重和10个偏置组成,由于结构比较简单连激活函数也没有,然后通过第二层的softmax层,最后的准确率只有91.8%,我们通过改进这次的准确率可以达到98.4%。
2、这次改进后的结构是由三层结构组成的,第一层是线性层,由784*500个权重和500个偏置组成,然后再通过RELU激活层去线性化,第二层是由500*10个权重和10个偏置组成,然后通过RELU激活层,第三层也是softmax层,除了结构上有改进之外,我们还加了三种对模型的优化算法。
三、TensorFlow代码实现
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#通过输入,神经网络的参数来进行输出
def inference(input_tensor,avger,weight1,biase1,weight2,biase2):
#判断是否使用滑动平均模型
#不使用滑动平均模型
if avger == None:
#计算第一层神经网络的前向传播,并使用RELU激活函数
layer1 = tf.nn.relu(tf.matmul(input_tensor,weight1) + biase1)
#计算第二层的神经网络的前向传播
return tf.matmul(layer1,weight2) + biase2
#使用滑动平均模型
else:
#通过滑动平均模型更新参数,利用更新后的参数进行前向传播计算
layer1 = tf.nn.relu(tf.matmul(input_tensor,avger.average(weight1))+avger.average(biase1))
#计算第二层神经网络的前向传播
return tf.matmul(layer1,avger.average(weight2)) + avger.average(biase2)
if __name__ == "__main__":
#定义第一层网络的输入节点数
#输入为784是因为,每张手写数字的图片大小为28*28的矩阵,将它转成一维向量就是1*784
input_node = 784
#定义最后一层网络的输出节点数
#输出为一个1*10的向量,正好可以表示0-9,10个数字
output_node = 10
#定义神经网络的结构
#定义第一层隐藏层的节点数
layer1_node = 500
#定义每次训练图片的张数,可以有效防止内存溢出
batch_size = 100
#定义基础的学习率用于指数衰减的学习率中
learning_rate_base = 0.8
#设置学习率的衰减率
learning_rate_decay = 0.99
#设置L1正则化中,模型复杂度在损失函数中所占的比例
regularization_rate = 0.0001
#设置训练的轮数
training_steps = 30000
#设置滑动平均的衰减率
moving_average_decay = 0.99
#定义输入节点
x = tf.placeholder(tf.float32,[None,input_node],name="x_input")
#定义输出节点
y_ = tf.placeholder(tf.float32,[None,output_node],name="y_output")
#设置第一层神经网络的权重
weight1 = tf.Variable(tf.truncated_normal([input_node,layer1_node],stddev=0.1))
#设置第一层神经网络的偏置
biase1 = tf.Variable(tf.constant(0.1,shape=[layer1_node]))
#设置第二层神经网络的权重
weight2 = tf.Variable(tf.truncated_normal([layer1_node,output_node],stddev=0.1))
#设置第二层神经网络的偏置
biase2 = tf.Variable(tf.constant(0.1,shape=[output_node]))
#计算神经网络的前向传播结果
#不适用参数的滑动平均值
y = inference(x,None,weight1,biase1,weight2,biase2)
#定义滑动平均的global_step
global_step = tf.Variable(0,trainable=False)
#初始化滑动平均
averge = tf.train.ExponentialMovingAverage(moving_average_decay,global_step)
#定义滑动平均所更新的列表,tf.trainable_variables()获取所有的列表
variables_averages = averge.apply(tf.trainable_variables())
#通过滑动平均,获取神经网络的前向传播参数
averge_y = inference(x,averge,weight1,biase1,weight2,biase2)
#使用交叉熵作为损失函数
# cross_entropy = -tf.reduce_sum(y_*tf.log(y))
cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=tf.argmax(y_,1),logits=y)
#计算交叉熵的平均值
cross_entropy_mean = tf.reduce_mean(cross_entropy)
#计算L2正则化损失函数
regularizer = tf.contrib.layers.l2_regularizer(regularization_rate)
#计算模型参数的L2正则化
regularization = regularizer(weight1) + regularizer(weight2)
#计算中的损失
loss = cross_entropy_mean + regularization
# 下载minist的手写数字的数据集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
#设置指数衰减学习率
learning_rate = tf.train.exponential_decay(learning_rate_base,
global_step,mnist.train.num_examples/batch_size
,learning_rate_decay)
#随机梯度下降优化损失函数
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss)
#每迭代一次需要更新神经网络中的参数
train_op = tf.group(train_step,variables_averages)
correct_prediction = tf.equal(tf.argmax(averge_y,1),tf.argmax(y_,1))
#计算数据的准确率
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
#初始化会话
with tf.Session() as sess:
#初始化参数
tf.initialize_all_variables().run()
# 验证数据
validate_feed = {x: mnist.validation.images, y_: mnist.validation.labels}
#迭代训练
for i in range(training_steps):
batch_x,batch_y = mnist.train.next_batch(batch_size)
sess.run(train_op,feed_dict={x:batch_x,y_:batch_y})
if i % 1000 == 0:
validate_acc = sess.run(accuracy,feed_dict=validate_feed)
print("After %d training step(s),validate accuracy using average"
"model is %g" % (i, validate_acc))
# 测试数据
test_feed = {x: mnist.test.images, y_: mnist.test.labels}
#训练完成之后,测试测试集的准确率
test_acc = sess.run(accuracy,feed_dict=test_feed)
print("After %d training step(s),test accuracy using average"
"model is %g"%(training_steps,test_acc))
#0.9841
#不使用滑动平均模型的准确率
#0.9838
#不使用L2正则化
#0.9845
#不使用指数衰减
#0.9681
四、总结
在使用三种优化算法对模型进行优化的时候发现,对模型使用三种优化算法的时候准确率为98.41%(每次运行结果可能不一样,因为模型训练过程的随机因素),只使用正则化和指数衰减算法的时候准确率为98.45%和同时使用三种优化算法的结果差不多。但,如果不是指数衰减算法你会发现在训练过程中,对于验证集的准确率是慢慢的提升上去的,而不是从一开始的10%左右,直接变为了97%。这个结果也能更好的解释了,指数衰减对于模型的作用。
最后
以上就是义气自行车为你收集整理的TensorFlow实现手写数字识别改进版的全部内容,希望文章能够帮你解决TensorFlow实现手写数字识别改进版所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复