- 我的目标:**在自定义RNN单元格中使用
add_loss
方法(在图形执行模式下)添加输入相关损耗。
- 使用Python 3.9
- 使用TensorFlow 2.8或2.10
- 假设
import tensorflow as tf
,我有一个子类tf.keras.Model
,它使用标准的tf.keras.layers.RNN
层和一个自定义RNN单元(子类tf.keras.layers.Layer
),在我的自定义RNN单元中,我调用self.add_loss(*)
来添加一个依赖于输入的损耗。 - 预期结果**:当我调用
Model.fit()
时,add_loss
方法被调用用于每个批处理和每个时间步,梯度计算步骤使用增加的损耗而不产生错误。
- 实际结果:**当我调用
Model.fit()
时,在梯度计算步骤中会引发InaccessibleTensorError
,特别是在Model.train_step()
内部调用self.losses
时。
Exception has occurred: InaccessibleTensorError
<tf.Tensor 'foo_model/rnn/while/bar_cell/Sum_1:0' shape=() dtype=float32> is out of scope and cannot be used here. Use return values, explicit Python locals or TensorFlow collections to access it.
Please see https://www.tensorflow.org/guide/function#all_outputs_of_a_tffunction_must_be_return_values for more information.
- 使用
unroll=True
初始化RNN
层时(使用eager-或graph-execution),不会引发该错误。不幸的是,这对我没有帮助,因为我的序列可能很长。调试时检查self.losses
显示了正确的元素数量(即4,每个时间步一个)。 - 使用立即执行和
unroll=False
时不会引发此错误。但检查self.losses
时显示self.losses
中的元素数不正确;有一个额外的元素(即5)。进一步调查发现,有一个额外的add_loss
调用。不确定为什么会发生这种情况。 - 切换到TensorFlow的最新稳定版本(2.10.0)无法修复此问题。
- 在TensorFlow的GitHub上搜索了Web、Stack Overflow和问题/代码后,我完全被难住了。
最小可重现示例
- 使用
pytest <name_of_file>.py
从命令行运行。
import pytest
import tensorflow as tf
class FooModel(tf.keras.Model):
"""A basic model for testing.
Attributes:
cell: The RNN cell layer.
"""
def __init__(self, rnn=None, **kwargs):
"""Initialize.
Args:
rnn: A Keras RNN layer.
kwargs: Additional key-word arguments.
Raises:
ValueError: If arguments are invalid.
"""
super().__init__(**kwargs)
# Assign layers.
self.rnn = rnn
def call(self, inputs, training=None):
"""Call.
Args:
inputs: A dictionary of inputs.
training (optional): Boolean indicating if training mode.
"""
output = self.rnn(inputs, training=training)
return output
class BarCell(tf.keras.layers.Layer):
"""RNN cell for testing."""
def __init__(self, **kwargs):
"""Initialize.
Args:
"""
super(BarCell, self).__init__(**kwargs)
# Satisfy RNNCell contract.
self.state_size = [tf.TensorShape([1]),]
def call(self, inputs, states, training=None):
"""Call."""
output = tf.reduce_sum(inputs, axis=1) + tf.constant(1.0)
self.add_loss(tf.reduce_sum(inputs))
states_tplus1 = [states[0] + 1]
return output, states_tplus1
@pytest.mark.parametrize(
"is_eager", [True, False]
)
@pytest.mark.parametrize(
"unroll", [True, False]
)
def test_rnn_fit_with_add_loss(is_eager, unroll):
"""Test fit method (triggering backprop)."""
tf.config.run_functions_eagerly(is_eager)
# Some dummy input formatted as a TF Dataset.
n_example = 5
x = tf.constant([
[[1, 2, 3], [2, 0, 0], [3, 0, 0], [4, 3, 4]],
[[1, 13, 8], [2, 0, 0], [3, 0, 0], [4, 13, 8]],
[[1, 5, 6], [2, 8, 0], [3, 16, 0], [4, 5, 6]],
[[1, 5, 12], [2, 14, 15], [3, 17, 18], [4, 5, 6]],
[[1, 5, 6], [2, 14, 15], [3, 17, 18], [4, 5, 6]],
], dtype=tf.float32)
y = tf.constant(
[
[[1], [2], [1], [2]],
[[10], [2], [1], [7]],
[[4], [2], [6], [2]],
[[4], [2], [1], [2]],
[[4], [2], [1], [2]],
], dtype=tf.float32
)
ds = tf.data.Dataset.from_tensor_slices((x, y))
ds = ds.batch(n_example, drop_remainder=False)
# A minimum model to reproduce the issue.
cell = BarCell()
rnn = tf.keras.layers.RNN(cell, return_sequences=True, unroll=unroll)
model = FooModel(rnn=rnn)
compile_kwargs = {
'loss': tf.keras.losses.MeanSquaredError(),
'optimizer': tf.keras.optimizers.Adam(learning_rate=.001),
}
model.compile(**compile_kwargs)
# Call fit which will trigger gradient computations and raise an error
# during graph execution.
model.fit(ds, epochs=1)
1条答案
按热度按时间rqenqsqc1#
我可以确认我也有同样的问题。注解以增加可见性。另外,我创建了一个与此相关的Github问题(https://github.com/tensorflow/tensorflow/issues/59319)。