-1

我正在Dataset使用该from_generator函数创建一个张量流。在图形/会话模式下,它工作正常:

import tensorflow as tf

x = {str(i): i for i in range(10)}

def gen():
  for i in x:
    yield x[i]

ds = tf.data.Dataset.from_generator(gen, tf.int32)
batch = ds.make_one_shot_iterator().get_next()

with tf.Session() as sess:
  while True:
    try:
      print(sess.run(batch), end=' ')
    except tf.errors.OutOfRangeError:
      break
# 0 1 2 3 4 5 6 7 8 9

然而,令人惊讶的是,它使用急切执行失败了:

import tensorflow as tf
tf.enable_eager_execution()

x = {str(i): i for i in range(10)}

def gen():
  for i in x:
    yield x[i]

ds = tf.data.Dataset.from_generator(gen, tf.int32)

for x in ds:
  print(x, end=' ')
# TypeError: Only integers, slices (`:`), ellipsis (`...`), tf.newaxis (`None`) and scalar tf.int32/tf.int64 tensors are valid indices, got '1'

我假设,由于生成器的主体是没有序列化的纯 python,所以 tensorflow 不会查看 - 实际上不在乎 - 生成器中的内容。但显然情况并非如此。那么为什么 tensorflow 会关心生成器内部的内容呢?假设无法更改生成器,有没有办法以某种方式解决这个问题?

4

1 回答 1

1

tl;dr这个问题与 TensorFlow 无关。您之前定义的循环变量 shadows x

事实 1:forPython 中的循环没有命名空间,并将循环变量泄漏到周围的命名空间中(globals()在您的示例中)。

事实 2:闭包是“动态的”,即gen生成器只知道它应该查找"x"要评估的名称x[i]。的实际值x将在迭代生成器时得到解决。

将这两者放在一起并展开循环的前两次迭代,for我们得到以下执行序列:

ds = tf.data.Dataset.from_generator(gen, tf.int32)
it = iter(ds)
x = next(it)  # Calls to the generator which yields back x[i].
print(x, end='')
# Calls to the generator as before, but x is no longer a dict so x[i]
# is actually indexing into a Tensor!
x = next(it)  

解决方法很简单:使用不同的循环变量名。

for item in ds:
  print(item, end=' ')
于 2019-11-06T12:06:21.027 回答