3.1.2 tfrecord格式使用方法
3.1.2.1 tfrecord文件介绍
tfrecord数据文件是将特征数据和特征数据对应的标签统一存储的二进制文件,能更好的利用内存,在tensorflow中快速的复制,移动,读取,存储。从宏观来讲,tfrecord其实是一种数据存储形式。使用tfrecord时,实际上是先读取原生数据,然后转换成tfrecord格式,再存储在硬盘上。而使用时,再把数据从相应的tfrecord文件中解码读取出来。
那么使用tfrecord和直接从硬盘读取原生数据相比到底有什么优势呢?其实,Tensorflow有和tfrecord配套的一些函数,可以加快数据的处理。实际读取tfrecord数据时,先以相应的tfrecord文件为参数,创建一个输入队列,这个队列有一定的容量(视具体硬件限制,用户可以设置不同的值),在一部分数据出队列时,tfrecord中的其他数据就可以通过预取进入队列,并且这个过程和网络的计算是独立进行的。
3.1.2.2 tfrecord文件数据的创建
tfrecord文件包含了tf.train.Example 协议缓冲区(protocol buffer,协议缓冲区包含了特征 Features)。可以 将数据填入到Example协议缓冲区(protocol buffer),将协议缓冲区序列化为一个字符串, 并且通过tf.python_io.TFRecordWriter class写入到TFRecords文件。
以创建100个大小为30x30的随机数组存入tfrecord为例:
首先导入包,并且创建一个名字为train的tfreocrd文件
import tensorflow as tf
import numpy as np
tfrecords_filename = 'train.tfrecords'
# Create tfrecord data ready to write
write = tf.python_io.TFRecordWriter(tfrecords_filename)
tf.python_io.TFRecordWriter用来创建tfrecord文件。
接下来创建一个循环依次写入100个30x30大小的数据。
for i in range(100):
img_raw = np.random.random_integers(0,255,size=(30,30)) # Create image size 30*30
img_raw = img_raw.tostring() # float data to bytes
example = tf.train.Example(features=tf.train.Features(
feature = {
'label':tf.train.Feature(int64_list=tf.train.Int64List(value=[i])),
'img_raw':tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw]))
}
))
write.write(example.SerializeToString())
write.close()
img_raw是通过numpy产生的随机数,用tostring转换成bytes的格式
example是数据存储区域(以字典的结构实现赋值)
write.write实现写入tfrecord。
赋值给example有三种数据格式分别为:
tf.train.Feature(int64_list = tf.train.Int64List(value=[int_scalar]))
tf.train.Feature(bytes_list = tf.train.BytesList(value=[array_string_or_byte]))
tf.train.Feature(bytes_list = tf.train.FloatList(value=[float_scalar]))
3.1.2.3 tfrecore文件数据的读取
首先,我们先创建数据流图,这个数据流图由一些流水线的阶段组成,阶段间用队列连接在一起。第一阶段将生成文件名,我们读取这些文件名并且把他们排到文件名队列中。第二阶段从文件中读取数据(使用Reader),产生样本,而且把样本放在一个样本队列中。根据你的设置,实际上也可以拷贝第二阶段的样本,使得他们相互独立,这样就可以从多个文件中并行读取。在第二阶段的最后是一个排队操作,就是入队到队列中去,在下一阶段出队。因为我们是要开始运行这些入队操作的线程,所以我们的训练循环会使得样本队列中的样本不断地出队。
以3.1.1.2中生成的train.tfrecords数据为例读取
import tensorflow as tf
import numpy as np
tfrecords_filename = 'train.tfrecords'
filename_queue = tf.train.string_input_producer([tfrecords_filename])
reader = tf.TFRecordReader()
_,serialized_example = reader.read(filename_queue)
features = tf.parse_single_example(serialized_example,features={
'label':tf.FixedLenFeature([],tf.int64),
'img_raw':tf.FixedLenFeature([],tf.string)
})
image = tf.decode_raw(features['img_raw'],tf.float32)
image = tf.reshape(image,[30,30])
label = tf.cast(features['label'],tf.int64)
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
try:
for i in range(20):
example,l = sess.run([image,label])
print(example,l)
except tf.errors.OutOfRangeError:
print("Done reading")
finally:
coord.request_stop()
coord.request_stop()
coord.join(threads)
在tf.train中要创建这些队列和执行入队操作,就要添加QueueRunner到一个使用tf.train.add_queue_runner函数的数据流图中。每个QueueRunner负责一个阶段,处理那些需要在线程中运行的入队操作的列表。一旦数据流图构造成功,tf.train.start_queue_runners函数就会要求数据流图中每个QueueRunner去开始它的线程运行入队操作。
在执行训练的时候,队列会被后台的线程填充好。如果设置了最大训练迭代数(epoch),在某些时候,样本出队的操作可能会抛出一个tf.OutOfRangeError的错误。这是因为tensorflow的队列已经到达了最大实际的最大迭代数,没有更多可用的样本了。