keras/keras_core/metrics/regression_metrics_test.py

393 lines
14 KiB
Python
Raw Normal View History

import numpy as np
from absl.testing import parameterized
from keras_core import testing
from keras_core.metrics import regression_metrics as metrics
class MeanSquaredErrorTest(testing.TestCase):
def test_config(self):
# TODO
pass
def test_unweighted(self):
mse_obj = metrics.MeanSquaredError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[[0, 0, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 1, 1, 1, 1]]
)
mse_obj.update_state(y_true, y_pred)
result = mse_obj.result()
self.assertAllClose(0.5, result, atol=1e-5)
def test_weighted(self):
mse_obj = metrics.MeanSquaredError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[[0, 0, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 1, 1, 1, 1]]
)
sample_weight = np.array([1.0, 1.5, 2.0, 2.5])
result = mse_obj(y_true, y_pred, sample_weight=sample_weight)
self.assertAllClose(0.54285, result, atol=1e-5)
class CosineSimilarityTest(testing.TestCase):
def l2_norm(self, x, axis):
epsilon = 1e-12
square_sum = np.sum(np.square(x), axis=axis, keepdims=True)
x_inv_norm = 1 / np.sqrt(np.maximum(square_sum, epsilon))
return np.multiply(x, x_inv_norm)
def setup(self, axis=1):
self.np_y_true = np.asarray([[1, 9, 2], [-5, -2, 6]], dtype=np.float32)
self.np_y_pred = np.asarray([[4, 8, 12], [8, 1, 3]], dtype=np.float32)
y_true = self.l2_norm(self.np_y_true, axis)
y_pred = self.l2_norm(self.np_y_pred, axis)
self.expected_loss = np.sum(np.multiply(y_true, y_pred), axis=(axis,))
self.y_true = self.np_y_true
self.y_pred = self.np_y_pred
def test_config(self):
cosine_obj = metrics.CosineSimilarity(
axis=2, name="my_cos", dtype="int32"
)
self.assertEqual(cosine_obj.name, "my_cos")
self.assertEqual(cosine_obj.dtype, "int32")
# Check save and restore config
cosine_obj2 = metrics.CosineSimilarity.from_config(
cosine_obj.get_config()
)
self.assertEqual(cosine_obj2.name, "my_cos")
self.assertEqual(cosine_obj2._dtype, "int32")
def test_unweighted(self):
self.setup()
cosine_obj = metrics.CosineSimilarity()
loss = cosine_obj(self.y_true, self.y_pred)
expected_loss = np.mean(self.expected_loss)
self.assertAlmostEqual(loss, expected_loss, 3)
def test_weighted(self):
self.setup()
cosine_obj = metrics.CosineSimilarity()
sample_weight = np.asarray([1.2, 3.4])
loss = cosine_obj(self.y_true, self.y_pred, sample_weight=sample_weight)
expected_loss = np.sum(self.expected_loss * sample_weight) / np.sum(
sample_weight
)
self.assertAlmostEqual(loss, expected_loss, 3)
def test_axis(self):
self.setup(axis=1)
cosine_obj = metrics.CosineSimilarity(axis=1)
loss = cosine_obj(self.y_true, self.y_pred)
expected_loss = np.mean(self.expected_loss)
self.assertAlmostEqual(loss, expected_loss, 3)
class MeanAbsoluteErrorTest(testing.TestCase):
def test_config(self):
mae_obj = metrics.MeanAbsoluteError(name="my_mae", dtype="int32")
self.assertEqual(mae_obj.name, "my_mae")
self.assertEqual(mae_obj._dtype, "int32")
# Check save and restore config
mae_obj2 = metrics.MeanAbsoluteError.from_config(mae_obj.get_config())
self.assertEqual(mae_obj2.name, "my_mae")
self.assertEqual(mae_obj2._dtype, "int32")
def test_unweighted(self):
mae_obj = metrics.MeanAbsoluteError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[[0, 0, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 1, 1, 1, 1]]
)
mae_obj.update_state(y_true, y_pred)
result = mae_obj.result()
self.assertAllClose(0.5, result, atol=1e-5)
def test_weighted(self):
mae_obj = metrics.MeanAbsoluteError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[[0, 0, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 1, 1, 1, 1]]
)
sample_weight = np.array([1.0, 1.5, 2.0, 2.5])
result = mae_obj(y_true, y_pred, sample_weight=sample_weight)
self.assertAllClose(0.54285, result, atol=1e-5)
class MeanAbsolutePercentageErrorTest(testing.TestCase):
def test_config(self):
mape_obj = metrics.MeanAbsolutePercentageError(
name="my_mape", dtype="int32"
)
self.assertEqual(mape_obj.name, "my_mape")
self.assertEqual(mape_obj._dtype, "int32")
# Check save and restore config
mape_obj2 = metrics.MeanAbsolutePercentageError.from_config(
mape_obj.get_config()
)
self.assertEqual(mape_obj2.name, "my_mape")
self.assertEqual(mape_obj2._dtype, "int32")
def test_unweighted(self):
mape_obj = metrics.MeanAbsolutePercentageError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[
[0, 0, 1, 1, 0],
[1, 1, 1, 1, 1],
[0, 1, 0, 1, 0],
[1, 1, 1, 1, 1],
],
dtype="float32",
)
result = mape_obj(y_true, y_pred)
self.assertAllClose(35e7, result, atol=1e-5)
def test_weighted(self):
mape_obj = metrics.MeanAbsolutePercentageError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[
[0, 0, 1, 1, 0],
[1, 1, 1, 1, 1],
[0, 1, 0, 1, 0],
[1, 1, 1, 1, 1],
],
dtype="float32",
)
sample_weight = np.array([1.0, 1.5, 2.0, 2.5])
result = mape_obj(y_true, y_pred, sample_weight=sample_weight)
self.assertAllClose(40e7, result, atol=1e-5)
class MeanSquaredLogarithmicErrorTest(testing.TestCase):
def test_config(self):
msle_obj = metrics.MeanSquaredLogarithmicError(
name="my_msle", dtype="int32"
)
self.assertEqual(msle_obj.name, "my_msle")
self.assertEqual(msle_obj._dtype, "int32")
# Check save and restore config
msle_obj2 = metrics.MeanSquaredLogarithmicError.from_config(
msle_obj.get_config()
)
self.assertEqual(msle_obj2.name, "my_msle")
self.assertEqual(msle_obj2._dtype, "int32")
def test_unweighted(self):
msle_obj = metrics.MeanSquaredLogarithmicError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[[0, 0, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 1, 1, 1, 1]]
)
msle_obj.update_state(y_true, y_pred)
result = msle_obj.result()
self.assertAllClose(0.24022, result, atol=1e-5)
def test_weighted(self):
msle_obj = metrics.MeanSquaredLogarithmicError()
y_true = np.array(
[[0, 1, 0, 1, 0], [0, 0, 1, 1, 1], [1, 1, 1, 1, 0], [0, 0, 0, 0, 1]]
)
y_pred = np.array(
[[0, 0, 1, 1, 0], [1, 1, 1, 1, 1], [0, 1, 0, 1, 0], [1, 1, 1, 1, 1]]
)
sample_weight = np.array([1.0, 1.5, 2.0, 2.5])
result = msle_obj(y_true, y_pred, sample_weight=sample_weight)
self.assertAllClose(0.26082, result, atol=1e-5)
class RootMeanSquaredErrorTest(testing.TestCase):
def test_config(self):
rmse_obj = metrics.RootMeanSquaredError(name="rmse", dtype="int32")
self.assertEqual(rmse_obj.name, "rmse")
self.assertEqual(rmse_obj._dtype, "int32")
rmse_obj2 = metrics.RootMeanSquaredError.from_config(
rmse_obj.get_config()
)
self.assertEqual(rmse_obj2.name, "rmse")
self.assertEqual(rmse_obj2._dtype, "int32")
def test_unweighted(self):
rmse_obj = metrics.RootMeanSquaredError()
y_true = np.array([2, 4, 6])
y_pred = np.array([1, 3, 2])
rmse_obj.update_state(y_true, y_pred)
result = rmse_obj.result()
# error = [-1, -1, -4], square(error) = [1, 1, 16], mean = 18/3 = 6
self.assertAllClose(np.sqrt(6), result, atol=1e-3)
def test_weighted(self):
rmse_obj = metrics.RootMeanSquaredError()
y_true = np.array([2, 4, 6])
y_pred = np.array([1, 3, 2])
y_true = np.array([2, 4, 6, 8])
y_pred = np.array([1, 3, 2, 3])
sample_weight = np.array([0, 1, 0, 1])
result = rmse_obj(y_true, y_pred, sample_weight=sample_weight)
self.assertAllClose(np.sqrt(13), result, atol=1e-3)
class LogCoshErrorTest(testing.TestCase):
def setup(self):
y_true = np.asarray([[1, 9, 2], [-5, -2, 6]], dtype=np.float32)
y_pred = np.asarray([[4, 8, 12], [8, 1, 3]], dtype=np.float32)
self.batch_size = 6
error = y_pred - y_true
self.expected_results = np.log((np.exp(error) + np.exp(-error)) / 2)
self.y_pred = y_pred
self.y_true = y_true
def test_config(self):
logcosh_obj = metrics.LogCoshError(name="logcosh", dtype="int32")
self.assertEqual(logcosh_obj.name, "logcosh")
self.assertEqual(logcosh_obj._dtype, "int32")
def test_unweighted(self):
self.setup()
logcosh_obj = metrics.LogCoshError()
logcosh_obj.update_state(self.y_true, self.y_pred)
result = logcosh_obj.result()
expected_result = np.sum(self.expected_results) / self.batch_size
self.assertAllClose(result, expected_result, atol=1e-3)
def test_weighted(self):
self.setup()
logcosh_obj = metrics.LogCoshError(dtype="float32")
sample_weight = np.array([[1.2], [3.4]])
result = logcosh_obj(
self.y_true, self.y_pred, sample_weight=sample_weight
)
sample_weight = np.asarray([1.2, 1.2, 1.2, 3.4, 3.4, 3.4]).reshape(
(2, 3)
)
expected_result = np.multiply(self.expected_results, sample_weight)
expected_result = np.sum(expected_result) / np.sum(sample_weight)
self.assertAllClose(result, expected_result, atol=1e-3)
class R2ScoreTest(parameterized.TestCase, testing.TestCase):
def _run_test(
self,
y_true,
y_pred,
sample_weights,
class_aggregation,
num_regressors,
reference_result,
):
r2 = metrics.R2Score(class_aggregation, num_regressors, dtype="float32")
r2.update_state(y_true, y_pred, sample_weights)
2023-05-08 20:03:32 +00:00
result = r2.result()
self.assertAllClose(result, reference_result, atol=1e-6)
def test_config(self):
r2_obj = metrics.R2Score(
class_aggregation=None, num_regressors=2, dtype="float32"
)
self.assertEqual(r2_obj.class_aggregation, None)
self.assertEqual(r2_obj.num_regressors, 2)
self.assertEqual(r2_obj.dtype, "float32")
# Check save and restore config
r2_obj2 = metrics.R2Score.from_config(r2_obj.get_config())
self.assertEqual(r2_obj2.class_aggregation, None)
self.assertEqual(r2_obj2.num_regressors, 2)
self.assertEqual(r2_obj2.dtype, "float32")
@parameterized.parameters(
# class_aggregation, num_regressors, result
(None, 0, [0.37, -1.295, 0.565]),
("uniform_average", 0, -0.12),
("variance_weighted_average", 0, -0.12),
)
def test_r2_sklearn_comparison(
self, class_aggregation, num_regressors, result
):
y_true = [[0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0, 0.0]]
y_pred = [[0.4, 0.5, 0.6], [0.1, 0.2, 0.3], [0.5, 0.8, 0.2]]
self._run_test(
y_true,
y_pred,
None,
class_aggregation=class_aggregation,
num_regressors=num_regressors,
reference_result=result,
)
@parameterized.parameters(
# class_aggregation, num_regressors, result
(None, 0, [0.17305559, -8.836666, -0.521]),
(None, 1, [0.054920673, -10.241904, -0.7382858]),
(None, 2, [-0.10259259, -12.115555, -1.0280001]),
("uniform_average", 0, -3.0615367889404297),
("uniform_average", 1, -3.641756534576416),
("uniform_average", 2, -4.415382385253906),
("variance_weighted_average", 0, -1.3710224628448486),
("variance_weighted_average", 1, -1.7097399234771729),
("variance_weighted_average", 2, -2.161363363265991),
)
def test_r2_tfa_comparison(self, class_aggregation, num_regressors, result):
y_true = [[0.0, 0.0, 1.0], [0.0, 1.0, 0.0], [1.0, 0.0, 0.0]]
y_pred = [[0.4, 0.9, 1.6], [0.1, 1.2, 0.6], [1.5, 0.8, 0.6]]
sample_weights = [0.8, 0.1, 0.4]
self._run_test(
y_true,
y_pred,
sample_weights,
class_aggregation=class_aggregation,
num_regressors=num_regressors,
reference_result=result,
)
def test_errors(self):
# Bad class_aggregation value
with self.assertRaisesRegex(
ValueError, "Invalid value for argument `class_aggregation`"
):
metrics.R2Score(class_aggregation="wrong")
# Bad num_regressors value
with self.assertRaisesRegex(
ValueError, "Invalid value for argument `num_regressors`"
):
metrics.R2Score(num_regressors=-1)
# Bad input shape
with self.assertRaisesRegex(ValueError, "expects 2D inputs with shape"):
r2 = metrics.R2Score()
r2.update_state([0.0, 1.0], [0.0, 1.0])