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] Unify API #1023

Open
wants to merge 78 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 73 commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
72771c0
draft
elephaint May 31, 2024
dd9f26e
next_iteration
elephaint Jun 4, 2024
e0ee8d1
next_iter
elephaint Jun 9, 2024
e7bbf30
next_iteration
elephaint Jun 11, 2024
3419432
next_iter
elephaint Jun 13, 2024
75bea55
draft
elephaint May 31, 2024
ef019d1
next_iteration
elephaint Jun 4, 2024
4313c13
next_iter
elephaint Jun 9, 2024
8101656
next_iteration
elephaint Jun 11, 2024
14fbf32
next_iter
elephaint Jun 13, 2024
ae6d73c
merge_main
elephaint Jun 14, 2024
302489e
fix_iql_and_isqf
elephaint Jun 14, 2024
0dcb6a2
fix_mixture_losses
elephaint Jun 14, 2024
9160647
add_quantile_to_distributionloss_predict
elephaint Jun 15, 2024
b73c097
add_quantile_to_mixture_loss_predict
elephaint Jun 16, 2024
20c18c5
bugfixes
elephaint Jun 18, 2024
a26ac29
fix_bugs
elephaint Jul 11, 2024
b20fe3f
fix_multivariate_bugs
elephaint Jul 12, 2024
1070f1d
Merge branch 'main' into fix/docs_and_refactoring
elephaint Jul 15, 2024
452388f
fix_json
elephaint Jul 15, 2024
2d3762f
Merge branch 'main' into fix/docs_and_refactoring
elephaint Jul 22, 2024
2419eb5
Merge branch 'main' into fix/docs_and_refactoring
elephaint Jul 26, 2024
bffa8d1
merge_main
elephaint Jul 26, 2024
f02b50f
merge_main
elephaint Sep 24, 2024
f80c59b
fix_examples_and_mixture_loss_bug
elephaint Sep 24, 2024
a60498b
add_exceptions_and_add_dev_dep_for_ci
elephaint Sep 24, 2024
b5ba554
fix_failing_polars_test
elephaint Sep 24, 2024
f4de0ff
fix_tests
elephaint Sep 25, 2024
a4ec70d
fix_tests
elephaint Sep 25, 2024
706ef74
fix_tests
elephaint Sep 25, 2024
829fc17
fix_docs_multivariate
elephaint Sep 25, 2024
efe2e76
fix_tests_in_models
elephaint Sep 25, 2024
47c36f7
reduce_multivariate_test_time
elephaint Sep 25, 2024
998e813
remove_stemgnn_from_test_and_add_contiguous
elephaint Sep 25, 2024
99c4b14
remove_contiguous_static
elephaint Sep 25, 2024
a4e4ee7
change_contiguous_windows
elephaint Sep 25, 2024
ff89950
improve_speed
elephaint Sep 26, 2024
b3fafc3
reduce_default_windows_batch_size_multivariate
elephaint Sep 26, 2024
87af3ac
fix_rnn_models
elephaint Sep 27, 2024
af070a9
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 8, 2024
ec32f28
improve_dilated_rnn
elephaint Oct 8, 2024
2801f19
fix_scalar_autodilatedrnn
elephaint Oct 8, 2024
6c3b2af
improve_speed_dilatedrnn_test
elephaint Oct 8, 2024
ccf8b2d
improve_speed_tests
elephaint Oct 8, 2024
8cba223
fix_loss_detach
elephaint Oct 8, 2024
e35f5e1
improve_speed_of_tests
elephaint Oct 8, 2024
5fc0437
fix_contiguous_multivariate
elephaint Oct 8, 2024
9c52adb
maybe_improve_drnn_speed
elephaint Oct 8, 2024
9d5a2bc
test_move_contiguous_for_better_performance
elephaint Oct 9, 2024
97507f0
improve_speed
elephaint Oct 9, 2024
5494554
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 9, 2024
e9bc822
try_fix_slow_test
elephaint Oct 9, 2024
baf7014
improve_speed_recurrent_models
elephaint Oct 10, 2024
fffbda3
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 10, 2024
9c727cc
improve_speed_tcn
elephaint Oct 10, 2024
1a0ba55
Merge branch 'fix/docs_and_refactoring' of https://github.com/Nixtla/…
elephaint Oct 10, 2024
6bb64be
windows_without_contiguous
elephaint Oct 10, 2024
a8a9362
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 10, 2024
d6e24de
merge_main
elephaint Oct 10, 2024
430732f
try_improve_nhits_bitcn_speed
elephaint Oct 11, 2024
6a472dc
reduce_test_time_models
elephaint Oct 11, 2024
ae49324
improve_losses
elephaint Oct 11, 2024
d681fdf
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 11, 2024
abe522b
change_forward_to_call_losses
elephaint Oct 11, 2024
932fd55
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 15, 2024
1f52b8e
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 15, 2024
0b980c0
fix_linting
elephaint Oct 15, 2024
63984e6
unify_quantile_and_level_in_predict
elephaint Oct 17, 2024
bbea7ba
Merge branch 'main' into fix/docs_and_refactoring
elephaint Oct 17, 2024
6f2272c
fix_parameter_errors
elephaint Oct 17, 2024
a4c8b54
rework_conformal
elephaint Oct 17, 2024
8ee4592
quantile_maybe_used
elephaint Oct 17, 2024
96ab536
fix_non_monotonic_iq_loss_and_redundant_cv_conformal
elephaint Oct 17, 2024
030dabe
Merge branch 'main' into fix/docs_and_refactoring
elephaint Nov 4, 2024
ddc617f
fix_batch_size_max_multivariate
elephaint Nov 19, 2024
c529ced
merge_main
elephaint Nov 19, 2024
b2c7691
fix_base_model
elephaint Nov 19, 2024
42d1abe
Merge branch 'main' into fix/docs_and_refactoring
elephaint Nov 26, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:
uv pip install --system "numpy<2" ".[dev]"

- name: Tests
run: nbdev_test --do_print --timing --n_workers 0 --flags polars
run: nbdev_test --do_print --timing --n_workers 0 --flags polars
7 changes: 5 additions & 2 deletions action_files/test_models/src/evaluation.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i noticed that this file and action_files/test_models/src/evaluation2.py are quite similar. i have a couple of suggestions:

  • this might be a good opportunity to use the utilsforecast evaluation features. we could replace mae and smape from the losses module and the evaluate function.
  • also, it looks like the only difference between this file and the second one is the list of models, correct? if that’s the case, we could combine them into a single file and use fire to pass the list of models. you could then call it in the .github/workflows/ci.yaml file.

the idea would be to abstract the code in the if __name__ == '__main__': clause, something like this:

def main(models: list):
    groups = ['Monthly']
    datasets = ['M3']
    evaluation = [evaluate(model, dataset, group) for model, group in product(models, groups) for dataset in datasets]
    evaluation = [eval_ for eval_ in evaluation if eval_ is not None]
    evaluation = pd.concat(evaluation)
    evaluation = evaluation[['dataset', 'model', 'time', 'mae', 'smape']]
    evaluation['time'] /= 60  # minutes
    evaluation = evaluation.set_index(['dataset', 'model']).stack().reset_index()
    evaluation.columns = ['dataset', 'model', 'metric', 'val']
    evaluation = evaluation.set_index(['dataset', 'metric', 'model']).unstack().round(3)
    evaluation = evaluation.droplevel(0, 1).reset_index()
    evaluation['AutoARIMA'] = [666.82, 15.35, 3.000]
    evaluation.to_csv('data/evaluation.csv')
    print(evaluation.T)

and then you could use fire inside the main clause:

if __name__ == '__main__':
    import fire
    fire.Fire(main)

this way, we can run it for different models inside .github/workflows/ci.yaml: python -m action_files.test_models.src.evaluation --models <list of models>. wdyt?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this also could apply to action_files/test_models/src/multivariate_evaluation.py. since we are changing models and datasets, we could define main(models: list, dataset: str).

Copy link
Contributor Author

@elephaint elephaint Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, one remarkt - why favour ci over circleci? (I'm ambivalent, don't know why we would prefer one over the other)

Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,12 @@ def evaluate(model: str, dataset: str, group: str):

if __name__ == '__main__':
groups = ['Monthly']
models = ['AutoDilatedRNN', 'RNN', 'TCN', 'DeepAR',
models = ['AutoDilatedRNN', 'RNN',
'TCN',
'DeepAR',
'NHITS', 'TFT', 'AutoMLP', 'DLinear', 'VanillaTransformer',
'BiTCN', 'TiDE', 'DeepNPTS', 'NBEATS', 'KAN']
'BiTCN', 'TiDE', 'DeepNPTS', 'NBEATS', 'KAN'
]
datasets = ['M3']
evaluation = [evaluate(model, dataset, group) for model, group in product(models, groups) for dataset in datasets]
evaluation = [eval_ for eval_ in evaluation if eval_ is not None]
Expand Down
11 changes: 6 additions & 5 deletions action_files/test_models/src/models.py
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we could also merge action_files/test_models/src/models.py, action_files/test_models/src/models2.py, and action_files/test_models/src/multivariate_models.py. from what i can tell, the only real difference between them is the list of models. if that’s the case, we could add a new parameter to main—maybe config: str or something similar—and then have a dictionary with different models based on the config. for example: {"multivariate": , ...}, and then we could call it like this: python -m action_files.test_models.src.models --config multivariate.

let me know what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, then we can still fire up multiple runners (for the sake of keeping test time under control it makes sense to split the tests)

Original file line number Diff line number Diff line change
Expand Up @@ -61,21 +61,22 @@ def main(dataset: str = 'M3', group: str = 'Monthly') -> None:
"random_seed": tune.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
}
config_drnn = {'input_size': tune.choice([2 * horizon]),
'encoder_hidden_size': tune.choice([124]),
'encoder_hidden_size': tune.choice([16]),
"max_steps": 300,
"val_check_steps": 100,
"random_seed": tune.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),}
"random_seed": tune.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
"scaler_type": "minmax1"}

models = [
AutoDilatedRNN(h=horizon, loss=MAE(), config=config_drnn, num_samples=2, cpus=1),
RNN(h=horizon, input_size=2 * horizon, encoder_hidden_size=50, max_steps=300),
TCN(h=horizon, input_size=2 * horizon, encoder_hidden_size=20, max_steps=300),
RNN(h=horizon, input_size=2 * horizon, encoder_hidden_size=64, max_steps=300),
TCN(h=horizon, input_size=2 * horizon, encoder_hidden_size=64, max_steps=300),
NHITS(h=horizon, input_size=2 * horizon, dropout_prob_theta=0.5, loss=MAE(), max_steps=1000, val_check_steps=500),
AutoMLP(h=horizon, loss=MAE(), config=config, num_samples=2, cpus=1),
DLinear(h=horizon, input_size=2 * horizon, loss=MAE(), max_steps=2000, val_check_steps=500),
TFT(h=horizon, input_size=2 * horizon, loss=SMAPE(), hidden_size=64, scaler_type='robust', windows_batch_size=512, max_steps=1500, val_check_steps=500),
VanillaTransformer(h=horizon, input_size=2 * horizon, loss=MAE(), hidden_size=64, scaler_type='minmax1', windows_batch_size=512, max_steps=1500, val_check_steps=500),
DeepAR(h=horizon, input_size=2 * horizon, scaler_type='minmax1', max_steps=1000),
DeepAR(h=horizon, input_size=2 * horizon, scaler_type='minmax1', max_steps=500),
BiTCN(h=horizon, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=500),
TiDE(h=horizon, input_size=2 * horizon, loss=MAE(), max_steps=1000, val_check_steps=500),
DeepNPTS(h=horizon, input_size=2 * horizon, loss=MAE(), max_steps=1000, val_check_steps=500),
Expand Down
62 changes: 26 additions & 36 deletions action_files/test_models/src/models2.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,39 @@
import time

import fire
import numpy as np
# import numpy as np
import pandas as pd
import pytorch_lightning as pl
import torch
# import pytorch_lightning as pl
# import torch

import neuralforecast
# import neuralforecast
from neuralforecast.core import NeuralForecast

from neuralforecast.models.gru import GRU
from neuralforecast.models.rnn import RNN
from neuralforecast.models.tcn import TCN
# from neuralforecast.models.rnn import RNN
# from neuralforecast.models.tcn import TCN
from neuralforecast.models.lstm import LSTM
from neuralforecast.models.dilated_rnn import DilatedRNN
from neuralforecast.models.deepar import DeepAR
from neuralforecast.models.mlp import MLP
from neuralforecast.models.nhits import NHITS
from neuralforecast.models.nbeats import NBEATS
# from neuralforecast.models.deepar import DeepAR
# from neuralforecast.models.mlp import MLP
# from neuralforecast.models.nhits import NHITS
# from neuralforecast.models.nbeats import NBEATS
Comment on lines +14 to +21
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the commented code going to be restored in the future? if this change is permanent, maybe we could delete those lines instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm kind of treating this file also as a testing file locally, we can delete it (it's mainly so that testing locally is faster that you don't need to type all that stuff every time)

from neuralforecast.models.nbeatsx import NBEATSx
from neuralforecast.models.tft import TFT
from neuralforecast.models.vanillatransformer import VanillaTransformer
from neuralforecast.models.informer import Informer
from neuralforecast.models.autoformer import Autoformer
from neuralforecast.models.patchtst import PatchTST
# from neuralforecast.models.tft import TFT
# from neuralforecast.models.vanillatransformer import VanillaTransformer
# from neuralforecast.models.informer import Informer
# from neuralforecast.models.autoformer import Autoformer
# from neuralforecast.models.patchtst import PatchTST

from neuralforecast.auto import (
AutoMLP, AutoNHITS, AutoNBEATS, AutoDilatedRNN, AutoTFT
# AutoMLP,
AutoNHITS,
AutoNBEATS,
# AutoDilatedRNN,
# AutoTFT
)

from neuralforecast.losses.pytorch import SMAPE, MAE
from neuralforecast.losses.pytorch import MAE
from ray import tune

from src.data import get_data
Expand All @@ -49,32 +53,18 @@ def main(dataset: str = 'M3', group: str = 'Monthly') -> None:
"scaler_type": "minmax1",
"random_seed": tune.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
}
config = {
"hidden_size": tune.choice([256, 512]),
"num_layers": tune.choice([2, 4]),
"input_size": tune.choice([2 * horizon]),
"max_steps": 1000,
"val_check_steps": 300,
"scaler_type": "minmax1",
"random_seed": tune.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
}
config_drnn = {'input_size': tune.choice([2 * horizon]),
'encoder_hidden_size': tune.choice([124]),
"max_steps": 300,
"val_check_steps": 100,
"random_seed": tune.choice([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),}
models = [
LSTM(h=horizon, input_size=2 * horizon, encoder_hidden_size=50, max_steps=300),
DilatedRNN(h=horizon, input_size=2 * horizon, encoder_hidden_size=50, max_steps=300),
GRU(h=horizon, input_size=2 * horizon, encoder_hidden_size=50, max_steps=300),
LSTM(h=horizon, input_size=2 * horizon, encoder_hidden_size=64, max_steps=300),
DilatedRNN(h=horizon, input_size=2 * horizon, encoder_hidden_size=64, max_steps=300),
GRU(h=horizon, input_size=2 * horizon, encoder_hidden_size=64, max_steps=300),
AutoNBEATS(h=horizon, loss=MAE(), config=config_nbeats, num_samples=2, cpus=1),
AutoNHITS(h=horizon, loss=MAE(), config=config_nbeats, num_samples=2, cpus=1),
NBEATSx(h=horizon, input_size=2 * horizon, loss=MAE(), max_steps=1000),
PatchTST(h=horizon, input_size=2 * horizon, patch_len=4, stride=4, loss=MAE(), scaler_type='minmax1', windows_batch_size=512, max_steps=1000, val_check_steps=500),
# PatchTST(h=horizon, input_size=2 * horizon, patch_len=4, stride=4, loss=MAE(), scaler_type='minmax1', windows_batch_size=512, max_steps=1000, val_check_steps=500),
]

# Models
for model in models[:-1]:
for model in models:
model_name = type(model).__name__
print(50*'-', model_name, 50*'-')
start = time.time()
Expand Down
16 changes: 8 additions & 8 deletions action_files/test_models/src/multivariate_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from neuralforecast.models.tsmixer import TSMixer
from neuralforecast.models.tsmixerx import TSMixerx
from neuralforecast.models.itransformer import iTransformer
# from neuralforecast.models.stemgnn import StemGNN
# # from neuralforecast.models.stemgnn import StemGNN
from neuralforecast.models.mlpmultivariate import MLPMultivariate
from neuralforecast.models.timemixer import TimeMixer

Expand All @@ -26,13 +26,13 @@ def main(dataset: str = 'multivariate', group: str = 'ETTm2') -> None:
train['ds'] = pd.to_datetime(train['ds'])

models = [
SOFTS(h=horizon, n_series=7, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=500),
TSMixer(h=horizon, n_series=7, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=500),
TSMixerx(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=500),
iTransformer(h=horizon, n_series=7, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=500),
# StemGNN(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), dropout_rate=0.0, max_steps=1000, val_check_steps=500),
MLPMultivariate(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), max_steps=1000, val_check_steps=500),
TimeMixer(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=500)
SOFTS(h=horizon, n_series=7, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=500, val_check_steps=100, windows_batch_size=64, inference_windows_batch_size=64),
TSMixer(h=horizon, n_series=7, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=100, windows_batch_size=64, inference_windows_batch_size=64),
TSMixerx(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), dropout=0.0, max_steps=1000, val_check_steps=100, windows_batch_size=64, inference_windows_batch_size=64),
iTransformer(h=horizon, n_series=7, input_size=2 * horizon, loss=MAE(), dropout=0.0, max_steps=500, val_check_steps=100, windows_batch_size=64, inference_windows_batch_size=64),
# StemGNN(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), dropout_rate=0.0, max_steps=1000, val_check_steps=500, windows_batch_size=64, inference_windows_batch_size=64),
MLPMultivariate(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), max_steps=1000, val_check_steps=100, windows_batch_size=64, inference_windows_batch_size=64),
TimeMixer(h=horizon, n_series=7, input_size=2*horizon, loss=MAE(), dropout=0.0, max_steps=500, val_check_steps=100, windows_batch_size=64, inference_windows_batch_size=64)
]

# Models
Expand Down
6 changes: 5 additions & 1 deletion nbs/common.base_auto.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,11 @@
" self.callbacks = callbacks\n",
"\n",
" # Base Class attributes\n",
" self.SAMPLING_TYPE = cls_model.SAMPLING_TYPE\n",
" self.EXOGENOUS_FUTR = cls_model.EXOGENOUS_FUTR\n",
" self.EXOGENOUS_HIST = cls_model.EXOGENOUS_HIST\n",
" self.EXOGENOUS_STAT = cls_model.EXOGENOUS_STAT\n",
" self.MULTIVARIATE = cls_model.MULTIVARIATE \n",
" self.RECURRENT = cls_model.RECURRENT \n",
"\n",
" def __repr__(self):\n",
" return type(self).__name__ if self.alias is None else self.alias\n",
Expand Down
Loading