Tensorflow组建全连接网络
预备知识——Tensorflow中常用函数
tf.get_collection(“”) 函数表示从 collection 集合中取出全部变量生成一个列表
tf.add( ) 函数表示将参数列表中对应元素相加
tf.cast(x,dtype) 函数表示将参数 x 转换为指定数据类型
tf.equal( ) 函数表示对比两个矩阵或者向量的元素。若对应元素相等,则返回 True;若对应元素不相等,则返回 False。
tf.reduce_mean(x,axis) 函数表示求取矩阵或张量指定维度的平均值。若不指定第二个参数,则在所有元素中取平均值;若指定第二个参数为 0,则在第一维元素上取平均值,即每一列求平均值;若指定第二个参数为 1,则在第二维元素上取平均值,即每一行求平均值
tf.argmax(x,axis) 函数表示返回指定维度 axis 下,参数 x 中最大值索引号
os.path.join() 函数表示把参数字符串按照路径命名规则拼接,先import os
字符串.split( ) 函数表示按照指定“拆分符”对字符串拆分,返回拆分列表
tf.Graph( ).as_default( ) 函数表示将当前图设置成为默认图,并返回一个上下文管理器。该函数一般与 with 关键字搭配使用,应用于将已经定义好的神经网络在计算图中复现
#表示将在 Graph()内定义的节点加入到计算图 g 中
with tf.Graph().as_default() as g
1、数据集相关函数
(1)、使用自带的数据集
加载数据集
使用 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 时,表示以独热码(只有一个比特为1,其他全为0的一种码制)形式存取数据集。若指定路径中没有数据集,则自动下载,并将 mnist 数据集分为训练集 train、验证集 validation 和测试集 test 存放。
返回数据集属性
#返回训练集 train 样本数
print “train data size:”,mnist.train.mun_examples
#返回验证集 validation 样本数
print “validation data size:”,mnist.validation.mun_examples
#返回测试集 test 样本数
print “test data size:”,mnist.test.mun_examples
#返回 mnist 数据集标签,如:在 mnist 数据集中,若想要查看训练集中第 0 张图片的标签,则使用如下函数
mnist.train.labels[0]
#返回 mnist 数据集图片像素值 ,如:查看训练集中第 0 张图片像素值
mnist.train.images[0]
输入数据集
BATCH_SIZE = 200
#mnist.train.next_batch()函数包含一个参数 BATCH_SIZE,表示随机从训练集中抽取 BATCH_SIZE
#个样本输入神经网络,并将样本的像素值和标签分别赋给 xs 和 ys。
xs,ys = mnist.train.next_batch(BATCH_SIZE)
print “xs shape:”,xs.shape
print “ys shape:”,ys.shape
#输出结果:xs.shape(200,784) ,输入两百个样本,每个样本有784个像素点
#输出结果:ys.shape(200,10) ,输出200个结果,每个结果有10种可能
(2)、制作数据集
a、生成 tfrecords 文件
tfrecords 文件是一种二进制文件,可先将图片和标签制作成该格式的文件。使用 tfrecords 进行数据读取,会提高内存利用率。
tf.train.Example: 用来存储训练数据。训练数据的特征用键值对的形式表示。 如:‘ img_raw ’ :值, ‘ label ’ :值 ,值是 Byteslist/Float List/Int64List
Serialize To String( ): 把数据序列化成字符串存储。
def write_tfRecord(tfRecordName,image_path,label_path):
#新建一个writer
writer = tf.python_io.TFRecordWriter(tfRecordName)
num_pic = 0
f = open(label_path,'r')
contents = f.readline()
f.close()
#循环遍历每张图和标签
for contents in contents:
value = contents.split()
img_path = Image.open(img_path)
img = Image.open(img_path)
img_raw = img.tobytes()
labels = [0]*10
labels[int(value[1])] = 1
#把每张图和标签封装到example中
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 = labels))}))
#把example进行序列化
writer.write(example.SerializeToString())
num_pic +=1
print("The number of picture:",num_pic)
writer.close()
print("write tfrecord successful")
def generate_tfRecord():
isExists = os.path.exists(data_path)
if not isExists:
os.makeddir(data_path)
print("The directory was created successfully")
else:
print("deirectory already exists")
write_tfRecord(tfRecord_train,image_train_path,label_train_path)
write_tfRecord(tfRecord_test,image_test_path,label_test_path)
b、解析 tfrecords 文件
def read_tfRecord(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_ipochs:循环读取的论述
#shuffle:布尔值,如为Turn则每轮随机打乱读取顺序,seed,随机读取时设置的种子,capacity,设置队列容量,share_name如果设置,该队列将在多个会话中以给定名称共享,
#所有具有此队列的设备斗可以通过share_name访问它,在分布式设置中使用这种方法意味着每个名称只能被访问此操作的其中一个会话看到,name操作的名称,cancel_op取消队列
filename_queue = tf.train.string_input_producer([tfRecord_path])
#新建一个reader
reader = tf.TFRecordReader()
#把读入的每个样本保存在serialized_example中进行解序列化,标签和图片的键名应该和制作tfrecords的键名相同,其中标签给出几分类
_,serialized_example = reader.read(filename_queue)
#将tf.train.Example协议内存块解析为张量,serialized一个标量字符串张量,features一个字典映射功能键
features = tf.parse_single_example(serialized_example,
features={
'label':tf.FixedLenFeature([10],tf.int64),
'img_raw':tf.FixedLenFeature([],tf.string)
})
#将img_raw字符串转化为8位无符号整型
img = tf.decode_raw(features['img_raw'],tf.uint8)
img.set_shape([784])
#变成0到1之间的浮点数
img = tf.cast(img,tf.float32)*(1./255)
把标签列表变成浮点数
label = tf.cast(features['label'],tf.float32)
return img,label
def get_tfrecord(num,isTrain = True):
if isTrain:
tfRecord_path = tfRecord_train
else:
tfRecord_path =tfRecord_test
img,label = read_tfRecord(tfRecord_path)
#tf.train.shuffle_batch随机读取一个batch的数据,参数说明:tensors待乱序处理的列表中的样本(标签和图像),batch_size从队列中提取的新批量大小
#capacity队列中元素的最大数量,min_after_dequeue出队后队列中的最小数量元素,用于确保元素的混合级别,num_threads排列tensors的线程数
#seed用于队列内的随机洗牌,enqueue_many,tensor中的每个张量是否是一个例子,shape每个示例的形状,allow_smaller_final_batch,布尔值,为True则队列中剩余数量不足时允许最终批次更小
#shared_name如果设置,该队列将在多个会话中以给定名称共享,name操作的名称
img_batch,label_batch = tf.train.shuffle_batch([img,label],
batch_size= num,
num_threads = 2,
capacity = 1000.
min_after_dequeue = 700)
return img_batch,label_batch
c、反向传播文件修改图片标签获取的接口
利用多线程提高图片和标签的批获取效率 :将批获取的操作放到线程协调器开启和关闭之间 。
tf.train.start_queue_runners( sess=None,
coord=None,
daemon=True,
start=True,
collection=tf.Graph Keys.QUEUE_RUNNERS)
这个函数将会启动输入队列的线程,填充训练样本到队列中,以便出队操作可以从队列中拿到样本。这种情况下最好配合使用一个 tf.train.Coordinator ,这样可以在发生错误的情况下正确地关闭这些线程。
参数说明:sess:用于运行队列操作的会话。 默认为默认会话。
coord:可选协调器,用于协调启动的线程。
daemon: 守护进程,线程是否应该标记为守护进程,这意味着它们不会阻止程序退出。
start:设置为 False 只创建线程,不启动它们。
collection :指定图集合以获取启动队列的 Graph Key 。默认为Graph Keys.QUEUE_RUNNERS。
#开启线程协调器:
coord = tf.train.Coordinator( )
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
#关闭线程协调器:
coord.request_stop( )
coord.join(threads)
2、训练神经网络
加载模型中参数的滑动平均值
在保存模型时,若模型中采用滑动平均,则参数的滑动平均值会保存在相应文件中。通过实例化 saver 对象,实现参数滑动平均值的加载:
ema = tf.train.Exponential Moving Average(滑动平均基数)
ema_restore = ema.variables_to_restore()
saver = tf.train.Saver(ema_restore)
神经网络模型准确率评估方法
一般通过计算在一组数据上的识别准确率,评估神经网络的效果:
#tf.equal()函数判断预测结果张量和实际标签张量的每个维度是否相等,若相等则返回 True,不相等则返回 False。
#y表示在一组数据(即 batch_size 个数据)上神经网络模型的预测结果,y 的形状为[batch_size,10],每一行表示一张图片的识别结果。
#通过tf.argmax()函数取出每张图片对应向量中最大值元素对应的索引值,组成长度为输入数据 batch_size 个的一维数组。
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
#tf.cast() 函数将得到的布尔型数值转化为实数型
#tf.reduce_mean()函数求平均值,最终得到神经网络模型在本组数据上的准确率。
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
断点续训
关键处理:加入 ckpt 操作:
采用tf.train.get_checkpoint_state(checkpoint_dir,latest_filename=None)
函数,如果断点文件夹中包含有效断点状态文件,则返回该文件。
checkpoint_dir:表示存储断点文件的目录
latest_filename=None:断点文件的可选名称,默认为“checkpoint”
采用saver.restore(sess, ckpt.model_checkpoint_path) 函数表示恢复当前会话,将 ckpt 中的值赋给 w 和 b。
sess:表示当前会话,之前保存的结果将被加载入这个会话
ckpt.model_checkpoint_path:表示模型存储的位置,不需要提供模
型的名字,它会去查看 checkpoint 文件,看看最新的是谁,叫做什么
ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
神经网络模型的保存
在反向传播过程中,一般会间隔一定轮数保存一次神经网络模型,并产生三个文件(保存当前图结构的.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)
神经网络模型的加载
#with 结构中进行加载保存的神经网络模型,若 ckpt 和保存的模型在指定路径中存在,则将保存的神经网络模型加载到当前会话中
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)
3、输入真实图片,输出预测结果
网络输出:一维数组(十个可能性概率),数组中最大的那个元素所对应的索引号就是预测的结果,任务分成两个函数完成 :
1)test Pic Arr = pre_pic(test Pic),对手写数字图片做预处理
2)pre Value = restore_model(test Pic Arr),将符合神经网络输入要求的图片喂给复现的神经网络模型,输出预测值
def application():
test Num = input("input the number of test pictures:")
for i in range(test Num):
test Pic = raw_input("the path of test picture:")
test Pic Arr = pre_pic(test Pic)
pre Value = restore_model(test Pic Arr)
print "The prediction number is:", pre Value
4、实例:实现手写体 mnist 数据集的识别任务
(1)、定义forward.py文件:
import tensorflow as tf
INPUT_NODE = 784
OUTPUT_NODE = 10
LAYERL_NODE = 500
def get_weight(shape,regularizer):
w = tf.Variable(tf.truncated_normal(shape,stddev=0.1))
#判断是否需要正则化
if regularizer != None:
tf.add_to_collection('losses',tf.contrib.layers.l2_regularizer(regularizer)(w))
return w
def get_bias(shape):
b = tf.Variable(tf.zeros(shape))
return b
def forward(x,regularizer):
w1 = get_weight([INPUT_NODE,LAYERL_NODE],regularizer)
b1 = get_bias([LAYERL_NODE])
y1 = tf.nn.relu(tf.matmul(x,w1)+b1)
w2 = get_weight([LAYERL_NODE,OUTPUT_NODE],regularizer)
b2 = get_bias([OUTPUT_NODE])
y = tf.matmul(y1,w2)+b2
return y
(2)、定义backward.py文件:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import forward
import os
BATCH_SIZE = 200
LEARNING_RATE_BASE = 0.1
LEARNING_RATE_DECAY = 0.99
REGULARIZER = 0.0001
STEPS = 50000
MOVING_AVERAGE_DECAY = 0.99
MODEL_SAVE_PATH = "F:\MODEL"
MODEL_NAME = "mnist_model"
def backward(mnist):
x = tf.placeholder(tf.float32,[None,forward.INPUT_NODE])
y_ = tf.placeholder(tf.float32,[None,forward.OUTPUT_NODE])
y = forward.forward(x,REGULARIZER)
global_step = tf.Variable(0,trainable = False)
#进行Softmax并求Cross-Entropy,logits为神经网络输出层的输出,label为一个一维的vector,
# 长度等于batch_size,每一个值的取值区间必须是[0,num_classes),其实每一个值就是代表了batch中对应样本的类别
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'))
#设置指数下降学习率
learning_rate = tf.train.exponential_decay(LEARNING_RATE_BASE,
global_step,
mnist.train.num_examples/BATCH_SIZE,
LEARNING_RATE_DECAY,
staircase=True)
train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)
#设置滑动平均
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')
saver = tf.train.Saver()
with tf.Session() as sess:
init_op = tf.global_variables_initializer()
sess.run(init_op)
ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
if ckpt and ckpt.model_checkpoint_path:
saver.restore(sess, ckpt.model_checkpoint_path)
for i in range(STEPS):
xs,ys = mnist.train.next_batch(BATCH_SIZE)
_,loss_value,step = sess.run([train_op,loss,global_step],feed_dict={x:xs,y_:ys})
if i % 1000 == 0:
print("After %d training steps , loss on training batch is %g."%(step,loss_value))
saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step=global_step)
def main():
mnist = input_data.read_data_sets("F:\MODEL",one_hot = True)
backward(mnist)
if __name__ =='__main__':
main()
声明:本博客为学习《人工智能实践:Tensorflow笔记》:
https://www.icourse163.org/learn/PKU-1002536002#/learn/content
后总结,非常感谢曹健老师教授,转载请说明出处。