【问题标题】:using a `tf.Tensor` as a Python `bool` is not allowed in Graph execution with `tf.data.Dataset`在使用 `tf.data.Dataset` 的图形执行中不允许使用 `tf.Tensor` 作为 Python `bool`
【发布时间】:2020-12-16 07:50:47
【问题描述】:

我试图让这个函数接受一个单元素张量。

def classi(i):
    out = np.zeros((1, 49), np.uint8)
    for j in range(len(classcount)):
        i -= classcount[j]
        if i<0:
            break
    out[0][j] += 1
    return tf.convert_to_tensor(out)
    #basically the error seems to be related to the if i<0 line

这个函数将在这里被另一个函数调用

def formatcars(elem):
    return (elem['image'], tf.function(classi(elem['label'])))
    #note elem['label'] is just a single element tensor of integer.

然后映射到汽车数据集。

dataset.map(formatcars)

我不断收到错误:

OperatorNotAllowedInGraphError: using a `tf.Tensor` as a Python `bool` is not allowed in Graph execution. Use Eager execution or decorate this function with @tf.function.

我尝试过启用急切执行。我试过使用 tf.function,使用 tf.cond、tf.greater、.tonumpy()、.eval() 等都无济于事。它不断给出同样的错误。我现在没有主意了。

classcount列表定义如下:

classcount = [ 1,  6,  4, 14, 13,  6,  2,  4,  3, 22,  6,  1, 15,  1,  2,  4,  1,
       12,  5,  1,  2,  4, 11,  2,  1,  1,  5,  4,  2,  1,  1,  1,  1,  1,
        6,  1,  4,  1,  1,  1,  3,  1,  2,  4,  1,  4,  3,  3,  1]

它只是一个从

创建的整数列表
import scipy
import tensorflow_datasets as tfds

dataset = tfds.load('cars196', split = 'train')
mat = scipy.io.loadmat('cars_annos.mat')
classcount = []
starti = 0
curmake = ''
for i in range(len(mat['class_names'][0])):
    print(mat['class_names'][0][i][0].split(' ', 1)[0])
    if mat['class_names'][0][i][0].split(' ', 1)[0] != curmake:
        print(i-starti)
        if i-starti != 0:
            classcount.append(i-starti)
        starti = i
    curmake = mat['class_names'][0][i][0].split(' ', 1)[0]
classcount.append(1)

cars_annos.mat 来自http://imagenet.stanford.edu/internal/car196/cars_annos.mat

【问题讨论】:

  • 欢迎来到stackoverflow。你能确定你提供的代码是minimal reproducible example吗?
  • 谢谢。我添加了用于生成类计数的代码。虽然如果你只是复制 [1, 6, 4, 14, ....] 并将其分配为 classcount 那么它应该是完全相同的列表。

标签: python tensorflow tensorflow-datasets


【解决方案1】:

由于错误状态,您不能在急切执行之外的 python 条件语句中使用张量作为布尔值,tf.data.Dataset 将强制您使用图形模式(出于性能原因)。您也不能简单地使用 @tf.function 装饰器来装饰函数,因为 Autograph 无法转换将张量用作 python 布尔值的代码(例如在条件语句中)。

最好的处理方法是使用 TF ops 重写函数。一种方法可能如下:

def graphmode_classi(i):
    """ 
    performs a cumulative sum on classcount and substract that sum from i
    the first negative value will give us the value to one hot encode
    """  
    cumsum = tf.math.cumsum(classcount)
    first_neg = tf.where((i - cumsum)<0)[0]
    return tf.one_hot(first_neg, 49)

我们可以比较我重写的函数是否等效:

# random data
data = tf.cast(tf.random.normal((200, 1))**2 * 10, tf.int32)
for d in data:
    assert (classi(d).numpy() == graphmode_classi(d).numpy()).all()

现在您应该可以通过tf.data.Dataset API 使用仅使用 tf ops 编写的函数了:

data = tf.cast(tf.random.normal((200, 1))**2 * 10, tf.int32)
ds = tf.data.Dataset.from_tensor_slices(data)
ds.map(graphmode_classi)

【讨论】:

  • 感谢您向我介绍了这么多我不知道的方法!它不能开箱即用,但我能够对其进行调整以产生我需要的输出,谢谢!编辑:删除代码,因为它没有正确显示。
猜你喜欢
  • 2020-05-04
  • 1970-01-01
  • 2018-08-17
  • 1970-01-01
  • 1970-01-01
  • 2021-04-18
  • 2018-07-12
  • 2018-03-20
  • 1970-01-01
相关资源
最近更新 更多