Reputation: 386
My code to use tensorflow keras custom loss (using additional input data to calculate loss) is as follows:
inp = Input(shape=(inp_seq_len,feature_size))
w = Input(shape=(1))
# code ommitted
def custom_loss(w):
def loss(y_true,y_pred):
return -y_true*y_pred*w
return loss
model = Model(
inputs=[inp, w],
outputs=[pred],
)
model.compile(loss=custom_loss(w), optimizer='adam')
When doing model.fit(), I got error: Inputs to eager execution function cannot be Keras symbolic tensors, but found: tf.Tensor 'input_19:0 shape=[None,1], dtype=float32
Following https://github.com/tensorflow/tensorflow/issues/34944, I did: tf.config.experimental_run_functions_eagerly(True)
Then I got error: Cannot convert a symbolic Tensor (truediv_20:0) to a numpy array
Please note that I followed Inputs to eager execution function cannot be Keras symbolic tensors to change my code.
My original code is (unpack inp and w from one inpA):
inpA = Input(shape=(inp_seq_len,feature_size+1))
inp = Lambda(lambda x: x[:,:,:feature_size])(inpA)
w = Flatten()(Lambda(lambda x: x[:,-1,feature_size])(inpA))
def custom_loss(w):
def loss(y_true,y_pred):
return -y_true*y_pred*w
return loss
model = Model(
inputs=[inpA],
outputs=[pred],
)
model.compile(loss=custom_loss(w), optimizer='adam')
The error I got with/without tf.config.experimental_run_functions_eagerly(True) is same as above.
What I can do?
Thanks.
Update: got this error when using code from the below post:
WARNING:tensorflow:Output dense_3 missing from loss dictionary. We assume this was done on purpose. The fit and evaluate APIs will not be expecting any data to be passed to dense_3.
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-5-1f23bd570780> in <module>()
19 m.add_loss( mse( true, out, sample_weight ) )
20 m.compile(loss=None, optimizer='adam')
---> 21 history = m.fit([X, y, W], y, epochs=10)
22
23 # final fitted model to compute predictions
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training.pyc in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_freq, max_queue_size, workers, use_multiprocessing, **kwargs)
817 max_queue_size=max_queue_size,
818 workers=workers,
--> 819 use_multiprocessing=use_multiprocessing)
820
821 def evaluate(self,
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training_v2.pyc in fit(self, model, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_freq, max_queue_size, workers, use_multiprocessing, **kwargs)
233 max_queue_size=max_queue_size,
234 workers=workers,
--> 235 use_multiprocessing=use_multiprocessing)
236
237 total_samples = _get_total_number_of_samples(training_data_adapter)
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training_v2.pyc in _process_training_inputs(model, x, y, batch_size, epochs, sample_weights, class_weights, steps_per_epoch, validation_split, validation_data, validation_steps, shuffle, distribution_strategy, max_queue_size, workers, use_multiprocessing)
591 max_queue_size=max_queue_size,
592 workers=workers,
--> 593 use_multiprocessing=use_multiprocessing)
594 val_adapter = None
595 if validation_data:
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training_v2.pyc in _process_inputs(model, mode, x, y, batch_size, epochs, sample_weights, class_weights, shuffle, steps, distribution_strategy, max_queue_size, workers, use_multiprocessing)
644 standardize_function = None
645 x, y, sample_weights = standardize(
--> 646 x, y, sample_weight=sample_weights)
647 elif adapter_cls is data_adapter.ListsOfScalarsDataAdapter:
648 standardize_function = standardize
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training.pyc in _standardize_user_data(self, x, y, sample_weight, class_weight, batch_size, check_steps, steps_name, steps, validation_split, shuffle, extract_tensors_from_dataset)
2381 is_dataset=is_dataset,
2382 class_weight=class_weight,
-> 2383 batch_size=batch_size)
2384
2385 def _standardize_tensors(self, x, y, sample_weight, run_eagerly, dict_inputs,
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training.pyc in _standardize_tensors(self, x, y, sample_weight, run_eagerly, dict_inputs, is_dataset, class_weight, batch_size)
2467 shapes=None,
2468 check_batch_axis=False, # Don't enforce the batch size.
-> 2469 exception_prefix='target')
2470
2471 # Generate sample-wise weight values given the `sample_weight` and
/nfs/anaconda2/lib/python2.7/site-packages/tensorflow_core/python/keras/engine/training_utils.pyc in standardize_input_data(data, names, shapes, check_batch_axis, exception_prefix)
494 raise ValueError(
495 'Error when checking model ' + exception_prefix + ': '
--> 496 'expected no data, but got:', data)
497 return []
498 if data is None:
ValueError: ('Error when checking model target: expected no data, but got:', array([3.39102071e-01, 1.23122638e-01, 7.54209531e-01, 8.10110230e-01,
Upvotes: 4
Views: 2611
Reputation: 22031
this is a workaround to pass additional arguments to a custom loss function, in your case an array of weights. the trick consists in using fake inputs which are useful to build and use the loss in the correct ways. don't forget that keras handles fixed batch dimension
I provide a dummy example in a regression problem. this can be easily modified according to your needs
def mse(y_true, y_pred, sample_weight):
error = y_true-y_pred
return K.mean(K.sqrt(error)*sample_weight)
X = np.random.uniform(0,1, (1000,10))
y = np.random.uniform(0,1, 1000)
W = np.random.uniform(1,2, 1000)
inp = Input((10,))
true = Input((1,))
sample_weight = Input((1,))
x = Dense(32, activation='relu')(inp)
out = Dense(1)(x)
m = Model([inp,true, sample_weight], out)
m.add_loss( mse( true, out, sample_weight ) )
m.compile(loss=None, optimizer='adam')
history = m.fit([X, y, W], y=None, epochs=10)
# final fitted model to compute predictions
final_m = Model(inp, out)
Upvotes: 2