我的训练集包含两种文件:训练图像,文件名如“1.png”,标签文件,名称如“1.label.txt”。
我在这样的教程中发现了Queue和Reader的一些用法:
filename_queue = tf.train.string_input_producer(filenames)
result.key, value = reader.read(filename_queue)
但是,因为我的训练集包含两种文件,一种对应一种。如何使用Queue和Reader之类的代码?
修改
我正在考虑使用一个包含基本名称的队列来提供给另外两个队列,分别是image和label。像这样的代码:
with tf.Session() as sess:
base_name_queue = tf.train.string_input_producer(['image_names'], num_epochs=20)
base_name = base_name_queue.dequeue()
image_name = base_name + ".png"
image_name_queue = data_flow_ops.FIFOQueue(32, image_name.dtype.base_dtype)
image_name_queue.enqueue([image_name])
x = image_name_queue.dequeue()
print_op = tf.Print(image_name, [image_name])
qr = tf.train.QueueRunner(base_name_queue, [base_name_queue] * 4)
coord = tf.train.Coordinator()
enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
for step in range(1000000):
if coord.should_stop():
break
print(sess.run(print_op))
coord.request_stop()
coord.join(enqueue_threads)
但是运行此代码会导致错误:
TypeError:Fetch参数包含无效类型,必须是字符串或Tensor。 (无法将FIFOQueue转换为Tensor或Operation。)
并且错误指向此行:
coord.join(enqueue_threads)
我认为我必须误解TensorFlow队列的工作原理。
答案 0 :(得分:9)
我已经找到了解决问题的方法。我想在这里发帖回答而不是删除我的问题,希望这能帮助TensorFlow新手。
答案包含两部分:
解决方案很简单:
dequeue
进行一些预处理。 shuffle_batch
代码在这里:
base_names = ['file1', 'file2']
base_tensor = tf.convert_to_tensor(base_names)
image_name_queue = tf.train.string_input_producer(
tensor + '.png',
shuffle=False # Note: must set shuffle to False
)
label_queue = tf.train.string_input_producer(
tensor + '.lable.txt',
shuffle=False # Note: must set shuffle to False
)
# use reader to read file
image_reader = tf.WholeFileReader()
image_key, image_raw = image_reader.read(image_name_queue)
image = tf.image.decode_png(image_raw)
label_reader = tf.WholeFileReader()
label_key, label_raw = label_reader.read(label_queue)
label = tf.image.decode_raw(label_raw)
# preprocess image
processed_image = tf.image.per_image_whitening(image)
batch = tf.train.shuffle_batch([processed_image, label], 10, 100, 100)
# print batch
queue_threads = queue_runner.start_queue_runners()
print(sess.run(batch))
队列实际上是一个队列(似乎毫无意义)。队列有两种方法:enqueue
和dequeue
。 enqueue
的输入为Tensor
(您可以将普通数据排入队列,但内部会将其转换为Tensor
)。 dequeue
的返回值为Tensor
。所以你可以像这样建立队列管道:
q1 = data_flow_ops.FIFOQueue(32, tf.int)
q2 = data_flow_ops.FIFOQueue(32, tf.int)
enq1 = q1.enqueue([1,2,3,4,5])
v1 = q1.dequeue()
enq2 = q2.enqueue(v1)
在TensorFlow中使用队列的好处是异步加载数据,这将提高性能并节省内存。上面的代码不可运行,因为没有运行这些操作的线程。 QueueRunner旨在描述如何并行enqueue
数据。因此,初始化QueueRunner的参数是enqueue
操作(enqueue
的输出)。
设置完所有QueueRunner
后,您必须启动所有线程。一种方法是在创建它们时启动它们:
enqueue_threads = qr.create_threads(sess, coord=coord, start=True)
或者,您可以在完成所有设置工作后启动所有线程:
# add queue runner
queue_runner.add_queue_runner(queue_runner.QueueRunner(q, [enq]))
# start all queue runners
queue_threads = queue_runner.start_queue_runners()
当所有线程都启动时,您必须决定何时退出。协调员在这里这样做。 Coordinator
就像是所有正在运行的线程之间的共享标志。如果其中一个完成或遇到错误,它将调用coord.request_stop()
,然后调用True
时所有线程将获得coord.should_stop()
。所以使用Coordinator
的模式是:
coord = tf.train.Coordinator()
for step in range(1000000):
if coord.should_stop():
break
print(sess.run(print_op))
coord.request_stop()
coord.join(enqueue_threads)
答案 1 :(得分:0)
您使用两个队列的方法可能会产生一些负面影响。因为你的一个队列将保存图像数据(大)和另一个文本数据(微小),所以其中一个队列可能会滞后于另一个队列。
我建议你去看tfrecord format而不是它。然后构造一个tfrecord文件,该文件包含数据和标签。之后,只使用一个队列同时获取数据和标签。