【2.3】MNIST 数据集输出手写数字识别准确率

一、数据集

数据集介绍

mnist 数据集:包含 7 万张黑底白字手写数字图片,其中 55000 张为训练集, 5000 张为验证集,10000 张为测试集。每张图片大小为 28*28 像素,图片中纯黑 色像素值为 0,纯白色像素值为 1。数据集的标签是长度为 10 的一维数组,数组 中每个元素索引号表示对应数字出现的概率。

在将 mnist 数据集作为输入喂入神经网络时,需先将数据集中每张图片变为长度 784 一维数组,将该数组作为神经网络输入特征喂入神经网络。

例如:

一张数字手写体图片变成长度为 784 的一维数组[0.0.0.0.0.231 0.235 0.459 ……0.219 0.0.0.0.]输入神经网络。该图片对应的标签为[0.0.0.0.0.0.1.0. 0.0],标签中索引号为 6 的元素为 1,表示是数字 6 出现的概率为 100%,则该图 片对应的识别结果是 6。

读入数据集

使用 input_data 模块中的 read_data_sets()函数加载 mnist 数据集:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets(’./data/’,one_hot=True)

在 read_data_sets()函数中有两个参数,第一个参数表示数据集存放路径,第 二个参数表示数据集的存取形式。当第二个参数为 Ture 时,表示以独热码形式 存取数据集。read_data_sets()函数运行时,会检查指定路径内是否已经有数据 集,若指定路径中没有数据集,则自动下载,并将 mnist 数据集分为训练集 train、 验证集 validation 和测试集 test 存放。在终端显示如下内容:

  • Extracting ./data/train-images-idx3-ubyte.gz
  • Extracting ./data/train-labels-idx1-ubyte.gz
  • Extracting ./data/tl0k-images-idx3-ubyte.gz
  • Extracting ./data/ tl0k-labels-idx1-ubyte.gz

划分数据集

返回 mnist 数据集中训练集 train、验证集 validation 和测试集 test 样本数 在 Tensorflow 中用以下函数返回子集样本数:

在 Tensorflow 中用以下函数返回子集样本数:

1.返回训练集 train 样本数

print “train data size:”,mnist.train.mun_examples

输出结果:train data size:55000

2.返回验证集 validation 样本数

print “validation data size:”,mnist.validation.mun_examples

输出结果:validation data size:5000

3.返回测试集 test 样本数

print “test data size:”,mnist.test.mun_examples

输出结果:test data size:10000

数据属性

使用 train.labels 函数返回 mnist 数据集标签

例如:

在 mnist 数据集中,若想要查看训练集中第 0 张图片的标签,则使用如下函数 mnist.train.labels[0]

输出结果:array([0.,0.,0.,0.,0.,0.,1.,0.,0.,0])

使用 train.images 函数返回 mnist 数据集图片像素值

例如:

在 mnist 数据集中,若想要查看训练集中第 0 张图片像素值,则使用如下函数 mnist.train.images[0]

输出结果:array([0. ,0. ,0. , 0. ,0. ,0. , 0. ,0. ,0. , … … …])

使用 mnist.train.next_batch()函数将数据输入神经网络

例如:

BATCH_SIZE = 200
xs,ys = mnist.train.next_batch(BATCH_SIZE)
print “xs shape:”,xs.shape
print “ys shape:”,ys.shape

输出结果:xs.shape(200,784)

输出结果:ys.shape(200,10)

其中,mnist.train.next_batch()函数包含一个参数 BATCH_SIZE,表示随机从训 练集中抽取 BATCH_SIZE 个样本输入神经网络,并将样本的像素值和标签分别赋 给 xs 和 ys。在本例中,BATCH_SIZE 设置为 200,表示一次将 200 个样本的像素 值和标签分别赋值给 xs 和 ys,故 xs 的形状为(200,784),对应的 ys 的形状为 (200,10)。 200表示200个变量,784表示每个变量对应784个元素;同里10.

实现“Mnist 数据集手写数字识别”的常用函数:

1.tf.get_collection(“”)函数表示从 collection 集合中取出全部变量生成 一个列表。

2.tf.add( )

函数表示将参数列表中对应元素相加。

例如:

x=tf.constant([[1,2],[1,2]])
y=tf.constant([[1,1],[1,2]])
z=tf.add(x,y)
print z
输出结果:[[2,3],[2,4]]

3.tf.cast(x,dtype)函数表示将参数 x 转换为指定数据类型。

例如:

A = tf.convert_to_tensor(np.array([[1,1,2,4], [3,4,8,5]]))
print A.dtype
b = tf.cast(A, tf.float32)
print b.dtype

结果输出:

<dtype: 'int64'>
<dtype: 'float32'>

从输出结果看出,将矩阵 A 由整数型变为 32 位浮点型。

4.tf.equal( )函数表示对比两个矩阵或者向量的元素。若对应元素相等,则返 回 True;若对应元素不相等,则返回 False。

例如:

A = [[1,3,4,5,6]]
B = [[1,3,4,3,2]]
with tf.Session( ) as sess:
print(sess.run(tf.equal(A, B)))

输出结果:[[ True True True False False]]

在矩阵 A 和 B 中,第 1、2、3 个元素相等,第 4、5 个元素不等,故输出结果中, 第 1、2、3 个元素取值为 True,第 4、5 个元素取值为 False。

5.tf.reduce_mean(x,axis)函数表示求取矩阵或张量指定维度的平均值。若不 指定第二个参数,则在所有元素中取平均值;若指定第二个参数为 0,则在第一 维元素上取平均值,即每一列求平均值;若指定第二个参数为 1,则在第二维元 素上取平均值,即每一行求平均值。

例如:

x = [[1., 1.]
[2., 2.]]
print(tf.reduce_mean(x))

输出结果:1.5

print(tf.reduce_mean(x, 0))

输出结果:[1.5, 1.5]

print(tf.reduce_mean(x, 1))

输出结果:[1., 1.]

6.tf.argmax(x,axis)函数表示返回指定维度 axis 下,参数 x 中最大值索引号。 例如:

在 tf.argmax([1,0,0],1)函数中,axis 为 1,参数 x 为[1,0,0],表示在参数 x 的第一个维度取最大值对应的索引号,故返回 0。

7.os.path.join()函数表示把参数字符串按照路径命名规则拼接。

例如:

import os
os.path.join('/hello/','good/boy/','doiido') 输出结果:'/hello/good/boy/doiido'

8.字符串.split( )函数表示按照指定“拆分符”对字符串拆分,返回拆分列表。 例如:

'./model/mnist_model-1001'.split('/')[-1].split('-')[-1] 

在该例子中,共进行两次拆分。第一个拆分符为‘/’,返回拆分列表,并提取 列表中索引为-1 的元素即倒数第一个元素;第二个拆分符为‘-’,返回拆分列 表,并提取列表中索引为-1 的元素即倒数第一个元素,故函数返回值为 1001。

9.tf.Graph( ).as_default( )函数表示将当前图设置成为默认图,并返回一 个上下文管理器。该函数一般与 with 关键字搭配使用,应用于将已经定义好 的神经网络在计算图中复现。 例如:

with tf.Graph().as_default() as g

表示将在 Graph()内定义的节点加入到 计算图 g 中。

二、神经网络的保存与加载

保存

在反向传播过程中,一般会间隔一定轮数保存一次神经网络模型,并产生三个 文件(保存当前图结构的.meta 文件、保存当前参数名的.index 文件、保存当 前参数的.data 文件),在 Tensorflow 中如下表示:

saver = tf.train.Saver() 
with tf.Session() as sess: 
	for i in range(STEPS):
		if i % 轮数 == 0:
			saver.save(sess, os.path.join(MODEL_SAVE_PATH,MODEL_NAME), global_step=global_step)

其中,tf.train.Saver()用来实例化 saver 对象。上述代码表示,神经网络每循 环规定的轮数,将神经网络模型中所有的参数等信息保存到指定的路径中,并在 存放网络模型的文件夹名称中注明保存模型时的训练轮数。

神经网络模型的加载

在测试网络效果时,需要将训练好的神经网络模型加载,在 Tensorflow 中这 样表示:

with tf.Session() as sess:
	ckpt = tf.train.get_checkpoint_state(存储路径) 
	if ckpt and ckpt.model_checkpoint_path:
		saver.restore(sess, ckpt.model_checkpoint_path)

在 with 结构中进行加载保存的神经网络模型,若 ckpt 和保存的模型在指定路 径中存在,则将保存的神经网络模型加载到当前会话中。

加载模型中参数的滑动平均值

在保存模型时,若模型中采用滑动平均,则参数的滑动平均值会保存在相应文件 中。通过实例化 saver 对象,实现参数滑动平均值的加载,在 Tensorflow 中如 下表示:

ema = tf.train.ExponentialMovingAverage(滑动平均基数)
ema_restore = ema.variables_to_restore()
saver = tf.train.Saver(ema_restore)

神经网络模型准确率评估方法

在网络评估时,一般通过计算在一组数据上的识别准确率,评估神经网络的效 果。在 Tensorflow 中这样表示:

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 

在上述中,y 表示在一组数据(即 batch_size 个数据)上神经网络模型的预测 结果,y 的形状为[batch_size,10],每一行表示一张图片的识别结果。通过 tf.argmax()函数取出每张图片对应向量中最大值元素对应的索引值,组成长度 为输入数据 batch_size 个的一维数组。通过 tf.equal()函数判断预测结果张量 和实际标签张量的每个维度是否相等,若相等则返回 True,不相等则返回 False。 通过 tf.cast()函数将得到的布尔型数值转化为实数型,再通过 tf.reduce_mean()函数求平均值,最终得到神经网络模型在本组数据上的准确率。

三、神经网络八股

神经网络八股包括前向传播过程、反向传播过程、反向传播过程中用到的正则化、 指数衰减学习率、滑动平均方法的设置、以及测试模块。

前向传播过程(forward.py)

前向传播过程完成神经网络的搭建,结构如下:

def forward(x, regularizer):
    w=
    b=
    y=
    return y

def get_weight(shape, regularizer):

def get_bias(shape):

前向传播过程中,需要定义神经网络中的参数 w 和偏置 b,定义由输入到输出的 网络结构。通过定义函数 get_weight()实现对参数 w 的设置,包括参数 w 的形 状和是否正则化的标志。同样,通过定义函数 get_bias()实现对偏置 b 的设置。

反向传播过程(backword.py)

反向传播过程完成网络参数的训练,结构如下:

def backward( mnist ):
	x = tf.placeholder(dtype, shape )
	y_ = tf.placeholder(dtype, shape )
	
#定义前向传播函数
y = forward( )
global_step =
loss =
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step) 

#实例化 saver 对象
saver = tf.train.Saver() 
with tf.Session() as sess:
	#初始化所有模型参数
	tf.initialize_all_variables().run()

#训练模型
for i in range(STEPS): 
	sess.run(train_step, feed_dict={x:
	if i % 轮数 == 0: 
		print
    	saver.save(   )

反向传播过程中,用 tf.placeholder(dtype, shape)函数实现训练样本 x 和样 本标签 y_占位,函数参数 dtype 表示数据的类型,shape 表示数据的形状;y 表 示定义的前向传播函数 forward;loss 表示定义的损失函数,一般为预测值与样 本标签的交叉熵(或均方误差)与正则化损失之和;train_step 表示利用优化算 法对模型参数进行优化,常用优化算法 GradientDescentOptimizer、 AdamOptimizer、MomentumOptimizer 算法,在上述代码中使用的 GradientDes centOptimizer 优化算法。接着实例化 saver 对象,其中利用 tf.initialize _all_variables().run()函数实例化所有参数模型,利用 sess.run( )函数实 现模型的训练优化过程,并每间隔一定轮数保存一次模型。

正则化、指数衰减学习率、滑动平均方法的设置

1.正则化项 regularization

当在前向传播过程中即 forward.py 文件中,设置正则化参数 regularization 为 1 时,则表明在反向传播过程中优化模型参数时,需要在损失函数中加入正则化 项。

结构如下:

首先,需要在前向传播过程即 forward.py 文件中加入

if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w)) 

其次,需要在反向传播过程即 backword.py 文件中加入

ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
cem = tf.reduce_mean(ce)

loss = cem + tf.add_n(tf.get_collection('losses'))

其中,tf.nn.sparse_softmax_cross_entropy_with_logits()表示 softmax()函 数与交叉熵一起使用。

2.数衰减学习率

在训练模型时,使用指数衰减学习率可以使模型在训练的前期快速收敛接近较优 解,又可以保证模型在训练后期不会有太大波动。

运用指数衰减学习率,需要在反向传播过程即 backword.py 文件中加入:

learning_rate = tf.train.exponential_decay(
LEARNING_RATE_BASE,
global_step,
LEARNING_RATE_STEP, LEARNING_RATE_DECAY,
staircase=True)

3.滑动平均

在模型训练时引入滑动平均可以使模型在测试数据上表现的更加健壮。 需要在反向传播过程即 backword.py 文件中加入:

ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,global_step)
ema_op = ema.apply(tf.trainable_variables())
with tf.control_dependencies([train_step, ema_op]):
	train_op = tf.no_op(name='train')

测试过程(test.py)

当神经网络模型训练完成后,便可用于测试数据集,验证神经网络的性能。结构 如下:

首先,制定模型测试函数 test()

def test( mnist ):
	with tf.Graph( ).as_default( ) as g: #给 x y_占位
		x = tf.placeholder(dtype,shape) 
		y_ = tf.placeholder(dtype,shape)
		#前向传播得到预测结果 y
		y = mnist_forward.forward(x, None) #前向传播得到 y

		#实例化可还原滑动平均的 saver
		ema = tf.train.ExponentialMovingAverage(滑动衰减率)
		ema_restore = ema.variables_to_restore() saver = tf.train.Saver(ema_restore) 

		#计算正确率
		correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_, 1))
		accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
		
		while True:
			with tf.Session() as sess:
				#加载训练好的模型
				ckpt = tf.train.get_checkpoint_state(存储路径) 

				#如果已有 ckpt 模型则恢复
				if ckpt and ckpt.model_checkpoint_path:
					#恢复会话
					saver.restore(sess, ckpt.model_checkpoint_path) 

					#恢复轮数
					global_ste = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
					
					#计算准确率
					accuracy_score = sess.run(accuracy, feed_dict={x:测试数据, y_:测试数据标签 })

					# 打印提示
					print("After %s training step(s), test accuracy=%g" % (global_step, accuracy_score)) 

				#如果没有模型
				else:
				print('No checkpoint file found') #模型不存在提示 return

其次,制定 main()函数

def main():
	#加载测试数据集
	mnist = input_data.read_data_sets("./data/", one_hot=True) #调用定义好的测试函数 test()

	test(mnist)

if __name__ == '__main__':
	main()

通过对测试数据的预测得到准确率,从而判断出训练出的神经网络模型的性能好 坏。当准确率低时,可能原因有模型需要改进,或者是训练数据量太少导致过拟 合。

四、实例

实现手写体 mnist 数据集的识别任务,共分为三个模块文件,分别是描述网络结 构的前向传播过程文件(mnist_forward.py)、描述网络参数优化方法的反向传 播过程文件(mnist_backward.py)、验证模型准确率的测试过程文件 (mnist_test.py)。

  1. 前向传播过程文件(mnist_forward.py)

在前向传播过程中,需要定义网络模型输入层个数、隐藏层节点数、输出层个数, 定义网络参数 w、偏置 b,定义由输入到输出的神经网络架构。 实现手写体 mnist 数据集的识别任务前向传播过程如下:

由上述代码可知,在前向传播过程中,规定网络输入结点为 784 个(代表每张输 入图片的像素个数),隐藏层节点 500 个,输出节点 10 个(表示输出为数字 0-9 的十分类)。由输入层到隐藏层的参数 w1 形状为[784,500],由隐藏层到输出层 的参数 w2 形状为[500,10],参数满足截断正态分布,并使用正则化,将每个参数的正则化损失加到总损失中。由输入层到隐藏层的偏置 b1 形状为长度为 500 的一维数组,由隐藏层到输出层的偏置 b2 形状为长度为 10 的一维数组,初始化 值为全 0。前向传播结构第一层为输入 x 与参数 w1 矩阵相乘加上偏置 b1,再经 过 relu 函数,得到隐藏层输出 y1。前向传播结构第二层为隐藏层输出 y1 与参 数 w2 矩阵相乘加上偏置 b2,得到输出 y。由于输出 y 要经过 softmax 函数,使 其符合概率分布,故输出 y 不经过 relu 函数。

2.反向传播过程文件(mnist_backward.py)

反向传播过程实现利用训练数据集对神经网络模型训练,通过降低损失函数值, 实现网络模型参数的优化,从而得到准确率高且泛化能力强的神经网络模型。 实现手写体 mnist 数据集的识别任务反向传播过程如下:

由上述代码可知,在反向传播过程中,首先引入 tensorflow、input_data、前向 传播 mnist_forward 和 os 模块,定义每轮喂入神经网络的图片数、初始学习率、 学习率衰减率、正则化系数、训练轮数、模型保存路径以及模型保存名称等相关 信息。在反向传播函数 backword 中,首先读入 mnist,用 placeholder 给训练 数据 x 和标签 y_占位,调用 mnist_forward 文件中的前向传播过程 forword()函 数,并设置正则化,计算训练数据集上的预测结果 y,并给当前计算轮数计数器 赋值,设定为不可训练类型。接着,调用包含所有参数正则化损失的损失函数 loss,并设定指数衰减学习率 learning_rate。然后,使用梯度衰减算法对模型 优化,降低损失函数,并定义参数的滑动平均。最后,在 with 结构中,实现所 有参数初始化,每次喂入 batch_size 组(即 200 组)训练数据和对应标签,循 环迭代 steps 轮,并每隔 1000 轮打印出一次损失函数值信息,并将当前会话加 载到指定路径。最后,通过主函数 main(),加载指定路径下的训练数据集,并调 用规定的 backward()函数训练模型。

3.测试过程文件(mnist_test.py)

当训练完模型后,给神经网络模型输入测试集验证网络的准确性和泛化性。注意, 所用的测试集和训练集是相互独立的。 实现手写体 mnist 数据集的识别任务测试传播过程如下:

在上述代码中,首先需要引入 time 模块、tensorflow、input_data、前向传播 mnist_forward、反向传播 mnist_backward 模块和 os 模块,并规定程序 5 秒的 循环间隔时间。接着,定义测试函数 test(),读入 mnist 数据集,利用 tf.Graph() 复现之前定义的计算图,利用 placeholder 给训练数据 x 和标签 y_占位,调用 mnist_forward 文件中的前向传播过程 forword()函数,计算训练数据集上的预 测结果 y。接着,实例化具有滑动平均的 saver 对象,从而在会话被加载时模型 中的所有参数被赋值为各自的滑动平均值,增强模型的稳定性,然后计算模型在 测试集上的准确率。在 with 结构中,加载指定路径下的 ckpt,若模型存在,则 加载出模型到当前对话,在测试数据集上进行准确率验证,并打印出当前轮数下 的准确率,若模型不存在,则打印出模型不存在的提示,从而 test()函数完成。 通过主函数 main(),加载指定路径下的测试数据集,并调用规定的 test 函数, 进行模型在测试集上的准确率验证。

运行以上三个文件,可得到手写体 mnist 数据集的识别任务的运行结果:

从终端显示的运行结果可以看出,随着训练轮数的增加,网络模型的损失函数 值在不断降低,并且在测试集上的准确率在不断提升,有较好的泛化能力。

六、输入手写数字输出识别结果

6.1 断点续训

关键处理:加入 ckpt 操作:

ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH) 
if ckpt and ckpt.model_checkpoint_path:
	saver.restore(sess, ckpt.model_checkpoint_path)

1.注解:

1)tf.train.get_checkpoint_state(checkpoint_dir,latest_filename=None)

该函数表示如果断点文件夹中包含有效断点状态文件,则返回该文件。

参数说明:checkpoint_dir:表示存储断点文件的目录 latest_filename=None:断点文件的可选名称,默认为“checkpoint”

2)saver.restore(sess, ckpt.model_checkpoint_path)

该函数表示恢复当前会话,将 ckpt 中的值赋给 w 和 b。

参数说明:sess:表示当前会话,之前保存的结果将被加载入这个会话; ckpt.model_checkpoint_path:表示模型存储的位置,不需要提供模 型的名字,它会去查看 checkpoint 文件,看看最新的是谁,叫做什么。

2.ckpt 代码位置:

3.实践代码验证

6.2 输入真实图片,输出预测结果

网络输入:一维数组(784 个像素点)

像素点:0-1 之间的浮点数(接近 0 越黑,接近 1 越白)

网络输出:一维数组(十个可能性概率),数组中最大的那个元素所对应的索 引号就是预测的结果。

关键处理:

def application():
	testNum = input("input the number of test pictures:") 
	for i in range(testNum):
		testPic = raw_input("the path of test picture:")
		testPicArr = pre_pic(testPic)
		preValue = restore_model(testPicArr)
		print "The prediction number is:", preValue

注解:

任务分成两个函数完成

1)testPicArr = pre_pic(testPic)对手写数字图片做预处理

2)preValue = restore_model(testPicArr) 将符合神经网络输入要求的图片喂 给复现的神经网络模型,输出预测值

具体代码:

1、注解:

1)main 函数中的 application 函数:输入要识别的几张图片(注意要给出待识 别图片的路径和名称)。

2)代码处理过程:

(1)模型的要求是黑底白字,但输入的图是白底黑字,所以需要对每个像素点 的值改为 255 减去原值以得到互补的反色。

(2)对图片做二值化处理(这样以滤掉噪声,另外调试中可适当调节阈值)。

(3)把图片形状拉成 1 行 784 列,并把值变为浮点型(因为要求像素点是 0-1 之间的浮点数)。

(4)接着让现有的 RGB 图从 0-255 之间的数变为 0-1 之间的浮点数。

(5)运行完成后返回到 main 函数。

(6)计算求得输出 y,y 的最大值所对应的列表索引号就是预测结果。

2、实践代码验证

1)运行 mnist_backward.py

2)运行 mnist_test.py 来监测模型的准确率

  1. 运行mnist_app.py输入10(表示循环验证十张图片)

6.3 制作数据集,实现特定应用

1、数据集生成读取文件(mnist_generateds.py)

tfrecords 文件

1)tfrecords:是一种二进制文件,可先将图片和标签制作成该格式的文件。 使用 tfrecords 进行数据读取,会提高内存利用率。

2)tf.train.Example: 用来存储训练数据。训练数据的特征用键值对的形式表 示。 如:‘ img_raw ’ :值 ‘ label ’ :值 值是 Byteslist/FloatList/Int64List

3)SerializeToString( ):把数据序列化成字符串存储。

生成 tfrecords 文件

具体代码

注解:

1)writer = tf.python_io.TFRecordWriter(tfRecordName) #新建一个 writer

2)for 循环遍历每张图和标签

3)example = tf.train.Example(features=tf.train.Features(feature={ ‘img_raw’:tf.train.Feature(bytes_list=tf.train.BytesList(value=[ img_raw])), ‘label’:tf.train.Feature(int64_list=tf.train.Int64List(value=lab els))})) # 把每张图片和标签封装到 example 中

4)writer.write(example.SerializeToString()) # 把 example 进行序列化 5)writer.close() #关闭 writer

解析 tfrecords 文件

具体代码:

注解:

1)filename_queue = tf.train.string_input_producer([tfRecord_path])

tf.train.string_input_producer( string_tensor,
                                num_epochs=None,
                                shuffle=True,
                                seed=None,
                                capacity=32,
                                shared_name=None,
                                name=None,
                                cancel_op=None)

该函数会生成一个先入先出的队列,文件阅读器会使用它来读取数据。

参数说明:

  • string_tensor: 存储图像和标签信息的 TFRecord 文件名列表
  • num_epochs: 循环读取的轮数(可选)
  • shuffle:布尔值(可选),如果为 True,则在每轮随机打乱读取顺序
  • seed:随机读取时设置的种子(可选)
  • capacity:设置队列容量
  • shared_name:(可选) 如果设置,该队列将在多个会话中以给定名 称共享。所有具有此队列的设备都可以通过 shared_name 访问它。在分布式设置中使用这种方法意味着每个名称只能被访问此操作的其中一个会话看到。
  • name:操作的名称(可选)
  • cancel_op:取消队列(None)

2)reader = tf.TFRecordReader() #新建一个 reader

3)_, serialized_example = reader.read(filename_queue)

features = tf.parse_single_example(serialized_example,features={ 'img_raw': tf.FixedLenFeature([ ], tf.string) ,'label': tf.FixedLenFeature([10], tf.int64)})

#把读出的每个样本保存在 serialized_example 中进行解序列化,标签和图片的 键名应该和制作 tfrecords 的键名相同,其中标签给出几分类。

tf.parse_single_example(serialized,
                        features,
                        name=None,
                        example_names=None)

该函数可以将 tf.train.Example 协议内存块(protocol buffer)解析为张量。

参数说明:

  • serialized: 一个标量字符串张量
  • features: 一个字典映射功能键 FixedLenFeature 或 VarLenFeature 值,也就是在协议内存块中储存的
  • name:操作的名称(可选)
  • example_names: 标量字符串联的名称(可选)

4)img = tf.decode_raw(features[‘img_raw’], tf.uint8) #将 img_raw 字符串转换为 8 位无符号整型

5)img.set_shape([784]) #将形状变为一行 784 列

6)img = tf.cast(img, tf.float32) * (1. / 255) #变成 0 到 1 之间的浮点数

7)label = tf.cast(features[‘label’], tf.float32)#把标签列表变为浮点数

8)return image,label #返回图片和标签(跳回到 get_tfrecord)

tf.train.shuffle_batch( tensors,batch_size,
                          capacity,
                          min_after_dequeue,
                          num_threads=1,
                          seed=None,
                          enqueue_many=False,
                         shapes=None,
                         allow_smaller_final_batch=False,
                         shared_name=None,
                         name=None)

这个函数随机读取一个 batch 的数据。

参数说明:

  • tensors: 待乱序处理的列表中的样本(图像和标签)
  • batch_size: 从队列中提取的新批量大小
  • capacity:队列中元素的最大数量
  • min_after_dequeue: 出队后队列中的最小数量元素,用于确保元素 的混合级别
  • num_threads: 排列 tensors 的线程数
  • seed:用于队列内的随机洗牌
  • enqueue_many: tensor 中的每个张量是否是一个例子
  • shapes: 每个示例的形状
  • allow_smaller_final_batch: (可选)布尔值。 如果为 True,则在 队列中剩余数量不足时允许最终批次更小。 shared_name:(可选)如果设置,该队列将在多个会话中以给定名称 共享。
  • name:操作的名称(可选)

10)return img_batch,label_batch #返回的图片和标签为随机抽取的 batch_size 组

2.反向传播文件修改图片标签获取的接口(mnist_backward.py)

√关键操作:利用多线程提高图片和标签的批获取效率

方法:将批获取的操作放到线程协调器开启和关闭之间 开启线程协调器:

coord = tf.train.Coordinator( )
threads = tf.train.start_queue_runners(sess=sess, coord=coord) 

关闭线程协调器:

coord.request_stop( ) 
coord.join(threads)

注解:

tf.train.start_queue_runners( sess=None,
                              coord=None,
                              daemon=True,
                              start=True,
                              collection=tf.GraphKeys.QUEUE_RUNNERS)

这个函数将会启动输入队列的线程,填充训练样本到队列中,以便出队操作可以 从队列中拿到样本。这种情况下最好配合使用一个 tf.train.Coordinator ,这 样可以在发生错误的情况下正确地关闭这些线程。

参数说明:

  • sess:用于运行队列操作的会话。 默认为默认会话。
  • coord:可选协调器,用于协调启动的线程。
  • daemon: 守护进程,线程是否应该标记为守护进程,这意味着它们不 会阻止程序退出。
  • start:设置为 False 只创建线程,不启动它们。
  • collection:指定图集合以获取启动队列的 GraphKey。默认为 GraphKeys.QUEUE_RUNNERS。

√具体对比反向传播中的 fc4 与 fc3 代码

注解:

1)train_num_examples=60000

在梯度下降学习率中需要计算多少轮更新一次学习率,这个值是 总样本数/batch size

之前:用 mnist.train.num_examples 表示总样本数;

现在:要手动给出训练的总样本数,这个数是 6 万。

2)image_batch, label_batch=mnist_generateds.get_tfrecord(BATCH_SIZE, isTrain=True)

之前:用 mnist.train.next_batch 函数读出图片和标签喂给网络;

现在:用函数 get_tfrecord 替换,一次批获取 batch_size 张图片和标签。 isTrain:用来区分训练阶段和测试阶段,True 表示训练,False 表示测试。

3)xs,ys=sess.run([img_batch,label_batch]) 之前:使用函数 xs,ys=mnist.train.next_batch(BATCH_SIZE) 现在:在 sess.run 中执行图片和标签的批获取。

3、测试文件修改图片标签获取的接口(mnist_test.py) √具体对比反向传播中的 fc4 与 fc3 代码(和反向传播类似)

注解:

1)TEST_NUM=10000

之前:用 mnist.test.num_examples 表示总样本数;

现在:要手动给出测试的总样本数,这个数是 1 万。

2)image_batch, label_batch=mnist_generateds.get_tfrecord(TEST_NUM,isTrain=False)

之前:用 mnist.test.next_batch 函数读出图片和标签喂给网络;

现在:用函数 get_tfrecord 替换读取所有测试集 1 万张图片。

isTrain:用来区分训练阶段和测试阶段,True 表示训练,False 表示测试。

3)xs,ys=sess.run([img_batch,label_batch])

之前:使用函数 xs,ys=mnist.test.next_batch(BATCH_SIZE)

现在:在 sess.run 中执行图片和标签的批获取。

4、实践代码验证

1)运行测试代码 mnist_test.py

2)准确率稳定在 95%以上后运行应用程序 mnist_app.py

参考资料:

北京大学 曹建老师 《人工智能实践:Tensorflow学习笔记》

药企,独角兽,苏州。团队长期招人,感兴趣的都可以发邮件聊聊:tiehan@sina.cn
个人公众号,比较懒,很少更新,可以在上面提问题,如果回复不及时,可发邮件给我: tiehan@sina.cn