原文地址:dom
https://blog.csdn.net/dcrmg/article/details/79776876函数
------------------------------------------------------------------------------------------------------------------spa
tensorflow中为了充分利用GPU,减小GPU等待数据的空闲时间,使用了两个线程分别执行数据读入和数据计算。.net
具体来讲就是使用一个线程源源不断的将硬盘中的图片数据读入到一个内存队列中,另外一个线程负责计算任务,所需数据直接从内存队列中获取。线程
tf在内存队列以前,还设立了一个文件名队列,文件名队列存放的是参与训练的文件名,要训练 N个epoch,则文件名队列中就含有N个批次的全部文件名。 示例图以下:code
图片来至于 https://zhuanlan.zhihu.com/p/27238630)orm
在N个epoch的文件名最后是一个结束标志,当tf读到这个结束标志的时候,会抛出一个 OutofRange 的异常,外部捕获到这个异常以后就能够结束程序了。而建立tf的文件名队列就须要使用到 tf.train.slice_input_producer 函数。blog
tf.train.slice_input_producer 队列
tf.train.slice_input_producer是一个tensor生成器,做用是按照设定,每次从一个tensor列表中按顺序或者随机抽取出一个tensor放入文件名队列。图片
slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None,
capacity=32, shared_name=None, name=None)
tf.train.slice_input_producer定义了样本放入文件名队列的方式,包括迭代次数,是否乱序等,要真正将文件放入文件名队列,还须要调用tf.train.start_queue_runners 函数来启动执行文件名队列填充的线程,以后计算单元才能够把数据读出来,不然文件名队列为空的,计算单元就会处于一直等待状态,致使系统阻塞。
tf.train.slice_input_producer 和 tf.train.start_queue_runners 使用:
import tensorflow as tf images = ['img1', 'img2', 'img3', 'img4', 'img5'] labels= [1,2,3,4,5] epoch_num=8 f = tf.train.slice_input_producer([images, labels],num_epochs=None,shuffle=False) with tf.Session() as sess: sess.run(tf.global_variables_initializer()) coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess=sess, coord=coord) for i in range(epoch_num): k = sess.run(f) print ('************************') print (i,k) coord.request_stop() coord.join(threads)
tf.train.slice_input_producer函数中shuffle=False,不对tensor列表乱序,输出:
若是设置shuffle=True,输出乱序:
tf.train.batch是一个tensor队列生成器,做用是按照给定的tensor顺序,把batch_size个tensor推送到文件队列,做为训练一个batch的数据,等待tensor出队执行计算。
batch(tensors, batch_size, num_threads=1, capacity=32, enqueue_many=False, shapes=None, dynamic_pad=False, allow_smaller_final_batch=False, shared_name=None, name=None)
若是tf.train.batch的第一个参数 tensors 传入的是tenor列表或者字典,返回的是tensor列表或字典,若是传入的是只含有一个元素的列表,返回的是单个的tensor,而不是一个列表。
如下举例: 一共有5个样本,设置迭代次数是2次,每一个batch中含有3个样本,不打乱样本顺序:
# -*- coding:utf-8 -*- import tensorflow as tf import numpy as np # 样本个数 sample_num=5 # 设置迭代次数 epoch_num = 2 # 设置一个批次中包含样本个数 batch_size = 3 # 计算每一轮epoch中含有的batch个数 batch_total = int(sample_num/batch_size)+1 # 生成4个数据和标签 def generate_data(sample_num=sample_num): labels = np.asarray(range(0, sample_num)) images = np.random.random([sample_num, 224, 224, 3]) print('image size {},label size :{}'.format(images.shape, labels.shape)) return images,labels def get_batch_data(batch_size=batch_size): images, label = generate_data() # 数据类型转换为tf.float32 images = tf.cast(images, tf.float32) label = tf.cast(label, tf.int32) #从tensor列表中按顺序或随机抽取一个tensor input_queue = tf.train.slice_input_producer([images, label], shuffle=False) image_batch, label_batch = tf.train.batch(input_queue, batch_size=batch_size, num_threads=1, capacity=64) return image_batch, label_batch image_batch, label_batch = get_batch_data(batch_size=batch_size) with tf.Session() as sess: coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess, coord) try: for i in range(epoch_num): # 每一轮迭代 print( '************' ) for j in range(batch_total): #每个batch print( '--------' ) # 获取每个batch中batch_size个样本和标签 image_batch_v, label_batch_v = sess.run([image_batch, label_batch]) print(image_batch_v.shape, label_batch_v) except tf.errors.OutOfRangeError: print("done") finally: coord.request_stop() coord.join(threads)
输出:
每次生成的batch中含有3个样本,不打乱次序,因此生成的tensor序列是按照‘0,1,2,3,4,0,1,2,3……’排列的。
若是设置每一个batch中含有2个样本,打乱次序,即设置 batch_size = 2, tf.train.slice_input_producer函数中 shuffle=True,输出为:
# -*- coding:utf-8 -*- import tensorflow as tf import numpy as np # 样本个数 sample_num=5 # 设置迭代次数 epoch_num = 2 # 设置一个批次中包含样本个数 batch_size = 2 # 计算每一轮epoch中含有的batch个数 batch_total = int(sample_num/batch_size)+1 # 生成4个数据和标签 def generate_data(sample_num=sample_num): labels = np.asarray(range(0, sample_num)) images = np.random.random([sample_num, 224, 224, 3]) print('image size {},label size :{}'.format(images.shape, labels.shape)) return images,labels def get_batch_data(batch_size=batch_size): images, label = generate_data() # 数据类型转换为tf.float32 images = tf.cast(images, tf.float32) label = tf.cast(label, tf.int32) #从tensor列表中按顺序或随机抽取一个tensor input_queue = tf.train.slice_input_producer([images, label], shuffle=True) image_batch, label_batch = tf.train.batch(input_queue, batch_size=batch_size, num_threads=1, capacity=64) return image_batch, label_batch image_batch, label_batch = get_batch_data(batch_size=batch_size) with tf.Session() as sess: coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(sess, coord) try: for i in range(epoch_num): # 每一轮迭代 print( '************' ) for j in range(batch_total): #每个batch print( '--------' ) # 获取每个batch中batch_size个样本和标签 image_batch_v, label_batch_v = sess.run([image_batch, label_batch]) print(image_batch_v.shape, label_batch_v) except tf.errors.OutOfRangeError: print("done") finally: coord.request_stop() coord.join(threads)
与tf.train.batch函数相对的还有一个tf.train.shuffle_batch函数,两个函数做用同样,都是生成必定数量的tensor, 组成训练一个batch须要的数据集,区别是tf.train.shuffle_batch会打乱样本顺序。