从设计的角度来看,为什么 TensorFlow 中 eager 和图形模式下的错误消息不同?



为什么在Tensorflow中,急切模式和图形模式下的错误消息不一样?

例如:在紧急模式下运行:

import tensorflow as tf
tf.enable_eager_execution()
a = tf.random_uniform(shape=[2, 3])
a_tile = tf.tile(a, [5])
print(a_tile)

产生错误消息:

Expected multiples argument to be a vector of length 2 but got length 1 [Op:Tile]

在图形模式下运行时:

import tensorflow as tf
a = tf.random_uniform(shape=[2, 3])
a_tile = tf.tile(a, [5])
sess = tf.Session()
r1 = sess.run(a_tile)
print(r1)

产生错误消息:

Shape must be rank 2 but is rank 1 for 'Tile' (op: 'Tile') with input shapes: [2,3], [1].

虽然这似乎是一个细微差别,但在某些情况下,一个错误消息中的错误消息(例如渴望(并不能准确地指示实际错误,例如tf.linspace(github(。与此相关的是热切模式和图形模式之间的不同行为,而不仅仅是在错误消息中。例如tf.while_oop(github(。

从设计的角度来看,渴望模式是如何融入现有的TF中的?我觉得了解TF设计可以提高生产力。

在热切执行和图形执行之间,绝大多数代码路径(例如每个操作的实现(完全相同,但并非全部相同。

当不使用急于执行时,即当使用图时,有一个不同的"图构建"one_answers"图执行"阶段(通过tf.Session.run(。例如,考虑这个简单的片段:

import tensorflow as tf
element = tf.gather([1, 2], [10])
# No error till this point, error will be thrown when we execute the graph
with tf.Session() as sess:
print(sess.run(element))

当启用紧急执行时,操作会立即执行,因此错误会提前出现:

import tensorflow as tf
tf.enable_eager_execution()
element = tf.gather([1, 2], [10])

构建图时的这些延迟错误可能会使事情变得难以使用,因此TensorFlow试图通过运行额外的检查(如形状验证(来在图构建时捕捉一些错误。对于TensorFlow(C++中的REGISTER_OP宏(中注册的每个操作,都有一个形状推断函数,用于验证输入的形状,并根据输入形状生成输出的形状。例如,请参见Tile操作的定义(以及相应的形状函数(。

这些形状推断功能旨在与操作的要求同步,这将在执行时再次验证要求。理想情况下,这些检查不必在内核和形状推理函数之间重复,并且错误消息是相同的。然而,在实践中,这些检查是重复的(在图构建时一次,在图执行时一次(,并且错误消息并不总是同步的。

当启用紧急执行时,形状推断函数(和相应的检查(将被跳过,因为它们是多余的(操作无论如何都会进行必要的检查(。然而,正如您所观察到的,这意味着错误消息可能会有所不同——在上面的tf.tile示例中,我认为对于GitHub上的tf.linspace问题也是如此。值得注意的是,在这两种情况下,在图和渴望中使用相同的代码都会出现错误,因此在渴望中调试代码,然后将代码作为图执行的意图应该仍然存在,尽管在图构建时存在这些额外检查的这些怪癖。

希望能解释一下设计和差异的原因。如果错误消息没有帮助,我建议提交一个错误(或者更好的是发送一个pull请求(来改进它。在这种特殊的情况下,内核实现似乎可以在这里提供更好的错误消息。

最新更新