def test_loss_dict(self): loss_container = compile_utils.LossesContainer( {"out1": "mse", "out2": "mae"}, {"out1": 1, "out2": 0.5} ) y_t = {"out1": tf.ones((10, 1)), "out2": tf.zeros((10, 1))} y_p = {"out1": tf.ones((10, 1)), "out2": tf.ones((10, 1))} sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertLen(loss_container._losses, 2) self.assertIsInstance(total_loss, tf.Tensor) self.assertEqual(total_loss.numpy(), 0.25) self.assertLen(loss_container.metrics, 3) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, "loss") self.assertEqual(loss_metric.result().numpy(), 0.25) out1_metric = loss_container.metrics[1] self.assertEqual(out1_metric.name, "out1_loss") self.assertEqual(out1_metric.result().numpy(), 0) out2_metric = loss_container.metrics[2] self.assertEqual(out2_metric.name, "out2_loss") self.assertEqual(out2_metric.result().numpy(), 0.5) loss_container.reset_state() self.assertEqual(loss_metric.result().numpy(), 0) self.assertEqual(out1_metric.result().numpy(), 0) self.assertEqual(out2_metric.result().numpy(), 0)
def test_loss_list(self): loss_container = compile_utils.LossesContainer(['mse', 'mae'], [1, 0.5]) y_t = [tf.ones((10, 1)), tf.zeros((10, 1))] y_p = [tf.ones((10, 1)), tf.ones((10, 1))] sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertEqual(loss_container._output_names, ['output_1', 'output_2']) self.assertLen(loss_container._losses, 2) self.assertEqual(total_loss.numpy(), 0.25) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 0.25) output_1_metric = loss_container.metrics[1] self.assertEqual(output_1_metric.name, 'output_1_loss') self.assertEqual(output_1_metric.result().numpy(), 0) output_2_metric = loss_container.metrics[2] self.assertEqual(output_2_metric.name, 'output_2_loss') self.assertEqual(output_2_metric.result().numpy(), 0.5) loss_container.reset_state() self.assertEqual(loss_metric.result().numpy(), 0) self.assertEqual(output_1_metric.result().numpy(), 0) self.assertEqual(output_2_metric.result().numpy(), 0)
def test_ragged_tensor_output(self): """ Ensure that ragged tensors can be passed as targets and predictions.""" def custom_loss_fn(y_true, y_pred): losses = tf.ragged.map_flat_values(losses_mod.mse, y_true, y_pred) return tf.reduce_mean(losses) class CustomLossClass(object): def __call__(self, y_true, y_pred): losses = tf.ragged.map_flat_values(losses_mod.mse, y_true, y_pred) return tf.reduce_mean(losses) loss_container = compile_utils.LossesContainer( [custom_loss_fn, CustomLossClass()]) v_t = tf.constant([[3., 4.], [1., 2.], [3., 5.]]) v_p = tf.constant([[3.1, 4.], [1., 2.], [3., 5.]]) y_t = tf.compat.v1.expand_dims( tf.RaggedTensor.from_row_splits(v_t, [0, 2, 3]), 0) y_p = tf.compat.v1.expand_dims( tf.RaggedTensor.from_row_splits(v_p, [0, 2, 3]), 0) loss_container(y_t, y_p) self.assertEqual(loss_container._losses[0].name, 'custom_loss_fn')
def test_missing_label_with_no_loss(self): # It's ok to exclude a label if that label has no # losses or metrics associated with it. loss_container = compile_utils.LossesContainer({ 'output1': 'mse', 'output3': 'mae' }) y_p = { 'output1': tf.convert_to_tensor([[0], [1], [2]]), 'output2': tf.convert_to_tensor([[3], [4], [5]]), 'output3': tf.convert_to_tensor([[6], [7], [8]]) } y_t = { 'output1': tf.convert_to_tensor([[1], [2], [3]]), 'output3': tf.convert_to_tensor([[4], [5], [6]]) } total_loss = loss_container(y_t, y_p) self.assertEqual(total_loss.numpy(), 3.) self.assertLen(loss_container.metrics, 3) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 3.) output_1_metric = loss_container.metrics[1] self.assertEqual(output_1_metric.name, 'output1_loss') self.assertEqual(output_1_metric.result().numpy(), 1.) output_3_metric = loss_container.metrics[2] self.assertEqual(output_3_metric.name, 'output3_loss') self.assertEqual(output_3_metric.result().numpy(), 2.)
def test_loss_dict(self): loss_container = compile_utils.LossesContainer( { 'out1': 'mse', 'out2': 'mae' }, { 'out1': 1, 'out2': 0.5 }) y_t = {'out1': tf.ones((10, 1)), 'out2': tf.zeros((10, 1))} y_p = {'out1': tf.ones((10, 1)), 'out2': tf.ones((10, 1))} sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertLen(loss_container._losses, 2) self.assertEqual(total_loss.numpy(), 0.25) self.assertLen(loss_container.metrics, 3) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 0.25) out1_metric = loss_container.metrics[1] self.assertEqual(out1_metric.name, 'out1_loss') self.assertEqual(out1_metric.result().numpy(), 0) out2_metric = loss_container.metrics[2] self.assertEqual(out2_metric.name, 'out2_loss') self.assertEqual(out2_metric.result().numpy(), 0.5)
def test_nested_structure(self): loss_container = compile_utils.LossesContainer( {"b": ["mse", None], "a": "mae"}, loss_weights={"b": [0.5, 0], "a": 1}, ) y_t = { "b": [tf.ones((10, 1)), tf.zeros((10, 1))], "a": tf.zeros((10, 1)), } y_p = { "b": [tf.zeros((10, 1)), tf.zeros((10, 1))], "a": tf.ones((10, 1)), } sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertIsInstance(total_loss, tf.Tensor) self.assertEqual(total_loss.numpy(), 0.75) self.assertLen(loss_container.metrics, 3) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, "loss") self.assertEqual(loss_metric.result().numpy(), 0.75) a_metric = loss_container.metrics[1] self.assertEqual(a_metric.name, "a_loss") self.assertEqual(a_metric.result().numpy(), 0.5) b_1_metric = loss_container.metrics[2] self.assertEqual(b_1_metric.name, "b_1_loss") self.assertEqual(b_1_metric.result().numpy(), 0.5)
def test_ragged_tensor_output(self): """Ensure that ragged tensors can be passed as targets and predictions.""" def custom_loss_fn(y_true, y_pred): """MSE supports RaggedTensors directly.""" return losses_mod.mse(y_true, y_pred) class CustomLossClass(losses_mod.Loss): """User defined loss function must implement RaggedTensor support.""" def call(self, y_true, y_pred): losses = tf.ragged.map_flat_values(tf.math.squared_difference, y_true, y_pred) return tf.reduce_mean(losses) loss_container = compile_utils.LossesContainer( [custom_loss_fn, CustomLossClass()]) v_t = tf.constant([[3., 4.], [1., 2.], [3., 5.]]) v_p = tf.constant([[3.1, 4.], [1., 2.], [3., 5.]]) y_t = tf.compat.v1.expand_dims( tf.RaggedTensor.from_row_splits(v_t, [0, 2, 3]), 0) y_p = tf.compat.v1.expand_dims( tf.RaggedTensor.from_row_splits(v_p, [0, 2, 3]), 0) loss_container(y_t, y_p) self.assertEqual(loss_container._losses[0].name, 'custom_loss_fn')
def test_float_dtypes(self): y_t = tf.constant([1, 9, 2, -5], shape=(2, 2), dtype=tf.float32) y_p = tf.constant([4, 8, 12, 8], shape=(2, 2), dtype=tf.float64) def my_mae(labels, preds): self.assertEqual(labels.dtype, tf.float64) self.assertEqual(preds.dtype, tf.float64) return backend.mean(tf.abs(preds - labels), axis=-1) loss_container = compile_utils.LossesContainer(my_mae) total_loss = loss_container(y_t, y_p) self.assertEqual(total_loss.dtype, tf.float64)
def test_no_input_mutation(self): loss = {"a": "mae"} loss_container = compile_utils.LossesContainer(loss) y_t = {"a": tf.zeros((10, 1))} y_p = {"a": tf.ones((10, 1)), "b": tf.zeros((10, 1))} sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertIsInstance(total_loss, tf.Tensor) self.assertEqual(total_loss.numpy(), 0.5) self.assertLen(loss, 1)
def test_loss_masking(self): loss_container = compile_utils.LossesContainer('mae') y_p = tf.constant([[[1], [1]], [[0], [0]]], dtype=tf.float32) y_t = tf.constant([[[1], [1]], [[1], [1]]], dtype=tf.float32) y_p._keras_mask = tf.constant([[1, 0], [1, 0]], dtype=tf.float32) total_loss = loss_container(y_t, y_p) self.assertAlmostEqual(total_loss.numpy(), .25) # sum over batch size self.assertLen(loss_container.metrics, 1) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertAlmostEqual(loss_metric.result().numpy(), .25)
def test_single_loss(self): loss_container = compile_utils.LossesContainer('mse') y_t, y_p = tf.ones((10, 5)), tf.zeros((10, 5)) total_loss = loss_container(y_t, y_p) self.assertTrue(loss_container._built) self.assertLen(loss_container._losses, 1) self.assertEqual(total_loss.numpy(), 1.) self.assertLen(loss_container.metrics, 1) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 1.)
def test_loss_sample_weight(self): loss_container = compile_utils.LossesContainer('mae') y_p = tf.constant([[[1], [1]], [[0], [0]]], dtype=tf.float32) y_t = tf.constant([[[1], [1]], [[1], [1]]], dtype=tf.float32) sw = tf.constant([[.2, .3], [.5, 0]], dtype=tf.float32) total_loss = loss_container(y_t, y_p, sample_weight=sw) # (0 * .2 + 0 * .3 + 1 * .5 + 1 * 0) / 4 self.assertAlmostEqual(total_loss.numpy(), .125) self.assertLen(loss_container.metrics, 1) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertAlmostEqual(loss_metric.result().numpy(), .125)
def test_custom_loss_callables(self): def custom_loss_fn(y_true, y_pred): return tf.reduce_sum(y_true - y_pred) class CustomLossClass(object): def __call__(self, y_true, y_pred): return tf.reduce_sum(y_true - y_pred) loss_container = compile_utils.LossesContainer( [custom_loss_fn, CustomLossClass()]) y_t, y_p = tf.ones((10, 5)), tf.zeros((10, 5)) loss_container(y_t, y_p) self.assertEqual(loss_container._losses[0].name, 'custom_loss_fn') self.assertEqual(loss_container._losses[1].name, 'custom_loss_class')
def test_loss_masking_sample_weight(self): loss_container = compile_utils.LossesContainer("mae") y_p = tf.constant([[[1], [1]], [[0], [0]]], dtype=tf.float32) y_t = tf.constant([[[1], [1]], [[1], [1]]], dtype=tf.float32) sw = tf.constant([[0.2, 0.3], [0.5, 0]], dtype=tf.float32) y_p._keras_mask = tf.constant([[1, 0], [1, 0]], dtype=tf.float32) total_loss = loss_container(y_t, y_p, sample_weight=sw) # (0 * .2 + 1 * .5) / 4 self.assertAlmostEqual(total_loss.numpy(), 0.125) # sum over batch size self.assertLen(loss_container.metrics, 1) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, "loss") self.assertAlmostEqual(loss_metric.result().numpy(), 0.125)
def test_single_loss(self): loss_container = compile_utils.LossesContainer("mse") y_t, y_p = tf.ones((10, 5)), tf.zeros((10, 5)) total_loss = loss_container(y_t, y_p) self.assertTrue(loss_container._built) self.assertLen(loss_container._losses, 1) self.assertIsInstance(total_loss, tf.Tensor) self.assertEqual(total_loss.numpy(), 1.0) self.assertLen(loss_container.metrics, 1) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, "loss") self.assertEqual(loss_metric.result().numpy(), 1.0) loss_container.reset_state() self.assertEqual(loss_metric.result().numpy(), 0.0)
def test_loss_partial_dict_with_output_names(self): loss_container = compile_utils.LossesContainer( {'out2': 'mae'}, {'out2': 1.}, output_names=['out1', 'out2']) y_t = [tf.ones((10, 1)), tf.zeros((10, 1))] y_p = [tf.ones((10, 1)), tf.ones((10, 1))] sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertEqual(total_loss.numpy(), 0.5) self.assertLen(loss_container.metrics, 2) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 0.5) out2_metric = loss_container.metrics[1] self.assertEqual(out2_metric.name, 'out2_loss') self.assertEqual(out2_metric.result().numpy(), 0.5)
def test_broadcast_single_loss(self): loss_container = compile_utils.LossesContainer('mse') y_t = [tf.ones((10, 1)), tf.zeros((10, 1))] y_p = [tf.ones((10, 1)), tf.ones((10, 1))] sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertEqual(total_loss.numpy(), 0.5) self.assertLen(loss_container.metrics, 3) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 0.5) output_1_metric = loss_container.metrics[1] self.assertEqual(output_1_metric.name, 'output_1_loss') self.assertEqual(output_1_metric.result().numpy(), 0.) output_2_metric = loss_container.metrics[2] self.assertEqual(output_2_metric.name, 'output_2_loss') self.assertEqual(output_2_metric.result().numpy(), 0.5)
def test_loss_dict_with_nones(self): loss_container = compile_utils.LossesContainer({ 'out1': None, 'out2': 'mae' }) y_t = {'out1': tf.ones((10, 1)), 'out2': tf.zeros((10, 1))} y_p = {'out1': tf.ones((10, 1)), 'out2': tf.ones((10, 1))} sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertIsInstance(total_loss, tf.Tensor) self.assertEqual(total_loss.numpy(), 0.5) self.assertLen(loss_container.metrics, 2) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 0.5) out2_metric = loss_container.metrics[1] self.assertEqual(out2_metric.name, 'out2_loss') self.assertEqual(out2_metric.result().numpy(), 0.5)
def test_nested_structure(self): loss_container = compile_utils.LossesContainer( { 'b': ['mse', None], 'a': 'mae' }, loss_weights={ 'b': [0.5, 0], 'a': 1 }) y_t = { 'b': [tf.ones((10, 1)), tf.zeros((10, 1))], 'a': tf.zeros((10, 1)) } y_p = { 'b': [tf.zeros((10, 1)), tf.zeros((10, 1))], 'a': tf.ones((10, 1)) } sw = tf.convert_to_tensor([0, 0, 0, 0, 0, 1, 1, 1, 1, 1]) total_loss = loss_container(y_t, y_p, sample_weight=sw) self.assertEqual(total_loss.numpy(), 0.75) self.assertLen(loss_container.metrics, 3) loss_metric = loss_container.metrics[0] self.assertEqual(loss_metric.name, 'loss') self.assertEqual(loss_metric.result().numpy(), 0.75) a_metric = loss_container.metrics[1] self.assertEqual(a_metric.name, 'a_loss') self.assertEqual(a_metric.result().numpy(), 0.5) b_1_metric = loss_container.metrics[2] self.assertEqual(b_1_metric.name, 'b_1_loss') self.assertEqual(b_1_metric.result().numpy(), 0.5)