From 36535c069c77dd139baa6acecf5549bd02b7eda3 Mon Sep 17 00:00:00 2001 From: thawn Date: Fri, 12 Jul 2024 20:44:46 +0200 Subject: [PATCH 1/2] refactored into a python package --- pyproject.toml | 47 ++++++ run.py | 12 +- .../timeserieslib}/__init__.py | 0 src/timeserieslib/_version.py | 16 ++ src/timeserieslib/data_provider/__init__.py | 1 + .../data_provider}/data_factory.py | 10 +- .../data_provider}/data_loader.py | 26 +-- .../timeserieslib/data_provider}/m4.py | 0 .../timeserieslib/data_provider}/uea.py | 0 {exp => src/timeserieslib/exp}/__init__.py | 0 .../exp}/exp_anomaly_detection.py | 20 +-- {exp => src/timeserieslib/exp}/exp_basic.py | 13 +- .../timeserieslib/exp}/exp_classification.py | 10 +- .../timeserieslib/exp}/exp_imputation.py | 12 +- .../exp}/exp_long_term_forecasting.py | 23 ++- .../exp}/exp_short_term_forecasting.py | 12 +- .../timeserieslib/layers}/AutoCorrelation.py | 0 .../layers}/Autoformer_EncDec.py | 0 .../timeserieslib/layers}/Conv_Blocks.py | 0 .../layers}/Crossformer_EncDec.py | 7 +- .../timeserieslib/layers}/ETSformer_EncDec.py | 0 {layers => src/timeserieslib/layers}/Embed.py | 0 .../layers}/FourierCorrelation.py | 0 .../layers}/MultiWaveletCorrelation.py | 0 .../layers}/Pyraformer_EncDec.py | 6 +- .../layers}/SelfAttention_Family.py | 17 +- .../timeserieslib/layers}/StandardNorm.py | 0 .../layers}/Transformer_EncDec.py | 0 .../timeserieslib/layers}/__init__.py | 0 .../timeserieslib/models}/Autoformer.py | 6 +- .../timeserieslib/models}/Crossformer.py | 23 ++- .../timeserieslib/models}/DLinear.py | 2 +- .../timeserieslib/models}/ETSformer.py | 4 +- .../timeserieslib/models}/FEDformer.py | 10 +- {models => src/timeserieslib/models}/FiLM.py | 0 {models => src/timeserieslib/models}/FreTS.py | 0 .../timeserieslib/models}/Informer.py | 8 +- {models => src/timeserieslib/models}/Koopa.py | 156 +++++++++--------- .../timeserieslib/models}/LightTS.py | 0 {models => src/timeserieslib/models}/MICN.py | 5 +- {models => src/timeserieslib/models}/Mamba.py | 19 ++- .../timeserieslib/models}/MambaSimple.py | 53 +++--- .../models}/Nonstationary_Transformer.py | 6 +- .../timeserieslib/models}/PatchTST.py | 32 ++-- .../timeserieslib/models}/Pyraformer.py | 18 +- .../timeserieslib/models}/Reformer.py | 12 +- .../timeserieslib/models}/SegRNN.py | 12 +- .../timeserieslib/models}/TSMixer.py | 0 .../models}/TemporalFusionTransformer.py | 43 +++-- {models => src/timeserieslib/models}/TiDE.py | 0 .../timeserieslib/models}/TimeMixer.py | 10 +- .../timeserieslib/models}/TimesNet.py | 30 ++-- .../timeserieslib/models}/Transformer.py | 6 +- .../timeserieslib/models}/__init__.py | 0 .../timeserieslib/models}/iTransformer.py | 6 +- {utils => src/timeserieslib/utils}/ADFtest.py | 0 .../timeserieslib/utils}/__init__.py | 0 .../timeserieslib/utils}/augmentation.py | 0 {utils => src/timeserieslib/utils}/dtw.py | 0 .../timeserieslib/utils}/dtw_metric.py | 0 {utils => src/timeserieslib/utils}/losses.py | 0 .../timeserieslib/utils}/m4_summary.py | 4 +- {utils => src/timeserieslib/utils}/masking.py | 0 {utils => src/timeserieslib/utils}/metrics.py | 0 .../timeserieslib/utils}/print_args.py | 0 .../timeserieslib/utils}/timefeatures.py | 0 {utils => src/timeserieslib/utils}/tools.py | 6 +- tutorial/TimesNet_tutorial.ipynb | 6 +- 68 files changed, 407 insertions(+), 302 deletions(-) create mode 100644 pyproject.toml rename {data_provider => src/timeserieslib}/__init__.py (100%) create mode 100644 src/timeserieslib/_version.py create mode 100644 src/timeserieslib/data_provider/__init__.py rename {data_provider => src/timeserieslib/data_provider}/data_factory.py (90%) rename {data_provider => src/timeserieslib/data_provider}/data_loader.py (97%) rename {data_provider => src/timeserieslib/data_provider}/m4.py (100%) rename {data_provider => src/timeserieslib/data_provider}/uea.py (100%) rename {exp => src/timeserieslib/exp}/__init__.py (100%) rename {exp => src/timeserieslib/exp}/exp_anomaly_detection.py (97%) rename {exp => src/timeserieslib/exp}/exp_basic.py (81%) rename {exp => src/timeserieslib/exp}/exp_classification.py (95%) rename {exp => src/timeserieslib/exp}/exp_imputation.py (95%) rename {exp => src/timeserieslib/exp}/exp_long_term_forecasting.py (95%) rename {exp => src/timeserieslib/exp}/exp_short_term_forecasting.py (96%) rename {layers => src/timeserieslib/layers}/AutoCorrelation.py (100%) rename {layers => src/timeserieslib/layers}/Autoformer_EncDec.py (100%) rename {layers => src/timeserieslib/layers}/Conv_Blocks.py (100%) rename {layers => src/timeserieslib/layers}/Crossformer_EncDec.py (96%) rename {layers => src/timeserieslib/layers}/ETSformer_EncDec.py (100%) rename {layers => src/timeserieslib/layers}/Embed.py (100%) rename {layers => src/timeserieslib/layers}/FourierCorrelation.py (100%) rename {layers => src/timeserieslib/layers}/MultiWaveletCorrelation.py (100%) rename {layers => src/timeserieslib/layers}/Pyraformer_EncDec.py (97%) rename {layers => src/timeserieslib/layers}/SelfAttention_Family.py (96%) rename {layers => src/timeserieslib/layers}/StandardNorm.py (100%) rename {layers => src/timeserieslib/layers}/Transformer_EncDec.py (100%) rename {layers => src/timeserieslib/layers}/__init__.py (100%) rename {models => src/timeserieslib/models}/Autoformer.py (95%) rename {models => src/timeserieslib/models}/Crossformer.py (91%) rename {models => src/timeserieslib/models}/DLinear.py (98%) rename {models => src/timeserieslib/models}/ETSformer.py (96%) rename {models => src/timeserieslib/models}/FEDformer.py (94%) rename {models => src/timeserieslib/models}/FiLM.py (100%) rename {models => src/timeserieslib/models}/FreTS.py (100%) rename {models => src/timeserieslib/models}/Informer.py (96%) rename {models => src/timeserieslib/models}/Koopa.py (76%) rename {models => src/timeserieslib/models}/LightTS.py (100%) rename {models => src/timeserieslib/models}/MICN.py (98%) rename {models => src/timeserieslib/models}/Mamba.py (80%) rename {models => src/timeserieslib/models}/MambaSimple.py (82%) rename {models => src/timeserieslib/models}/Nonstationary_Transformer.py (97%) rename {models => src/timeserieslib/models}/PatchTST.py (89%) rename {models => src/timeserieslib/models}/Pyraformer.py (89%) rename {models => src/timeserieslib/models}/Reformer.py (95%) rename {models => src/timeserieslib/models}/SegRNN.py (91%) rename {models => src/timeserieslib/models}/TSMixer.py (100%) rename {models => src/timeserieslib/models}/TemporalFusionTransformer.py (87%) rename {models => src/timeserieslib/models}/TiDE.py (100%) rename {models => src/timeserieslib/models}/TimeMixer.py (98%) rename {models => src/timeserieslib/models}/TimesNet.py (90%) rename {models => src/timeserieslib/models}/Transformer.py (95%) rename {models => src/timeserieslib/models}/__init__.py (100%) rename {models => src/timeserieslib/models}/iTransformer.py (96%) rename {utils => src/timeserieslib/utils}/ADFtest.py (100%) rename {utils => src/timeserieslib/utils}/__init__.py (100%) rename {utils => src/timeserieslib/utils}/augmentation.py (100%) rename {utils => src/timeserieslib/utils}/dtw.py (100%) rename {utils => src/timeserieslib/utils}/dtw_metric.py (100%) rename {utils => src/timeserieslib/utils}/losses.py (100%) rename {utils => src/timeserieslib/utils}/m4_summary.py (98%) rename {utils => src/timeserieslib/utils}/masking.py (100%) rename {utils => src/timeserieslib/utils}/metrics.py (100%) rename {utils => src/timeserieslib/utils}/print_args.py (100%) rename {utils => src/timeserieslib/utils}/timefeatures.py (100%) rename {utils => src/timeserieslib/utils}/tools.py (94%) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..88464832 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,47 @@ +[build-system] +requires = ["setuptools", "setuptools_scm[toml]>7.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "timeserieslib" +description = "A library for time series analysis" +readme = "README.md" +requires-python = ">=3.8" +authors = [ + +] +keywords = ["regression", "python", "sklearn"] +license = {text = "BSD3 License"} #??? unclear +classifiers = [ + "Programming Language :: Python :: 3", +] +dependencies = [ + "einops>=0.4.0", + "matplotlib>=3.7.0", + "numpy>=1.23.5", + "pandas>=1.5.3", + "patool>=1.12", + "reformer-pytorch>=1.4.4", + "scikit-learn>=1.2.2", + "scipy>=1.10.1", + "sktime>=0.16.1", + "sympy>=1.11.1", + "torch>=1.7.1", + "tqdm>=4.64.1," +] +dynamic = ["version"] + +[tool.setuptools] +# packages = ["timeserieslib"] +include-package-data = true + +[tool.setuptools.packages.find] +where = ["src"] +include = ["vfdt*"] +namespaces = true + +[tool.setuptools_scm] +write_to = "src/timeserieslib/_version.py" + +[tool.setuptools.dynamic] +version = {attr = "timeserieslib._version.__version__"} diff --git a/run.py b/run.py index 2d8994a0..41fed3de 100644 --- a/run.py +++ b/run.py @@ -1,12 +1,12 @@ import argparse import os import torch -from exp.exp_long_term_forecasting import Exp_Long_Term_Forecast -from exp.exp_imputation import Exp_Imputation -from exp.exp_short_term_forecasting import Exp_Short_Term_Forecast -from exp.exp_anomaly_detection import Exp_Anomaly_Detection -from exp.exp_classification import Exp_Classification -from utils.print_args import print_args +from timeserieslib.exp.exp_long_term_forecasting import Exp_Long_Term_Forecast +from timeserieslib.exp.exp_imputation import Exp_Imputation +from timeserieslib.exp.exp_short_term_forecasting import Exp_Short_Term_Forecast +from timeserieslib.exp.exp_anomaly_detection import Exp_Anomaly_Detection +from timeserieslib.exp.exp_classification import Exp_Classification +from timeserieslib.utils.print_args import print_args import random import numpy as np diff --git a/data_provider/__init__.py b/src/timeserieslib/__init__.py similarity index 100% rename from data_provider/__init__.py rename to src/timeserieslib/__init__.py diff --git a/src/timeserieslib/_version.py b/src/timeserieslib/_version.py new file mode 100644 index 00000000..da77490d --- /dev/null +++ b/src/timeserieslib/_version.py @@ -0,0 +1,16 @@ +# file generated by setuptools_scm +# don't change, don't track in version control +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple, Union + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = '0.1.dev220+g8cee66a.d20240712' +__version_tuple__ = version_tuple = (0, 1, 'dev220', 'g8cee66a.d20240712') diff --git a/src/timeserieslib/data_provider/__init__.py b/src/timeserieslib/data_provider/__init__.py new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/timeserieslib/data_provider/__init__.py @@ -0,0 +1 @@ + diff --git a/data_provider/data_factory.py b/src/timeserieslib/data_provider/data_factory.py similarity index 90% rename from data_provider/data_factory.py rename to src/timeserieslib/data_provider/data_factory.py index 7af7698a..603d1835 100644 --- a/data_provider/data_factory.py +++ b/src/timeserieslib/data_provider/data_factory.py @@ -1,6 +1,6 @@ -from data_provider.data_loader import Dataset_ETT_hour, Dataset_ETT_minute, Dataset_Custom, Dataset_M4, PSMSegLoader, \ +from timeserieslib.data_provider.data_loader import Dataset_ETT_hour, Dataset_ETT_minute, Dataset_Custom, Dataset_M4, PSMSegLoader, \ MSLSegLoader, SMAPSegLoader, SMDSegLoader, SWATSegLoader, UEAloader -from data_provider.uea import collate_fn +from timeserieslib.data_provider.uea import collate_fn from torch.utils.data import DataLoader data_dict = { @@ -31,7 +31,7 @@ def data_provider(args, flag): if args.task_name == 'anomaly_detection': drop_last = False data_set = Data( - args = args, + args=args, root_path=args.root_path, win_size=args.seq_len, flag=flag, @@ -47,7 +47,7 @@ def data_provider(args, flag): elif args.task_name == 'classification': drop_last = False data_set = Data( - args = args, + args=args, root_path=args.root_path, flag=flag, ) @@ -65,7 +65,7 @@ def data_provider(args, flag): if args.data == 'm4': drop_last = False data_set = Data( - args = args, + args=args, root_path=args.root_path, data_path=args.data_path, flag=flag, diff --git a/data_provider/data_loader.py b/src/timeserieslib/data_provider/data_loader.py similarity index 97% rename from data_provider/data_loader.py rename to src/timeserieslib/data_provider/data_loader.py index 2bcb5cbd..65be63ce 100644 --- a/data_provider/data_loader.py +++ b/src/timeserieslib/data_provider/data_loader.py @@ -6,12 +6,12 @@ import torch from torch.utils.data import Dataset, DataLoader from sklearn.preprocessing import StandardScaler -from utils.timefeatures import time_features -from data_provider.m4 import M4Dataset, M4Meta -from data_provider.uea import subsample, interpolate_missing, Normalizer +from timeserieslib.utils.timefeatures import time_features +from timeserieslib.data_provider.m4 import M4Dataset, M4Meta +from timeserieslib.data_provider.uea import subsample, interpolate_missing, Normalizer from sktime.datasets import load_from_tsfile_to_dataframe import warnings -from utils.augmentation import run_augmentation_single +from timeserieslib.utils.augmentation import run_augmentation_single warnings.filterwarnings('ignore') @@ -23,7 +23,7 @@ def __init__(self, args, root_path, flag='train', size=None, # size [seq_len, label_len, pred_len] self.args = args # info - if size == None: + if size is None: self.seq_len = 24 * 4 * 4 self.label_len = 24 * 4 self.pred_len = 24 * 4 @@ -79,14 +79,14 @@ def __read_data__(self): data_stamp = df_stamp.drop(['date'], 1).values elif self.timeenc == 1: data_stamp = time_features(pd.to_datetime(df_stamp['date'].values), freq=self.freq) - data_stamp = data_stamp.transpose(1, 0) + data_stamp = data_stamp.transpose(1, 0) self.data_x = data[border1:border2] self.data_y = data[border1:border2] if self.set_type == 0 and self.args.augmentation_ratio > 0: self.data_x, self.data_y, augmentation_tags = run_augmentation_single(self.data_x, self.data_y, self.args) - + self.data_stamp = data_stamp def __getitem__(self, index): @@ -116,7 +116,7 @@ def __init__(self, args, root_path, flag='train', size=None, # size [seq_len, label_len, pred_len] self.args = args # info - if size == None: + if size is None: self.seq_len = 24 * 4 * 4 self.label_len = 24 * 4 self.pred_len = 24 * 4 @@ -211,7 +211,7 @@ def __init__(self, args, root_path, flag='train', size=None, # size [seq_len, label_len, pred_len] self.args = args # info - if size == None: + if size is None: self.seq_len = 24 * 4 * 4 self.label_len = 24 * 4 self.pred_len = 24 * 4 @@ -359,7 +359,7 @@ def __getitem__(self, index): insample[-len(insample_window):, 0] = insample_window insample_mask[-len(insample_window):, 0] = 1.0 outsample_window = sampled_timeseries[ - cut_point - self.label_len:min(len(sampled_timeseries), cut_point + self.pred_len)] + cut_point - self.label_len:min(len(sampled_timeseries), cut_point + self.pred_len)] outsample[:len(outsample_window), 0] = outsample_window outsample_mask[:len(outsample_window), 0] = 1.0 return insample, outsample, insample_mask, outsample_mask @@ -676,7 +676,7 @@ def load_all(self, root_path, file_list=None, flag=None): data_paths = list(filter(lambda x: re.search(flag, x), data_paths)) input_paths = [p for p in data_paths if os.path.isfile(p) and p.endswith('.ts')] if len(input_paths) == 0: - pattern='*.ts' + pattern = '*.ts' raise Exception("No .ts files found using pattern: '{}'".format(pattern)) all_df, labels_df = self.load_single(input_paths[0]) # a single file contains dataset @@ -685,7 +685,7 @@ def load_all(self, root_path, file_list=None, flag=None): def load_single(self, filepath): df, labels = load_from_tsfile_to_dataframe(filepath, return_separate_X_and_y=True, - replace_missing_vals_with='NaN') + replace_missing_vals_with='NaN') labels = pd.Series(labels, dtype="category") self.class_names = labels.cat.categories labels_df = pd.DataFrame(labels.cat.codes, @@ -742,7 +742,7 @@ def __getitem__(self, ind): batch_x = batch_x.reshape((1 * seq_len, num_columns)) return self.instance_norm(torch.from_numpy(batch_x)), \ - torch.from_numpy(labels) + torch.from_numpy(labels) def __len__(self): return len(self.all_IDs) diff --git a/data_provider/m4.py b/src/timeserieslib/data_provider/m4.py similarity index 100% rename from data_provider/m4.py rename to src/timeserieslib/data_provider/m4.py diff --git a/data_provider/uea.py b/src/timeserieslib/data_provider/uea.py similarity index 100% rename from data_provider/uea.py rename to src/timeserieslib/data_provider/uea.py diff --git a/exp/__init__.py b/src/timeserieslib/exp/__init__.py similarity index 100% rename from exp/__init__.py rename to src/timeserieslib/exp/__init__.py diff --git a/exp/exp_anomaly_detection.py b/src/timeserieslib/exp/exp_anomaly_detection.py similarity index 97% rename from exp/exp_anomaly_detection.py rename to src/timeserieslib/exp/exp_anomaly_detection.py index dfddc230..2f8d575e 100644 --- a/exp/exp_anomaly_detection.py +++ b/src/timeserieslib/exp/exp_anomaly_detection.py @@ -1,18 +1,18 @@ -from data_provider.data_factory import data_provider -from exp.exp_basic import Exp_Basic -from utils.tools import EarlyStopping, adjust_learning_rate, adjustment +import numpy as np +import warnings +import time +import os +from torch import optim +import torch.nn as nn +import torch +from timeserieslib.data_provider.data_factory import data_provider +from timeserieslib.exp.exp_basic import Exp_Basic +from timeserieslib.utils.tools import EarlyStopping, adjust_learning_rate, adjustment from sklearn.metrics import precision_recall_fscore_support from sklearn.metrics import accuracy_score import torch.multiprocessing torch.multiprocessing.set_sharing_strategy('file_system') -import torch -import torch.nn as nn -from torch import optim -import os -import time -import warnings -import numpy as np warnings.filterwarnings('ignore') diff --git a/exp/exp_basic.py b/src/timeserieslib/exp/exp_basic.py similarity index 81% rename from exp/exp_basic.py rename to src/timeserieslib/exp/exp_basic.py index fee70ef9..20f0351c 100644 --- a/exp/exp_basic.py +++ b/src/timeserieslib/exp/exp_basic.py @@ -1,8 +1,12 @@ import os import torch -from models import Autoformer, Transformer, TimesNet, Nonstationary_Transformer, DLinear, FEDformer, \ +from timeserieslib.models import Autoformer, Transformer, TimesNet, Nonstationary_Transformer, DLinear, FEDformer, \ Informer, LightTS, Reformer, ETSformer, Pyraformer, PatchTST, MICN, Crossformer, FiLM, iTransformer, \ - Koopa, TiDE, FreTS, TimeMixer, TSMixer, SegRNN, MambaSimple, Mamba, TemporalFusionTransformer + Koopa, TiDE, FreTS, TimeMixer, TSMixer, SegRNN, MambaSimple, TemporalFusionTransformer +try: + from timeserieslib.models import Mamba # Mamba does not work without cuda +except ModuleNotFoundError: + Mamba = None class Exp_Basic(object): @@ -29,12 +33,15 @@ def __init__(self, args): 'TiDE': TiDE, 'FreTS': FreTS, 'MambaSimple': MambaSimple, - 'Mamba': Mamba, 'TimeMixer': TimeMixer, 'TSMixer': TSMixer, 'SegRNN': SegRNN, 'TemporalFusionTransformer': TemporalFusionTransformer } + if Mamba is not None: + self.model_dict['Mamba'] = Mamba + elif self.args.model == 'Mamba': + raise ModuleNotFoundError('Mamba is not installed') self.device = self._acquire_device() self.model = self._build_model().to(self.device) diff --git a/exp/exp_classification.py b/src/timeserieslib/exp/exp_classification.py similarity index 95% rename from exp/exp_classification.py rename to src/timeserieslib/exp/exp_classification.py index 0a26061d..08cbc881 100644 --- a/exp/exp_classification.py +++ b/src/timeserieslib/exp/exp_classification.py @@ -1,6 +1,6 @@ -from data_provider.data_factory import data_provider -from exp.exp_basic import Exp_Basic -from utils.tools import EarlyStopping, adjust_learning_rate, cal_accuracy +from timeserieslib.data_provider.data_factory import data_provider +from timeserieslib.exp.exp_basic import Exp_Basic +from timeserieslib.utils.tools import EarlyStopping, adjust_learning_rate, cal_accuracy import torch import torch.nn as nn from torch import optim @@ -183,8 +183,8 @@ def test(self, setting, test=0): os.makedirs(folder_path) print('accuracy:{}'.format(accuracy)) - file_name='result_classification.txt' - f = open(os.path.join(folder_path,file_name), 'a') + file_name = 'result_classification.txt' + f = open(os.path.join(folder_path, file_name), 'a') f.write(setting + " \n") f.write('accuracy:{}'.format(accuracy)) f.write('\n') diff --git a/exp/exp_imputation.py b/src/timeserieslib/exp/exp_imputation.py similarity index 95% rename from exp/exp_imputation.py rename to src/timeserieslib/exp/exp_imputation.py index 70080b23..ea029cf0 100644 --- a/exp/exp_imputation.py +++ b/src/timeserieslib/exp/exp_imputation.py @@ -1,7 +1,7 @@ -from data_provider.data_factory import data_provider -from exp.exp_basic import Exp_Basic -from utils.tools import EarlyStopping, adjust_learning_rate, visual -from utils.metrics import metric +from timeserieslib.data_provider.data_factory import data_provider +from timeserieslib.exp.exp_basic import Exp_Basic +from timeserieslib.utils.tools import EarlyStopping, adjust_learning_rate, visual +from timeserieslib.utils.metrics import metric import torch import torch.nn as nn from torch import optim @@ -186,7 +186,7 @@ def test(self, setting, test=0): f_dim = -1 if self.args.features == 'MS' else 0 outputs = outputs[:, :, f_dim:] - # add support for MS + # add support for MS batch_x = batch_x[:, :, f_dim:] mask = mask[:, :, f_dim:] @@ -200,7 +200,7 @@ def test(self, setting, test=0): if i % 20 == 0: filled = true[0, :, -1].copy() filled = filled * mask[0, :, -1].detach().cpu().numpy() + \ - pred[0, :, -1] * (1 - mask[0, :, -1].detach().cpu().numpy()) + pred[0, :, -1] * (1 - mask[0, :, -1].detach().cpu().numpy()) visual(true[0, :, -1], filled, os.path.join(folder_path, str(i) + '.pdf')) preds = np.concatenate(preds, 0) diff --git a/exp/exp_long_term_forecasting.py b/src/timeserieslib/exp/exp_long_term_forecasting.py similarity index 95% rename from exp/exp_long_term_forecasting.py rename to src/timeserieslib/exp/exp_long_term_forecasting.py index 43b15d74..2c6dfa2b 100644 --- a/exp/exp_long_term_forecasting.py +++ b/src/timeserieslib/exp/exp_long_term_forecasting.py @@ -1,7 +1,7 @@ -from data_provider.data_factory import data_provider -from exp.exp_basic import Exp_Basic -from utils.tools import EarlyStopping, adjust_learning_rate, visual -from utils.metrics import metric +from timeserieslib.data_provider.data_factory import data_provider +from timeserieslib.exp.exp_basic import Exp_Basic +from timeserieslib.utils.tools import EarlyStopping, adjust_learning_rate, visual +from timeserieslib.utils.metrics import metric import torch import torch.nn as nn from torch import optim @@ -9,8 +9,8 @@ import time import warnings import numpy as np -from utils.dtw_metric import dtw,accelerated_dtw -from utils.augmentation import run_augmentation,run_augmentation_single +from timeserieslib.utils.dtw_metric import dtw, accelerated_dtw +from timeserieslib.utils.augmentation import run_augmentation, run_augmentation_single warnings.filterwarnings('ignore') @@ -223,7 +223,7 @@ def test(self, setting, test=0): shape = outputs.shape outputs = test_data.inverse_transform(outputs.squeeze(0)).reshape(shape) batch_y = test_data.inverse_transform(batch_y.squeeze(0)).reshape(shape) - + outputs = outputs[:, :, f_dim:] batch_y = batch_y[:, :, f_dim:] @@ -252,14 +252,14 @@ def test(self, setting, test=0): folder_path = './results/' + setting + '/' if not os.path.exists(folder_path): os.makedirs(folder_path) - + # dtw calculation if self.args.use_dtw: dtw_list = [] - manhattan_distance = lambda x, y: np.abs(x - y) + def manhattan_distance(x, y): return np.abs(x - y) for i in range(preds.shape[0]): - x = preds[i].reshape(-1,1) - y = trues[i].reshape(-1,1) + x = preds[i].reshape(-1, 1) + y = trues[i].reshape(-1, 1) if i % 100 == 0: print("calculating dtw iter:", i) d, _, _, _ = accelerated_dtw(x, y, dist=manhattan_distance) @@ -267,7 +267,6 @@ def test(self, setting, test=0): dtw = np.array(dtw_list).mean() else: dtw = -999 - mae, mse, rmse, mape, mspe = metric(preds, trues) print('mse:{}, mae:{}, dtw:{}'.format(mse, mae, dtw)) diff --git a/exp/exp_short_term_forecasting.py b/src/timeserieslib/exp/exp_short_term_forecasting.py similarity index 96% rename from exp/exp_short_term_forecasting.py rename to src/timeserieslib/exp/exp_short_term_forecasting.py index 90a0d8b4..261e9239 100644 --- a/exp/exp_short_term_forecasting.py +++ b/src/timeserieslib/exp/exp_short_term_forecasting.py @@ -1,9 +1,9 @@ -from data_provider.data_factory import data_provider -from data_provider.m4 import M4Meta -from exp.exp_basic import Exp_Basic -from utils.tools import EarlyStopping, adjust_learning_rate, visual -from utils.losses import mape_loss, mase_loss, smape_loss -from utils.m4_summary import M4Summary +from timeserieslib.data_provider.data_factory import data_provider +from timeserieslib.data_provider.m4 import M4Meta +from timeserieslib.exp.exp_basic import Exp_Basic +from timeserieslib.utils.tools import EarlyStopping, adjust_learning_rate, visual +from timeserieslib.utils.losses import mape_loss, mase_loss, smape_loss +from timeserieslib.utils.m4_summary import M4Summary import torch import torch.nn as nn from torch import optim diff --git a/layers/AutoCorrelation.py b/src/timeserieslib/layers/AutoCorrelation.py similarity index 100% rename from layers/AutoCorrelation.py rename to src/timeserieslib/layers/AutoCorrelation.py diff --git a/layers/Autoformer_EncDec.py b/src/timeserieslib/layers/Autoformer_EncDec.py similarity index 100% rename from layers/Autoformer_EncDec.py rename to src/timeserieslib/layers/Autoformer_EncDec.py diff --git a/layers/Conv_Blocks.py b/src/timeserieslib/layers/Conv_Blocks.py similarity index 100% rename from layers/Conv_Blocks.py rename to src/timeserieslib/layers/Conv_Blocks.py diff --git a/layers/Crossformer_EncDec.py b/src/timeserieslib/layers/Crossformer_EncDec.py similarity index 96% rename from layers/Crossformer_EncDec.py rename to src/timeserieslib/layers/Crossformer_EncDec.py index 42fc3225..9370a8d4 100644 --- a/layers/Crossformer_EncDec.py +++ b/src/timeserieslib/layers/Crossformer_EncDec.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn from einops import rearrange, repeat -from layers.SelfAttention_Family import TwoStageAttentionLayer +from timeserieslib.layers.SelfAttention_Family import TwoStageAttentionLayer class SegMerging(nn.Module): @@ -31,7 +31,7 @@ def forward(self, x): class scale_block(nn.Module): - def __init__(self, configs, win_size, d_model, n_heads, d_ff, depth, dropout, \ + def __init__(self, configs, win_size, d_model, n_heads, d_ff, depth, dropout, seg_num=10, factor=10): super(scale_block, self).__init__() @@ -43,7 +43,7 @@ def __init__(self, configs, win_size, d_model, n_heads, d_ff, depth, dropout, \ self.encode_layers = nn.ModuleList() for i in range(depth): - self.encode_layers.append(TwoStageAttentionLayer(configs, seg_num, factor, d_model, n_heads, \ + self.encode_layers.append(TwoStageAttentionLayer(configs, seg_num, factor, d_model, n_heads, d_ff, dropout)) def forward(self, x, attn_mask=None, tau=None, delta=None): @@ -111,7 +111,6 @@ def __init__(self, layers): super(Decoder, self).__init__() self.decode_layers = nn.ModuleList(layers) - def forward(self, x, cross): final_predict = None i = 0 diff --git a/layers/ETSformer_EncDec.py b/src/timeserieslib/layers/ETSformer_EncDec.py similarity index 100% rename from layers/ETSformer_EncDec.py rename to src/timeserieslib/layers/ETSformer_EncDec.py diff --git a/layers/Embed.py b/src/timeserieslib/layers/Embed.py similarity index 100% rename from layers/Embed.py rename to src/timeserieslib/layers/Embed.py diff --git a/layers/FourierCorrelation.py b/src/timeserieslib/layers/FourierCorrelation.py similarity index 100% rename from layers/FourierCorrelation.py rename to src/timeserieslib/layers/FourierCorrelation.py diff --git a/layers/MultiWaveletCorrelation.py b/src/timeserieslib/layers/MultiWaveletCorrelation.py similarity index 100% rename from layers/MultiWaveletCorrelation.py rename to src/timeserieslib/layers/MultiWaveletCorrelation.py diff --git a/layers/Pyraformer_EncDec.py b/src/timeserieslib/layers/Pyraformer_EncDec.py similarity index 97% rename from layers/Pyraformer_EncDec.py rename to src/timeserieslib/layers/Pyraformer_EncDec.py index 1af1bf2c..25fe3028 100644 --- a/layers/Pyraformer_EncDec.py +++ b/src/timeserieslib/layers/Pyraformer_EncDec.py @@ -2,8 +2,8 @@ import torch.nn as nn import torch.nn.functional as F from torch.nn.modules.linear import Linear -from layers.SelfAttention_Family import AttentionLayer, FullAttention -from layers.Embed import DataEmbedding +from timeserieslib.layers.SelfAttention_Family import AttentionLayer, FullAttention +from timeserieslib.layers.Embed import DataEmbedding import math @@ -103,7 +103,7 @@ class Encoder(nn.Module): def __init__(self, configs, window_size, inner_size): super().__init__() - d_bottleneck = configs.d_model//4 + d_bottleneck = configs.d_model // 4 self.mask, self.all_size = get_mask( configs.seq_len, window_size, inner_size) diff --git a/layers/SelfAttention_Family.py b/src/timeserieslib/layers/SelfAttention_Family.py similarity index 96% rename from layers/SelfAttention_Family.py rename to src/timeserieslib/layers/SelfAttention_Family.py index 584fbed4..05725cb8 100644 --- a/layers/SelfAttention_Family.py +++ b/src/timeserieslib/layers/SelfAttention_Family.py @@ -2,7 +2,7 @@ import torch.nn as nn import numpy as np from math import sqrt -from utils.masking import TriangularCausalMask, ProbMask +from timeserieslib.utils.masking import TriangularCausalMask, ProbMask from reformer_pytorch import LSHSelfAttention from einops import rearrange, repeat @@ -104,8 +104,8 @@ def _prob_QK(self, Q, K, sample_k, n_top): # n_top: c*ln(L_q) # use the reduced Q to calculate Q_K Q_reduce = Q[torch.arange(B)[:, None, None], - torch.arange(H)[None, :, None], - M_top, :] # factor*ln(L_q) + torch.arange(H)[None, :, None], + M_top, :] # factor*ln(L_q) Q_K = torch.matmul(Q_reduce, K.transpose(-2, -1)) # factor*ln(L_q)*L_k return Q_K, M_top @@ -133,13 +133,13 @@ def _update_context(self, context_in, V, scores, index, L_Q, attn_mask): attn = torch.softmax(scores, dim=-1) # nn.Softmax(dim=-1)(scores) context_in[torch.arange(B)[:, None, None], - torch.arange(H)[None, :, None], - index, :] = torch.matmul(attn, V).type_as(context_in) + torch.arange(H)[None, :, None], + index, :] = torch.matmul(attn, V).type_as(context_in) if self.output_attention: attns = (torch.ones([B, H, L_V, L_V]) / L_V).type_as(attn).to(attn.device) attns[torch.arange(B)[:, None, None], torch.arange(H)[ - None, :, None], index, :] = attn + None, :, None], index, :] = attn return context_in, attns else: return context_in, None @@ -153,7 +153,7 @@ def forward(self, queries, keys, values, attn_mask, tau=None, delta=None): values = values.transpose(2, 1) U_part = self.factor * \ - np.ceil(np.log(L_K)).astype('int').item() # c*ln(L_k) + np.ceil(np.log(L_K)).astype('int').item() # c*ln(L_k) u = self.factor * \ np.ceil(np.log(L_Q)).astype('int').item() # c*ln(L_q) @@ -287,7 +287,8 @@ def forward(self, x, attn_mask=None, tau=None, delta=None): dim_in = dim_in + self.dropout(self.MLP1(dim_in)) dim_in = self.norm2(dim_in) - # Cross Dimension Stage: use a small set of learnable vectors to aggregate and distribute messages to build the D-to-D connection + # Cross Dimension Stage: use a small set of learnable vectors to aggregate + # and distribute messages to build the D-to-D connection dim_send = rearrange(dim_in, '(b ts_d) seg_num d_model -> (b seg_num) ts_d d_model', b=batch) batch_router = repeat(self.router, 'seg_num factor d_model -> (repeat seg_num) factor d_model', repeat=batch) dim_buffer, attn = self.dim_sender(batch_router, dim_send, dim_send, attn_mask=None, tau=None, delta=None) diff --git a/layers/StandardNorm.py b/src/timeserieslib/layers/StandardNorm.py similarity index 100% rename from layers/StandardNorm.py rename to src/timeserieslib/layers/StandardNorm.py diff --git a/layers/Transformer_EncDec.py b/src/timeserieslib/layers/Transformer_EncDec.py similarity index 100% rename from layers/Transformer_EncDec.py rename to src/timeserieslib/layers/Transformer_EncDec.py diff --git a/layers/__init__.py b/src/timeserieslib/layers/__init__.py similarity index 100% rename from layers/__init__.py rename to src/timeserieslib/layers/__init__.py diff --git a/models/Autoformer.py b/src/timeserieslib/models/Autoformer.py similarity index 95% rename from models/Autoformer.py rename to src/timeserieslib/models/Autoformer.py index 8faf0a2a..3cdf5fcf 100644 --- a/models/Autoformer.py +++ b/src/timeserieslib/models/Autoformer.py @@ -1,9 +1,9 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Embed import DataEmbedding, DataEmbedding_wo_pos -from layers.AutoCorrelation import AutoCorrelation, AutoCorrelationLayer -from layers.Autoformer_EncDec import Encoder, Decoder, EncoderLayer, DecoderLayer, my_Layernorm, series_decomp +from timeserieslib.layers.Embed import DataEmbedding, DataEmbedding_wo_pos +from timeserieslib.layers.AutoCorrelation import AutoCorrelation, AutoCorrelationLayer +from timeserieslib.layers.Autoformer_EncDec import Encoder, Decoder, EncoderLayer, DecoderLayer, my_Layernorm, series_decomp import math import numpy as np diff --git a/models/Crossformer.py b/src/timeserieslib/models/Crossformer.py similarity index 91% rename from models/Crossformer.py rename to src/timeserieslib/models/Crossformer.py index c47eebe3..bb6cd948 100644 --- a/models/Crossformer.py +++ b/src/timeserieslib/models/Crossformer.py @@ -2,10 +2,10 @@ import torch.nn as nn import torch.nn.functional as F from einops import rearrange, repeat -from layers.Crossformer_EncDec import scale_block, Encoder, Decoder, DecoderLayer -from layers.Embed import PatchEmbedding -from layers.SelfAttention_Family import AttentionLayer, FullAttention, TwoStageAttentionLayer -from models.PatchTST import FlattenHead +from timeserieslib.layers.Crossformer_EncDec import scale_block, Encoder, Decoder, DecoderLayer +from timeserieslib.layers.Embed import PatchEmbedding +from timeserieslib.layers.SelfAttention_Family import AttentionLayer, FullAttention, TwoStageAttentionLayer +from timeserieslib.models.PatchTST import FlattenHead from math import ceil @@ -15,6 +15,7 @@ class Model(nn.Module): """ Paper link: https://openreview.net/pdf?id=vSVLM2j9eie """ + def __init__(self, configs): super(Model, self).__init__() self.enc_in = configs.enc_in @@ -32,7 +33,13 @@ def __init__(self, configs): self.head_nf = configs.d_model * self.out_seg_num # Embedding - self.enc_value_embedding = PatchEmbedding(configs.d_model, self.seg_len, self.seg_len, self.pad_in_len - configs.seq_len, 0) + self.enc_value_embedding = PatchEmbedding( + configs.d_model, + self.seg_len, + self.seg_len, + self.pad_in_len - + configs.seq_len, + 0) self.enc_pos_embedding = nn.Parameter( torch.randn(1, configs.enc_in, self.in_seg_num, configs.d_model)) self.pre_norm = nn.LayerNorm(configs.d_model) @@ -77,12 +84,10 @@ def __init__(self, configs): self.projection = nn.Linear( self.head_nf * configs.enc_in, configs.num_class) - - def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): # embedding x_enc, n_vars = self.enc_value_embedding(x_enc.permute(0, 2, 1)) - x_enc = rearrange(x_enc, '(b d) seg_num d_model -> b d seg_num d_model', d = n_vars) + x_enc = rearrange(x_enc, '(b d) seg_num d_model -> b d seg_num d_model', d=n_vars) x_enc += self.enc_pos_embedding x_enc = self.pre_norm(x_enc) enc_out, attns = self.encoder(x_enc) @@ -142,4 +147,4 @@ def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): if self.task_name == 'classification': dec_out = self.classification(x_enc, x_mark_enc) return dec_out # [B, N] - return None \ No newline at end of file + return None diff --git a/models/DLinear.py b/src/timeserieslib/models/DLinear.py similarity index 98% rename from models/DLinear.py rename to src/timeserieslib/models/DLinear.py index 6b680472..213904d3 100644 --- a/models/DLinear.py +++ b/src/timeserieslib/models/DLinear.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Autoformer_EncDec import series_decomp +from timeserieslib.layers.Autoformer_EncDec import series_decomp class Model(nn.Module): diff --git a/models/ETSformer.py b/src/timeserieslib/models/ETSformer.py similarity index 96% rename from models/ETSformer.py rename to src/timeserieslib/models/ETSformer.py index a79b3da7..cd68bce0 100644 --- a/models/ETSformer.py +++ b/src/timeserieslib/models/ETSformer.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn -from layers.Embed import DataEmbedding -from layers.ETSformer_EncDec import EncoderLayer, Encoder, DecoderLayer, Decoder, Transform +from timeserieslib.layers.Embed import DataEmbedding +from timeserieslib.layers.ETSformer_EncDec import EncoderLayer, Encoder, DecoderLayer, Decoder, Transform class Model(nn.Module): diff --git a/models/FEDformer.py b/src/timeserieslib/models/FEDformer.py similarity index 94% rename from models/FEDformer.py rename to src/timeserieslib/models/FEDformer.py index 9a4933e9..a3ec56db 100644 --- a/models/FEDformer.py +++ b/src/timeserieslib/models/FEDformer.py @@ -1,11 +1,11 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Embed import DataEmbedding -from layers.AutoCorrelation import AutoCorrelationLayer -from layers.FourierCorrelation import FourierBlock, FourierCrossAttention -from layers.MultiWaveletCorrelation import MultiWaveletCross, MultiWaveletTransform -from layers.Autoformer_EncDec import Encoder, Decoder, EncoderLayer, DecoderLayer, my_Layernorm, series_decomp +from timeserieslib.layers.Embed import DataEmbedding +from timeserieslib.layers.AutoCorrelation import AutoCorrelationLayer +from timeserieslib.layers.FourierCorrelation import FourierBlock, FourierCrossAttention +from timeserieslib.layers.MultiWaveletCorrelation import MultiWaveletCross, MultiWaveletTransform +from timeserieslib.layers.Autoformer_EncDec import Encoder, Decoder, EncoderLayer, DecoderLayer, my_Layernorm, series_decomp class Model(nn.Module): diff --git a/models/FiLM.py b/src/timeserieslib/models/FiLM.py similarity index 100% rename from models/FiLM.py rename to src/timeserieslib/models/FiLM.py diff --git a/models/FreTS.py b/src/timeserieslib/models/FreTS.py similarity index 100% rename from models/FreTS.py rename to src/timeserieslib/models/FreTS.py diff --git a/models/Informer.py b/src/timeserieslib/models/Informer.py similarity index 96% rename from models/Informer.py rename to src/timeserieslib/models/Informer.py index 1b5e9ec8..bee482c3 100644 --- a/models/Informer.py +++ b/src/timeserieslib/models/Informer.py @@ -1,9 +1,9 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Transformer_EncDec import Decoder, DecoderLayer, Encoder, EncoderLayer, ConvLayer -from layers.SelfAttention_Family import ProbAttention, AttentionLayer -from layers.Embed import DataEmbedding +from timeserieslib.layers.Transformer_EncDec import Decoder, DecoderLayer, Encoder, EncoderLayer, ConvLayer +from timeserieslib.layers.SelfAttention_Family import ProbAttention, AttentionLayer +from timeserieslib.layers.Embed import DataEmbedding class Model(nn.Module): @@ -82,7 +82,7 @@ def long_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): dec_out = self.decoder(dec_out, enc_out, x_mask=None, cross_mask=None) return dec_out # [B, L, D] - + def short_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): # Normalization mean_enc = x_enc.mean(1, keepdim=True).detach() # B x 1 x E diff --git a/models/Koopa.py b/src/timeserieslib/models/Koopa.py similarity index 76% rename from models/Koopa.py rename to src/timeserieslib/models/Koopa.py index 0eea9415..4fce5e97 100644 --- a/models/Koopa.py +++ b/src/timeserieslib/models/Koopa.py @@ -1,39 +1,40 @@ import math import torch import torch.nn as nn -from data_provider.data_factory import data_provider - +from timeserieslib.data_provider.data_factory import data_provider class FourierFilter(nn.Module): """ Fourier Filter: to time-variant and time-invariant term """ + def __init__(self, mask_spectrum): super(FourierFilter, self).__init__() self.mask_spectrum = mask_spectrum - + def forward(self, x): xf = torch.fft.rfft(x, dim=1) mask = torch.ones_like(xf) mask[:, self.mask_spectrum, :] = 0 - x_var = torch.fft.irfft(xf*mask, dim=1) + x_var = torch.fft.irfft(xf * mask, dim=1) x_inv = x - x_var - + return x_var, x_inv - + class MLP(nn.Module): ''' Multilayer perceptron to encode/decode high dimension representation of sequential data ''' - def __init__(self, - f_in, - f_out, - hidden_dim=128, - hidden_layers=2, + + def __init__(self, + f_in, + f_out, + hidden_dim=128, + hidden_layers=2, dropout=0.05, - activation='tanh'): + activation='tanh'): super(MLP, self).__init__() self.f_in = f_in self.f_out = f_out @@ -46,13 +47,13 @@ def __init__(self, self.activation = nn.Tanh() else: raise NotImplementedError - - layers = [nn.Linear(self.f_in, self.hidden_dim), + + layers = [nn.Linear(self.f_in, self.hidden_dim), self.activation, nn.Dropout(self.dropout)] - for i in range(self.hidden_layers-2): + for i in range(self.hidden_layers - 2): layers += [nn.Linear(self.hidden_dim, self.hidden_dim), self.activation, nn.Dropout(dropout)] - + layers += [nn.Linear(hidden_dim, f_out)] self.layers = nn.Sequential(*layers) @@ -61,16 +62,17 @@ def forward(self, x): # y: B x S x f_out y = self.layers(x) return y - + class KPLayer(nn.Module): """ A demonstration of finding one step transition of linear system by DMD iteratively """ - def __init__(self): + + def __init__(self): super(KPLayer, self).__init__() - - self.K = None # B E E + + self.K = None # B E E def one_step_forward(self, z, return_rec=False, return_K=False): B, input_len, E = z.shape @@ -78,7 +80,7 @@ def one_step_forward(self, z, return_rec=False, return_K=False): x, y = z[:, :-1], z[:, 1:] # solve linear system - self.K = torch.linalg.lstsq(x, y).solution # B E E + self.K = torch.linalg.lstsq(x, y).solution # B E E if torch.isnan(self.K).any(): print('Encounter K with nan, replace K by identity matrix') self.K = torch.eye(self.K.shape[1]).to(self.K.device).unsqueeze(0).repeat(B, 1, 1) @@ -89,10 +91,10 @@ def one_step_forward(self, z, return_rec=False, return_K=False): return z_rec, z_pred return z_pred - + def forward(self, z, pred_len=1): assert pred_len >= 1, 'prediction length should not be less than 1' - z_rec, z_pred= self.one_step_forward(z, return_rec=True) + z_rec, z_pred = self.one_step_forward(z, return_rec=True) z_preds = [z_pred] for i in range(1, pred_len): z_pred = torch.bmm(z_pred, self.K) @@ -105,11 +107,12 @@ class KPLayerApprox(nn.Module): """ Find koopman transition of linear system by DMD with multistep K approximation """ - def __init__(self): + + def __init__(self): super(KPLayerApprox, self).__init__() - - self.K = None # B E E - self.K_step = None # B E E + + self.K = None # B E E + self.K_step = None # B E E def forward(self, z, pred_len=1): # z: B L E, koopman invariance space representation @@ -120,14 +123,14 @@ def forward(self, z, pred_len=1): x, y = z[:, :-1], z[:, 1:] # solve linear system - self.K = torch.linalg.lstsq(x, y).solution # B E E + self.K = torch.linalg.lstsq(x, y).solution # B E E if torch.isnan(self.K).any(): print('Encounter K with nan, replace K by identity matrix') self.K = torch.eye(self.K.shape[1]).to(self.K.device).unsqueeze(0).repeat(B, 1, 1) - z_rec = torch.cat((z[:, :1], torch.bmm(x, self.K)), dim=1) # B L E - + z_rec = torch.cat((z[:, :1], torch.bmm(x, self.K)), dim=1) # B L E + if pred_len <= input_len: self.K_step = torch.linalg.matrix_power(self.K, pred_len) if torch.isnan(self.K_step).any(): @@ -146,13 +149,14 @@ def forward(self, z, pred_len=1): z_pred = torch.cat(all_pred, dim=1)[:, :pred_len, :] return z_rec, z_pred - + class TimeVarKP(nn.Module): """ Koopman Predictor with DMD (analysitical solution of Koopman operator) Utilize local variations within individual sliding window to predict the future of time-variant term """ + def __init__(self, enc_in=8, input_len=96, @@ -162,7 +166,7 @@ def __init__(self, encoder=None, decoder=None, multistep=False, - ): + ): super(TimeVarKP, self).__init__() self.input_len = input_len self.pred_len = pred_len @@ -170,32 +174,32 @@ def __init__(self, self.seg_len = seg_len self.dynamic_dim = dynamic_dim self.multistep = multistep - self.encoder, self.decoder = encoder, decoder + self.encoder, self.decoder = encoder, decoder self.freq = math.ceil(self.input_len / self.seg_len) # segment number of input self.step = math.ceil(self.pred_len / self.seg_len) # segment number of output self.padding_len = self.seg_len * self.freq - self.input_len # Approximate mulitstep K by KPLayerApprox when pred_len is large - self.dynamics = KPLayerApprox() if self.multistep else KPLayer() + self.dynamics = KPLayerApprox() if self.multistep else KPLayer() def forward(self, x): # x: B L C B, L, C = x.shape - res = torch.cat((x[:, L-self.padding_len:, :], x) ,dim=1) + res = torch.cat((x[:, L - self.padding_len:, :], x), dim=1) res = res.chunk(self.freq, dim=1) # F x B P C, P means seg_len res = torch.stack(res, dim=1).reshape(B, self.freq, -1) # B F PC - res = self.encoder(res) # B F H - x_rec, x_pred = self.dynamics(res, self.step) # B F H, B S H + res = self.encoder(res) # B F H + x_rec, x_pred = self.dynamics(res, self.step) # B F H, B S H - x_rec = self.decoder(x_rec) # B F PC + x_rec = self.decoder(x_rec) # B F PC x_rec = x_rec.reshape(B, self.freq, self.seg_len, self.enc_in) x_rec = x_rec.reshape(B, -1, self.enc_in)[:, :self.input_len, :] # B L C - + x_pred = self.decoder(x_pred) # B S PC x_pred = x_pred.reshape(B, self.step, self.seg_len, self.enc_in) - x_pred = x_pred.reshape(B, -1, self.enc_in)[:, :self.pred_len, :] # B S C + x_pred = x_pred.reshape(B, -1, self.enc_in)[:, :self.pred_len, :] # B S C return x_rec, x_pred @@ -205,6 +209,7 @@ class TimeInvKP(nn.Module): Koopman Predictor with learnable Koopman operator Utilize lookback and forecast window snapshots to predict the future of time-invariant term """ + def __init__(self, input_len=96, pred_len=96, @@ -219,17 +224,17 @@ def __init__(self, self.decoder = decoder K_init = torch.randn(self.dynamic_dim, self.dynamic_dim) - U, _, V = torch.svd(K_init) # stable initialization + U, _, V = torch.svd(K_init) # stable initialization self.K = nn.Linear(self.dynamic_dim, self.dynamic_dim, bias=False) self.K.weight.data = torch.mm(U, V.t()) - + def forward(self, x): # x: B L C - res = x.transpose(1, 2) # B C L - res = self.encoder(res) # B C H - res = self.K(res) # B C H - res = self.decoder(res) # B C S - res = res.transpose(1, 2) # B S C + res = x.transpose(1, 2) # B C L + res = self.encoder(res) # B C H + res = self.K(res) # B C H + res = self.decoder(res) # B C S + res = res.transpose(1, 2) # B S C return res @@ -238,6 +243,7 @@ class Model(nn.Module): ''' Paper link: https://arxiv.org/pdf/2305.18803.pdf ''' + def __init__(self, configs, dynamic_dim=128, hidden_dim=64, hidden_layers=2, num_blocks=3, multistep=False): """ mask_spectrum: list, shared frequency spectrums @@ -268,32 +274,32 @@ def __init__(self, configs, dynamic_dim=128, hidden_dim=64, hidden_layers=2, num # shared encoder/decoder to make koopman embedding consistent self.time_inv_encoder = MLP(f_in=self.input_len, f_out=self.dynamic_dim, activation='relu', - hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) + hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) self.time_inv_decoder = MLP(f_in=self.dynamic_dim, f_out=self.pred_len, activation='relu', - hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) + hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) self.time_inv_kps = self.time_var_kps = nn.ModuleList([ - TimeInvKP(input_len=self.input_len, - pred_len=self.pred_len, - dynamic_dim=self.dynamic_dim, - encoder=self.time_inv_encoder, - decoder=self.time_inv_decoder) - for _ in range(self.num_blocks)]) + TimeInvKP(input_len=self.input_len, + pred_len=self.pred_len, + dynamic_dim=self.dynamic_dim, + encoder=self.time_inv_encoder, + decoder=self.time_inv_decoder) + for _ in range(self.num_blocks)]) # shared encoder/decoder to make koopman embedding consistent - self.time_var_encoder = MLP(f_in=self.seg_len*self.enc_in, f_out=self.dynamic_dim, activation='tanh', - hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) - self.time_var_decoder = MLP(f_in=self.dynamic_dim, f_out=self.seg_len*self.enc_in, activation='tanh', - hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) + self.time_var_encoder = MLP(f_in=self.seg_len * self.enc_in, f_out=self.dynamic_dim, activation='tanh', + hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) + self.time_var_decoder = MLP(f_in=self.dynamic_dim, f_out=self.seg_len * self.enc_in, activation='tanh', + hidden_dim=self.hidden_dim, hidden_layers=self.hidden_layers) self.time_var_kps = nn.ModuleList([ - TimeVarKP(enc_in=configs.enc_in, - input_len=self.input_len, - pred_len=self.pred_len, - seg_len=self.seg_len, - dynamic_dim=self.dynamic_dim, - encoder=self.time_var_encoder, - decoder=self.time_var_decoder, - multistep=self.multistep) - for _ in range(self.num_blocks)]) + TimeVarKP(enc_in=configs.enc_in, + input_len=self.input_len, + pred_len=self.pred_len, + seg_len=self.seg_len, + dynamic_dim=self.dynamic_dim, + encoder=self.time_var_encoder, + decoder=self.time_var_decoder, + multistep=self.multistep) + for _ in range(self.num_blocks)]) def _get_mask_spectrum(self, configs): """ @@ -304,12 +310,12 @@ def _get_mask_spectrum(self, configs): for data in train_loader: lookback_window = data[0] amps += abs(torch.fft.rfft(lookback_window, dim=1)).mean(dim=0).mean(dim=1) - mask_spectrum = amps.topk(int(amps.shape[0]*self.alpha)).indices - return mask_spectrum # as the spectrums of time-invariant component - + mask_spectrum = amps.topk(int(amps.shape[0] * self.alpha)).indices + return mask_spectrum # as the spectrums of time-invariant component + def forecast(self, x_enc): # Series Stationarization adopted from NSformer - mean_enc = x_enc.mean(1, keepdim=True).detach() # B x 1 x E + mean_enc = x_enc.mean(1, keepdim=True).detach() # B x 1 x E x_enc = x_enc - mean_enc std_enc = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() x_enc = x_enc / std_enc @@ -329,9 +335,9 @@ def forecast(self, x_enc): # Series Stationarization adopted from NSformer res = forecast * std_enc + mean_enc - return res - + return res + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec): if self.task_name == 'long_term_forecast': dec_out = self.forecast(x_enc) - return dec_out[:, -self.pred_len:, :] # [B, L, D] + return dec_out[:, -self.pred_len:, :] # [B, L, D] diff --git a/models/LightTS.py b/src/timeserieslib/models/LightTS.py similarity index 100% rename from models/LightTS.py rename to src/timeserieslib/models/LightTS.py diff --git a/models/MICN.py b/src/timeserieslib/models/MICN.py similarity index 98% rename from models/MICN.py rename to src/timeserieslib/models/MICN.py index aeac6932..b3264de9 100644 --- a/models/MICN.py +++ b/src/timeserieslib/models/MICN.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn -from layers.Embed import DataEmbedding -from layers.Autoformer_EncDec import series_decomp, series_decomp_multi +from timeserieslib.layers.Embed import DataEmbedding +from timeserieslib.layers.Autoformer_EncDec import series_decomp, series_decomp_multi import torch.nn.functional as F @@ -108,6 +108,7 @@ class Model(nn.Module): """ Paper link: https://openreview.net/pdf?id=zt53IDUR1U """ + def __init__(self, configs, conv_kernel=[12, 16]): """ conv_kernel: downsampling and upsampling convolution kernel_size diff --git a/models/Mamba.py b/src/timeserieslib/models/Mamba.py similarity index 80% rename from models/Mamba.py rename to src/timeserieslib/models/Mamba.py index edece42a..e582b412 100644 --- a/models/Mamba.py +++ b/src/timeserieslib/models/Mamba.py @@ -6,25 +6,26 @@ from mamba_ssm import Mamba -from layers.Embed import DataEmbedding +from timeserieslib.layers.Embed import DataEmbedding + class Model(nn.Module): - + def __init__(self, configs): super(Model, self).__init__() self.task_name = configs.task_name self.pred_len = configs.pred_len self.d_inner = configs.d_model * configs.expand - self.dt_rank = math.ceil(configs.d_model / 16) # TODO implement "auto" - + self.dt_rank = math.ceil(configs.d_model / 16) # TODO implement "auto" + self.embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, configs.dropout) self.mamba = Mamba( - d_model = configs.d_model, - d_state = configs.d_ff, - d_conv = configs.d_conv, - expand = configs.expand, + d_model=configs.d_model, + d_state=configs.d_ff, + d_conv=configs.d_conv, + expand=configs.expand, ) self.out_layer = nn.Linear(configs.d_model, configs.c_out, bias=False) @@ -47,4 +48,4 @@ def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): x_out = self.forecast(x_enc, x_mark_enc) return x_out[:, -self.pred_len:, :] - # other tasks not implemented \ No newline at end of file + # other tasks not implemented diff --git a/models/MambaSimple.py b/src/timeserieslib/models/MambaSimple.py similarity index 82% rename from models/MambaSimple.py rename to src/timeserieslib/models/MambaSimple.py index 5cfc5d16..238b44c9 100644 --- a/models/MambaSimple.py +++ b/src/timeserieslib/models/MambaSimple.py @@ -5,7 +5,7 @@ import torch.nn.functional as F from einops import rearrange, repeat, einsum -from layers.Embed import DataEmbedding +from timeserieslib.layers.Embed import DataEmbedding class Model(nn.Module): @@ -25,7 +25,8 @@ def __init__(self, configs): self.embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, configs.dropout) - self.layers = nn.ModuleList([ResidualBlock(configs, self.d_inner, self.dt_rank) for _ in range(configs.e_layers)]) + self.layers = nn.ModuleList([ResidualBlock(configs, self.d_inner, self.dt_rank) + for _ in range(configs.e_layers)]) self.norm = RMSNorm(configs.d_model) self.out_layer = nn.Linear(configs.d_model, configs.c_out, bias=False) @@ -60,15 +61,14 @@ def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): if self.task_name in ['short_term_forecast', 'long_term_forecast']: x_out = self.forecast(x_enc, x_mark_enc) return x_out[:, -self.pred_len:, :] - - + # other tasks not implemented class ResidualBlock(nn.Module): def __init__(self, configs, d_inner, dt_rank): super(ResidualBlock, self).__init__() - + self.mixer = MambaBlock(configs, d_inner, dt_rank) self.norm = RMSNorm(configs.d_model) @@ -76,6 +76,7 @@ def forward(self, x): output = self.mixer(self.norm(x)) + x return output + class MambaBlock(nn.Module): def __init__(self, configs, d_inner, dt_rank): super(MambaBlock, self).__init__() @@ -83,14 +84,14 @@ def __init__(self, configs, d_inner, dt_rank): self.dt_rank = dt_rank self.in_proj = nn.Linear(configs.d_model, self.d_inner * 2, bias=False) - + self.conv1d = nn.Conv1d( - in_channels = self.d_inner, - out_channels = self.d_inner, - bias = True, - kernel_size = configs.d_conv, - padding = configs.d_conv - 1, - groups = self.d_inner + in_channels=self.d_inner, + out_channels=self.d_inner, + bias=True, + kernel_size=configs.d_conv, + padding=configs.d_conv - 1, + groups=self.d_inner ) # takes in x and outputs the input-specific delta, B, C @@ -111,7 +112,7 @@ def forward(self, x): """ (b, l, d) = x.shape - x_and_res = self.in_proj(x) # [B, L, 2 * d_inner] + x_and_res = self.in_proj(x) # [B, L, 2 * d_inner] (x, res) = x_and_res.split(split_size=[self.d_inner, self.d_inner], dim=-1) x = rearrange(x, "b l d -> b d l") @@ -126,20 +127,19 @@ def forward(self, x): output = self.out_proj(y) return output - def ssm(self, x): """ Algorithm 2 in Section 3.2 in the paper """ - + (d_in, n) = self.A_log.shape - A = -torch.exp(self.A_log.float()) # [d_in, n] - D = self.D.float() # [d_in] + A = -torch.exp(self.A_log.float()) # [d_in, n] + D = self.D.float() # [d_in] - x_dbl = self.x_proj(x) # [B, L, d_rank + 2 * d_ff] - (delta, B, C) = x_dbl.split(split_size=[self.dt_rank, n, n], dim=-1) # delta: [B, L, d_rank]; B, C: [B, L, n] - delta = F.softplus(self.dt_proj(delta)) # [B, L, d_in] + x_dbl = self.x_proj(x) # [B, L, d_rank + 2 * d_ff] + (delta, B, C) = x_dbl.split(split_size=[self.dt_rank, n, n], dim=-1) # delta: [B, L, d_rank]; B, C: [B, L, n] + delta = F.softplus(self.dt_proj(delta)) # [B, L, d_in] y = self.selective_scan(x, delta, A, B, C, D) return y @@ -148,8 +148,12 @@ def selective_scan(self, u, delta, A, B, C, D): (b, l, d_in) = u.shape n = A.shape[1] - deltaA = torch.exp(einsum(delta, A, "b l d, d n -> b l d n")) # A is discretized using zero-order hold (ZOH) discretization - deltaB_u = einsum(delta, B, u, "b l d, b l n, b l d -> b l d n") # B is discretized using a simplified Euler discretization instead of ZOH. From a discussion with authors: "A is the more important term and the performance doesn't change much with the simplification on B" + # A is discretized using zero-order hold (ZOH) discretization + deltaA = torch.exp(einsum(delta, A, "b l d, d n -> b l d n")) + # B is discretized using a simplified Euler discretization instead of ZOH. + # From a discussion with authors: "A is the more important term and the + # performance doesn't change much with the simplification on B" + deltaB_u = einsum(delta, B, u, "b l d, b l n, b l d -> b l d n") # selective scan, sequential instead of parallel x = torch.zeros((b, d_in, n), device=deltaA.device) @@ -159,11 +163,12 @@ def selective_scan(self, u, delta, A, B, C, D): y = einsum(x, C[:, i, :], "b d n, b n -> b d") ys.append(y) - y = torch.stack(ys, dim=1) # [B, L, d_in] + y = torch.stack(ys, dim=1) # [B, L, d_in] y = y + u * D return y + class RMSNorm(nn.Module): def __init__(self, d_model, eps=1e-5): super(RMSNorm, self).__init__() @@ -172,4 +177,4 @@ def __init__(self, d_model, eps=1e-5): def forward(self, x): output = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) * self.weight - return output \ No newline at end of file + return output diff --git a/models/Nonstationary_Transformer.py b/src/timeserieslib/models/Nonstationary_Transformer.py similarity index 97% rename from models/Nonstationary_Transformer.py rename to src/timeserieslib/models/Nonstationary_Transformer.py index 9abc2dff..2c21e162 100644 --- a/models/Nonstationary_Transformer.py +++ b/src/timeserieslib/models/Nonstationary_Transformer.py @@ -1,8 +1,8 @@ import torch import torch.nn as nn -from layers.Transformer_EncDec import Decoder, DecoderLayer, Encoder, EncoderLayer -from layers.SelfAttention_Family import DSAttention, AttentionLayer -from layers.Embed import DataEmbedding +from timeserieslib.layers.Transformer_EncDec import Decoder, DecoderLayer, Encoder, EncoderLayer +from timeserieslib.layers.SelfAttention_Family import DSAttention, AttentionLayer +from timeserieslib.layers.Embed import DataEmbedding import torch.nn.functional as F diff --git a/models/PatchTST.py b/src/timeserieslib/models/PatchTST.py similarity index 89% rename from models/PatchTST.py rename to src/timeserieslib/models/PatchTST.py index ec90c2e9..ef1aacb6 100644 --- a/models/PatchTST.py +++ b/src/timeserieslib/models/PatchTST.py @@ -1,16 +1,20 @@ import torch from torch import nn -from layers.Transformer_EncDec import Encoder, EncoderLayer -from layers.SelfAttention_Family import FullAttention, AttentionLayer -from layers.Embed import PatchEmbedding +from timeserieslib.layers.Transformer_EncDec import Encoder, EncoderLayer +from timeserieslib.layers.SelfAttention_Family import FullAttention, AttentionLayer +from timeserieslib.layers.Embed import PatchEmbedding + class Transpose(nn.Module): - def __init__(self, *dims, contiguous=False): + def __init__(self, *dims, contiguous=False): super().__init__() self.dims, self.contiguous = dims, contiguous + def forward(self, x): - if self.contiguous: return x.transpose(*self.dims).contiguous() - else: return x.transpose(*self.dims) + if self.contiguous: + return x.transpose(*self.dims).contiguous() + else: + return x.transpose(*self.dims) class FlattenHead(nn.Module): @@ -61,12 +65,12 @@ def __init__(self, configs, patch_len=16, stride=8): activation=configs.activation ) for l in range(configs.e_layers) ], - norm_layer=nn.Sequential(Transpose(1,2), nn.BatchNorm1d(configs.d_model), Transpose(1,2)) + norm_layer=nn.Sequential(Transpose(1, 2), nn.BatchNorm1d(configs.d_model), Transpose(1, 2)) ) # Prediction Head self.head_nf = configs.d_model * \ - int((configs.seq_len - patch_len) / stride + 2) + int((configs.seq_len - patch_len) / stride + 2) if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': self.head = FlattenHead(configs.enc_in, self.head_nf, configs.pred_len, head_dropout=configs.dropout) @@ -107,9 +111,9 @@ def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): # De-Normalization from Non-stationary Transformer dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) return dec_out def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): @@ -143,9 +147,9 @@ def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): # De-Normalization from Non-stationary Transformer dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) return dec_out def anomaly_detection(self, x_enc): @@ -176,9 +180,9 @@ def anomaly_detection(self, x_enc): # De-Normalization from Non-stationary Transformer dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) return dec_out def classification(self, x_enc, x_mark_enc): diff --git a/models/Pyraformer.py b/src/timeserieslib/models/Pyraformer.py similarity index 89% rename from models/Pyraformer.py rename to src/timeserieslib/models/Pyraformer.py index d92693c0..59056e4b 100644 --- a/models/Pyraformer.py +++ b/src/timeserieslib/models/Pyraformer.py @@ -1,15 +1,15 @@ import torch import torch.nn as nn -from layers.Pyraformer_EncDec import Encoder +from timeserieslib.layers.Pyraformer_EncDec import Encoder class Model(nn.Module): - """ + """ Pyraformer: Pyramidal attention to reduce complexity Paper link: https://openreview.net/pdf?id=0EXmFzUn5I """ - def __init__(self, configs, window_size=[4,4], inner_size=5): + def __init__(self, configs, window_size=[4, 4], inner_size=5): """ window_size: list, the downsample window size in pyramidal attention. inner_size: int, the size of neighbour attention @@ -20,27 +20,27 @@ def __init__(self, configs, window_size=[4,4], inner_size=5): self.d_model = configs.d_model if self.task_name == 'short_term_forecast': - window_size = [2,2] + window_size = [2, 2] self.encoder = Encoder(configs, window_size, inner_size) if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': self.projection = nn.Linear( - (len(window_size)+1)*self.d_model, self.pred_len * configs.enc_in) + (len(window_size) + 1) * self.d_model, self.pred_len * configs.enc_in) elif self.task_name == 'imputation' or self.task_name == 'anomaly_detection': self.projection = nn.Linear( - (len(window_size)+1)*self.d_model, configs.enc_in, bias=True) + (len(window_size) + 1) * self.d_model, configs.enc_in, bias=True) elif self.task_name == 'classification': self.act = torch.nn.functional.gelu self.dropout = nn.Dropout(configs.dropout) self.projection = nn.Linear( - (len(window_size)+1)*self.d_model * configs.seq_len, configs.num_class) + (len(window_size) + 1) * self.d_model * configs.seq_len, configs.num_class) def long_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): enc_out = self.encoder(x_enc, x_mark_enc)[:, -1, :] dec_out = self.projection(enc_out).view( enc_out.size(0), self.pred_len, -1) return dec_out - + def short_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): # Normalization mean_enc = x_enc.mean(1, keepdim=True).detach() # B x 1 x E @@ -51,7 +51,7 @@ def short_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): enc_out = self.encoder(x_enc, x_mark_enc)[:, -1, :] dec_out = self.projection(enc_out).view( enc_out.size(0), self.pred_len, -1) - + dec_out = dec_out * std_enc + mean_enc return dec_out diff --git a/models/Reformer.py b/src/timeserieslib/models/Reformer.py similarity index 95% rename from models/Reformer.py rename to src/timeserieslib/models/Reformer.py index b29336c0..85dfd4da 100644 --- a/models/Reformer.py +++ b/src/timeserieslib/models/Reformer.py @@ -1,9 +1,9 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Transformer_EncDec import Encoder, EncoderLayer -from layers.SelfAttention_Family import ReformerLayer -from layers.Embed import DataEmbedding +from timeserieslib.layers.Transformer_EncDec import Encoder, EncoderLayer +from timeserieslib.layers.SelfAttention_Family import ReformerLayer +from timeserieslib.layers.Embed import DataEmbedding class Model(nn.Module): @@ -14,8 +14,8 @@ class Model(nn.Module): def __init__(self, configs, bucket_size=4, n_hashes=4): """ - bucket_size: int, - n_hashes: int, + bucket_size: int, + n_hashes: int, """ super(Model, self).__init__() self.task_name = configs.task_name @@ -60,7 +60,7 @@ def long_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): dec_out = self.projection(enc_out) return dec_out # [B, L, D] - + def short_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): # Normalization mean_enc = x_enc.mean(1, keepdim=True).detach() # B x 1 x E diff --git a/models/SegRNN.py b/src/timeserieslib/models/SegRNN.py similarity index 91% rename from models/SegRNN.py rename to src/timeserieslib/models/SegRNN.py index afff1bc0..fb578490 100644 --- a/models/SegRNN.py +++ b/src/timeserieslib/models/SegRNN.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Autoformer_EncDec import series_decomp +from timeserieslib.layers.Autoformer_EncDec import series_decomp class Model(nn.Module): @@ -34,7 +34,7 @@ def __init__(self, configs): nn.ReLU() ) self.rnn = nn.GRU(input_size=self.d_model, hidden_size=self.d_model, num_layers=1, bias=True, - batch_first=True, bidirectional=False) + batch_first=True, bidirectional=False) self.pos_emb = nn.Parameter(torch.randn(self.seg_num_y, self.d_model // 2)) self.channel_emb = nn.Parameter(torch.randn(self.enc_in, self.d_model // 2)) @@ -56,13 +56,13 @@ def encoder(self, x): # normalization and permute b,s,c -> b,c,s seq_last = x[:, -1:, :].detach() - x = (x - seq_last).permute(0, 2, 1) # b,c,s + x = (x - seq_last).permute(0, 2, 1) # b,c,s # segment and embedding b,c,s -> bc,n,w -> bc,n,d x = self.valueEmbedding(x.reshape(-1, self.seg_num_x, self.seg_len)) # encoding - _, hn = self.rnn(x) # bc,n,d 1,bc,d + _, hn = self.rnn(x) # bc,n,d 1,bc,d # m,d//2 -> 1,m,d//2 -> c,m,d//2 # c,d//2 -> c,1,d//2 -> c,m,d//2 @@ -70,9 +70,9 @@ def encoder(self, x): pos_emb = torch.cat([ self.pos_emb.unsqueeze(0).repeat(self.enc_in, 1, 1), self.channel_emb.unsqueeze(1).repeat(1, self.seg_num_y, 1) - ], dim=-1).view(-1, 1, self.d_model).repeat(batch_size,1,1) + ], dim=-1).view(-1, 1, self.d_model).repeat(batch_size, 1, 1) - _, hy = self.rnn(pos_emb, hn.repeat(1, 1, self.seg_num_y).view(1, -1, self.d_model)) # bcm,1,d 1,bcm,d + _, hy = self.rnn(pos_emb, hn.repeat(1, 1, self.seg_num_y).view(1, -1, self.d_model)) # bcm,1,d 1,bcm,d # 1,bcm,d -> 1,bcm,w -> b,c,s y = self.predict(hy).view(-1, self.enc_in, self.pred_len) diff --git a/models/TSMixer.py b/src/timeserieslib/models/TSMixer.py similarity index 100% rename from models/TSMixer.py rename to src/timeserieslib/models/TSMixer.py diff --git a/models/TemporalFusionTransformer.py b/src/timeserieslib/models/TemporalFusionTransformer.py similarity index 87% rename from models/TemporalFusionTransformer.py rename to src/timeserieslib/models/TemporalFusionTransformer.py index 564c8350..1e38cdca 100644 --- a/models/TemporalFusionTransformer.py +++ b/src/timeserieslib/models/TemporalFusionTransformer.py @@ -1,7 +1,7 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Embed import DataEmbedding, TemporalEmbedding +from timeserieslib.layers.Embed import DataEmbedding, TemporalEmbedding from torch import Tensor from typing import Optional from collections import namedtuple @@ -54,7 +54,7 @@ def __init__(self, d_model, embed_type='timeF', freq='h'): self.embed = nn.ModuleList([nn.Linear(1, d_model, bias=False) for _ in range(d_inp)]) def forward(self, x): - return torch.stack([embed(x[:,:,i].unsqueeze(-1)) for i, embed in enumerate(self.embed)], dim=-2) + return torch.stack([embed(x[:, :, i].unsqueeze(-1)) for i, embed in enumerate(self.embed)], dim=-2) class TFTEmbedding(nn.Module): @@ -66,23 +66,26 @@ def __init__(self, configs): self.static_len = len(self.static_pos) self.observed_len = len(self.observed_pos) - self.static_embedding = nn.ModuleList([DataEmbedding(1,configs.d_model,dropout=configs.dropout) for _ in range(self.static_len)]) \ + self.static_embedding = nn.ModuleList([DataEmbedding(1, configs.d_model, dropout=configs.dropout) for _ in range(self.static_len)]) \ if self.static_len else None - self.observed_embedding = nn.ModuleList([DataEmbedding(1,configs.d_model,dropout=configs.dropout) for _ in range(self.observed_len)]) + self.observed_embedding = nn.ModuleList( + [DataEmbedding(1, configs.d_model, dropout=configs.dropout) for _ in range(self.observed_len)]) self.known_embedding = TFTTemporalEmbedding(configs.d_model, configs.embed, configs.freq) \ if configs.embed != 'timeF' else TFTTimeFeatureEmbedding(configs.d_model, configs.embed, configs.freq) def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec): if self.static_len: # static_input: [B,C,d_model] - static_input = torch.stack([embed(x_enc[:,:1,self.static_pos[i]].unsqueeze(-1), None).squeeze(1) for i, embed in enumerate(self.static_embedding)], dim=-2) + static_input = torch.stack([embed(x_enc[:, :1, self.static_pos[i]].unsqueeze(-1), None).squeeze(1) + for i, embed in enumerate(self.static_embedding)], dim=-2) else: static_input = None # observed_input: [B,T,C,d_model] - observed_input = torch.stack([embed(x_enc[:,:,self.observed_pos[i]].unsqueeze(-1), None) for i, embed in enumerate(self.observed_embedding)], dim=-2) + observed_input = torch.stack([embed(x_enc[:, :, self.observed_pos[i]].unsqueeze(-1), None) + for i, embed in enumerate(self.observed_embedding)], dim=-2) - x_mark = torch.cat([x_mark_enc, x_mark_dec[:,-self.pred_len:,:]], dim=-2) + x_mark = torch.cat([x_mark_enc, x_mark_dec[:, -self.pred_len:, :]], dim=-2) # known_input: [B,T,C,d_model] known_input = self.known_embedding(x_mark) @@ -140,7 +143,12 @@ def forward(self, a: Tensor, c: Optional[Tensor] = None): class VariableSelectionNetwork(nn.Module): def __init__(self, d_model, variable_num, dropout=0.0): super(VariableSelectionNetwork, self).__init__() - self.joint_grn = GRN(d_model * variable_num, variable_num, hidden_size=d_model, context_size=d_model, dropout=dropout) + self.joint_grn = GRN( + d_model * variable_num, + variable_num, + hidden_size=d_model, + context_size=d_model, + dropout=dropout) self.variable_grns = nn.ModuleList([GRN(d_model, d_model, dropout=dropout) for _ in range(variable_num)]) def forward(self, x: Tensor, context: Optional[Tensor] = None): @@ -152,7 +160,7 @@ def forward(self, x: Tensor, context: Optional[Tensor] = None): selection_weights = self.joint_grn(x_flattened, context) selection_weights = F.softmax(selection_weights, dim=-1) - x_processed = torch.stack([grn(x[...,i,:]) for i, grn in enumerate(self.variable_grns)], dim=-1) + x_processed = torch.stack([grn(x[..., i, :]) for i, grn in enumerate(self.variable_grns)], dim=-1) selection_result = torch.matmul(x_processed, selection_weights.unsqueeze(-1)).squeeze(-1) return selection_result @@ -215,7 +223,11 @@ def __init__(self, configs): self.history_encoder = nn.LSTM(configs.d_model, configs.d_model, batch_first=True) self.future_encoder = nn.LSTM(configs.d_model, configs.d_model, batch_first=True) self.gate_after_lstm = GateAddNorm(configs.d_model, configs.d_model) - self.enrichment_grn = GRN(configs.d_model, configs.d_model, context_size=configs.d_model, dropout=configs.dropout) + self.enrichment_grn = GRN( + configs.d_model, + configs.d_model, + context_size=configs.d_model, + dropout=configs.dropout) self.attention = InterpretableMultiHeadAttention(configs) self.gate_after_attention = GateAddNorm(configs.d_model, configs.d_model) self.position_wise_grn = GRN(configs.d_model, configs.d_model, dropout=configs.dropout) @@ -241,13 +253,14 @@ def forward(self, history_input, future_input, c_c, c_h, c_e): # Temporal self-attention attention_out = self.attention(enriched_features) # [B,T,d] # Don't compute historical loss - attention_out = self.gate_after_attention(attention_out[:,-self.pred_len:], enriched_features[:,-self.pred_len:]) + attention_out = self.gate_after_attention( + attention_out[:, -self.pred_len:], enriched_features[:, -self.pred_len:]) # Position-wise feed-forward out = self.position_wise_grn(attention_out) # [B,T,d] # Final skip connection - out = self.gate_final(out, temporal_features[:,-self.pred_len:]) + out = self.gate_final(out, temporal_features[:, -self.pred_len:]) return self.out_projection(out) @@ -287,8 +300,8 @@ def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): c_s, c_c, c_h, c_e = self.static_encoder(static_input) # Temporal input Selection - history_input = torch.cat([observed_input, known_input[:,:self.seq_len]], dim=-2) - future_input = known_input[:,self.seq_len:] + history_input = torch.cat([observed_input, known_input[:, :self.seq_len]], dim=-2) + future_input = known_input[:, self.seq_len:] history_input = self.history_vsn(history_input, c_s) future_input = self.future_vsn(future_input, c_s) @@ -306,4 +319,4 @@ def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec): dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) # [B,pred_len,C] dec_out = torch.cat([torch.zeros_like(x_enc), dec_out], dim=1) return dec_out # [B, T, D] - return None \ No newline at end of file + return None diff --git a/models/TiDE.py b/src/timeserieslib/models/TiDE.py similarity index 100% rename from models/TiDE.py rename to src/timeserieslib/models/TiDE.py diff --git a/models/TimeMixer.py b/src/timeserieslib/models/TimeMixer.py similarity index 98% rename from models/TimeMixer.py rename to src/timeserieslib/models/TimeMixer.py index ddfe1c63..04ed2fa6 100755 --- a/models/TimeMixer.py +++ b/src/timeserieslib/models/TimeMixer.py @@ -1,9 +1,9 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Autoformer_EncDec import series_decomp -from layers.Embed import DataEmbedding_wo_pos -from layers.StandardNorm import Normalize +from timeserieslib.layers.Autoformer_EncDec import series_decomp +from timeserieslib.layers.Embed import DataEmbedding_wo_pos +from timeserieslib.layers.StandardNorm import Normalize class DFT_series_decomp(nn.Module): @@ -491,9 +491,9 @@ def imputation(self, x_enc, x_mark_enc, mask): dec_out = dec_out.reshape(B, self.configs.c_out, -1).permute(0, 2, 1).contiguous() dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) return dec_out def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): diff --git a/models/TimesNet.py b/src/timeserieslib/models/TimesNet.py similarity index 90% rename from models/TimesNet.py rename to src/timeserieslib/models/TimesNet.py index c4bb86f3..820b918a 100644 --- a/models/TimesNet.py +++ b/src/timeserieslib/models/TimesNet.py @@ -2,8 +2,8 @@ import torch.nn as nn import torch.nn.functional as F import torch.fft -from layers.Embed import DataEmbedding -from layers.Conv_Blocks import Inception_Block_V1 +from timeserieslib.layers.Embed import DataEmbedding +from timeserieslib.layers.Conv_Blocks import Inception_Block_V1 def FFT_for_Period(x, k=2): @@ -43,7 +43,7 @@ def forward(self, x): # padding if (self.seq_len + self.pred_len) % period != 0: length = ( - ((self.seq_len + self.pred_len) // period) + 1) * period + ((self.seq_len + self.pred_len) // period) + 1) * period padding = torch.zeros([x.shape[0], (length - (self.seq_len + self.pred_len)), x.shape[2]]).to(x.device) out = torch.cat([x, padding], dim=1) else: @@ -120,11 +120,11 @@ def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): # De-Normalization from Non-stationary Transformer dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat( - 1, self.pred_len + self.seq_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat( - 1, self.pred_len + self.seq_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1)) return dec_out def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): @@ -148,11 +148,11 @@ def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): # De-Normalization from Non-stationary Transformer dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat( - 1, self.pred_len + self.seq_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat( - 1, self.pred_len + self.seq_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1)) return dec_out def anomaly_detection(self, x_enc): @@ -173,11 +173,11 @@ def anomaly_detection(self, x_enc): # De-Normalization from Non-stationary Transformer dec_out = dec_out * \ - (stdev[:, 0, :].unsqueeze(1).repeat( - 1, self.pred_len + self.seq_len, 1)) + (stdev[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1)) dec_out = dec_out + \ - (means[:, 0, :].unsqueeze(1).repeat( - 1, self.pred_len + self.seq_len, 1)) + (means[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1)) return dec_out def classification(self, x_enc, x_mark_enc): diff --git a/models/Transformer.py b/src/timeserieslib/models/Transformer.py similarity index 95% rename from models/Transformer.py rename to src/timeserieslib/models/Transformer.py index cf678326..7f7355a8 100644 --- a/models/Transformer.py +++ b/src/timeserieslib/models/Transformer.py @@ -1,9 +1,9 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Transformer_EncDec import Decoder, DecoderLayer, Encoder, EncoderLayer, ConvLayer -from layers.SelfAttention_Family import FullAttention, AttentionLayer -from layers.Embed import DataEmbedding +from timeserieslib.layers.Transformer_EncDec import Decoder, DecoderLayer, Encoder, EncoderLayer, ConvLayer +from timeserieslib.layers.SelfAttention_Family import FullAttention, AttentionLayer +from timeserieslib.layers.Embed import DataEmbedding import numpy as np diff --git a/models/__init__.py b/src/timeserieslib/models/__init__.py similarity index 100% rename from models/__init__.py rename to src/timeserieslib/models/__init__.py diff --git a/models/iTransformer.py b/src/timeserieslib/models/iTransformer.py similarity index 96% rename from models/iTransformer.py rename to src/timeserieslib/models/iTransformer.py index 62088450..ee3ed981 100644 --- a/models/iTransformer.py +++ b/src/timeserieslib/models/iTransformer.py @@ -1,9 +1,9 @@ import torch import torch.nn as nn import torch.nn.functional as F -from layers.Transformer_EncDec import Encoder, EncoderLayer -from layers.SelfAttention_Family import FullAttention, AttentionLayer -from layers.Embed import DataEmbedding_inverted +from timeserieslib.layers.Transformer_EncDec import Encoder, EncoderLayer +from timeserieslib.layers.SelfAttention_Family import FullAttention, AttentionLayer +from timeserieslib.layers.Embed import DataEmbedding_inverted import numpy as np diff --git a/utils/ADFtest.py b/src/timeserieslib/utils/ADFtest.py similarity index 100% rename from utils/ADFtest.py rename to src/timeserieslib/utils/ADFtest.py diff --git a/utils/__init__.py b/src/timeserieslib/utils/__init__.py similarity index 100% rename from utils/__init__.py rename to src/timeserieslib/utils/__init__.py diff --git a/utils/augmentation.py b/src/timeserieslib/utils/augmentation.py similarity index 100% rename from utils/augmentation.py rename to src/timeserieslib/utils/augmentation.py diff --git a/utils/dtw.py b/src/timeserieslib/utils/dtw.py similarity index 100% rename from utils/dtw.py rename to src/timeserieslib/utils/dtw.py diff --git a/utils/dtw_metric.py b/src/timeserieslib/utils/dtw_metric.py similarity index 100% rename from utils/dtw_metric.py rename to src/timeserieslib/utils/dtw_metric.py diff --git a/utils/losses.py b/src/timeserieslib/utils/losses.py similarity index 100% rename from utils/losses.py rename to src/timeserieslib/utils/losses.py diff --git a/utils/m4_summary.py b/src/timeserieslib/utils/m4_summary.py similarity index 98% rename from utils/m4_summary.py rename to src/timeserieslib/utils/m4_summary.py index acd50fef..10258649 100644 --- a/utils/m4_summary.py +++ b/src/timeserieslib/utils/m4_summary.py @@ -20,8 +20,8 @@ import numpy as np import pandas as pd -from data_provider.m4 import M4Dataset -from data_provider.m4 import M4Meta +from timeserieslib.data_provider.m4 import M4Dataset +from timeserieslib.data_provider.m4 import M4Meta import os diff --git a/utils/masking.py b/src/timeserieslib/utils/masking.py similarity index 100% rename from utils/masking.py rename to src/timeserieslib/utils/masking.py diff --git a/utils/metrics.py b/src/timeserieslib/utils/metrics.py similarity index 100% rename from utils/metrics.py rename to src/timeserieslib/utils/metrics.py diff --git a/utils/print_args.py b/src/timeserieslib/utils/print_args.py similarity index 100% rename from utils/print_args.py rename to src/timeserieslib/utils/print_args.py diff --git a/utils/timefeatures.py b/src/timeserieslib/utils/timefeatures.py similarity index 100% rename from utils/timefeatures.py rename to src/timeserieslib/utils/timefeatures.py diff --git a/utils/tools.py b/src/timeserieslib/utils/tools.py similarity index 94% rename from utils/tools.py rename to src/timeserieslib/utils/tools.py index 08fb91b9..c2454bac 100644 --- a/utils/tools.py +++ b/src/timeserieslib/utils/tools.py @@ -19,7 +19,7 @@ def adjust_learning_rate(optimizer, epoch, args): 10: 5e-7, 15: 1e-7, 20: 5e-8 } elif args.lradj == "cosine": - lr_adjust = {epoch: args.learning_rate /2 * (1 + math.cos(epoch / args.train_epochs * math.pi))} + lr_adjust = {epoch: args.learning_rate / 2 * (1 + math.cos(epoch / args.train_epochs * math.pi))} if epoch in lr_adjust.keys(): lr = lr_adjust[epoch] for param_group in optimizer.param_groups: @@ -34,7 +34,7 @@ def __init__(self, patience=7, verbose=False, delta=0): self.counter = 0 self.best_score = None self.early_stop = False - self.val_loss_min = np.Inf + self.val_loss_min = np.inf self.delta = delta def __call__(self, val_loss, model, path): @@ -115,4 +115,4 @@ def adjustment(gt, pred): def cal_accuracy(y_pred, y_true): - return np.mean(y_pred == y_true) \ No newline at end of file + return np.mean(y_pred == y_true) diff --git a/tutorial/TimesNet_tutorial.ipynb b/tutorial/TimesNet_tutorial.ipynb index d589d2ad..e86f69de 100644 --- a/tutorial/TimesNet_tutorial.ipynb +++ b/tutorial/TimesNet_tutorial.ipynb @@ -47,8 +47,8 @@ "import torch.nn as nn\n", "import torch.nn.functional as F\n", "import torch.fft\n", - "from layers.Embed import DataEmbedding\n", - "from layers.Conv_Blocks import Inception_Block_V1 \n", + "from timeserieslib.layers.Embed import DataEmbedding\n", + "from timeserieslib.layers.Conv_Blocks import Inception_Block_V1 \n", " #convolution block used for convoluting the 2D time data, changeable" ] }, @@ -712,7 +712,7 @@ " self.counter = 0 # now how many times loss not on decrease\n", " self.best_score = None\n", " self.early_stop = False\n", - " self.val_loss_min = np.Inf\n", + " self.val_loss_min = np.inf\n", " self.delta = delta\n", "\n", " def __call__(self, val_loss, model, path):\n", From 2b5844c99755cc411cfb51fa37897898db3cdfaf Mon Sep 17 00:00:00 2001 From: thawn Date: Fri, 12 Jul 2024 20:57:24 +0200 Subject: [PATCH 2/2] removed _version.py from git since it is autogenerated --- .gitignore | 1 + src/timeserieslib/_version.py | 16 ---------------- 2 files changed, 1 insertion(+), 16 deletions(-) delete mode 100644 src/timeserieslib/_version.py diff --git a/.gitignore b/.gitignore index 35bfd564..6c944992 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ __pycache__/ *.so # Distribution / packaging +_version.py .Python build/ develop-eggs/ diff --git a/src/timeserieslib/_version.py b/src/timeserieslib/_version.py deleted file mode 100644 index da77490d..00000000 --- a/src/timeserieslib/_version.py +++ /dev/null @@ -1,16 +0,0 @@ -# file generated by setuptools_scm -# don't change, don't track in version control -TYPE_CHECKING = False -if TYPE_CHECKING: - from typing import Tuple, Union - VERSION_TUPLE = Tuple[Union[int, str], ...] -else: - VERSION_TUPLE = object - -version: str -__version__: str -__version_tuple__: VERSION_TUPLE -version_tuple: VERSION_TUPLE - -__version__ = version = '0.1.dev220+g8cee66a.d20240712' -__version_tuple__ = version_tuple = (0, 1, 'dev220', 'g8cee66a.d20240712')