9、数据读取(一)——队列操作实现同步
1、我们要处理的数据一般在文件(图片,文档等)当中,读取数据之后才能使用深度学习算法进行训练,tf提供了多种数据的读取方式。
- CSV文件读取
- 图片读取
- 二进制文件读取
- tfrecords文件读取
2、在计算需要快速进行的时候,如何提高I/O的速度?(即如何解决I/O和计算不平衡的问题)
在训练的过程中,我们需要训练的数据往往会非常的大,不可能执行一次性读取的操作,不仅消耗内存,而且“计算”要花费更长的时间去等待“读取”的完成才能继续,tf提供了真正的多线程、队列以及文件的改善(tfrecords文件格式)机制,可以并行的去执行多个任务,
tf让子线程去读取数据,这样主线程就可以直接进行模型的训练。子线程没读取到一定量的数据(如100个)之后,主线程进行模型的训练。
3、队列和线程
(1)队列和队列管理器
在训练样本的时候,希望读入的训练样本时有序的
● tf.FlFOQueue 先进先出队列,按顺序出队列
API :
FIFOQueue(capacity, dtypes, name='fifo_queue')
创建-一个以先进先出的顺序对元素进行排队的队列
● capacity:整数。队列的大小,可能存储在此队列中的元素数量的上限,
● dtypes: DType对象列表。长度dtypes必须等于每个队列元素中的张量数, dtype的类型形状,决定了后面进队列元素形状
method
● dequeue(name=None) #出队列
● enqueue(vals, name=None): #进队列
● enqueue_many(vals, name=None); #vals列表或者元组,把很多数据数据同时放进去,返回一个进队列操作
● size(name=None) #队列当前的元素个数,常用于判断
例:对队列进行操作,队列Q中有三个数据,每取一个数据,对数据进行+1操作,再把结果放入队列
① 定义一个队列
Q = tf.FIFOQueue(3, tf.float32)
② 放入数据
enq_many = Q.enqueue_many(vals = [[0.1,0.2,0.3]]) #enq,enter_queue进队列
③出队列,加1操作,进队列
out_q = Q.dequeue() #此时out_q是一个tensor,可以run之后取出数据 data = out_q + 1 #符号重载 en_q = Q.enqueue(data)
依赖性,下一个op和上一个op之间必须存在计算的操作关系(如加一等),才能说他们拥有依赖性,此时只需运行最后一个即可。
这里的data 和out_q存在计算的操作关系,而out_q和enq_many没有关系
④ 会话
with tf.Session() as sess: #初始化队列 sess.run(enq_many) for i in range(100): sess.run(en_q) for i in range(Q.size().eval()): print(sess.run(Q.dequeue()))
⑤ 错误显示:
ValueError: Shape () must have rank at least 1
原因:
enq_many = Q.enqueue_many(vals = [0.1,0.2,0.3]) #vals 列表或者元组
[文档解释]该操作沿着第0维将每个组件张量分割成多个队列元素。“vals”中的所有张量必须在第0维中具有相同的大小。如果执行此操作时队列已满,则它将阻塞,直到所有元素都已排队。
这里应该是[[0.1,0.2,0.3],]才能将其的分量[0.1,0.2,0.3]切片,创建为队列元素
⑥ 完整代码
1 import tensorflow as tf 2 import os 3 os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' #去掉警告,将警告级别提升 4 5 # 模拟一下同步先处理数据,然后才能取数据训练 6 # 每一个op需要在session中去运行 7 # tf中,运行操作有依赖性(比如第二步) 8 9 # 1. 首先定义队列 10 Q = tf.FIFOQueue(3, tf.float32) #队列的大小 11 enq_many = Q.enqueue_many(vals = [[0.1,0.2,0.3],]) #vals 列表或者元组, 该op返回一个进队列操作 12 13 # 2.定义一些读取数据,取数据的过程, 取数据 ,+1, 入队列 14 out_q = Q.dequeue() #此时out_q是一个tensor,可以run之后取出数据 15 data = out_q + 1 #符号重载 16 en_q = Q.enqueue(data) 17 # 依赖性,下一个op和上一个op之间必须存在计算操作关系(如加一等),才能说他们拥有依赖性 18 # 这里的data 和out_q存在计算的操作关系,而out_q和enq_many没有关系 19 20 with tf.Session() as sess: 21 #初始化队列 22 sess.run(enq_many) 23 # sess.graph() 24 #处理数据,从队列中取数据 (放数据) 25 for i in range(100): 26 sess.run(en_q) #运行依赖的最后一个,这里打印是没有数据的 27 28 #训练数据 (这里假设为取数据) 29 for i in range(Q.size().eval()): # Q.size()是一个op,需要加eval()取值 30 print(sess.run(Q.dequeue()))
输出:
33.2 33.3 34.1
● tf.RandomShuffleQueue 随机出队列