TensorFlow FIFOQueue不是FIFO?

时间:2017-05-29 13:56:27

标签: python tensorflow

我将特定顺序的项目排入TensorFlow FIFOQueue,并期望能够以相同的顺序将它们出列,但这不是我观察到的行为。

运行以下独立代码演示了方法和行为。这已经在TensorFlow 1.1上运行在Python 2.7上(但可能在Python 3中有效)。

from __future__ import division, print_function, unicode_literals
import math
import numpy
import tensorflow as tf
from tensorflow.python.training import queue_runner
from tensorflow.python.ops import control_flow_ops

row_count, column_count = 7, 5
batch_size, step_size = 3, 2

# Create some random data
data = numpy.arange(row_count * column_count).reshape(
    (row_count, column_count))
print(data)

batch_count = int(math.ceil(row_count / batch_size))
step_count = int(math.ceil(column_count / step_size))
print(batch_count, step_count)

slices = tf.train.slice_input_producer([data], num_epochs=1, shuffle=False)
batch = tf.train.batch(slices, batch_size, allow_smaller_final_batch=True)

queue = tf.FIFOQueue(32, dtypes=[batch.dtype])
enqueue_ops = []
dependency = None

for step_index in range(step_count):
    step = tf.strided_slice(
        batch, [0, step_index * step_size],
        [tf.shape(batch)[0], (step_index + 1) * step_size])

    if dependency is None:
        dependency = step
    else:
        step = control_flow_ops.with_dependencies([dependency], step)

    enqueue_ops.append(queue.enqueue(step))

queue_runner.add_queue_runner(queue_runner.QueueRunner(
    queue=queue, enqueue_ops=[tf.group(*enqueue_ops)]))
step = queue.dequeue()

supervisor = tf.train.Supervisor()

with supervisor.managed_session() as session:
    for batch_index in range(batch_count):
        for step_index in range(step_count):
            print("Batch %d, step %d" % (batch_index, step_index))
            print(session.run(step))

预期输出

Batch 0, step 0
[[ 0  1]
 [ 5  6]
 [10 11]]
Batch 0, step 1
[[ 2  3]
 [ 7  8]
 [12 13]]
Batch 0, step 2
[[ 4]
 [ 9]
 [14]]
Batch 1, step 0
[[15 16]
 [20 21]
 [25 26]]
Batch 1, step 1
[[17 18]
 [22 23]
 [27 28]]
Batch 1, step 2
[[19]
 [24]
 [29]]
Batch 2, step 0
[[30 31]]
Batch 2, step 1
[[32 33]]
Batch 2, step 2
[[34]]

实际输出是

Batch 0, step 0
[[ 0  1]
 [ 5  6]
 [10 11]]
Batch 0, step 1
[[ 4]
 [ 9]
 [14]]
Batch 0, step 2
[[ 2  3]
 [ 7  8]
 [12 13]]
Batch 1, step 0
[[15 16]
 [20 21]
 [25 26]]
Batch 1, step 1
[[19]
 [24]
 [29]]
Batch 1, step 2
[[17 18]
 [22 23]
 [27 28]]
Batch 2, step 0
[[30 31]]
Batch 2, step 1
[[32 33]]
Batch 2, step 2
[[34]]

请注意,批次0和1中的步骤顺序不正确。我一直无法确定步骤的顺序。似乎批次总是按顺序排列,但每批中的步骤以“随机”顺序出现:它看起来是确定性的,但不是FIFO。

我尝试过使用和不使用上面代码中使用的显式依赖声明。我已经尝试将队列容量设置为1.我尝试设置enqueue_ops=enqueue_ops而不是使用tf.group,但这些更改都没有帮助,最后一个导致非常奇怪的输出。

也许tf.group忽略了依赖关系?

1 个答案:

答案 0 :(得分:0)

tensorflow.python.ops.control_flow_ops.with_dependencies似乎没有按照我的想法工作,或者我使用不正确。如果我转而使用tf.control_dependencies,我会得到我需要的行为:

from __future__ import division, print_function, unicode_literals
import math
import numpy
import tensorflow as tf
from tensorflow.python.training import queue_runner

row_count, column_count = 7, 5
batch_size, step_size = 3, 2

# Create some random data
data = numpy.arange(row_count * column_count).reshape(
    (row_count, column_count))
print(data)

batch_count = int(math.ceil(row_count / batch_size))
step_count = int(math.ceil(column_count / step_size))
print(batch_count, step_count)

slices = tf.train.slice_input_producer([data], num_epochs=1, shuffle=False)
batch = tf.train.batch(slices, batch_size, allow_smaller_final_batch=True)

queue = tf.FIFOQueue(32, dtypes=[batch.dtype])
enqueue_ops = []
dependency = None

for step_index in range(step_count):
    step = tf.strided_slice(
        batch, [0, step_index * step_size],
        [tf.shape(batch)[0], (step_index + 1) * step_size])

    if dependency is None:
        dependency = queue.enqueue(step)
    else:
        with tf.control_dependencies([dependency]):
            step = queue.enqueue(step)
            dependency = step

    enqueue_ops.append(step)

queue_runner.add_queue_runner(queue_runner.QueueRunner(
    queue=queue, enqueue_ops=[tf.group(*enqueue_ops)]))
step = queue.dequeue()

supervisor = tf.train.Supervisor()

with supervisor.managed_session() as session:
    for batch_index in range(batch_count):
        for step_index in range(step_count):
            print("Batch %d, step %d" % (batch_index, step_index))
            print(session.run(step))

这个答案是由answer to another SO question推动的。