Inputs to eager execution function cannot be Keras symbolic tensors
Your code works just fine with latest tensorflow (2.3) if you replace your fit row with
model.fit((data_x, data_y, data_w))
So:
import numpy as np
import tensorflow as tf
from tensorflow.keras import layers, losses, models
# HERE
def loss_fcn(y_true, y_pred):
w = y_pred[:, :, -1] # HERE
y_pred = y_pred[:, :, :-1] # HERE
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, 1) # HERE
data_y = np.random.rand(5, 4, 1)
x = layers.Input([4, 1])
w = layers.Input([4, 1]) # HERE
y = layers.Activation('tanh')(x)
output = layers.Concatenate()([y, w]) # HERE
model = models.Model(inputs=[x, w], outputs=output) # HERE
loss = loss_fcn # HERE
model.compile(loss=loss)
model.fit((data_x, data_y, data_w))
print('Done.')
Further, I found tf.reduce_mean, K.mean, tf.square, tf.exp etc. implemented in a loss funtion cause the same error.
One alternative solution is to pass weights as additional output features rather than input features.
This keeps the model completely free of anything weights related, and the weights appear only in the loss function and the .fit()
call:
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)
One drawback still is that you need to manipulate (potentially) large arrays when merging y
and w
in numpy.stack()
, so anymore more TensorFlow-like will be appreciated.
Another way:
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))
I think this is the most elegant solution.