我有一张图表:
- preprocessing_op1 -> op2 -> img
/ \
slice_input_producer([imgs, labels]) tf.train.batch(num_threads=n)
\- - - - - - - label - - - - - - -/
这是典型的数据I / O管道。
问题:tf.train.batch()的多个线程都有竞争条件。 例如Thread1获取sample1_img和sample2_label,因为Thread2已经采用了sample1_label,形成了一对(sample1_img,sample2_label)。我想这是因为slice_input_producer有两个独立的队列用于imgs和标签,两个队列独立工作。
Q1。 n个排队线程中的每一个都运行自己的子图副本吗?如果是,设置num_threads = n需要运行时相应子图的n倍内存?如果不是,那么线程是否会运行子图的不同部分以进行一次排队操作?
Q2(已解决)。如果我创建一个FIFOQueue并将(img,label)的元组排入队列,那么该对将会原子地出列,并且多线程实际上会有所帮助。它是否正确? (虽然它不是100%利用率,因为标签张量等待img tensor的预处理)
Q3(已解决)。是否有像tuple_input_producer()这样的函数,它采用张量列表并在内部只使用一个队列?
更新(Q2,Q3)
我对slice_input_tensor错了。 问题只发生在两个队列中,而不是slice_input_producer。
所以只需使用slice_input_producer,如果两个张量需要进入不同的队列,我可以使用单线程瓶颈(QueueRunner)将它们捆绑在一起。
示例代码(0.11):
import tensorflow as tf
import numpy as np
a = tf.train.string_input_producer(map(str,range(100)), shuffle=False).dequeue()
b = tf.train.string_input_producer(map(str,range(100)), shuffle=False).dequeue()
op1 = tf.identity(a)
op2 = tf.identity(op1)
c1, c2 = tf.train.batch([op2,b], num_threads=10, batch_size=10)
with tf.Session() as sess, tf.device('/gpu:0'):
sess.run([tf.initialize_all_variables()])
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess, coord)
for i in range(10):
d1, d2 = sess.run([c1,c2])
print d1, d2
coord.request_stop()
coord.join(threads)
结果(见第一行):
['0' '2' '1' '7' '4' '3' '6' '8' '9' '5'] ['0' '2' '1' '6' '5' '4' '7' '8' '9' '3']
['10' '11' '12' '13' '14' '15' '16' '17' '18' '19'] ['10' '11' '12' '13' '14' '15' '16' '17' '18' '19']
['20' '21' '22' '23' '24' '25' '26' '27' '28' '29'] ['20' '21' '22' '23' '24' '25' '26' '27' '28' '29']
['30' '31' '33' '32' '34' '35' '36' '37' '38' '39'] ['30' '31' '33' '32' '34' '35' '36' '37' '38' '39']
['40' '41' '42' '43' '44' '45' '46' '47' '48' '49'] ['40' '41' '42' '43' '44' '45' '46' '47' '48' '49']
['50' '51' '52' '53' '54' '55' '56' '57' '58' '59'] ['50' '51' '52' '53' '54' '55' '56' '57' '58' '59']
['60' '61' '62' '63' '64' '65' '66' '67' '68' '69'] ['60' '61' '62' '63' '64' '65' '66' '67' '68' '69']
['70' '71' '72' '73' '74' '75' '76' '77' '78' '79'] ['70' '71' '72' '73' '74' '75' '76' '77' '78' '79']
['80' '81' '82' '83' '84' '85' '86' '87' '88' '89'] ['80' '81' '82' '83' '84' '85' '86' '88' '89' '87']
['90' '91' '92' '93' '94' '95' '96' '97' '98' '99'] ['90' '91' '92' '93' '94' '95' '96' '97' '98' '99']
答案 0 :(得分:0)
您有并行运行调用,称为"步骤"并且每个步骤都维护自己在执行期间生成的张量副本。因此,在最坏的情况下,N个并行步骤需要N倍的内存。在实践中,它往往比N倍更好,因为只要不再需要张量,就会释放内存。队列和变量等有状态对象跨步骤共享。
您的案例中发生的情况如下:
step1: dequeue queue1
step2: dequeue queue1
step2: dequeue queue2
step1: dequeue queue2
您可以看到两个步骤的队列都不同步。两种避免它的方法:
在第二个示例中,您将有一个dequeue
op返回一对image/label
,并且事情应保持同步,因为dequeues
是原子的
答案 1 :(得分:0)
我已尝试使用tf = 0.12.1
的Update示例代码当迭代从范围(10)变为范围(100)时,也会发生不匹配。
如果我用num_threads = 1修改了tf.train.batch
参数,它就解决了。
我还没试过Combine two queues into a single queue with images/labels, and dequeue from that queue in parallel.
。