文件写入与读取
tensorflow程序读取数据一种3中方法
- 供给数据(feeding):在tensorflow程序运行的每一步,让python代码供给数据
- 从文件读取数据:在tensorflow图的起始,让一个输入管道从文件中读取数据
- 预加载数据:在tensorflow图中定义常量或变量来保存所有数据(仅适用于数据量比较小的情况)
1.预加载数据:
import tensorflow as tf
x1=tf.constant([2,3,4])
x2=tf.constant([4,0,1])
y=tf.add(x1,x2)
with tf.Session() as sess:
print(sess.run(y))
x1,x2保存具体的值,将数据直接内嵌到图中,再将图传入会话中执行,当数据量较大时,图的输出会遇到效率问题。
2.供给数据
import tensorflow as tf
x1=tf.placeholder(tf.int32)
x2=tf.placeholder(tf.int32)
v1=[2,3,4]
v2=[4,0,1]
y=tf.add(x1,x2)
with tf.Session() as sess:
print(sess.run(y,feed_dict={x1:v1,x2:v2}))
x1,x2只是占位符,跟get_variable和variable定义出的变量不同。没有具体的值,运行的时候需要sess.run()中的feed_dict参数,将python产生的参数传入计算图并计算y。
以上两种方法在遇到大型数据的时候,就很吃力,feed_dict中间环节的增加。最优方案是在计算图中定义好文件读取的方法,让tensorflow自己从文件中读取数据,并解码成可用的样本集。
3.Tensorflow中的队列机制,从文件读取数据
从文件中读取数据的方法有很多,从文本里写入图片数据的路径和标签,用tensorflow的read_file()读入图片;也可以将图片和标签的值直接存放在CSV或者txt文件。
- 从字典结构的数据文件读取
- 从bin文件读取
- 从CSV(TXT)读取
- 从原图读取
- TFRecord格式文件的读取
Tensorflow的队列机制:
通过多线程将读取与计算数据两个操作分开,海量数据无法一次性载入内存,需要一边从硬盘中读取,一边进行训练,为了加快训练速度,可以采用多个线程读取数据,一个线程消耗数据。
Tensorflow中Queue的概念和用法
- Queue是TF队列和缓存机制的实现
- QueueRunner是TF中对操作Queue的线程的封装
- Coordinator是TF中用来协调线程运行的工具
三者互相配合也可以单独使用
1.Queue
根据实现方式不同,分成以下几种类型:
- tf.FIFOQueu:按先入先出顺序的队列
- tf.RandomShuffleQueue:随机顺序出列的队列
- tf.PaddingFIFOQueue:以固定长度批量出列的队列
- tf.PriorityQueue:带优先级出列的队列
- 。。。
上述类型创建使用方法基本相同
创建函数的参数:
tf.FIFOQueue(capacity,dbytes,shapes=None,names=None,shared_name=None,name=“fifo_queue”)
Queue主要包含入列enqueue和出列的dequeue两个操作。队列本身也是图中的一个节点,其他节点(enqueue和dequeue)可以修改队列节点中的内容。enqueue操作返回计算图中的Operation节点,dequeue操作返回一个Tensor值。Tensor在创建时同样只是一个定义(或“声明”),需要在Session中运行才能获得真正的数值。
2.QueueRunner
在数据输入的应用场景中,入队操作从硬盘上读取,放入内存中,速度较慢。使用QueueRunner可以创建一系列新的线程进行入队操作,让主线程继续使用数据。如果在神经网络训练场景中,就是训练网络和读取数据是异步的,主线程在训练网络,另一个线程在将数据从硬盘读入内存。
q=tf.FIFOQueue(10,"float")
counter=tf.Variable(0.0)
increment_op=tf.assign_add(counter,1.0)
enqueue_op=q.enqueue(counter)
qr=tf.train.QueueRunner(q,enqueue_ops=[increment_op,enqueue]*2])
#主线程
sess=tf.Session()
sess.run(tf.initialize_all_variables())
#启动入队线程
enqueue_threads=qr.create_threads(sess,start=True)
#主线程
for i in range(0,10):
print(sess.run(q.dequeue()))
没有使用sess.close()主线程就没有结束,入队线程也会一直运行。
增加计数的线程不断在后台运行,执行入队的线程会先执行10次,因为队列长度只有10,然后主线程开始消费,当一部分数据消费后,入队的进行又会开始执行,最终主线程消费完10个数据后停止,但其他线程继续运行,程序不会结束,如果使用功能sess.close()则该线程停止,且入队线程会报错。因为会话停止。
因为tensorflow在图上进行,要驱动一张图进行运算,必须送入数据,如果没有数据,则sess.run()无法执行,tf也不会报错,会一直挂起,等待数据准备好。
3.Coordinator
是用来保存线程组运行状态的协调器对象,可以单独和python线程使用。
将QueueRunner和Coordinator一起使用,当任何一个线程出现异常时,能够正常结束整个程序,同时主线程也可以直接调用request_stop()方法来停止所有子线程的执行。
从文件中读取数据
1.从字典结构的数据文件读取(python数据格式)
创建字典结构的数据文件:
- 先要准备好图片结构,使用功能opencv进行图像读取
- 把cv2.imread()读取到的图像进行裁切、扭曲等处理
- 使用numpy对数据进行处理,比如维度合并
- 把处理好的每一张图像的数据和标签分别存放在对应的list或ndarray中
- 创建一个字典,包含两个元素,"data"和“labels”,分别赋值为上面的list
- 使用功能pickle模块对字典进行序列化,并保存到文件中
针对图片较多的情况,不太可能把所有图像都写入文件,可以分批把图像写入几个文件中。
2.从bin文件读取
bin文件需要一定长度的size格式存储,比如每个样本的值占多少字节,label占多少字节。这对于每个样本都是固定的,然后一个接一个存储,因此可以使用tf.FixedLengthRecordReader类每次读取固定长度的字节,正好可以对应一个样本存储的字节,并用tfdecode_raw进行解析。
具体操作详见上述参考文章。
3.从CSV(TXT)文件读取
数据量不是很大的时候,可以从CSV或者TXT 文件进行读取。