渴望执行功能的输入不能是Keras符号张量

ber*_*ers 5 python deep-learning keras tensorflow eager-execution

我正在尝试在tf.Keras(TensorFlow 2.0.0rc0)中为稀疏注释数据的3-D U-Net 实现依赖于样本和像素的依赖损失加权(Cicek 2016,arxiv:1606.06650)。

这是我的代码:

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, losses, models

# disabling eager execution makes this example work:
# tf.python.framework_ops.disable_eager_execution()


def get_loss_fcn(w):
    def loss_fcn(y_true, y_pred):
        loss = w * losses.mse(y_true, y_pred)
        return loss
    return loss_fcn


data_x = np.random.rand(5, 4, 1)
data_w = np.random.rand(5, 4)
data_y = np.random.rand(5, 4, 1)

x = layers.Input([4, 1])
w = layers.Input([4])
y = layers.Activation('tanh')(x)
model = models.Model(inputs=[x, w], outputs=y)
loss = get_loss_fcn(model.input[1])

# using another loss makes it work, too:
# loss = 'mse'

model.compile(loss=loss)
model.fit((data_x, data_w), data_y)

print('Done.')
Run Code Online (Sandbox Code Playgroud)

在禁用急切执行时,此方法运行良好,但TensorFlow 2的要点之一是默认情况下具有急切执行。我和那个目标之间是自定义损失函数,如您所见(使用'mse'损失也可以消除该错误):

  File "MWE.py", line 30, in <module>
    model.fit((data_x, data_w), data_y)
[...]
tensorflow.python.eager.core._SymbolicException: Inputs to eager execution function cannot be Keras symbolic tensors, but found [<tf.Tensor 'input_2:0' shape=(None, 4) dtype=float32>]
Run Code Online (Sandbox Code Playgroud)

我该怎么做才能使这种结构能够执行得当呢?

我曾经有一个想法是w将输出连接起来,yy_pred分为原始函数y_predw损失函数,但这是我想避免的一种技巧。不过,它的工作原理是# HERE

  File "MWE.py", line 30, in <module>
    model.fit((data_x, data_w), data_y)
[...]
tensorflow.python.eager.core._SymbolicException: Inputs to eager execution function cannot be Keras symbolic tensors, but found [<tf.Tensor 'input_2:0' shape=(None, 4) dtype=float32>]
Run Code Online (Sandbox Code Playgroud)

还有其他想法吗?

ber*_*ers 9

一种替代解决方案是将权重作为附加输出特征而不是输入特征传递。

这使模型完全没有任何与权重相关的东西,权重只出现在损失函数和.fit()调用中:

import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, losses, models

data_x = 2 * np.ones((7, 11, 15, 3), dtype=float)
data_y = 5 * np.ones((7, 9, 13, 5), dtype=float)

x = layers.Input(data_x.shape[1:])
y = layers.Conv2D(5, kernel_size=3)(x)
model = models.Model(inputs=x, outputs=y)


def loss(y_true, y_pred):
    (y_true, w) = tf.split(y_true, num_or_size_splits=[-1, 1], axis=-1)
    loss = tf.squeeze(w, axis=-1) * losses.mse(y_true, y_pred)

    tf.print(tf.math.reduce_mean(y_true), "== 5")
    tf.print(tf.math.reduce_mean(w), "== 3")

    return loss


model.compile(loss=loss)

data_w = 3 * np.ones((7, 9, 13, 1), dtype=float)
data_yw = np.concatenate((data_y, data_w), axis=-1)
model.fit(data_x, data_yw)
Run Code Online (Sandbox Code Playgroud)

一个缺点仍然是你需要在合并ywin时操作(潜在的)大型数组numpy.stack(),所以更多类似 TensorFlow 的东西将受到赞赏。

  • 问题是你失去了 keras 的很多便利(即回调)。 (2认同)

fea*_*eer 6

其它的办法:

from tensorflow.keras import layers, models, losses
import numpy as np

def loss_fcn(y_true, y_pred, w):
    loss = w * losses.mse(y_true, y_pred)
    return loss


data_x = np.random.rand(5, 4, 1)
data_w = np.random.rand(5, 4)
data_y = np.random.rand(5, 4, 1)

x = layers.Input([4, 1])
y_true = layers.Input([4, 1])
w = layers.Input([4])
y = layers.Activation('tanh')(x)


model = models.Model(inputs=[x, y_true, w], outputs=y)
model.add_loss(loss_fcn(y, y_true, w))


model.compile()
model.fit((data_x, data_y, data_w))
Run Code Online (Sandbox Code Playgroud)

我认为这是最优雅的解决方案。