diff --git a/aeon/regression/deep_learning/_inception_time.py b/aeon/regression/deep_learning/_inception_time.py index 96e8a38362..d29967ae09 100644 --- a/aeon/regression/deep_learning/_inception_time.py +++ b/aeon/regression/deep_learning/_inception_time.py @@ -336,6 +336,39 @@ def _predict(self, X) -> np.ndarray: return ypreds + @classmethod + def load_model(cls, model_paths): + """ + Load pre-trained regressors instead of fitting. + + This enables full use of the estimator's functionality such as predict. + + Parameters + ---------- + model_paths : list of str (list of paths including the + model names and extension) + List of file paths to the saved .keras models of each regressor. + + Returns + ------- + InceptionTimeRegressor + An instance of InceptionTimeRegressor with the pre-trained models loaded. + """ + assert isinstance( + model_paths, list + ), "model_paths should be a list of paths to the models" + + regressor = cls(n_regressors=len(model_paths)) + regressor.regressors_ = [] + + for path in model_paths: + ind_regressor = IndividualInceptionRegressor() + ind_regressor.load_model(path) + regressor.regressors_.append(ind_regressor) + + regressor.is_fitted = True + return regressor + @classmethod def _get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. diff --git a/aeon/regression/deep_learning/_lite_time.py b/aeon/regression/deep_learning/_lite_time.py index 9af8bbaf4e..7750094019 100644 --- a/aeon/regression/deep_learning/_lite_time.py +++ b/aeon/regression/deep_learning/_lite_time.py @@ -262,6 +262,39 @@ def _predict(self, X) -> np.ndarray: return vals + @classmethod + def load_model(cls, model_paths): + """ + Load pre-trained regressors instead of fitting. + + This enables full use of the estimator's functionality such as predict. + + Parameters + ---------- + model_paths : list of str (list of paths including the + model names and extension) + List of file paths to the saved .keras models of each regressor. + + Returns + ------- + LITETimeRegressor + An instance of LITETimeRegressor with the pre-trained models loaded. + """ + assert isinstance( + model_paths, list + ), "model_paths should be a list of paths to the models" + + regressor = cls(n_regressors=len(model_paths)) + regressor.regressors_ = [] + + for path in model_paths: + ind_regressor = IndividualLITERegressor() + ind_regressor.load_model(path) + regressor.regressors_.append(ind_regressor) + + regressor.is_fitted = True + return regressor + @classmethod def _get_test_params(cls, parameter_set="default"): """Return testing parameter settings for the estimator. diff --git a/aeon/regression/deep_learning/tests/test_inception_time.py b/aeon/regression/deep_learning/tests/test_inception_time.py new file mode 100644 index 0000000000..9d88cde70b --- /dev/null +++ b/aeon/regression/deep_learning/tests/test_inception_time.py @@ -0,0 +1,55 @@ +"""Tests for save/load functionality of InceptionTimeRegressor.""" + +import glob +import os +import tempfile + +import numpy as np +import pytest + +from aeon.regression.deep_learning import InceptionTimeRegressor +from aeon.testing.data_generation import make_example_3d_numpy +from aeon.utils.validation._dependencies import _check_soft_dependencies + + +@pytest.mark.skipif( + not _check_soft_dependencies("tensorflow", severity="none"), + reason="skip test if required soft dependency not available", +) +def test_save_load_inceptiontime_regressor(): + """Test saving and loading for InceptionTimeRegressor.""" + with tempfile.TemporaryDirectory() as temp: + temp_dir = os.path.join(temp, "") + + X, y = make_example_3d_numpy( + n_cases=10, + n_channels=1, + n_timepoints=12, + return_y=True, + regression_target=True, + ) + + model = InceptionTimeRegressor( + n_epochs=1, + random_state=42, + save_best_model=True, + file_path=temp_dir, + n_regressors=1, + ) + model.fit(X, y) + + y_pred_orig = model.predict(X) + + model_files = glob.glob( + os.path.join(temp_dir, f"{model.best_file_name}*.keras") + ) + + loaded_model = InceptionTimeRegressor.load_model(model_paths=model_files) + + assert isinstance(loaded_model, InceptionTimeRegressor) + + preds = loaded_model.predict(X) + assert isinstance(preds, np.ndarray) + + assert len(preds) == len(y) + np.testing.assert_array_almost_equal(preds, y_pred_orig, decimal=4) diff --git a/aeon/regression/deep_learning/tests/test_lite_time.py b/aeon/regression/deep_learning/tests/test_lite_time.py new file mode 100644 index 0000000000..554c647ea8 --- /dev/null +++ b/aeon/regression/deep_learning/tests/test_lite_time.py @@ -0,0 +1,55 @@ +"""Tests for save/load functionality of LITETimeRegressor.""" + +import glob +import os +import tempfile + +import numpy as np +import pytest + +from aeon.regression.deep_learning import LITETimeRegressor +from aeon.testing.data_generation import make_example_3d_numpy +from aeon.utils.validation._dependencies import _check_soft_dependencies + + +@pytest.mark.skipif( + not _check_soft_dependencies("tensorflow", severity="none"), + reason="skip test if required soft dependency not available", +) +def test_save_load_litetimeregressor_regressor(): + """Test saving and loading for LITETimeRegressor.""" + with tempfile.TemporaryDirectory() as temp: + temp_dir = os.path.join(temp, "") + + X, y = make_example_3d_numpy( + n_cases=10, + n_channels=1, + n_timepoints=12, + return_y=True, + regression_target=True, + ) + + model = LITETimeRegressor( + n_epochs=1, + random_state=42, + save_best_model=True, + file_path=temp_dir, + n_regressors=1, + ) + model.fit(X, y) + + y_pred_orig = model.predict(X) + + model_files = glob.glob( + os.path.join(temp_dir, f"{model.best_file_name}*.keras") + ) + + loaded_model = LITETimeRegressor.load_model(model_paths=model_files) + + assert isinstance(loaded_model, LITETimeRegressor) + + preds = loaded_model.predict(X) + assert isinstance(preds, np.ndarray) + + assert len(preds) == len(y) + np.testing.assert_array_almost_equal(preds, y_pred_orig, decimal=4)