From d6dd462886a47b8a0378bd704730937b58ebe329 Mon Sep 17 00:00:00 2001 From: gameloader Date: Thu, 28 Aug 2025 10:17:59 +0000 Subject: [PATCH] first commit --- .gitignore | 168 ++ CONTRIBUTING.md | 20 + LICENSE | 21 + README.md | 171 ++ data_provider/__init__.py | 1 + data_provider/data_factory.py | 86 + data_provider/data_loader.py | 748 ++++++++ data_provider/m4.py | 138 ++ data_provider/uea.py | 125 ++ exp/__init__.py | 0 exp/exp_anomaly_detection.py | 207 +++ exp/exp_basic.py | 80 + exp/exp_classification.py | 192 ++ exp/exp_imputation.py | 228 +++ exp/exp_long_term_forecasting.py | 268 +++ exp/exp_short_term_forecasting.py | 235 +++ layers/AutoCorrelation.py | 163 ++ layers/Autoformer_EncDec.py | 203 +++ layers/Conv_Blocks.py | 60 + layers/Crossformer_EncDec.py | 131 ++ layers/DECOMP.py | 22 + layers/DEMA.py | 23 + layers/DWT_Decomposition.py | 1268 ++++++++++++++ layers/EMA.py | 23 + layers/ETSformer_EncDec.py | 334 ++++ layers/Embed.py | 190 ++ layers/FourierCorrelation.py | 162 ++ layers/GraphMixer.py | 83 + layers/MultiWaveletCorrelation.py | 587 +++++++ layers/Pyraformer_EncDec.py | 218 +++ layers/RevIN.py | 59 + layers/SeasonPatch.py | 67 + layers/SelfAttention_Family.py | 302 ++++ layers/StandardNorm.py | 68 + layers/TSTEncoder.py | 91 + layers/Transformer_EncDec.py | 135 ++ layers/__init__.py | 0 models/Autoformer.py | 157 ++ models/Crossformer.py | 145 ++ models/DLinear.py | 110 ++ models/ETSformer.py | 110 ++ models/FEDformer.py | 178 ++ models/FiLM.py | 268 +++ models/FreTS.py | 118 ++ models/Informer.py | 147 ++ models/Koopa.py | 337 ++++ models/LightTS.py | 165 ++ models/MICN.py | 222 +++ models/Mamba.py | 50 + models/MambaSimple.py | 162 ++ models/MultiPatchFormer.py | 365 ++++ models/Nonstationary_Transformer.py | 230 +++ models/PAttn.py | 62 + models/PatchTST.py | 227 +++ models/Pyraformer.py | 101 ++ models/Reformer.py | 132 ++ models/SCINet.py | 188 ++ models/SegRNN.py | 119 ++ models/TSMixer.py | 54 + models/TemporalFusionTransformer.py | 309 ++++ models/TiDE.py | 145 ++ models/TimeMixer.py | 516 ++++++ models/TimeXer.py | 225 +++ models/TimesNet.py | 215 +++ models/Transformer.py | 124 ++ models/WPMixer.py | 319 ++++ models/__init__.py | 0 models/iTransformer.py | 132 ++ models/xPatch_SparseChannel.py | 166 ++ requirements.txt | 14 + run.py | 261 +++ scripts/anomaly_detection/MSL/Autoformer.sh | 20 + scripts/anomaly_detection/MSL/Crossformer.sh | 20 + scripts/anomaly_detection/MSL/DLinear.sh | 20 + scripts/anomaly_detection/MSL/ETSformer.sh | 21 + scripts/anomaly_detection/MSL/FEDformer.sh | 20 + scripts/anomaly_detection/MSL/FiLM.sh | 20 + scripts/anomaly_detection/MSL/Informer.sh | 20 + scripts/anomaly_detection/MSL/LightTS.sh | 20 + scripts/anomaly_detection/MSL/MICN.sh | 20 + scripts/anomaly_detection/MSL/Pyraformer.sh | 20 + scripts/anomaly_detection/MSL/Reformer.sh | 20 + scripts/anomaly_detection/MSL/TimesNet.sh | 21 + scripts/anomaly_detection/MSL/Transformer.sh | 20 + scripts/anomaly_detection/MSL/iTransformer.sh | 20 + scripts/anomaly_detection/PSM/Autoformer.sh | 20 + scripts/anomaly_detection/PSM/DLinear.sh | 20 + scripts/anomaly_detection/PSM/TimesNet.sh | 21 + scripts/anomaly_detection/PSM/Transformer.sh | 20 + scripts/anomaly_detection/SMAP/Autoformer.sh | 20 + scripts/anomaly_detection/SMAP/TimesNet.sh | 21 + scripts/anomaly_detection/SMAP/Transformer.sh | 20 + scripts/anomaly_detection/SMD/Autoformer.sh | 20 + scripts/anomaly_detection/SMD/TimesNet.sh | 21 + scripts/anomaly_detection/SMD/Transformer.sh | 20 + scripts/anomaly_detection/SWAT/Autoformer.sh | 21 + scripts/anomaly_detection/SWAT/TimesNet.sh | 161 ++ scripts/anomaly_detection/SWAT/Transformer.sh | 21 + scripts/classification/Autoformer.sh | 183 ++ scripts/classification/Crossformer.sh | 183 ++ scripts/classification/DLinear.sh | 183 ++ scripts/classification/ETSformer.sh | 193 ++ scripts/classification/FEDformer.sh | 183 ++ scripts/classification/FiLM.sh | 185 ++ scripts/classification/Informer.sh | 183 ++ scripts/classification/LightTS.sh | 183 ++ scripts/classification/MICN.sh | 184 ++ scripts/classification/PatchTST.sh | 183 ++ scripts/classification/Pyraformer.sh | 183 ++ scripts/classification/Reformer.sh | 183 ++ scripts/classification/TimesNet.sh | 182 ++ scripts/classification/Transformer.sh | 183 ++ scripts/classification/iTransformer.sh | 193 ++ .../classification/xPatch_SparseChannel.sh | 32 + scripts/exogenous_forecast/ECL/TimeXer.sh | 89 + scripts/exogenous_forecast/EPF/TimeXer.sh | 114 ++ scripts/exogenous_forecast/ETTh1/TimeXer.sh | 94 + scripts/exogenous_forecast/ETTh2/TimeXer.sh | 95 + scripts/exogenous_forecast/ETTm1/TimeXer.sh | 92 + scripts/exogenous_forecast/ETTm2/TimeXer.sh | 92 + scripts/exogenous_forecast/Traffic/TimeXer.sh | 96 + scripts/exogenous_forecast/Weather/TimeXer.sh | 89 + scripts/imputation/ECL_script/Autoformer.sh | 111 ++ scripts/imputation/ECL_script/DLinear.sh | 111 ++ scripts/imputation/ECL_script/ETSformer.sh | 111 ++ scripts/imputation/ECL_script/FEDformer.sh | 111 ++ scripts/imputation/ECL_script/Informer.sh | 111 ++ scripts/imputation/ECL_script/LightTS.sh | 111 ++ scripts/imputation/ECL_script/Pyraformer.sh | 111 ++ scripts/imputation/ECL_script/Reformer.sh | 111 ++ scripts/imputation/ECL_script/TimesNet.sh | 111 ++ scripts/imputation/ECL_script/Transformer.sh | 111 ++ scripts/imputation/ECL_script/iTransformer.sh | 111 ++ .../imputation/ETT_script/Autoformer_ETTh1.sh | 111 ++ .../imputation/ETT_script/Autoformer_ETTh2.sh | 111 ++ .../imputation/ETT_script/Autoformer_ETTm1.sh | 111 ++ .../imputation/ETT_script/Autoformer_ETTm2.sh | 111 ++ .../ETT_script/Crossformer_ETTh1.sh | 111 ++ .../imputation/ETT_script/DLinear_ETTh1.sh | 111 ++ scripts/imputation/ETT_script/FiLM_ETTh1.sh | 111 ++ scripts/imputation/ETT_script/MICN_ETTh1.sh | 115 ++ .../Nonstationary_Transformer_ETTh1.sh | 119 ++ scripts/imputation/ETT_script/TiDE_ETTh1.sh | 110 ++ .../imputation/ETT_script/TimesNet_ETTh1.sh | 111 ++ .../imputation/ETT_script/TimesNet_ETTh2.sh | 111 ++ .../imputation/ETT_script/TimesNet_ETTm1.sh | 111 ++ .../imputation/ETT_script/TimesNet_ETTm2.sh | 111 ++ .../ETT_script/Transformer_ETTh1.sh | 111 ++ .../ETT_script/Transformer_ETTh2.sh | 111 ++ .../ETT_script/Transformer_ETTm1.sh | 111 ++ .../ETT_script/Transformer_ETTm2.sh | 111 ++ .../ETT_script/iTransformer_ETTh2.sh | 111 ++ .../imputation/Weather_script/Autoformer.sh | 111 ++ scripts/imputation/Weather_script/TimesNet.sh | 111 ++ .../imputation/Weather_script/Transformer.sh | 111 ++ .../AugmentSample/Classification/PatchTST.sh | 28 + .../AugmentSample/Forecasting/PatchTST.sh | 33 + .../AugmentSample/ReadMe.md | 97 ++ .../ECL_script/Autoformer.sh | 87 + .../ECL_script/Crossformer.sh | 103 ++ .../long_term_forecast/ECL_script/DLinear.sh | 87 + .../ECL_script/ETSformer.sh | 87 + .../ECL_script/FEDformer.sh | 87 + scripts/long_term_forecast/ECL_script/FiLM.sh | 91 + .../long_term_forecast/ECL_script/Informer.sh | 87 + .../long_term_forecast/ECL_script/Koopa.sh | 87 + .../long_term_forecast/ECL_script/LightTS.sh | 87 + scripts/long_term_forecast/ECL_script/MICN.sh | 99 ++ .../long_term_forecast/ECL_script/Mamba.sh | 30 + .../ECL_script/MultiPatchFormer.sh | 98 ++ .../ECL_script/Nonstationary_Transformer.sh | 99 ++ .../long_term_forecast/ECL_script/PatchTST.sh | 91 + .../ECL_script/Pyraformer.sh | 87 + .../long_term_forecast/ECL_script/Reformer.sh | 87 + .../long_term_forecast/ECL_script/SegRNN.sh | 27 + .../long_term_forecast/ECL_script/TSMixer.sh | 98 ++ .../ECL_script/TimeMixer.sh | 134 ++ .../long_term_forecast/ECL_script/TimeXer.sh | 88 + .../long_term_forecast/ECL_script/TimesNet.sh | 99 ++ .../ECL_script/Transformer.sh | 87 + .../long_term_forecast/ECL_script/WPMixer.sh | 49 + .../ECL_script/iTransformer.sh | 105 ++ .../ETT_script/Autoformer_ETTh1.sh | 87 + .../ETT_script/Autoformer_ETTh2.sh | 87 + .../ETT_script/Autoformer_ETTm1.sh | 87 + .../ETT_script/Autoformer_ETTm2.sh | 87 + .../ETT_script/Crossformer_ETTh1.sh | 87 + .../ETT_script/Crossformer_ETTh2.sh | 87 + .../ETT_script/Crossformer_ETTm1.sh | 83 + .../ETT_script/Crossformer_ETTm2.sh | 87 + .../ETT_script/DLinear_ETTh1.sh | 87 + .../ETT_script/ETSformer_ETTh1.sh | 87 + .../ETT_script/FEDformer_ETTh1.sh | 87 + .../ETT_script/FiLM_ETTh1.sh | 87 + .../ETT_script/FiLM_ETTh2.sh | 87 + .../ETT_script/FiLM_ETTm1.sh | 87 + .../ETT_script/FiLM_ETTm2.sh | 87 + .../ETT_script/Informer_ETTh1.sh | 87 + .../ETT_script/Koopa_ETTh1.sh | 87 + .../ETT_script/Koopa_ETTh2.sh | 87 + .../ETT_script/Koopa_ETTm1.sh | 87 + .../ETT_script/Koopa_ETTm2.sh | 87 + .../ETT_script/LightTS_ETTh1.sh | 87 + .../ETT_script/MICN_ETTh1.sh | 87 + .../ETT_script/MICN_ETTh2.sh | 87 + .../ETT_script/MICN_ETTm1.sh | 91 + .../ETT_script/MICN_ETTm2.sh | 91 + .../ETT_script/MambaSimple_ETTh1.sh | 29 + .../ETT_script/Mamba_ETT_all.sh | 4 + .../ETT_script/Mamba_ETTh1.sh | 28 + .../ETT_script/Mamba_ETTh2.sh | 28 + .../ETT_script/Mamba_ETTm1.sh | 28 + .../ETT_script/Mamba_ETTm2.sh | 28 + .../ETT_script/MultiPatchFormer_ETTh1.sh | 90 + .../ETT_script/MultiPatchFormer_ETTm1.sh | 98 ++ .../Nonstationary_Transformer_ETTh1.sh | 99 ++ .../Nonstationary_Transformer_ETTh2.sh | 95 + .../Nonstationary_Transformer_ETTm1.sh | 91 + .../Nonstationary_Transformer_ETTm2.sh | 95 + .../ETT_script/PAttn_ETTh1.sh | 83 + .../ETT_script/PatchTST_ETTh1.sh | 91 + .../ETT_script/PatchTST_ETTh2.sh | 91 + .../ETT_script/PatchTST_ETTm1.sh | 95 + .../ETT_script/PatchTST_ETTm2.sh | 95 + .../ETT_script/Pyraformer_ETTh1.sh | 87 + .../ETT_script/Pyraformer_ETTh2.sh | 87 + .../ETT_script/Pyraformer_ETTm1.sh | 87 + .../ETT_script/Pyraformer_ETTm2.sh | 87 + .../ETT_script/Reformer_ETTh1.sh | 87 + .../ETT_script/SegRNN_ETTh1.sh | 26 + .../ETT_script/SegRNN_ETTh2.sh | 26 + .../ETT_script/SegRNN_ETTm1.sh | 26 + .../ETT_script/SegRNN_ETTm2.sh | 26 + .../ETT_script/TSMixer_ETTh1.sh | 86 + .../ETT_script/TSMixer_ETTh2.sh | 86 + .../ETT_script/TSMixer_ETTm1.sh | 86 + .../ETT_script/TSMixer_ETTm2.sh | 86 + .../ETT_script/TiDE_ETTh1.sh | 112 ++ .../ETT_script/TimeMixer_ETTh1.sh | 125 ++ .../ETT_script/TimeMixer_ETTh2.sh | 111 ++ .../ETT_script/TimeMixer_ETTm1.sh | 115 ++ .../ETT_script/TimeMixer_ETTm2.sh | 115 ++ .../ETT_script/TimeXer_ETTh1.sh | 94 + .../ETT_script/TimeXer_ETTh2.sh | 94 + .../ETT_script/TimeXer_ETTm1.sh | 94 + .../ETT_script/TimeXer_ETTm2.sh | 95 + .../ETT_script/TimesNet_ETTh1.sh | 102 ++ .../ETT_script/TimesNet_ETTh2.sh | 99 ++ .../ETT_script/TimesNet_ETTm1.sh | 100 ++ .../ETT_script/TimesNet_ETTm2.sh | 101 ++ .../ETT_script/Transformer_ETTh1.sh | 87 + .../ETT_script/Transformer_ETTh2.sh | 87 + .../ETT_script/Transformer_ETTm1.sh | 83 + .../ETT_script/Transformer_ETTm2.sh | 87 + .../ETT_script/WPMixer_ETTh1.sh | 50 + .../ETT_script/WPMixer_ETTh2.sh | 49 + .../ETT_script/WPMixer_ETTm1.sh | 49 + .../ETT_script/WPMixer_ETTm2.sh | 50 + .../ETT_script/iTransformer_ETTh2.sh | 95 + .../Exchange_script/Autoformer.sh | 89 + .../Exchange_script/Crossformer.sh | 101 ++ .../Exchange_script/FiLM.sh | 92 + .../Exchange_script/Koopa.sh | 87 + .../Exchange_script/MICN.sh | 101 ++ .../Exchange_script/Mamba.sh | 28 + .../Nonstationary_Transformer.sh | 96 + .../Exchange_script/PatchTST.sh | 88 + .../Exchange_script/Pyraformer.sh | 89 + .../Exchange_script/TimesNet.sh | 101 ++ .../Exchange_script/Transformer.sh | 88 + .../ILI_script/Autoformer.sh | 87 + .../ILI_script/Crossformer.sh | 103 ++ scripts/long_term_forecast/ILI_script/FiLM.sh | 88 + .../long_term_forecast/ILI_script/Koopa.sh | 87 + scripts/long_term_forecast/ILI_script/MICN.sh | 99 ++ .../ILI_script/Nonstationary_Transformer.sh | 95 + .../long_term_forecast/ILI_script/PatchTST.sh | 96 + .../long_term_forecast/ILI_script/TimesNet.sh | 99 ++ .../ILI_script/Transformer.sh | 87 + scripts/long_term_forecast/Mamba_all.sh | 4 + .../Traffic_script/Autoformer.sh | 91 + .../Traffic_script/Crossformer.sh | 99 ++ .../long_term_forecast/Traffic_script/FiLM.sh | 91 + .../Traffic_script/Koopa.sh | 87 + .../long_term_forecast/Traffic_script/MICN.sh | 99 ++ .../Traffic_script/Mamba.sh | 29 + .../Traffic_script/MultiPatchFormer.sh | 96 + .../Nonstationary_Transformer.sh | 99 ++ .../Traffic_script/PatchTST.sh | 103 ++ .../Traffic_script/Pyraformer.sh | 91 + .../Traffic_script/SegRNN.sh | 27 + .../Traffic_script/TSMixer.sh | 101 ++ .../Traffic_script/TimeMixer.sh | 125 ++ .../Traffic_script/TimeXer.sh | 99 ++ .../Traffic_script/TimesNet.sh | 99 ++ .../Traffic_script/Transformer.sh | 91 + .../Traffic_script/WPMixer.sh | 49 + .../Traffic_script/iTransformer.sh | 103 ++ .../Weather_script/Autoformer.sh | 88 + .../Weather_script/Crossformer.sh | 102 ++ .../long_term_forecast/Weather_script/FiLM.sh | 85 + .../long_term_forecast/Weather_script/MICN.sh | 102 ++ .../Weather_script/Mamba.sh | 29 + .../Weather_script/MultiPatchFormer.sh | 98 ++ .../Nonstationary_Transformer.sh | 96 + .../Weather_script/PatchTST.sh | 97 ++ .../Weather_script/Pyraformer.sh | 88 + .../Weather_script/SegRNN.sh | 27 + .../Weather_script/TSMixer.sh | 99 ++ .../Weather_script/TimeMixer.sh | 133 ++ .../Weather_script/TimeXer.sh | 93 + .../Weather_script/TimesNet.sh | 102 ++ .../Weather_script/Transformer.sh | 88 + .../Weather_script/WPMixer.sh | 49 + .../Weather_script/iTransformer.sh | 98 ++ scripts/short_term_forecast/Autoformer_M4.sh | 135 ++ scripts/short_term_forecast/Crossformer_M4.sh | 147 ++ scripts/short_term_forecast/DLinear_M4.sh | 135 ++ scripts/short_term_forecast/ETSformer_M4.sh | 135 ++ scripts/short_term_forecast/FEDformer_M4.sh | 135 ++ scripts/short_term_forecast/FiLM_M4.sh | 147 ++ scripts/short_term_forecast/Informer_M4.sh | 135 ++ scripts/short_term_forecast/LightTS_M4.sh | 135 ++ scripts/short_term_forecast/MICN_M4.sh | 147 ++ scripts/short_term_forecast/Mamba_M4.sh | 135 ++ .../Nonstationary_Transformer_M4.sh | 147 ++ scripts/short_term_forecast/Pyraformer_M4.sh | 135 ++ scripts/short_term_forecast/Reformer_M4.sh | 135 ++ scripts/short_term_forecast/TSMixer_M4.sh | 135 ++ scripts/short_term_forecast/TimeMixer_M4.sh | 180 ++ scripts/short_term_forecast/TimesNet_M4.sh | 147 ++ scripts/short_term_forecast/Transformer_M4.sh | 135 ++ .../short_term_forecast/iTransformer_M4.sh | 135 ++ tutorial/TimesNet_tutorial.ipynb | 1552 +++++++++++++++++ tutorial/conv.png | Bin 0 -> 683079 bytes tutorial/dataset.png | Bin 0 -> 30465 bytes tutorial/fft.png | Bin 0 -> 637644 bytes tutorial/result.png | Bin 0 -> 70386 bytes utils/ADFtest.py | 74 + utils/__init__.py | 0 utils/augmentation.py | 434 +++++ utils/dtw.py | 223 +++ utils/dtw_metric.py | 156 ++ utils/losses.py | 89 + utils/m4_summary.py | 140 ++ utils/masking.py | 26 + utils/metrics.py | 41 + utils/print_args.py | 58 + utils/timefeatures.py | 148 ++ utils/tools.py | 120 ++ 350 files changed, 39789 insertions(+) create mode 100644 .gitignore create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 data_provider/__init__.py create mode 100644 data_provider/data_factory.py create mode 100644 data_provider/data_loader.py create mode 100644 data_provider/m4.py create mode 100644 data_provider/uea.py create mode 100644 exp/__init__.py create mode 100644 exp/exp_anomaly_detection.py create mode 100644 exp/exp_basic.py create mode 100644 exp/exp_classification.py create mode 100644 exp/exp_imputation.py create mode 100644 exp/exp_long_term_forecasting.py create mode 100644 exp/exp_short_term_forecasting.py create mode 100644 layers/AutoCorrelation.py create mode 100644 layers/Autoformer_EncDec.py create mode 100644 layers/Conv_Blocks.py create mode 100644 layers/Crossformer_EncDec.py create mode 100644 layers/DECOMP.py create mode 100644 layers/DEMA.py create mode 100644 layers/DWT_Decomposition.py create mode 100644 layers/EMA.py create mode 100644 layers/ETSformer_EncDec.py create mode 100644 layers/Embed.py create mode 100644 layers/FourierCorrelation.py create mode 100644 layers/GraphMixer.py create mode 100644 layers/MultiWaveletCorrelation.py create mode 100644 layers/Pyraformer_EncDec.py create mode 100644 layers/RevIN.py create mode 100644 layers/SeasonPatch.py create mode 100644 layers/SelfAttention_Family.py create mode 100755 layers/StandardNorm.py create mode 100644 layers/TSTEncoder.py create mode 100644 layers/Transformer_EncDec.py create mode 100644 layers/__init__.py create mode 100644 models/Autoformer.py create mode 100644 models/Crossformer.py create mode 100644 models/DLinear.py create mode 100644 models/ETSformer.py create mode 100644 models/FEDformer.py create mode 100644 models/FiLM.py create mode 100644 models/FreTS.py create mode 100644 models/Informer.py create mode 100644 models/Koopa.py create mode 100644 models/LightTS.py create mode 100644 models/MICN.py create mode 100644 models/Mamba.py create mode 100644 models/MambaSimple.py create mode 100644 models/MultiPatchFormer.py create mode 100644 models/Nonstationary_Transformer.py create mode 100644 models/PAttn.py create mode 100644 models/PatchTST.py create mode 100644 models/Pyraformer.py create mode 100644 models/Reformer.py create mode 100644 models/SCINet.py create mode 100644 models/SegRNN.py create mode 100644 models/TSMixer.py create mode 100644 models/TemporalFusionTransformer.py create mode 100644 models/TiDE.py create mode 100755 models/TimeMixer.py create mode 100644 models/TimeXer.py create mode 100644 models/TimesNet.py create mode 100644 models/Transformer.py create mode 100644 models/WPMixer.py create mode 100644 models/__init__.py create mode 100644 models/iTransformer.py create mode 100644 models/xPatch_SparseChannel.py create mode 100644 requirements.txt create mode 100644 run.py create mode 100644 scripts/anomaly_detection/MSL/Autoformer.sh create mode 100644 scripts/anomaly_detection/MSL/Crossformer.sh create mode 100644 scripts/anomaly_detection/MSL/DLinear.sh create mode 100644 scripts/anomaly_detection/MSL/ETSformer.sh create mode 100644 scripts/anomaly_detection/MSL/FEDformer.sh create mode 100644 scripts/anomaly_detection/MSL/FiLM.sh create mode 100644 scripts/anomaly_detection/MSL/Informer.sh create mode 100644 scripts/anomaly_detection/MSL/LightTS.sh create mode 100644 scripts/anomaly_detection/MSL/MICN.sh create mode 100644 scripts/anomaly_detection/MSL/Pyraformer.sh create mode 100644 scripts/anomaly_detection/MSL/Reformer.sh create mode 100644 scripts/anomaly_detection/MSL/TimesNet.sh create mode 100644 scripts/anomaly_detection/MSL/Transformer.sh create mode 100644 scripts/anomaly_detection/MSL/iTransformer.sh create mode 100644 scripts/anomaly_detection/PSM/Autoformer.sh create mode 100644 scripts/anomaly_detection/PSM/DLinear.sh create mode 100644 scripts/anomaly_detection/PSM/TimesNet.sh create mode 100644 scripts/anomaly_detection/PSM/Transformer.sh create mode 100644 scripts/anomaly_detection/SMAP/Autoformer.sh create mode 100644 scripts/anomaly_detection/SMAP/TimesNet.sh create mode 100644 scripts/anomaly_detection/SMAP/Transformer.sh create mode 100644 scripts/anomaly_detection/SMD/Autoformer.sh create mode 100644 scripts/anomaly_detection/SMD/TimesNet.sh create mode 100644 scripts/anomaly_detection/SMD/Transformer.sh create mode 100644 scripts/anomaly_detection/SWAT/Autoformer.sh create mode 100644 scripts/anomaly_detection/SWAT/TimesNet.sh create mode 100644 scripts/anomaly_detection/SWAT/Transformer.sh create mode 100644 scripts/classification/Autoformer.sh create mode 100644 scripts/classification/Crossformer.sh create mode 100644 scripts/classification/DLinear.sh create mode 100644 scripts/classification/ETSformer.sh create mode 100644 scripts/classification/FEDformer.sh create mode 100644 scripts/classification/FiLM.sh create mode 100644 scripts/classification/Informer.sh create mode 100644 scripts/classification/LightTS.sh create mode 100644 scripts/classification/MICN.sh create mode 100644 scripts/classification/PatchTST.sh create mode 100644 scripts/classification/Pyraformer.sh create mode 100644 scripts/classification/Reformer.sh create mode 100644 scripts/classification/TimesNet.sh create mode 100644 scripts/classification/Transformer.sh create mode 100644 scripts/classification/iTransformer.sh create mode 100644 scripts/classification/xPatch_SparseChannel.sh create mode 100644 scripts/exogenous_forecast/ECL/TimeXer.sh create mode 100644 scripts/exogenous_forecast/EPF/TimeXer.sh create mode 100644 scripts/exogenous_forecast/ETTh1/TimeXer.sh create mode 100644 scripts/exogenous_forecast/ETTh2/TimeXer.sh create mode 100644 scripts/exogenous_forecast/ETTm1/TimeXer.sh create mode 100644 scripts/exogenous_forecast/ETTm2/TimeXer.sh create mode 100644 scripts/exogenous_forecast/Traffic/TimeXer.sh create mode 100644 scripts/exogenous_forecast/Weather/TimeXer.sh create mode 100644 scripts/imputation/ECL_script/Autoformer.sh create mode 100644 scripts/imputation/ECL_script/DLinear.sh create mode 100644 scripts/imputation/ECL_script/ETSformer.sh create mode 100644 scripts/imputation/ECL_script/FEDformer.sh create mode 100644 scripts/imputation/ECL_script/Informer.sh create mode 100644 scripts/imputation/ECL_script/LightTS.sh create mode 100644 scripts/imputation/ECL_script/Pyraformer.sh create mode 100644 scripts/imputation/ECL_script/Reformer.sh create mode 100644 scripts/imputation/ECL_script/TimesNet.sh create mode 100644 scripts/imputation/ECL_script/Transformer.sh create mode 100644 scripts/imputation/ECL_script/iTransformer.sh create mode 100644 scripts/imputation/ETT_script/Autoformer_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/Autoformer_ETTh2.sh create mode 100644 scripts/imputation/ETT_script/Autoformer_ETTm1.sh create mode 100644 scripts/imputation/ETT_script/Autoformer_ETTm2.sh create mode 100644 scripts/imputation/ETT_script/Crossformer_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/DLinear_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/FiLM_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/MICN_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/Nonstationary_Transformer_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/TiDE_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/TimesNet_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/TimesNet_ETTh2.sh create mode 100644 scripts/imputation/ETT_script/TimesNet_ETTm1.sh create mode 100644 scripts/imputation/ETT_script/TimesNet_ETTm2.sh create mode 100644 scripts/imputation/ETT_script/Transformer_ETTh1.sh create mode 100644 scripts/imputation/ETT_script/Transformer_ETTh2.sh create mode 100644 scripts/imputation/ETT_script/Transformer_ETTm1.sh create mode 100644 scripts/imputation/ETT_script/Transformer_ETTm2.sh create mode 100644 scripts/imputation/ETT_script/iTransformer_ETTh2.sh create mode 100644 scripts/imputation/Weather_script/Autoformer.sh create mode 100644 scripts/imputation/Weather_script/TimesNet.sh create mode 100644 scripts/imputation/Weather_script/Transformer.sh create mode 100644 scripts/long_term_forecast/AugmentSample/Classification/PatchTST.sh create mode 100644 scripts/long_term_forecast/AugmentSample/Forecasting/PatchTST.sh create mode 100644 scripts/long_term_forecast/AugmentSample/ReadMe.md create mode 100644 scripts/long_term_forecast/ECL_script/Autoformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/Crossformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/DLinear.sh create mode 100644 scripts/long_term_forecast/ECL_script/ETSformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/FEDformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/FiLM.sh create mode 100644 scripts/long_term_forecast/ECL_script/Informer.sh create mode 100644 scripts/long_term_forecast/ECL_script/Koopa.sh create mode 100644 scripts/long_term_forecast/ECL_script/LightTS.sh create mode 100644 scripts/long_term_forecast/ECL_script/MICN.sh create mode 100644 scripts/long_term_forecast/ECL_script/Mamba.sh create mode 100644 scripts/long_term_forecast/ECL_script/MultiPatchFormer.sh create mode 100644 scripts/long_term_forecast/ECL_script/Nonstationary_Transformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/PatchTST.sh create mode 100644 scripts/long_term_forecast/ECL_script/Pyraformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/Reformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/SegRNN.sh create mode 100755 scripts/long_term_forecast/ECL_script/TSMixer.sh create mode 100755 scripts/long_term_forecast/ECL_script/TimeMixer.sh create mode 100644 scripts/long_term_forecast/ECL_script/TimeXer.sh create mode 100644 scripts/long_term_forecast/ECL_script/TimesNet.sh create mode 100644 scripts/long_term_forecast/ECL_script/Transformer.sh create mode 100644 scripts/long_term_forecast/ECL_script/WPMixer.sh create mode 100644 scripts/long_term_forecast/ECL_script/iTransformer.sh create mode 100644 scripts/long_term_forecast/ETT_script/Autoformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Autoformer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Autoformer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Autoformer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Crossformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Crossformer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Crossformer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Crossformer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/DLinear_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/ETSformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/FEDformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/FiLM_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/FiLM_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/FiLM_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/FiLM_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Informer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Koopa_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Koopa_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Koopa_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Koopa_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/LightTS_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/MICN_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/MICN_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/MICN_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/MICN_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/MambaSimple_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Mamba_ETT_all.sh create mode 100644 scripts/long_term_forecast/ETT_script/Mamba_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Mamba_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Mamba_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Mamba_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/PAttn_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/PatchTST_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/PatchTST_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/PatchTST_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/PatchTST_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Pyraformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Pyraformer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Pyraformer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Pyraformer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Reformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/SegRNN_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/SegRNN_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/SegRNN_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/SegRNN_ETTm2.sh create mode 100755 scripts/long_term_forecast/ETT_script/TSMixer_ETTh1.sh create mode 100755 scripts/long_term_forecast/ETT_script/TSMixer_ETTh2.sh create mode 100755 scripts/long_term_forecast/ETT_script/TSMixer_ETTm1.sh create mode 100755 scripts/long_term_forecast/ETT_script/TSMixer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/TiDE_ETTh1.sh create mode 100755 scripts/long_term_forecast/ETT_script/TimeMixer_ETTh1.sh create mode 100755 scripts/long_term_forecast/ETT_script/TimeMixer_ETTh2.sh create mode 100755 scripts/long_term_forecast/ETT_script/TimeMixer_ETTm1.sh create mode 100755 scripts/long_term_forecast/ETT_script/TimeMixer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimeXer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimeXer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimeXer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimeXer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimesNet_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimesNet_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimesNet_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/TimesNet_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Transformer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Transformer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/Transformer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/Transformer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/WPMixer_ETTh1.sh create mode 100644 scripts/long_term_forecast/ETT_script/WPMixer_ETTh2.sh create mode 100644 scripts/long_term_forecast/ETT_script/WPMixer_ETTm1.sh create mode 100644 scripts/long_term_forecast/ETT_script/WPMixer_ETTm2.sh create mode 100644 scripts/long_term_forecast/ETT_script/iTransformer_ETTh2.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Autoformer.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Crossformer.sh create mode 100644 scripts/long_term_forecast/Exchange_script/FiLM.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Koopa.sh create mode 100644 scripts/long_term_forecast/Exchange_script/MICN.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Mamba.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Nonstationary_Transformer.sh create mode 100644 scripts/long_term_forecast/Exchange_script/PatchTST.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Pyraformer.sh create mode 100644 scripts/long_term_forecast/Exchange_script/TimesNet.sh create mode 100644 scripts/long_term_forecast/Exchange_script/Transformer.sh create mode 100644 scripts/long_term_forecast/ILI_script/Autoformer.sh create mode 100644 scripts/long_term_forecast/ILI_script/Crossformer.sh create mode 100644 scripts/long_term_forecast/ILI_script/FiLM.sh create mode 100644 scripts/long_term_forecast/ILI_script/Koopa.sh create mode 100644 scripts/long_term_forecast/ILI_script/MICN.sh create mode 100644 scripts/long_term_forecast/ILI_script/Nonstationary_Transformer.sh create mode 100644 scripts/long_term_forecast/ILI_script/PatchTST.sh create mode 100644 scripts/long_term_forecast/ILI_script/TimesNet.sh create mode 100644 scripts/long_term_forecast/ILI_script/Transformer.sh create mode 100644 scripts/long_term_forecast/Mamba_all.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Autoformer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Crossformer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/FiLM.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Koopa.sh create mode 100644 scripts/long_term_forecast/Traffic_script/MICN.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Mamba.sh create mode 100644 scripts/long_term_forecast/Traffic_script/MultiPatchFormer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Nonstationary_Transformer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/PatchTST.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Pyraformer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/SegRNN.sh create mode 100755 scripts/long_term_forecast/Traffic_script/TSMixer.sh create mode 100755 scripts/long_term_forecast/Traffic_script/TimeMixer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/TimeXer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/TimesNet.sh create mode 100644 scripts/long_term_forecast/Traffic_script/Transformer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/WPMixer.sh create mode 100644 scripts/long_term_forecast/Traffic_script/iTransformer.sh create mode 100644 scripts/long_term_forecast/Weather_script/Autoformer.sh create mode 100644 scripts/long_term_forecast/Weather_script/Crossformer.sh create mode 100644 scripts/long_term_forecast/Weather_script/FiLM.sh create mode 100644 scripts/long_term_forecast/Weather_script/MICN.sh create mode 100644 scripts/long_term_forecast/Weather_script/Mamba.sh create mode 100644 scripts/long_term_forecast/Weather_script/MultiPatchFormer.sh create mode 100644 scripts/long_term_forecast/Weather_script/Nonstationary_Transformer.sh create mode 100644 scripts/long_term_forecast/Weather_script/PatchTST.sh create mode 100644 scripts/long_term_forecast/Weather_script/Pyraformer.sh create mode 100644 scripts/long_term_forecast/Weather_script/SegRNN.sh create mode 100755 scripts/long_term_forecast/Weather_script/TSMixer.sh create mode 100755 scripts/long_term_forecast/Weather_script/TimeMixer.sh create mode 100644 scripts/long_term_forecast/Weather_script/TimeXer.sh create mode 100644 scripts/long_term_forecast/Weather_script/TimesNet.sh create mode 100644 scripts/long_term_forecast/Weather_script/Transformer.sh create mode 100644 scripts/long_term_forecast/Weather_script/WPMixer.sh create mode 100644 scripts/long_term_forecast/Weather_script/iTransformer.sh create mode 100644 scripts/short_term_forecast/Autoformer_M4.sh create mode 100644 scripts/short_term_forecast/Crossformer_M4.sh create mode 100644 scripts/short_term_forecast/DLinear_M4.sh create mode 100644 scripts/short_term_forecast/ETSformer_M4.sh create mode 100644 scripts/short_term_forecast/FEDformer_M4.sh create mode 100644 scripts/short_term_forecast/FiLM_M4.sh create mode 100644 scripts/short_term_forecast/Informer_M4.sh create mode 100644 scripts/short_term_forecast/LightTS_M4.sh create mode 100644 scripts/short_term_forecast/MICN_M4.sh create mode 100644 scripts/short_term_forecast/Mamba_M4.sh create mode 100644 scripts/short_term_forecast/Nonstationary_Transformer_M4.sh create mode 100644 scripts/short_term_forecast/Pyraformer_M4.sh create mode 100644 scripts/short_term_forecast/Reformer_M4.sh create mode 100755 scripts/short_term_forecast/TSMixer_M4.sh create mode 100755 scripts/short_term_forecast/TimeMixer_M4.sh create mode 100644 scripts/short_term_forecast/TimesNet_M4.sh create mode 100644 scripts/short_term_forecast/Transformer_M4.sh create mode 100644 scripts/short_term_forecast/iTransformer_M4.sh create mode 100644 tutorial/TimesNet_tutorial.ipynb create mode 100644 tutorial/conv.png create mode 100644 tutorial/dataset.png create mode 100644 tutorial/fft.png create mode 100644 tutorial/result.png create mode 100644 utils/ADFtest.py create mode 100644 utils/__init__.py create mode 100644 utils/augmentation.py create mode 100644 utils/dtw.py create mode 100644 utils/dtw_metric.py create mode 100644 utils/losses.py create mode 100644 utils/m4_summary.py create mode 100644 utils/masking.py create mode 100644 utils/metrics.py create mode 100644 utils/print_args.py create mode 100644 utils/timefeatures.py create mode 100644 utils/tools.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d3acf7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,168 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ +/scripts/long_term_forecast/Traffic_script/PatchTST1.sh +/backups/ +/result.xlsx +/~$result.xlsx +/Time-Series-Library.zip +/temp.sh + +.idea +/tv_result.xlsx +/test.py +/m4_results/ +/test_results/ +/PatchTST_results.xlsx +/seq_len_long_term_forecast/ +/progress.xlsx +/scripts/short_term_forecast/PatchTST_M4.sh +/run_tv.py + +/scripts/long_term_forecast/ETT_tv_script/ +/dataset/ +/data/ +data_factory_all.py +data_loader_all.py +/scripts/short_term_forecast/tv_script/ +/exp/exp_short_term_forecasting_tv.py +/exp/exp_long_term_forecasting_tv.py +/timesnetv2.xlsx +/scripts/anomaly_detection/tmp/ +/scripts/imputation/tmp/ +/utils/self_tools.py +/scripts/exp_scripts/ + +checkpoints/ +results/ +result_long_term_forecast.txt +result_anomaly_detection.txt +scripts/augmentation/ +run_anylearn.py +environment.txt \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..67f5a65 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,20 @@ +## Instructions for Contributing to TSlib + +Sincerely thanks to all the researchers who want to use or contribute to TSlib. + +Since our team may not have enough time to fix all the bugs and catch up with the latest model, your contribution is essential to this project. + +### (1) Fix Bug + +You can directly propose a pull request and add detailed descriptions to the comment, such as [this pull request](https://github.com/thuml/Time-Series-Library/pull/498). + +### (2) Add a new time series model + +Thanks to creative researchers, extensive great TS models are presented, which advance this community significantly. If you want to add your model to TSlib, here are some instructions: + +- Propose an issue to describe your model and give a link to your paper and official code. We will discuss whether your model is suitable for this library, such as [this issue](https://github.com/thuml/Time-Series-Library/issues/346). +- Propose a pull request in a similar style as TSlib, which means adding an additional file to ./models and providing corresponding scripts for reproduction, such as [this pull request](https://github.com/thuml/Time-Series-Library/pull/446). + +Note: Given that there are a lot of TS models that have been proposed, we may not have enough time to judge which model can be a remarkable supplement to the current library. Thus, we decide ONLY to add the officially published paper to our library. Peer review can be a reliable criterion. + +Thanks again for your valuable contributions. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..278c267 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 THUML @ Tsinghua University + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..06bddb1 --- /dev/null +++ b/README.md @@ -0,0 +1,171 @@ +# Time Series Library (TSLib) +TSLib is an open-source library for deep learning researchers, especially for deep time series analysis. + +We provide a neat code base to evaluate advanced deep time series models or develop your model, which covers five mainstream tasks: **long- and short-term forecasting, imputation, anomaly detection, and classification.** + +:triangular_flag_on_post:**News** (2024.10) We have included [[TimeXer]](https://arxiv.org/abs/2402.19072), which defined a practical forecasting paradigm: Forecasting with Exogenous Variables. Considering both practicability and computation efficiency, we believe the new forecasting paradigm defined in TimeXer can be the "right" task for future research. + +:triangular_flag_on_post:**News** (2024.10) Our lab has open-sourced [[OpenLTM]](https://github.com/thuml/OpenLTM), which provides a distinct pretrain-finetuning paradigm compared to TSLib. If you are interested in Large Time Series Models, you may find this repository helpful. + +:triangular_flag_on_post:**News** (2024.07) We wrote a comprehensive survey of [[Deep Time Series Models]](https://arxiv.org/abs/2407.13278) with a rigorous benchmark based on TSLib. In this paper, we summarized the design principles of current time series models supported by insightful experiments, hoping to be helpful to future research. + +:triangular_flag_on_post:**News** (2024.04) Many thanks for the great work from [frecklebars](https://github.com/thuml/Time-Series-Library/pull/378). The famous sequential model [Mamba](https://arxiv.org/abs/2312.00752) has been included in our library. See [this file](https://github.com/thuml/Time-Series-Library/blob/main/models/Mamba.py), where you need to install `mamba_ssm` with pip at first. + +:triangular_flag_on_post:**News** (2024.03) Given the inconsistent look-back length of various papers, we split the long-term forecasting in the leaderboard into two categories: Look-Back-96 and Look-Back-Searching. We recommend researchers read [TimeMixer](https://openreview.net/pdf?id=7oLshfEIC2), which includes both look-back length settings in experiments for scientific rigor. + +:triangular_flag_on_post:**News** (2023.10) We add an implementation to [iTransformer](https://arxiv.org/abs/2310.06625), which is the state-of-the-art model for long-term forecasting. The official code and complete scripts of iTransformer can be found [here](https://github.com/thuml/iTransformer). + +:triangular_flag_on_post:**News** (2023.09) We added a detailed [tutorial](https://github.com/thuml/Time-Series-Library/blob/main/tutorial/TimesNet_tutorial.ipynb) for [TimesNet](https://openreview.net/pdf?id=ju_Uqw384Oq) and this library, which is quite friendly to beginners of deep time series analysis. + +:triangular_flag_on_post:**News** (2023.02) We release the TSlib as a comprehensive benchmark and code base for time series models, which is extended from our previous GitHub repository [Autoformer](https://github.com/thuml/Autoformer). + +## Leaderboard for Time Series Analysis + +Till March 2024, the top three models for five different tasks are: + +| Model
Ranking | Long-term
Forecasting
Look-Back-96 | Long-term
Forecasting
Look-Back-Searching | Short-term
Forecasting | Imputation | Classification | Anomaly
Detection | +| ---------------- | ----------------------------------------------------- | ----------------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -------------------------------------------------- | +| 🥇 1st | [TimeXer](https://arxiv.org/abs/2402.19072) | [TimeMixer](https://openreview.net/pdf?id=7oLshfEIC2) | [TimesNet](https://arxiv.org/abs/2210.02186) | [TimesNet](https://arxiv.org/abs/2210.02186) | [TimesNet](https://arxiv.org/abs/2210.02186) | [TimesNet](https://arxiv.org/abs/2210.02186) | +| 🥈 2nd | [iTransformer](https://arxiv.org/abs/2310.06625) | [PatchTST](https://github.com/yuqinie98/PatchTST) | [Non-stationary
Transformer](https://github.com/thuml/Nonstationary_Transformers) | [Non-stationary
Transformer](https://github.com/thuml/Nonstationary_Transformers) | [Non-stationary
Transformer](https://github.com/thuml/Nonstationary_Transformers) | [FEDformer](https://github.com/MAZiqing/FEDformer) | +| 🥉 3rd | [TimeMixer](https://openreview.net/pdf?id=7oLshfEIC2) | [DLinear](https://arxiv.org/pdf/2205.13504.pdf) | [FEDformer](https://github.com/MAZiqing/FEDformer) | [Autoformer](https://github.com/thuml/Autoformer) | [Informer](https://github.com/zhouhaoyi/Informer2020) | [Autoformer](https://github.com/thuml/Autoformer) | + + +**Note: We will keep updating this leaderboard.** If you have proposed advanced and awesome models, you can send us your paper/code link or raise a pull request. We will add them to this repo and update the leaderboard as soon as possible. + +**Compared models of this leaderboard.** ☑ means that their codes have already been included in this repo. + - [x] **TimeXer** - TimeXer: Empowering Transformers for Time Series Forecasting with Exogenous Variables [[NeurIPS 2024]](https://arxiv.org/abs/2402.19072) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/TimeXer.py) + - [x] **TimeMixer** - TimeMixer: Decomposable Multiscale Mixing for Time Series Forecasting [[ICLR 2024]](https://openreview.net/pdf?id=7oLshfEIC2) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/TimeMixer.py). + - [x] **TSMixer** - TSMixer: An All-MLP Architecture for Time Series Forecasting [[arXiv 2023]](https://arxiv.org/pdf/2303.06053.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/TSMixer.py) + - [x] **iTransformer** - iTransformer: Inverted Transformers Are Effective for Time Series Forecasting [[ICLR 2024]](https://arxiv.org/abs/2310.06625) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/iTransformer.py). + - [x] **PatchTST** - A Time Series is Worth 64 Words: Long-term Forecasting with Transformers [[ICLR 2023]](https://openreview.net/pdf?id=Jbdc0vTOcol) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/PatchTST.py). + - [x] **TimesNet** - TimesNet: Temporal 2D-Variation Modeling for General Time Series Analysis [[ICLR 2023]](https://openreview.net/pdf?id=ju_Uqw384Oq) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/TimesNet.py). + - [x] **DLinear** - Are Transformers Effective for Time Series Forecasting? [[AAAI 2023]](https://arxiv.org/pdf/2205.13504.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/DLinear.py). + - [x] **LightTS** - Less Is More: Fast Multivariate Time Series Forecasting with Light Sampling-oriented MLP Structures [[arXiv 2022]](https://arxiv.org/abs/2207.01186) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/LightTS.py). + - [x] **ETSformer** - ETSformer: Exponential Smoothing Transformers for Time-series Forecasting [[arXiv 2022]](https://arxiv.org/abs/2202.01381) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/ETSformer.py). + - [x] **Non-stationary Transformer** - Non-stationary Transformers: Exploring the Stationarity in Time Series Forecasting [[NeurIPS 2022]](https://openreview.net/pdf?id=ucNDIDRNjjv) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Nonstationary_Transformer.py). + - [x] **FEDformer** - FEDformer: Frequency Enhanced Decomposed Transformer for Long-term Series Forecasting [[ICML 2022]](https://proceedings.mlr.press/v162/zhou22g.html) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/FEDformer.py). + - [x] **Pyraformer** - Pyraformer: Low-complexity Pyramidal Attention for Long-range Time Series Modeling and Forecasting [[ICLR 2022]](https://openreview.net/pdf?id=0EXmFzUn5I) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Pyraformer.py). + - [x] **Autoformer** - Autoformer: Decomposition Transformers with Auto-Correlation for Long-Term Series Forecasting [[NeurIPS 2021]](https://openreview.net/pdf?id=I55UqU-M11y) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Autoformer.py). + - [x] **Informer** - Informer: Beyond Efficient Transformer for Long Sequence Time-Series Forecasting [[AAAI 2021]](https://ojs.aaai.org/index.php/AAAI/article/view/17325/17132) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Informer.py). + - [x] **Reformer** - Reformer: The Efficient Transformer [[ICLR 2020]](https://openreview.net/forum?id=rkgNKkHtvB) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Reformer.py). + - [x] **Transformer** - Attention is All You Need [[NeurIPS 2017]](https://proceedings.neurips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Transformer.py). + +See our latest paper [[TimesNet]](https://arxiv.org/abs/2210.02186) for the comprehensive benchmark. We will release a real-time updated online version soon. + +**Newly added baselines.** We will add them to the leaderboard after a comprehensive evaluation. + - [x] **MultiPatchFormer** - A multiscale model for multivariate time series forecasting [[Scientific Reports 2025]](https://www.nature.com/articles/s41598-024-82417-4) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/MultiPatchFormer.py) + - [x] **WPMixer** - WPMixer: Efficient Multi-Resolution Mixing for Long-Term Time Series Forecasting [[AAAI 2025]](https://arxiv.org/abs/2412.17176) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/WPMixer.py) + - [x] **PAttn** - Are Language Models Actually Useful for Time Series Forecasting? [[NeurIPS 2024]](https://arxiv.org/pdf/2406.16964) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/PAttn.py) + - [x] **Mamba** - Mamba: Linear-Time Sequence Modeling with Selective State Spaces [[arXiv 2023]](https://arxiv.org/abs/2312.00752) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Mamba.py) + - [x] **SegRNN** - SegRNN: Segment Recurrent Neural Network for Long-Term Time Series Forecasting [[arXiv 2023]](https://arxiv.org/abs/2308.11200.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/SegRNN.py). + - [x] **Koopa** - Koopa: Learning Non-stationary Time Series Dynamics with Koopman Predictors [[NeurIPS 2023]](https://arxiv.org/pdf/2305.18803.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Koopa.py). + - [x] **FreTS** - Frequency-domain MLPs are More Effective Learners in Time Series Forecasting [[NeurIPS 2023]](https://arxiv.org/pdf/2311.06184.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/FreTS.py). + - [x] **MICN** - MICN: Multi-scale Local and Global Context Modeling for Long-term Series Forecasting [[ICLR 2023]](https://openreview.net/pdf?id=zt53IDUR1U)[[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/MICN.py). + - [x] **Crossformer** - Crossformer: Transformer Utilizing Cross-Dimension Dependency for Multivariate Time Series Forecasting [[ICLR 2023]](https://openreview.net/pdf?id=vSVLM2j9eie)[[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/Crossformer.py). + - [x] **TiDE** - Long-term Forecasting with TiDE: Time-series Dense Encoder [[arXiv 2023]](https://arxiv.org/pdf/2304.08424.pdf) [[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/TiDE.py). + - [x] **SCINet** - SCINet: Time Series Modeling and Forecasting with Sample Convolution and Interaction [[NeurIPS 2022]](https://openreview.net/pdf?id=AyajSjTAzmg)[[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/SCINet.py). + - [x] **FiLM** - FiLM: Frequency improved Legendre Memory Model for Long-term Time Series Forecasting [[NeurIPS 2022]](https://openreview.net/forum?id=zTQdHSQUQWc)[[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/FiLM.py). + - [x] **TFT** - Temporal Fusion Transformers for Interpretable Multi-horizon Time Series Forecasting [[arXiv 2019]](https://arxiv.org/abs/1912.09363)[[Code]](https://github.com/thuml/Time-Series-Library/blob/main/models/TemporalFusionTransformer.py). + +## Usage + +1. Install Python 3.8. For convenience, execute the following command. + +``` +pip install -r requirements.txt +``` + +2. Prepare Data. You can obtain the well pre-processed datasets from [[Google Drive]](https://drive.google.com/drive/folders/13Cg1KYOlzM5C7K8gK8NfC-F3EYxkM3D2?usp=sharing) or [[Baidu Drive]](https://pan.baidu.com/s/1r3KhGd0Q9PJIUZdfEYoymg?pwd=i9iy), Then place the downloaded data in the folder`./dataset`. Here is a summary of supported datasets. + +

+ +

+ +3. Train and evaluate model. We provide the experiment scripts for all benchmarks under the folder `./scripts/`. You can reproduce the experiment results as the following examples: + +``` +# long-term forecast +bash ./scripts/long_term_forecast/ETT_script/TimesNet_ETTh1.sh +# short-term forecast +bash ./scripts/short_term_forecast/TimesNet_M4.sh +# imputation +bash ./scripts/imputation/ETT_script/TimesNet_ETTh1.sh +# anomaly detection +bash ./scripts/anomaly_detection/PSM/TimesNet.sh +# classification +bash ./scripts/classification/TimesNet.sh +``` + +4. Develop your own model. + +- Add the model file to the folder `./models`. You can follow the `./models/Transformer.py`. +- Include the newly added model in the `Exp_Basic.model_dict` of `./exp/exp_basic.py`. +- Create the corresponding scripts under the folder `./scripts`. + +Note: + +(1) About classification: Since we include all five tasks in a unified code base, the accuracy of each subtask may fluctuate but the average performance can be reproduced (even a bit better). We have provided the reproduced checkpoints [here](https://github.com/thuml/Time-Series-Library/issues/494). + +(2) About anomaly detection: Some discussion about the adjustment strategy in anomaly detection can be found [here](https://github.com/thuml/Anomaly-Transformer/issues/14). The key point is that the adjustment strategy corresponds to an event-level metric. + +## Citation + +If you find this repo useful, please cite our paper. + +``` +@inproceedings{wu2023timesnet, + title={TimesNet: Temporal 2D-Variation Modeling for General Time Series Analysis}, + author={Haixu Wu and Tengge Hu and Yong Liu and Hang Zhou and Jianmin Wang and Mingsheng Long}, + booktitle={International Conference on Learning Representations}, + year={2023}, +} + +@article{wang2024tssurvey, + title={Deep Time Series Models: A Comprehensive Survey and Benchmark}, + author={Yuxuan Wang and Haixu Wu and Jiaxiang Dong and Yong Liu and Mingsheng Long and Jianmin Wang}, + booktitle={arXiv preprint arXiv:2407.13278}, + year={2024}, +} +``` + +## Contact +If you have any questions or suggestions, feel free to contact our maintenance team: + +Current: +- Haixu Wu (Ph.D. student, wuhx23@mails.tsinghua.edu.cn) +- Yong Liu (Ph.D. student, liuyong21@mails.tsinghua.edu.cn) +- Huikun Weng (Undergraduate, wenghk22@mails.tsinghua.edu.cn) + +Previous: +- Yuxuan Wang (Ph.D. student, wangyuxu22@mails.tsinghua.edu.cn) +- Tengge Hu (Master student, htg21@mails.tsinghua.edu.cn) +- Haoran Zhang (Master student, z-hr20@mails.tsinghua.edu.cn) +- Jiawei Guo (Undergraduate, guo-jw21@mails.tsinghua.edu.cn) + +Or describe it in Issues. + +## Acknowledgement + +This library is constructed based on the following repos: + +- Forecasting: https://github.com/thuml/Autoformer. + +- Anomaly Detection: https://github.com/thuml/Anomaly-Transformer. + +- Classification: https://github.com/thuml/Flowformer. + +All the experiment datasets are public, and we obtain them from the following links: + +- Long-term Forecasting and Imputation: https://github.com/thuml/Autoformer. + +- Short-term Forecasting: https://github.com/ServiceNow/N-BEATS. + +- Anomaly Detection: https://github.com/thuml/Anomaly-Transformer. + +- Classification: https://www.timeseriesclassification.com/. + +## All Thanks To Our Contributors + + + + diff --git a/data_provider/__init__.py b/data_provider/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/data_provider/__init__.py @@ -0,0 +1 @@ + diff --git a/data_provider/data_factory.py b/data_provider/data_factory.py new file mode 100644 index 0000000..7fc458f --- /dev/null +++ b/data_provider/data_factory.py @@ -0,0 +1,86 @@ +from 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 torch.utils.data import DataLoader + +data_dict = { + 'ETTh1': Dataset_ETT_hour, + 'ETTh2': Dataset_ETT_hour, + 'ETTm1': Dataset_ETT_minute, + 'ETTm2': Dataset_ETT_minute, + 'custom': Dataset_Custom, + 'm4': Dataset_M4, + 'PSM': PSMSegLoader, + 'MSL': MSLSegLoader, + 'SMAP': SMAPSegLoader, + 'SMD': SMDSegLoader, + 'SWAT': SWATSegLoader, + 'UEA': UEAloader +} + + +def data_provider(args, flag): + Data = data_dict[args.data] + timeenc = 0 if args.embed != 'timeF' else 1 + + shuffle_flag = False if (flag == 'test' or flag == 'TEST') else True + drop_last = False + batch_size = args.batch_size + freq = args.freq + + if args.task_name == 'anomaly_detection': + drop_last = False + data_set = Data( + args = args, + root_path=args.root_path, + win_size=args.seq_len, + flag=flag, + ) + print(flag, len(data_set)) + data_loader = DataLoader( + data_set, + batch_size=batch_size, + shuffle=shuffle_flag, + num_workers=args.num_workers, + drop_last=drop_last) + return data_set, data_loader + elif args.task_name == 'classification': + drop_last = False + data_set = Data( + args = args, + root_path=args.root_path, + flag=flag, + ) + + data_loader = DataLoader( + data_set, + batch_size=batch_size, + shuffle=shuffle_flag, + num_workers=args.num_workers, + drop_last=drop_last, + collate_fn=lambda x: collate_fn(x, max_len=args.seq_len) + ) + return data_set, data_loader + else: + if args.data == 'm4': + drop_last = False + data_set = Data( + args = args, + root_path=args.root_path, + data_path=args.data_path, + flag=flag, + size=[args.seq_len, args.label_len, args.pred_len], + features=args.features, + target=args.target, + timeenc=timeenc, + freq=freq, + seasonal_patterns=args.seasonal_patterns + ) + print(flag, len(data_set)) + data_loader = DataLoader( + data_set, + batch_size=batch_size, + shuffle=shuffle_flag, + num_workers=args.num_workers, + drop_last=drop_last) + return data_set, data_loader diff --git a/data_provider/data_loader.py b/data_provider/data_loader.py new file mode 100644 index 0000000..dcbea31 --- /dev/null +++ b/data_provider/data_loader.py @@ -0,0 +1,748 @@ +import os +import numpy as np +import pandas as pd +import glob +import re +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 sktime.datasets import load_from_tsfile_to_dataframe +import warnings +from utils.augmentation import run_augmentation_single + +warnings.filterwarnings('ignore') + + +class Dataset_ETT_hour(Dataset): + def __init__(self, args, root_path, flag='train', size=None, + features='S', data_path='ETTh1.csv', + target='OT', scale=True, timeenc=0, freq='h', seasonal_patterns=None): + # size [seq_len, label_len, pred_len] + self.args = args + # info + if size == None: + self.seq_len = 24 * 4 * 4 + self.label_len = 24 * 4 + self.pred_len = 24 * 4 + else: + self.seq_len = size[0] + self.label_len = size[1] + self.pred_len = size[2] + # init + assert flag in ['train', 'test', 'val'] + type_map = {'train': 0, 'val': 1, 'test': 2} + self.set_type = type_map[flag] + + self.features = features + self.target = target + self.scale = scale + self.timeenc = timeenc + self.freq = freq + + self.root_path = root_path + self.data_path = data_path + self.__read_data__() + + def __read_data__(self): + self.scaler = StandardScaler() + df_raw = pd.read_csv(os.path.join(self.root_path, + self.data_path)) + + border1s = [0, 12 * 30 * 24 - self.seq_len, 12 * 30 * 24 + 4 * 30 * 24 - self.seq_len] + border2s = [12 * 30 * 24, 12 * 30 * 24 + 4 * 30 * 24, 12 * 30 * 24 + 8 * 30 * 24] + border1 = border1s[self.set_type] + border2 = border2s[self.set_type] + + if self.features == 'M' or self.features == 'MS': + cols_data = df_raw.columns[1:] + df_data = df_raw[cols_data] + elif self.features == 'S': + df_data = df_raw[[self.target]] + + if self.scale: + train_data = df_data[border1s[0]:border2s[0]] + self.scaler.fit(train_data.values) + data = self.scaler.transform(df_data.values) + else: + data = df_data.values + + df_stamp = df_raw[['date']][border1:border2] + df_stamp['date'] = pd.to_datetime(df_stamp.date) + if self.timeenc == 0: + df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1) + df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1) + df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1) + df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1) + 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) + + 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): + s_begin = index + s_end = s_begin + self.seq_len + r_begin = s_end - self.label_len + r_end = r_begin + self.label_len + self.pred_len + + seq_x = self.data_x[s_begin:s_end] + seq_y = self.data_y[r_begin:r_end] + seq_x_mark = self.data_stamp[s_begin:s_end] + seq_y_mark = self.data_stamp[r_begin:r_end] + + return seq_x, seq_y, seq_x_mark, seq_y_mark + + def __len__(self): + return len(self.data_x) - self.seq_len - self.pred_len + 1 + + def inverse_transform(self, data): + return self.scaler.inverse_transform(data) + + +class Dataset_ETT_minute(Dataset): + def __init__(self, args, root_path, flag='train', size=None, + features='S', data_path='ETTm1.csv', + target='OT', scale=True, timeenc=0, freq='t', seasonal_patterns=None): + # size [seq_len, label_len, pred_len] + self.args = args + # info + if size == None: + self.seq_len = 24 * 4 * 4 + self.label_len = 24 * 4 + self.pred_len = 24 * 4 + else: + self.seq_len = size[0] + self.label_len = size[1] + self.pred_len = size[2] + # init + assert flag in ['train', 'test', 'val'] + type_map = {'train': 0, 'val': 1, 'test': 2} + self.set_type = type_map[flag] + + self.features = features + self.target = target + self.scale = scale + self.timeenc = timeenc + self.freq = freq + + self.root_path = root_path + self.data_path = data_path + self.__read_data__() + + def __read_data__(self): + self.scaler = StandardScaler() + df_raw = pd.read_csv(os.path.join(self.root_path, + self.data_path)) + + border1s = [0, 12 * 30 * 24 * 4 - self.seq_len, 12 * 30 * 24 * 4 + 4 * 30 * 24 * 4 - self.seq_len] + border2s = [12 * 30 * 24 * 4, 12 * 30 * 24 * 4 + 4 * 30 * 24 * 4, 12 * 30 * 24 * 4 + 8 * 30 * 24 * 4] + border1 = border1s[self.set_type] + border2 = border2s[self.set_type] + + if self.features == 'M' or self.features == 'MS': + cols_data = df_raw.columns[1:] + df_data = df_raw[cols_data] + elif self.features == 'S': + df_data = df_raw[[self.target]] + + if self.scale: + train_data = df_data[border1s[0]:border2s[0]] + self.scaler.fit(train_data.values) + data = self.scaler.transform(df_data.values) + else: + data = df_data.values + + df_stamp = df_raw[['date']][border1:border2] + df_stamp['date'] = pd.to_datetime(df_stamp.date) + if self.timeenc == 0: + df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1) + df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1) + df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1) + df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1) + df_stamp['minute'] = df_stamp.date.apply(lambda row: row.minute, 1) + df_stamp['minute'] = df_stamp.minute.map(lambda x: x // 15) + 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) + + 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): + s_begin = index + s_end = s_begin + self.seq_len + r_begin = s_end - self.label_len + r_end = r_begin + self.label_len + self.pred_len + + seq_x = self.data_x[s_begin:s_end] + seq_y = self.data_y[r_begin:r_end] + seq_x_mark = self.data_stamp[s_begin:s_end] + seq_y_mark = self.data_stamp[r_begin:r_end] + + return seq_x, seq_y, seq_x_mark, seq_y_mark + + def __len__(self): + return len(self.data_x) - self.seq_len - self.pred_len + 1 + + def inverse_transform(self, data): + return self.scaler.inverse_transform(data) + + +class Dataset_Custom(Dataset): + def __init__(self, args, root_path, flag='train', size=None, + features='S', data_path='ETTh1.csv', + target='OT', scale=True, timeenc=0, freq='h', seasonal_patterns=None): + # size [seq_len, label_len, pred_len] + self.args = args + # info + if size == None: + self.seq_len = 24 * 4 * 4 + self.label_len = 24 * 4 + self.pred_len = 24 * 4 + else: + self.seq_len = size[0] + self.label_len = size[1] + self.pred_len = size[2] + # init + assert flag in ['train', 'test', 'val'] + type_map = {'train': 0, 'val': 1, 'test': 2} + self.set_type = type_map[flag] + + self.features = features + self.target = target + self.scale = scale + self.timeenc = timeenc + self.freq = freq + + self.root_path = root_path + self.data_path = data_path + self.__read_data__() + + def __read_data__(self): + self.scaler = StandardScaler() + df_raw = pd.read_csv(os.path.join(self.root_path, + self.data_path)) + + ''' + df_raw.columns: ['date', ...(other features), target feature] + ''' + cols = list(df_raw.columns) + cols.remove(self.target) + cols.remove('date') + df_raw = df_raw[['date'] + cols + [self.target]] + num_train = int(len(df_raw) * 0.7) + num_test = int(len(df_raw) * 0.2) + num_vali = len(df_raw) - num_train - num_test + border1s = [0, num_train - self.seq_len, len(df_raw) - num_test - self.seq_len] + border2s = [num_train, num_train + num_vali, len(df_raw)] + border1 = border1s[self.set_type] + border2 = border2s[self.set_type] + + if self.features == 'M' or self.features == 'MS': + cols_data = df_raw.columns[1:] + df_data = df_raw[cols_data] + elif self.features == 'S': + df_data = df_raw[[self.target]] + + if self.scale: + train_data = df_data[border1s[0]:border2s[0]] + self.scaler.fit(train_data.values) + data = self.scaler.transform(df_data.values) + else: + data = df_data.values + + df_stamp = df_raw[['date']][border1:border2] + df_stamp['date'] = pd.to_datetime(df_stamp.date) + if self.timeenc == 0: + df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1) + df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1) + df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1) + df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1) + 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) + + 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): + s_begin = index + s_end = s_begin + self.seq_len + r_begin = s_end - self.label_len + r_end = r_begin + self.label_len + self.pred_len + + seq_x = self.data_x[s_begin:s_end] + seq_y = self.data_y[r_begin:r_end] + seq_x_mark = self.data_stamp[s_begin:s_end] + seq_y_mark = self.data_stamp[r_begin:r_end] + + return seq_x, seq_y, seq_x_mark, seq_y_mark + + def __len__(self): + return len(self.data_x) - self.seq_len - self.pred_len + 1 + + def inverse_transform(self, data): + return self.scaler.inverse_transform(data) + + +class Dataset_M4(Dataset): + def __init__(self, args, root_path, flag='pred', size=None, + features='S', data_path='ETTh1.csv', + target='OT', scale=False, inverse=False, timeenc=0, freq='15min', + seasonal_patterns='Yearly'): + # size [seq_len, label_len, pred_len] + # init + self.features = features + self.target = target + self.scale = scale + self.inverse = inverse + self.timeenc = timeenc + self.root_path = root_path + + self.seq_len = size[0] + self.label_len = size[1] + self.pred_len = size[2] + + self.seasonal_patterns = seasonal_patterns + self.history_size = M4Meta.history_size[seasonal_patterns] + self.window_sampling_limit = int(self.history_size * self.pred_len) + self.flag = flag + + self.__read_data__() + + def __read_data__(self): + # M4Dataset.initialize() + if self.flag == 'train': + dataset = M4Dataset.load(training=True, dataset_file=self.root_path) + else: + dataset = M4Dataset.load(training=False, dataset_file=self.root_path) + training_values = np.array( + [v[~np.isnan(v)] for v in + dataset.values[dataset.groups == self.seasonal_patterns]]) # split different frequencies + self.ids = np.array([i for i in dataset.ids[dataset.groups == self.seasonal_patterns]]) + self.timeseries = [ts for ts in training_values] + + def __getitem__(self, index): + insample = np.zeros((self.seq_len, 1)) + insample_mask = np.zeros((self.seq_len, 1)) + outsample = np.zeros((self.pred_len + self.label_len, 1)) + outsample_mask = np.zeros((self.pred_len + self.label_len, 1)) # m4 dataset + + sampled_timeseries = self.timeseries[index] + cut_point = np.random.randint(low=max(1, len(sampled_timeseries) - self.window_sampling_limit), + high=len(sampled_timeseries), + size=1)[0] + + insample_window = sampled_timeseries[max(0, cut_point - self.seq_len):cut_point] + insample[-len(insample_window):, 0] = insample_window + insample_mask[-len(insample_window):, 0] = 1.0 + outsample_window = sampled_timeseries[ + max(0, 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 + + def __len__(self): + return len(self.timeseries) + + def inverse_transform(self, data): + return self.scaler.inverse_transform(data) + + def last_insample_window(self): + """ + The last window of insample size of all timeseries. + This function does not support batching and does not reshuffle timeseries. + + :return: Last insample window of all timeseries. Shape "timeseries, insample size" + """ + insample = np.zeros((len(self.timeseries), self.seq_len)) + insample_mask = np.zeros((len(self.timeseries), self.seq_len)) + for i, ts in enumerate(self.timeseries): + ts_last_window = ts[-self.seq_len:] + insample[i, -len(ts):] = ts_last_window + insample_mask[i, -len(ts):] = 1.0 + return insample, insample_mask + + +class PSMSegLoader(Dataset): + def __init__(self, args, root_path, win_size, step=1, flag="train"): + self.flag = flag + self.step = step + self.win_size = win_size + self.scaler = StandardScaler() + data = pd.read_csv(os.path.join(root_path, 'train.csv')) + data = data.values[:, 1:] + data = np.nan_to_num(data) + self.scaler.fit(data) + data = self.scaler.transform(data) + test_data = pd.read_csv(os.path.join(root_path, 'test.csv')) + test_data = test_data.values[:, 1:] + test_data = np.nan_to_num(test_data) + self.test = self.scaler.transform(test_data) + self.train = data + data_len = len(self.train) + self.val = self.train[(int)(data_len * 0.8):] + self.test_labels = pd.read_csv(os.path.join(root_path, 'test_label.csv')).values[:, 1:] + print("test:", self.test.shape) + print("train:", self.train.shape) + + def __len__(self): + if self.flag == "train": + return (self.train.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'val'): + return (self.val.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'test'): + return (self.test.shape[0] - self.win_size) // self.step + 1 + else: + return (self.test.shape[0] - self.win_size) // self.win_size + 1 + + def __getitem__(self, index): + index = index * self.step + if self.flag == "train": + return np.float32(self.train[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'val'): + return np.float32(self.val[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'test'): + return np.float32(self.test[index:index + self.win_size]), np.float32( + self.test_labels[index:index + self.win_size]) + else: + return np.float32(self.test[ + index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]), np.float32( + self.test_labels[index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]) + + +class MSLSegLoader(Dataset): + def __init__(self, args, root_path, win_size, step=1, flag="train"): + self.flag = flag + self.step = step + self.win_size = win_size + self.scaler = StandardScaler() + data = np.load(os.path.join(root_path, "MSL_train.npy")) + self.scaler.fit(data) + data = self.scaler.transform(data) + test_data = np.load(os.path.join(root_path, "MSL_test.npy")) + self.test = self.scaler.transform(test_data) + self.train = data + data_len = len(self.train) + self.val = self.train[(int)(data_len * 0.8):] + self.test_labels = np.load(os.path.join(root_path, "MSL_test_label.npy")) + print("test:", self.test.shape) + print("train:", self.train.shape) + + def __len__(self): + if self.flag == "train": + return (self.train.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'val'): + return (self.val.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'test'): + return (self.test.shape[0] - self.win_size) // self.step + 1 + else: + return (self.test.shape[0] - self.win_size) // self.win_size + 1 + + def __getitem__(self, index): + index = index * self.step + if self.flag == "train": + return np.float32(self.train[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'val'): + return np.float32(self.val[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'test'): + return np.float32(self.test[index:index + self.win_size]), np.float32( + self.test_labels[index:index + self.win_size]) + else: + return np.float32(self.test[ + index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]), np.float32( + self.test_labels[index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]) + + +class SMAPSegLoader(Dataset): + def __init__(self, args, root_path, win_size, step=1, flag="train"): + self.flag = flag + self.step = step + self.win_size = win_size + self.scaler = StandardScaler() + data = np.load(os.path.join(root_path, "SMAP_train.npy")) + self.scaler.fit(data) + data = self.scaler.transform(data) + test_data = np.load(os.path.join(root_path, "SMAP_test.npy")) + self.test = self.scaler.transform(test_data) + self.train = data + data_len = len(self.train) + self.val = self.train[(int)(data_len * 0.8):] + self.test_labels = np.load(os.path.join(root_path, "SMAP_test_label.npy")) + print("test:", self.test.shape) + print("train:", self.train.shape) + + def __len__(self): + + if self.flag == "train": + return (self.train.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'val'): + return (self.val.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'test'): + return (self.test.shape[0] - self.win_size) // self.step + 1 + else: + return (self.test.shape[0] - self.win_size) // self.win_size + 1 + + def __getitem__(self, index): + index = index * self.step + if self.flag == "train": + return np.float32(self.train[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'val'): + return np.float32(self.val[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'test'): + return np.float32(self.test[index:index + self.win_size]), np.float32( + self.test_labels[index:index + self.win_size]) + else: + return np.float32(self.test[ + index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]), np.float32( + self.test_labels[index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]) + + +class SMDSegLoader(Dataset): + def __init__(self, args, root_path, win_size, step=100, flag="train"): + self.flag = flag + self.step = step + self.win_size = win_size + self.scaler = StandardScaler() + data = np.load(os.path.join(root_path, "SMD_train.npy")) + self.scaler.fit(data) + data = self.scaler.transform(data) + test_data = np.load(os.path.join(root_path, "SMD_test.npy")) + self.test = self.scaler.transform(test_data) + self.train = data + data_len = len(self.train) + self.val = self.train[(int)(data_len * 0.8):] + self.test_labels = np.load(os.path.join(root_path, "SMD_test_label.npy")) + + def __len__(self): + if self.flag == "train": + return (self.train.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'val'): + return (self.val.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'test'): + return (self.test.shape[0] - self.win_size) // self.step + 1 + else: + return (self.test.shape[0] - self.win_size) // self.win_size + 1 + + def __getitem__(self, index): + index = index * self.step + if self.flag == "train": + return np.float32(self.train[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'val'): + return np.float32(self.val[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'test'): + return np.float32(self.test[index:index + self.win_size]), np.float32( + self.test_labels[index:index + self.win_size]) + else: + return np.float32(self.test[ + index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]), np.float32( + self.test_labels[index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]) + + +class SWATSegLoader(Dataset): + def __init__(self, args, root_path, win_size, step=1, flag="train"): + self.flag = flag + self.step = step + self.win_size = win_size + self.scaler = StandardScaler() + + train_data = pd.read_csv(os.path.join(root_path, 'swat_train2.csv')) + test_data = pd.read_csv(os.path.join(root_path, 'swat2.csv')) + labels = test_data.values[:, -1:] + train_data = train_data.values[:, :-1] + test_data = test_data.values[:, :-1] + + self.scaler.fit(train_data) + train_data = self.scaler.transform(train_data) + test_data = self.scaler.transform(test_data) + self.train = train_data + self.test = test_data + data_len = len(self.train) + self.val = self.train[(int)(data_len * 0.8):] + self.test_labels = labels + print("test:", self.test.shape) + print("train:", self.train.shape) + + def __len__(self): + """ + Number of images in the object dataset. + """ + if self.flag == "train": + return (self.train.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'val'): + return (self.val.shape[0] - self.win_size) // self.step + 1 + elif (self.flag == 'test'): + return (self.test.shape[0] - self.win_size) // self.step + 1 + else: + return (self.test.shape[0] - self.win_size) // self.win_size + 1 + + def __getitem__(self, index): + index = index * self.step + if self.flag == "train": + return np.float32(self.train[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'val'): + return np.float32(self.val[index:index + self.win_size]), np.float32(self.test_labels[0:self.win_size]) + elif (self.flag == 'test'): + return np.float32(self.test[index:index + self.win_size]), np.float32( + self.test_labels[index:index + self.win_size]) + else: + return np.float32(self.test[ + index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]), np.float32( + self.test_labels[index // self.step * self.win_size:index // self.step * self.win_size + self.win_size]) + + +class UEAloader(Dataset): + """ + Dataset class for datasets included in: + Time Series Classification Archive (www.timeseriesclassification.com) + Argument: + limit_size: float in (0, 1) for debug + Attributes: + all_df: (num_samples * seq_len, num_columns) dataframe indexed by integer indices, with multiple rows corresponding to the same index (sample). + Each row is a time step; Each column contains either metadata (e.g. timestamp) or a feature. + feature_df: (num_samples * seq_len, feat_dim) dataframe; contains the subset of columns of `all_df` which correspond to selected features + feature_names: names of columns contained in `feature_df` (same as feature_df.columns) + all_IDs: (num_samples,) series of IDs contained in `all_df`/`feature_df` (same as all_df.index.unique() ) + labels_df: (num_samples, num_labels) pd.DataFrame of label(s) for each sample + max_seq_len: maximum sequence (time series) length. If None, script argument `max_seq_len` will be used. + (Moreover, script argument overrides this attribute) + """ + + def __init__(self, args, root_path, file_list=None, limit_size=None, flag=None): + self.args = args + self.root_path = root_path + self.flag = flag + self.all_df, self.labels_df = self.load_all(root_path, file_list=file_list, flag=flag) + self.all_IDs = self.all_df.index.unique() # all sample IDs (integer indices 0 ... num_samples-1) + + if limit_size is not None: + if limit_size > 1: + limit_size = int(limit_size) + else: # interpret as proportion if in (0, 1] + limit_size = int(limit_size * len(self.all_IDs)) + self.all_IDs = self.all_IDs[:limit_size] + self.all_df = self.all_df.loc[self.all_IDs] + + # use all features + self.feature_names = self.all_df.columns + self.feature_df = self.all_df + + # pre_process + normalizer = Normalizer() + self.feature_df = normalizer.normalize(self.feature_df) + print(len(self.all_IDs)) + + def load_all(self, root_path, file_list=None, flag=None): + """ + Loads datasets from ts files contained in `root_path` into a dataframe, optionally choosing from `pattern` + Args: + root_path: directory containing all individual .ts files + file_list: optionally, provide a list of file paths within `root_path` to consider. + Otherwise, entire `root_path` contents will be used. + Returns: + all_df: a single (possibly concatenated) dataframe with all data corresponding to specified files + labels_df: dataframe containing label(s) for each sample + """ + # Select paths for training and evaluation + if file_list is None: + data_paths = glob.glob(os.path.join(root_path, '*')) # list of all paths + else: + data_paths = [os.path.join(root_path, p) for p in file_list] + if len(data_paths) == 0: + raise Exception('No files found using: {}'.format(os.path.join(root_path, '*'))) + if flag is not 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' + 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 + + return all_df, labels_df + + def load_single(self, filepath): + df, labels = load_from_tsfile_to_dataframe(filepath, return_separate_X_and_y=True, + replace_missing_vals_with='NaN') + labels = pd.Series(labels, dtype="category") + self.class_names = labels.cat.categories + labels_df = pd.DataFrame(labels.cat.codes, + dtype=np.int8) # int8-32 gives an error when using nn.CrossEntropyLoss + + lengths = df.applymap( + lambda x: len(x)).values # (num_samples, num_dimensions) array containing the length of each series + + horiz_diffs = np.abs(lengths - np.expand_dims(lengths[:, 0], -1)) + + if np.sum(horiz_diffs) > 0: # if any row (sample) has varying length across dimensions + df = df.applymap(subsample) + + lengths = df.applymap(lambda x: len(x)).values + vert_diffs = np.abs(lengths - np.expand_dims(lengths[0, :], 0)) + if np.sum(vert_diffs) > 0: # if any column (dimension) has varying length across samples + self.max_seq_len = int(np.max(lengths[:, 0])) + else: + self.max_seq_len = lengths[0, 0] + + # First create a (seq_len, feat_dim) dataframe for each sample, indexed by a single integer ("ID" of the sample) + # Then concatenate into a (num_samples * seq_len, feat_dim) dataframe, with multiple rows corresponding to the + # sample index (i.e. the same scheme as all datasets in this project) + + df = pd.concat((pd.DataFrame({col: df.loc[row, col] for col in df.columns}).reset_index(drop=True).set_index( + pd.Series(lengths[row, 0] * [row])) for row in range(df.shape[0])), axis=0) + + # Replace NaN values + grp = df.groupby(by=df.index) + df = grp.transform(interpolate_missing) + + return df, labels_df + + def instance_norm(self, case): + if self.root_path.count('EthanolConcentration') > 0: # special process for numerical stability + mean = case.mean(0, keepdim=True) + case = case - mean + stdev = torch.sqrt(torch.var(case, dim=1, keepdim=True, unbiased=False) + 1e-5) + case /= stdev + return case + else: + return case + + def __getitem__(self, ind): + batch_x = self.feature_df.loc[self.all_IDs[ind]].values + labels = self.labels_df.loc[self.all_IDs[ind]].values + if self.flag == "TRAIN" and self.args.augmentation_ratio > 0: + num_samples = len(self.all_IDs) + num_columns = self.feature_df.shape[1] + seq_len = int(self.feature_df.shape[0] / num_samples) + batch_x = batch_x.reshape((1, seq_len, num_columns)) + batch_x, labels, augmentation_tags = run_augmentation_single(batch_x, labels, self.args) + + batch_x = batch_x.reshape((1 * seq_len, num_columns)) + + return self.instance_norm(torch.from_numpy(batch_x)), \ + torch.from_numpy(labels) + + def __len__(self): + return len(self.all_IDs) diff --git a/data_provider/m4.py b/data_provider/m4.py new file mode 100644 index 0000000..3ab32c6 --- /dev/null +++ b/data_provider/m4.py @@ -0,0 +1,138 @@ +# This source code is provided for the purposes of scientific reproducibility +# under the following limited license from Element AI Inc. The code is an +# implementation of the N-BEATS model (Oreshkin et al., N-BEATS: Neural basis +# expansion analysis for interpretable time series forecasting, +# https://arxiv.org/abs/1905.10437). The copyright to the source code is +# licensed under the Creative Commons - Attribution-NonCommercial 4.0 +# International license (CC BY-NC 4.0): +# https://creativecommons.org/licenses/by-nc/4.0/. Any commercial use (whether +# for the benefit of third parties or internally in production) requires an +# explicit license. The subject-matter of the N-BEATS model and associated +# materials are the property of Element AI Inc. and may be subject to patent +# protection. No license to patents is granted hereunder (whether express or +# implied). Copyright © 2020 Element AI Inc. All rights reserved. + +""" +M4 Dataset +""" +import logging +import os +from collections import OrderedDict +from dataclasses import dataclass +from glob import glob + +import numpy as np +import pandas as pd +import patoolib +from tqdm import tqdm +import logging +import os +import pathlib +import sys +from urllib import request + + +def url_file_name(url: str) -> str: + """ + Extract file name from url. + + :param url: URL to extract file name from. + :return: File name. + """ + return url.split('/')[-1] if len(url) > 0 else '' + + +def download(url: str, file_path: str) -> None: + """ + Download a file to the given path. + + :param url: URL to download + :param file_path: Where to download the content. + """ + + def progress(count, block_size, total_size): + progress_pct = float(count * block_size) / float(total_size) * 100.0 + sys.stdout.write('\rDownloading {} to {} {:.1f}%'.format(url, file_path, progress_pct)) + sys.stdout.flush() + + if not os.path.isfile(file_path): + opener = request.build_opener() + opener.addheaders = [('User-agent', 'Mozilla/5.0')] + request.install_opener(opener) + pathlib.Path(os.path.dirname(file_path)).mkdir(parents=True, exist_ok=True) + f, _ = request.urlretrieve(url, file_path, progress) + sys.stdout.write('\n') + sys.stdout.flush() + file_info = os.stat(f) + logging.info(f'Successfully downloaded {os.path.basename(file_path)} {file_info.st_size} bytes.') + else: + file_info = os.stat(file_path) + logging.info(f'File already exists: {file_path} {file_info.st_size} bytes.') + + +@dataclass() +class M4Dataset: + ids: np.ndarray + groups: np.ndarray + frequencies: np.ndarray + horizons: np.ndarray + values: np.ndarray + + @staticmethod + def load(training: bool = True, dataset_file: str = '../dataset/m4') -> 'M4Dataset': + """ + Load cached dataset. + + :param training: Load training part if training is True, test part otherwise. + """ + info_file = os.path.join(dataset_file, 'M4-info.csv') + train_cache_file = os.path.join(dataset_file, 'training.npz') + test_cache_file = os.path.join(dataset_file, 'test.npz') + m4_info = pd.read_csv(info_file) + return M4Dataset(ids=m4_info.M4id.values, + groups=m4_info.SP.values, + frequencies=m4_info.Frequency.values, + horizons=m4_info.Horizon.values, + values=np.load( + train_cache_file if training else test_cache_file, + allow_pickle=True)) + + +@dataclass() +class M4Meta: + seasonal_patterns = ['Yearly', 'Quarterly', 'Monthly', 'Weekly', 'Daily', 'Hourly'] + horizons = [6, 8, 18, 13, 14, 48] + frequencies = [1, 4, 12, 1, 1, 24] + horizons_map = { + 'Yearly': 6, + 'Quarterly': 8, + 'Monthly': 18, + 'Weekly': 13, + 'Daily': 14, + 'Hourly': 48 + } # different predict length + frequency_map = { + 'Yearly': 1, + 'Quarterly': 4, + 'Monthly': 12, + 'Weekly': 1, + 'Daily': 1, + 'Hourly': 24 + } + history_size = { + 'Yearly': 1.5, + 'Quarterly': 1.5, + 'Monthly': 1.5, + 'Weekly': 10, + 'Daily': 10, + 'Hourly': 10 + } # from interpretable.gin + + +def load_m4_info() -> pd.DataFrame: + """ + Load M4Info file. + + :return: Pandas DataFrame of M4Info. + """ + return pd.read_csv(INFO_FILE_PATH) diff --git a/data_provider/uea.py b/data_provider/uea.py new file mode 100644 index 0000000..f0dd0ab --- /dev/null +++ b/data_provider/uea.py @@ -0,0 +1,125 @@ +import os +import numpy as np +import pandas as pd +import torch + + +def collate_fn(data, max_len=None): + """Build mini-batch tensors from a list of (X, mask) tuples. Mask input. Create + Args: + data: len(batch_size) list of tuples (X, y). + - X: torch tensor of shape (seq_length, feat_dim); variable seq_length. + - y: torch tensor of shape (num_labels,) : class indices or numerical targets + (for classification or regression, respectively). num_labels > 1 for multi-task models + max_len: global fixed sequence length. Used for architectures requiring fixed length input, + where the batch length cannot vary dynamically. Longer sequences are clipped, shorter are padded with 0s + Returns: + X: (batch_size, padded_length, feat_dim) torch tensor of masked features (input) + targets: (batch_size, padded_length, feat_dim) torch tensor of unmasked features (output) + target_masks: (batch_size, padded_length, feat_dim) boolean torch tensor + 0 indicates masked values to be predicted, 1 indicates unaffected/"active" feature values + padding_masks: (batch_size, padded_length) boolean tensor, 1 means keep vector at this position, 0 means padding + """ + + batch_size = len(data) + features, labels = zip(*data) + + # Stack and pad features and masks (convert 2D to 3D tensors, i.e. add batch dimension) + lengths = [X.shape[0] for X in features] # original sequence length for each time series + if max_len is None: + max_len = max(lengths) + + X = torch.zeros(batch_size, max_len, features[0].shape[-1]) # (batch_size, padded_length, feat_dim) + for i in range(batch_size): + end = min(lengths[i], max_len) + X[i, :end, :] = features[i][:end, :] + + targets = torch.stack(labels, dim=0) # (batch_size, num_labels) + + padding_masks = padding_mask(torch.tensor(lengths, dtype=torch.int16), + max_len=max_len) # (batch_size, padded_length) boolean tensor, "1" means keep + + return X, targets, padding_masks + + +def padding_mask(lengths, max_len=None): + """ + Used to mask padded positions: creates a (batch_size, max_len) boolean mask from a tensor of sequence lengths, + where 1 means keep element at this position (time step) + """ + batch_size = lengths.numel() + max_len = max_len or lengths.max_val() # trick works because of overloading of 'or' operator for non-boolean types + return (torch.arange(0, max_len, device=lengths.device) + .type_as(lengths) + .repeat(batch_size, 1) + .lt(lengths.unsqueeze(1))) + + +class Normalizer(object): + """ + Normalizes dataframe across ALL contained rows (time steps). Different from per-sample normalization. + """ + + def __init__(self, norm_type='standardization', mean=None, std=None, min_val=None, max_val=None): + """ + Args: + norm_type: choose from: + "standardization", "minmax": normalizes dataframe across ALL contained rows (time steps) + "per_sample_std", "per_sample_minmax": normalizes each sample separately (i.e. across only its own rows) + mean, std, min_val, max_val: optional (num_feat,) Series of pre-computed values + """ + + self.norm_type = norm_type + self.mean = mean + self.std = std + self.min_val = min_val + self.max_val = max_val + + def normalize(self, df): + """ + Args: + df: input dataframe + Returns: + df: normalized dataframe + """ + if self.norm_type == "standardization": + if self.mean is None: + self.mean = df.mean() + self.std = df.std() + return (df - self.mean) / (self.std + np.finfo(float).eps) + + elif self.norm_type == "minmax": + if self.max_val is None: + self.max_val = df.max() + self.min_val = df.min() + return (df - self.min_val) / (self.max_val - self.min_val + np.finfo(float).eps) + + elif self.norm_type == "per_sample_std": + grouped = df.groupby(by=df.index) + return (df - grouped.transform('mean')) / grouped.transform('std') + + elif self.norm_type == "per_sample_minmax": + grouped = df.groupby(by=df.index) + min_vals = grouped.transform('min') + return (df - min_vals) / (grouped.transform('max') - min_vals + np.finfo(float).eps) + + else: + raise (NameError(f'Normalize method "{self.norm_type}" not implemented')) + + +def interpolate_missing(y): + """ + Replaces NaN values in pd.Series `y` using linear interpolation + """ + if y.isna().any(): + y = y.interpolate(method='linear', limit_direction='both') + return y + + +def subsample(y, limit=256, factor=2): + """ + If a given Series is longer than `limit`, returns subsampled sequence by the specified integer factor + """ + if len(y) > limit: + return y[::factor].reset_index(drop=True) + return y diff --git a/exp/__init__.py b/exp/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/exp/exp_anomaly_detection.py b/exp/exp_anomaly_detection.py new file mode 100644 index 0000000..0e856c6 --- /dev/null +++ b/exp/exp_anomaly_detection.py @@ -0,0 +1,207 @@ +from data_provider.data_factory import data_provider +from exp.exp_basic import Exp_Basic +from 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') + + +class Exp_Anomaly_Detection(Exp_Basic): + def __init__(self, args): + super(Exp_Anomaly_Detection, self).__init__(args) + + def _build_model(self): + model = self.model_dict[self.args.model].Model(self.args).float() + + if self.args.use_multi_gpu and self.args.use_gpu: + model = nn.DataParallel(model, device_ids=self.args.device_ids) + return model + + def _get_data(self, flag): + data_set, data_loader = data_provider(self.args, flag) + return data_set, data_loader + + def _select_optimizer(self): + model_optim = optim.Adam(self.model.parameters(), lr=self.args.learning_rate) + return model_optim + + def _select_criterion(self): + criterion = nn.MSELoss() + return criterion + + def vali(self, vali_data, vali_loader, criterion): + total_loss = [] + self.model.eval() + with torch.no_grad(): + for i, (batch_x, _) in enumerate(vali_loader): + batch_x = batch_x.float().to(self.device) + + outputs = self.model(batch_x, None, None, None) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, :, f_dim:] + pred = outputs.detach() + true = batch_x.detach() + + loss = criterion(pred, true) + total_loss.append(loss.item()) + total_loss = np.average(total_loss) + self.model.train() + return total_loss + + def train(self, setting): + train_data, train_loader = self._get_data(flag='train') + vali_data, vali_loader = self._get_data(flag='val') + test_data, test_loader = self._get_data(flag='test') + + path = os.path.join(self.args.checkpoints, setting) + if not os.path.exists(path): + os.makedirs(path) + + time_now = time.time() + + train_steps = len(train_loader) + early_stopping = EarlyStopping(patience=self.args.patience, verbose=True) + + model_optim = self._select_optimizer() + criterion = self._select_criterion() + + for epoch in range(self.args.train_epochs): + iter_count = 0 + train_loss = [] + + self.model.train() + epoch_time = time.time() + for i, (batch_x, batch_y) in enumerate(train_loader): + iter_count += 1 + model_optim.zero_grad() + + batch_x = batch_x.float().to(self.device) + + outputs = self.model(batch_x, None, None, None) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, :, f_dim:] + loss = criterion(outputs, batch_x) + train_loss.append(loss.item()) + + if (i + 1) % 100 == 0: + print("\titers: {0}, epoch: {1} | loss: {2:.7f}".format(i + 1, epoch + 1, loss.item())) + speed = (time.time() - time_now) / iter_count + left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i) + print('\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time)) + iter_count = 0 + time_now = time.time() + + loss.backward() + model_optim.step() + + print("Epoch: {} cost time: {}".format(epoch + 1, time.time() - epoch_time)) + train_loss = np.average(train_loss) + vali_loss = self.vali(vali_data, vali_loader, criterion) + test_loss = self.vali(test_data, test_loader, criterion) + + print("Epoch: {0}, Steps: {1} | Train Loss: {2:.7f} Vali Loss: {3:.7f} Test Loss: {4:.7f}".format( + epoch + 1, train_steps, train_loss, vali_loss, test_loss)) + early_stopping(vali_loss, self.model, path) + if early_stopping.early_stop: + print("Early stopping") + break + adjust_learning_rate(model_optim, epoch + 1, self.args) + + best_model_path = path + '/' + 'checkpoint.pth' + self.model.load_state_dict(torch.load(best_model_path)) + + return self.model + + def test(self, setting, test=0): + test_data, test_loader = self._get_data(flag='test') + train_data, train_loader = self._get_data(flag='train') + if test: + print('loading model') + self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth'))) + + attens_energy = [] + folder_path = './test_results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + self.model.eval() + self.anomaly_criterion = nn.MSELoss(reduce=False) + + # (1) stastic on the train set + with torch.no_grad(): + for i, (batch_x, batch_y) in enumerate(train_loader): + batch_x = batch_x.float().to(self.device) + # reconstruction + outputs = self.model(batch_x, None, None, None) + # criterion + score = torch.mean(self.anomaly_criterion(batch_x, outputs), dim=-1) + score = score.detach().cpu().numpy() + attens_energy.append(score) + + attens_energy = np.concatenate(attens_energy, axis=0).reshape(-1) + train_energy = np.array(attens_energy) + + # (2) find the threshold + attens_energy = [] + test_labels = [] + for i, (batch_x, batch_y) in enumerate(test_loader): + batch_x = batch_x.float().to(self.device) + # reconstruction + outputs = self.model(batch_x, None, None, None) + # criterion + score = torch.mean(self.anomaly_criterion(batch_x, outputs), dim=-1) + score = score.detach().cpu().numpy() + attens_energy.append(score) + test_labels.append(batch_y) + + attens_energy = np.concatenate(attens_energy, axis=0).reshape(-1) + test_energy = np.array(attens_energy) + combined_energy = np.concatenate([train_energy, test_energy], axis=0) + threshold = np.percentile(combined_energy, 100 - self.args.anomaly_ratio) + print("Threshold :", threshold) + + # (3) evaluation on the test set + pred = (test_energy > threshold).astype(int) + test_labels = np.concatenate(test_labels, axis=0).reshape(-1) + test_labels = np.array(test_labels) + gt = test_labels.astype(int) + + print("pred: ", pred.shape) + print("gt: ", gt.shape) + + # (4) detection adjustment + gt, pred = adjustment(gt, pred) + + pred = np.array(pred) + gt = np.array(gt) + print("pred: ", pred.shape) + print("gt: ", gt.shape) + + accuracy = accuracy_score(gt, pred) + precision, recall, f_score, support = precision_recall_fscore_support(gt, pred, average='binary') + print("Accuracy : {:0.4f}, Precision : {:0.4f}, Recall : {:0.4f}, F-score : {:0.4f} ".format( + accuracy, precision, + recall, f_score)) + + f = open("result_anomaly_detection.txt", 'a') + f.write(setting + " \n") + f.write("Accuracy : {:0.4f}, Precision : {:0.4f}, Recall : {:0.4f}, F-score : {:0.4f} ".format( + accuracy, precision, + recall, f_score)) + f.write('\n') + f.write('\n') + f.close() + return diff --git a/exp/exp_basic.py b/exp/exp_basic.py new file mode 100644 index 0000000..7dc9811 --- /dev/null +++ b/exp/exp_basic.py @@ -0,0 +1,80 @@ +import os +import torch +from 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, TemporalFusionTransformer, SCINet, PAttn, TimeXer, \ + WPMixer, MultiPatchFormer, xPatch_SparseChannel + + +class Exp_Basic(object): + def __init__(self, args): + self.args = args + self.model_dict = { + 'TimesNet': TimesNet, + 'Autoformer': Autoformer, + 'Transformer': Transformer, + 'Nonstationary_Transformer': Nonstationary_Transformer, + 'DLinear': DLinear, + 'FEDformer': FEDformer, + 'Informer': Informer, + 'LightTS': LightTS, + 'Reformer': Reformer, + 'ETSformer': ETSformer, + 'PatchTST': PatchTST, + 'Pyraformer': Pyraformer, + 'MICN': MICN, + 'Crossformer': Crossformer, + 'FiLM': FiLM, + 'iTransformer': iTransformer, + 'Koopa': Koopa, + 'TiDE': TiDE, + 'FreTS': FreTS, + 'MambaSimple': MambaSimple, + 'TimeMixer': TimeMixer, + 'TSMixer': TSMixer, + 'SegRNN': SegRNN, + 'TemporalFusionTransformer': TemporalFusionTransformer, + "SCINet": SCINet, + 'PAttn': PAttn, + 'TimeXer': TimeXer, + 'WPMixer': WPMixer, + 'MultiPatchFormer': MultiPatchFormer, + 'xPatch_SparseChannel': xPatch_SparseChannel + } + if args.model == 'Mamba': + print('Please make sure you have successfully installed mamba_ssm') + from models import Mamba + self.model_dict['Mamba'] = Mamba + + self.device = self._acquire_device() + self.model = self._build_model().to(self.device) + + def _build_model(self): + raise NotImplementedError + return None + + def _acquire_device(self): + if self.args.use_gpu and self.args.gpu_type == 'cuda': + os.environ["CUDA_VISIBLE_DEVICES"] = str( + self.args.gpu) if not self.args.use_multi_gpu else self.args.devices + device = torch.device('cuda:{}'.format(self.args.gpu)) + print('Use GPU: cuda:{}'.format(self.args.gpu)) + elif self.args.use_gpu and self.args.gpu_type == 'mps': + device = torch.device('mps') + print('Use GPU: mps') + else: + device = torch.device('cpu') + print('Use CPU') + return device + + def _get_data(self): + pass + + def vali(self): + pass + + def train(self): + pass + + def test(self): + pass diff --git a/exp/exp_classification.py b/exp/exp_classification.py new file mode 100644 index 0000000..bd8d19f --- /dev/null +++ b/exp/exp_classification.py @@ -0,0 +1,192 @@ +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 +import torch +import torch.nn as nn +from torch import optim +import os +import time +import warnings +import numpy as np +import pdb + +warnings.filterwarnings('ignore') + + +class Exp_Classification(Exp_Basic): + def __init__(self, args): + super(Exp_Classification, self).__init__(args) + + def _build_model(self): + # model input depends on data + train_data, train_loader = self._get_data(flag='TRAIN') + test_data, test_loader = self._get_data(flag='TEST') + self.args.seq_len = max(train_data.max_seq_len, test_data.max_seq_len) + self.args.pred_len = 96 + self.args.enc_in = train_data.feature_df.shape[1] + self.args.num_class = len(train_data.class_names) + # model init + model = self.model_dict[self.args.model].Model(self.args).float() + if self.args.use_multi_gpu and self.args.use_gpu: + model = nn.DataParallel(model, device_ids=self.args.device_ids) + return model + + def _get_data(self, flag): + data_set, data_loader = data_provider(self.args, flag) + return data_set, data_loader + + def _select_optimizer(self): + # model_optim = optim.Adam(self.model.parameters(), lr=self.args.learning_rate) + model_optim = optim.RAdam(self.model.parameters(), lr=self.args.learning_rate) + return model_optim + + def _select_criterion(self): + criterion = nn.CrossEntropyLoss() + return criterion + + def vali(self, vali_data, vali_loader, criterion): + total_loss = [] + preds = [] + trues = [] + self.model.eval() + with torch.no_grad(): + for i, (batch_x, label, padding_mask) in enumerate(vali_loader): + batch_x = batch_x.float().to(self.device) + padding_mask = padding_mask.float().to(self.device) + label = label.to(self.device) + + outputs = self.model(batch_x, padding_mask, None, None) + + pred = outputs.detach() + loss = criterion(pred, label.long().squeeze()) + total_loss.append(loss.item()) + + preds.append(outputs.detach()) + trues.append(label) + + total_loss = np.average(total_loss) + + preds = torch.cat(preds, 0) + trues = torch.cat(trues, 0) + probs = torch.nn.functional.softmax(preds) # (total_samples, num_classes) est. prob. for each class and sample + predictions = torch.argmax(probs, dim=1).cpu().numpy() # (total_samples,) int class index for each sample + trues = trues.flatten().cpu().numpy() + accuracy = cal_accuracy(predictions, trues) + + self.model.train() + return total_loss, accuracy + + def train(self, setting): + train_data, train_loader = self._get_data(flag='TRAIN') + vali_data, vali_loader = self._get_data(flag='TEST') + test_data, test_loader = self._get_data(flag='TEST') + + path = os.path.join(self.args.checkpoints, setting) + if not os.path.exists(path): + os.makedirs(path) + + time_now = time.time() + + train_steps = len(train_loader) + early_stopping = EarlyStopping(patience=self.args.patience, verbose=True) + + model_optim = self._select_optimizer() + criterion = self._select_criterion() + + for epoch in range(self.args.train_epochs): + iter_count = 0 + train_loss = [] + + self.model.train() + epoch_time = time.time() + + for i, (batch_x, label, padding_mask) in enumerate(train_loader): + iter_count += 1 + model_optim.zero_grad() + + batch_x = batch_x.float().to(self.device) + padding_mask = padding_mask.float().to(self.device) + label = label.to(self.device) + + outputs = self.model(batch_x, padding_mask, None, None) + loss = criterion(outputs, label.long().squeeze(-1)) + train_loss.append(loss.item()) + + if (i + 1) % 100 == 0: + print("\titers: {0}, epoch: {1} | loss: {2:.7f}".format(i + 1, epoch + 1, loss.item())) + speed = (time.time() - time_now) / iter_count + left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i) + print('\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time)) + iter_count = 0 + time_now = time.time() + + loss.backward() + nn.utils.clip_grad_norm_(self.model.parameters(), max_norm=4.0) + model_optim.step() + + print("Epoch: {} cost time: {}".format(epoch + 1, time.time() - epoch_time)) + train_loss = np.average(train_loss) + vali_loss, val_accuracy = self.vali(vali_data, vali_loader, criterion) + # test_loss, test_accuracy = self.vali(test_data, test_loader, criterion) + + print( + "Epoch: {0}, Steps: {1} | Train Loss: {2:.3f} Vali Loss: {3:.3f} Vali Acc: {4:.3f}" # Test Loss: {5:.3f} Test Acc: {6:.3f}" + .format(epoch + 1, train_steps, train_loss, vali_loss, val_accuracy)) + # test_loss, test_accuracy)) + early_stopping(-val_accuracy, self.model, path) + if early_stopping.early_stop: + print("Early stopping") + break + + best_model_path = path + '/' + 'checkpoint.pth' + self.model.load_state_dict(torch.load(best_model_path)) + + return self.model + + def test(self, setting, test=0): + test_data, test_loader = self._get_data(flag='TEST') + if test: + print('loading model') + self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth'))) + + preds = [] + trues = [] + folder_path = './test_results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + self.model.eval() + with torch.no_grad(): + for i, (batch_x, label, padding_mask) in enumerate(test_loader): + batch_x = batch_x.float().to(self.device) + padding_mask = padding_mask.float().to(self.device) + label = label.to(self.device) + + outputs = self.model(batch_x, padding_mask, None, None) + + preds.append(outputs.detach()) + trues.append(label) + + preds = torch.cat(preds, 0) + trues = torch.cat(trues, 0) + print('test shape:', preds.shape, trues.shape) + + probs = torch.nn.functional.softmax(preds) # (total_samples, num_classes) est. prob. for each class and sample + predictions = torch.argmax(probs, dim=1).cpu().numpy() # (total_samples,) int class index for each sample + trues = trues.flatten().cpu().numpy() + accuracy = cal_accuracy(predictions, trues) + + # result save + folder_path = './results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + print('accuracy:{}'.format(accuracy)) + 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') + f.write('\n') + f.close() + return diff --git a/exp/exp_imputation.py b/exp/exp_imputation.py new file mode 100644 index 0000000..efc9054 --- /dev/null +++ b/exp/exp_imputation.py @@ -0,0 +1,228 @@ +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 +import torch +import torch.nn as nn +from torch import optim +import os +import time +import warnings +import numpy as np + +warnings.filterwarnings('ignore') + + +class Exp_Imputation(Exp_Basic): + def __init__(self, args): + super(Exp_Imputation, self).__init__(args) + + def _build_model(self): + model = self.model_dict[self.args.model].Model(self.args).float() + + if self.args.use_multi_gpu and self.args.use_gpu: + model = nn.DataParallel(model, device_ids=self.args.device_ids) + return model + + def _get_data(self, flag): + data_set, data_loader = data_provider(self.args, flag) + return data_set, data_loader + + def _select_optimizer(self): + model_optim = optim.Adam(self.model.parameters(), lr=self.args.learning_rate) + return model_optim + + def _select_criterion(self): + criterion = nn.MSELoss() + return criterion + + def vali(self, vali_data, vali_loader, criterion): + total_loss = [] + self.model.eval() + with torch.no_grad(): + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(vali_loader): + batch_x = batch_x.float().to(self.device) + batch_x_mark = batch_x_mark.float().to(self.device) + + # random mask + B, T, N = batch_x.shape + """ + B = batch size + T = seq len + N = number of features + """ + mask = torch.rand((B, T, N)).to(self.device) + mask[mask <= self.args.mask_rate] = 0 # masked + mask[mask > self.args.mask_rate] = 1 # remained + inp = batch_x.masked_fill(mask == 0, 0) + + outputs = self.model(inp, batch_x_mark, None, None, mask) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, :, f_dim:] + + # add support for MS + batch_x = batch_x[:, :, f_dim:] + mask = mask[:, :, f_dim:] + + pred = outputs.detach() + true = batch_x.detach() + mask = mask.detach() + + loss = criterion(pred[mask == 0], true[mask == 0]) + total_loss.append(loss.item()) + total_loss = np.average(total_loss) + self.model.train() + return total_loss + + def train(self, setting): + train_data, train_loader = self._get_data(flag='train') + vali_data, vali_loader = self._get_data(flag='val') + test_data, test_loader = self._get_data(flag='test') + + path = os.path.join(self.args.checkpoints, setting) + if not os.path.exists(path): + os.makedirs(path) + + time_now = time.time() + + train_steps = len(train_loader) + early_stopping = EarlyStopping(patience=self.args.patience, verbose=True) + + model_optim = self._select_optimizer() + criterion = self._select_criterion() + + for epoch in range(self.args.train_epochs): + iter_count = 0 + train_loss = [] + + self.model.train() + epoch_time = time.time() + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(train_loader): + iter_count += 1 + model_optim.zero_grad() + + batch_x = batch_x.float().to(self.device) + batch_x_mark = batch_x_mark.float().to(self.device) + + # random mask + B, T, N = batch_x.shape + mask = torch.rand((B, T, N)).to(self.device) + mask[mask <= self.args.mask_rate] = 0 # masked + mask[mask > self.args.mask_rate] = 1 # remained + inp = batch_x.masked_fill(mask == 0, 0) + + outputs = self.model(inp, batch_x_mark, None, None, mask) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, :, f_dim:] + + # add support for MS + batch_x = batch_x[:, :, f_dim:] + mask = mask[:, :, f_dim:] + + loss = criterion(outputs[mask == 0], batch_x[mask == 0]) + train_loss.append(loss.item()) + + if (i + 1) % 100 == 0: + print("\titers: {0}, epoch: {1} | loss: {2:.7f}".format(i + 1, epoch + 1, loss.item())) + speed = (time.time() - time_now) / iter_count + left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i) + print('\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time)) + iter_count = 0 + time_now = time.time() + + loss.backward() + model_optim.step() + + print("Epoch: {} cost time: {}".format(epoch + 1, time.time() - epoch_time)) + train_loss = np.average(train_loss) + vali_loss = self.vali(vali_data, vali_loader, criterion) + test_loss = self.vali(test_data, test_loader, criterion) + + print("Epoch: {0}, Steps: {1} | Train Loss: {2:.7f} Vali Loss: {3:.7f} Test Loss: {4:.7f}".format( + epoch + 1, train_steps, train_loss, vali_loss, test_loss)) + early_stopping(vali_loss, self.model, path) + if early_stopping.early_stop: + print("Early stopping") + break + adjust_learning_rate(model_optim, epoch + 1, self.args) + + best_model_path = path + '/' + 'checkpoint.pth' + self.model.load_state_dict(torch.load(best_model_path)) + + return self.model + + def test(self, setting, test=0): + test_data, test_loader = self._get_data(flag='test') + if test: + print('loading model') + self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth'))) + + preds = [] + trues = [] + masks = [] + folder_path = './test_results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + self.model.eval() + with torch.no_grad(): + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(test_loader): + batch_x = batch_x.float().to(self.device) + batch_x_mark = batch_x_mark.float().to(self.device) + + # random mask + B, T, N = batch_x.shape + mask = torch.rand((B, T, N)).to(self.device) + mask[mask <= self.args.mask_rate] = 0 # masked + mask[mask > self.args.mask_rate] = 1 # remained + inp = batch_x.masked_fill(mask == 0, 0) + + # imputation + outputs = self.model(inp, batch_x_mark, None, None, mask) + + # eval + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, :, f_dim:] + + # add support for MS + batch_x = batch_x[:, :, f_dim:] + mask = mask[:, :, f_dim:] + + outputs = outputs.detach().cpu().numpy() + pred = outputs + true = batch_x.detach().cpu().numpy() + preds.append(pred) + trues.append(true) + masks.append(mask.detach().cpu()) + + 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()) + visual(true[0, :, -1], filled, os.path.join(folder_path, str(i) + '.pdf')) + + preds = np.concatenate(preds, 0) + trues = np.concatenate(trues, 0) + masks = np.concatenate(masks, 0) + print('test shape:', preds.shape, trues.shape) + + # result save + folder_path = './results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + mae, mse, rmse, mape, mspe = metric(preds[masks == 0], trues[masks == 0]) + print('mse:{}, mae:{}'.format(mse, mae)) + f = open("result_imputation.txt", 'a') + f.write(setting + " \n") + f.write('mse:{}, mae:{}'.format(mse, mae)) + f.write('\n') + f.write('\n') + f.close() + + np.save(folder_path + 'metrics.npy', np.array([mae, mse, rmse, mape, mspe])) + np.save(folder_path + 'pred.npy', preds) + np.save(folder_path + 'true.npy', trues) + return diff --git a/exp/exp_long_term_forecasting.py b/exp/exp_long_term_forecasting.py new file mode 100644 index 0000000..63ed56c --- /dev/null +++ b/exp/exp_long_term_forecasting.py @@ -0,0 +1,268 @@ +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 +import torch +import torch.nn as nn +from torch import optim +import os +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 + +warnings.filterwarnings('ignore') + + +class Exp_Long_Term_Forecast(Exp_Basic): + def __init__(self, args): + super(Exp_Long_Term_Forecast, self).__init__(args) + + def _build_model(self): + model = self.model_dict[self.args.model].Model(self.args).float() + + if self.args.use_multi_gpu and self.args.use_gpu: + model = nn.DataParallel(model, device_ids=self.args.device_ids) + return model + + def _get_data(self, flag): + data_set, data_loader = data_provider(self.args, flag) + return data_set, data_loader + + def _select_optimizer(self): + model_optim = optim.Adam(self.model.parameters(), lr=self.args.learning_rate) + return model_optim + + def _select_criterion(self): + criterion = nn.MSELoss() + return criterion + + + def vali(self, vali_data, vali_loader, criterion): + total_loss = [] + self.model.eval() + with torch.no_grad(): + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(vali_loader): + batch_x = batch_x.float().to(self.device) + batch_y = batch_y.float() + + batch_x_mark = batch_x_mark.float().to(self.device) + batch_y_mark = batch_y_mark.float().to(self.device) + + # decoder input + dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float() + dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device) + # encoder - decoder + if self.args.use_amp: + with torch.cuda.amp.autocast(): + outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark) + else: + outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark) + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, f_dim:] + batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device) + + pred = outputs.detach() + true = batch_y.detach() + + loss = criterion(pred, true) + + total_loss.append(loss.item()) + total_loss = np.average(total_loss) + self.model.train() + return total_loss + + def train(self, setting): + train_data, train_loader = self._get_data(flag='train') + vali_data, vali_loader = self._get_data(flag='val') + test_data, test_loader = self._get_data(flag='test') + + path = os.path.join(self.args.checkpoints, setting) + if not os.path.exists(path): + os.makedirs(path) + + time_now = time.time() + + train_steps = len(train_loader) + early_stopping = EarlyStopping(patience=self.args.patience, verbose=True) + + model_optim = self._select_optimizer() + criterion = self._select_criterion() + + if self.args.use_amp: + scaler = torch.cuda.amp.GradScaler() + + for epoch in range(self.args.train_epochs): + iter_count = 0 + train_loss = [] + + self.model.train() + epoch_time = time.time() + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(train_loader): + iter_count += 1 + model_optim.zero_grad() + batch_x = batch_x.float().to(self.device) + batch_y = batch_y.float().to(self.device) + batch_x_mark = batch_x_mark.float().to(self.device) + batch_y_mark = batch_y_mark.float().to(self.device) + + # decoder input + dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float() + dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device) + + # encoder - decoder + if self.args.use_amp: + with torch.cuda.amp.autocast(): + outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, f_dim:] + batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device) + loss = criterion(outputs, batch_y) + train_loss.append(loss.item()) + else: + outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, f_dim:] + batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device) + loss = criterion(outputs, batch_y) + train_loss.append(loss.item()) + + if (i + 1) % 100 == 0: + print("\titers: {0}, epoch: {1} | loss: {2:.7f}".format(i + 1, epoch + 1, loss.item())) + speed = (time.time() - time_now) / iter_count + left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i) + print('\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time)) + iter_count = 0 + time_now = time.time() + + if self.args.use_amp: + scaler.scale(loss).backward() + scaler.step(model_optim) + scaler.update() + else: + loss.backward() + model_optim.step() + + print("Epoch: {} cost time: {}".format(epoch + 1, time.time() - epoch_time)) + train_loss = np.average(train_loss) + vali_loss = self.vali(vali_data, vali_loader, criterion) + test_loss = self.vali(test_data, test_loader, criterion) + + print("Epoch: {0}, Steps: {1} | Train Loss: {2:.7f} Vali Loss: {3:.7f} Test Loss: {4:.7f}".format( + epoch + 1, train_steps, train_loss, vali_loss, test_loss)) + early_stopping(vali_loss, self.model, path) + if early_stopping.early_stop: + print("Early stopping") + break + + adjust_learning_rate(model_optim, epoch + 1, self.args) + + best_model_path = path + '/' + 'checkpoint.pth' + self.model.load_state_dict(torch.load(best_model_path)) + + return self.model + + def test(self, setting, test=0): + test_data, test_loader = self._get_data(flag='test') + if test: + print('loading model') + self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth'))) + + preds = [] + trues = [] + folder_path = './test_results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + self.model.eval() + with torch.no_grad(): + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(test_loader): + batch_x = batch_x.float().to(self.device) + batch_y = batch_y.float().to(self.device) + + batch_x_mark = batch_x_mark.float().to(self.device) + batch_y_mark = batch_y_mark.float().to(self.device) + + # decoder input + dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float() + dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device) + # encoder - decoder + if self.args.use_amp: + with torch.cuda.amp.autocast(): + outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark) + else: + outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, :] + batch_y = batch_y[:, -self.args.pred_len:, :].to(self.device) + outputs = outputs.detach().cpu().numpy() + batch_y = batch_y.detach().cpu().numpy() + if test_data.scale and self.args.inverse: + shape = batch_y.shape + if outputs.shape[-1] != batch_y.shape[-1]: + outputs = np.tile(outputs, [1, 1, int(batch_y.shape[-1] / outputs.shape[-1])]) + outputs = test_data.inverse_transform(outputs.reshape(shape[0] * shape[1], -1)).reshape(shape) + batch_y = test_data.inverse_transform(batch_y.reshape(shape[0] * shape[1], -1)).reshape(shape) + + outputs = outputs[:, :, f_dim:] + batch_y = batch_y[:, :, f_dim:] + + pred = outputs + true = batch_y + + preds.append(pred) + trues.append(true) + if i % 20 == 0: + input = batch_x.detach().cpu().numpy() + if test_data.scale and self.args.inverse: + shape = input.shape + input = test_data.inverse_transform(input.reshape(shape[0] * shape[1], -1)).reshape(shape) + gt = np.concatenate((input[0, :, -1], true[0, :, -1]), axis=0) + pd = np.concatenate((input[0, :, -1], pred[0, :, -1]), axis=0) + visual(gt, pd, os.path.join(folder_path, str(i) + '.pdf')) + + preds = np.concatenate(preds, axis=0) + trues = np.concatenate(trues, axis=0) + print('test shape:', preds.shape, trues.shape) + preds = preds.reshape(-1, preds.shape[-2], preds.shape[-1]) + trues = trues.reshape(-1, trues.shape[-2], trues.shape[-1]) + print('test shape:', preds.shape, trues.shape) + + # result save + 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) + for i in range(preds.shape[0]): + 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) + dtw_list.append(d) + dtw = np.array(dtw_list).mean() + else: + dtw = 'Not calculated' + + mae, mse, rmse, mape, mspe = metric(preds, trues) + print('mse:{}, mae:{}, dtw:{}'.format(mse, mae, dtw)) + f = open("result_long_term_forecast.txt", 'a') + f.write(setting + " \n") + f.write('mse:{}, mae:{}, dtw:{}'.format(mse, mae, dtw)) + f.write('\n') + f.write('\n') + f.close() + + np.save(folder_path + 'metrics.npy', np.array([mae, mse, rmse, mape, mspe])) + np.save(folder_path + 'pred.npy', preds) + np.save(folder_path + 'true.npy', trues) + + return diff --git a/exp/exp_short_term_forecasting.py b/exp/exp_short_term_forecasting.py new file mode 100644 index 0000000..90a0d8b --- /dev/null +++ b/exp/exp_short_term_forecasting.py @@ -0,0 +1,235 @@ +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 +import torch +import torch.nn as nn +from torch import optim +import os +import time +import warnings +import numpy as np +import pandas + +warnings.filterwarnings('ignore') + + +class Exp_Short_Term_Forecast(Exp_Basic): + def __init__(self, args): + super(Exp_Short_Term_Forecast, self).__init__(args) + + def _build_model(self): + if self.args.data == 'm4': + self.args.pred_len = M4Meta.horizons_map[self.args.seasonal_patterns] # Up to M4 config + self.args.seq_len = 2 * self.args.pred_len # input_len = 2*pred_len + self.args.label_len = self.args.pred_len + self.args.frequency_map = M4Meta.frequency_map[self.args.seasonal_patterns] + model = self.model_dict[self.args.model].Model(self.args).float() + + if self.args.use_multi_gpu and self.args.use_gpu: + model = nn.DataParallel(model, device_ids=self.args.device_ids) + return model + + def _get_data(self, flag): + data_set, data_loader = data_provider(self.args, flag) + return data_set, data_loader + + def _select_optimizer(self): + model_optim = optim.Adam(self.model.parameters(), lr=self.args.learning_rate) + return model_optim + + def _select_criterion(self, loss_name='MSE'): + if loss_name == 'MSE': + return nn.MSELoss() + elif loss_name == 'MAPE': + return mape_loss() + elif loss_name == 'MASE': + return mase_loss() + elif loss_name == 'SMAPE': + return smape_loss() + + def train(self, setting): + train_data, train_loader = self._get_data(flag='train') + vali_data, vali_loader = self._get_data(flag='val') + + path = os.path.join(self.args.checkpoints, setting) + if not os.path.exists(path): + os.makedirs(path) + + time_now = time.time() + + train_steps = len(train_loader) + early_stopping = EarlyStopping(patience=self.args.patience, verbose=True) + + model_optim = self._select_optimizer() + criterion = self._select_criterion(self.args.loss) + mse = nn.MSELoss() + + for epoch in range(self.args.train_epochs): + iter_count = 0 + train_loss = [] + + self.model.train() + epoch_time = time.time() + for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(train_loader): + iter_count += 1 + model_optim.zero_grad() + batch_x = batch_x.float().to(self.device) + + batch_y = batch_y.float().to(self.device) + batch_y_mark = batch_y_mark.float().to(self.device) + + # decoder input + dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float() + dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device) + + outputs = self.model(batch_x, None, dec_inp, None) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, f_dim:] + batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device) + + batch_y_mark = batch_y_mark[:, -self.args.pred_len:, f_dim:].to(self.device) + loss_value = criterion(batch_x, self.args.frequency_map, outputs, batch_y, batch_y_mark) + loss_sharpness = mse((outputs[:, 1:, :] - outputs[:, :-1, :]), (batch_y[:, 1:, :] - batch_y[:, :-1, :])) + loss = loss_value # + loss_sharpness * 1e-5 + train_loss.append(loss.item()) + + if (i + 1) % 100 == 0: + print("\titers: {0}, epoch: {1} | loss: {2:.7f}".format(i + 1, epoch + 1, loss.item())) + speed = (time.time() - time_now) / iter_count + left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i) + print('\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time)) + iter_count = 0 + time_now = time.time() + + loss.backward() + model_optim.step() + + print("Epoch: {} cost time: {}".format(epoch + 1, time.time() - epoch_time)) + train_loss = np.average(train_loss) + vali_loss = self.vali(train_loader, vali_loader, criterion) + test_loss = vali_loss + print("Epoch: {0}, Steps: {1} | Train Loss: {2:.7f} Vali Loss: {3:.7f} Test Loss: {4:.7f}".format( + epoch + 1, train_steps, train_loss, vali_loss, test_loss)) + early_stopping(vali_loss, self.model, path) + if early_stopping.early_stop: + print("Early stopping") + break + + adjust_learning_rate(model_optim, epoch + 1, self.args) + + best_model_path = path + '/' + 'checkpoint.pth' + self.model.load_state_dict(torch.load(best_model_path)) + + return self.model + + def vali(self, train_loader, vali_loader, criterion): + x, _ = train_loader.dataset.last_insample_window() + y = vali_loader.dataset.timeseries + x = torch.tensor(x, dtype=torch.float32).to(self.device) + x = x.unsqueeze(-1) + + self.model.eval() + with torch.no_grad(): + # decoder input + B, _, C = x.shape + dec_inp = torch.zeros((B, self.args.pred_len, C)).float().to(self.device) + dec_inp = torch.cat([x[:, -self.args.label_len:, :], dec_inp], dim=1).float() + # encoder - decoder + outputs = torch.zeros((B, self.args.pred_len, C)).float() # .to(self.device) + id_list = np.arange(0, B, 500) # validation set size + id_list = np.append(id_list, B) + for i in range(len(id_list) - 1): + outputs[id_list[i]:id_list[i + 1], :, :] = self.model(x[id_list[i]:id_list[i + 1]], None, + dec_inp[id_list[i]:id_list[i + 1]], + None).detach().cpu() + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, f_dim:] + pred = outputs + true = torch.from_numpy(np.array(y)) + batch_y_mark = torch.ones(true.shape) + + loss = criterion(x.detach().cpu()[:, :, 0], self.args.frequency_map, pred[:, :, 0], true, batch_y_mark) + + self.model.train() + return loss + + def test(self, setting, test=0): + _, train_loader = self._get_data(flag='train') + _, test_loader = self._get_data(flag='test') + x, _ = train_loader.dataset.last_insample_window() + y = test_loader.dataset.timeseries + x = torch.tensor(x, dtype=torch.float32).to(self.device) + x = x.unsqueeze(-1) + + if test: + print('loading model') + self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth'))) + + folder_path = './test_results/' + setting + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + self.model.eval() + with torch.no_grad(): + B, _, C = x.shape + dec_inp = torch.zeros((B, self.args.pred_len, C)).float().to(self.device) + dec_inp = torch.cat([x[:, -self.args.label_len:, :], dec_inp], dim=1).float() + # encoder - decoder + outputs = torch.zeros((B, self.args.pred_len, C)).float().to(self.device) + id_list = np.arange(0, B, 1) + id_list = np.append(id_list, B) + for i in range(len(id_list) - 1): + outputs[id_list[i]:id_list[i + 1], :, :] = self.model(x[id_list[i]:id_list[i + 1]], None, + dec_inp[id_list[i]:id_list[i + 1]], None) + + if id_list[i] % 1000 == 0: + print(id_list[i]) + + f_dim = -1 if self.args.features == 'MS' else 0 + outputs = outputs[:, -self.args.pred_len:, f_dim:] + outputs = outputs.detach().cpu().numpy() + + preds = outputs + trues = y + x = x.detach().cpu().numpy() + + for i in range(0, preds.shape[0], preds.shape[0] // 10): + gt = np.concatenate((x[i, :, 0], trues[i]), axis=0) + pd = np.concatenate((x[i, :, 0], preds[i, :, 0]), axis=0) + visual(gt, pd, os.path.join(folder_path, str(i) + '.pdf')) + + print('test shape:', preds.shape) + + # result save + folder_path = './m4_results/' + self.args.model + '/' + if not os.path.exists(folder_path): + os.makedirs(folder_path) + + forecasts_df = pandas.DataFrame(preds[:, :, 0], columns=[f'V{i + 1}' for i in range(self.args.pred_len)]) + forecasts_df.index = test_loader.dataset.ids[:preds.shape[0]] + forecasts_df.index.name = 'id' + forecasts_df.set_index(forecasts_df.columns[0], inplace=True) + forecasts_df.to_csv(folder_path + self.args.seasonal_patterns + '_forecast.csv') + + print(self.args.model) + file_path = './m4_results/' + self.args.model + '/' + if 'Weekly_forecast.csv' in os.listdir(file_path) \ + and 'Monthly_forecast.csv' in os.listdir(file_path) \ + and 'Yearly_forecast.csv' in os.listdir(file_path) \ + and 'Daily_forecast.csv' in os.listdir(file_path) \ + and 'Hourly_forecast.csv' in os.listdir(file_path) \ + and 'Quarterly_forecast.csv' in os.listdir(file_path): + m4_summary = M4Summary(file_path, self.args.root_path) + # m4_forecast.set_index(m4_winner_forecast.columns[0], inplace=True) + smape_results, owa_results, mape, mase = m4_summary.evaluate() + print('smape:', smape_results) + print('mape:', mape) + print('mase:', mase) + print('owa:', owa_results) + else: + print('After all 6 tasks are finished, you can calculate the averaged index') + return diff --git a/layers/AutoCorrelation.py b/layers/AutoCorrelation.py new file mode 100644 index 0000000..c566461 --- /dev/null +++ b/layers/AutoCorrelation.py @@ -0,0 +1,163 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import matplotlib.pyplot as plt +import numpy as np +import math +from math import sqrt +import os + + +class AutoCorrelation(nn.Module): + """ + AutoCorrelation Mechanism with the following two phases: + (1) period-based dependencies discovery + (2) time delay aggregation + This block can replace the self-attention family mechanism seamlessly. + """ + + def __init__(self, mask_flag=True, factor=1, scale=None, attention_dropout=0.1, output_attention=False): + super(AutoCorrelation, self).__init__() + self.factor = factor + self.scale = scale + self.mask_flag = mask_flag + self.output_attention = output_attention + self.dropout = nn.Dropout(attention_dropout) + + def time_delay_agg_training(self, values, corr): + """ + SpeedUp version of Autocorrelation (a batch-normalization style design) + This is for the training phase. + """ + head = values.shape[1] + channel = values.shape[2] + length = values.shape[3] + # find top k + top_k = int(self.factor * math.log(length)) + mean_value = torch.mean(torch.mean(corr, dim=1), dim=1) + index = torch.topk(torch.mean(mean_value, dim=0), top_k, dim=-1)[1] + weights = torch.stack([mean_value[:, index[i]] for i in range(top_k)], dim=-1) + # update corr + tmp_corr = torch.softmax(weights, dim=-1) + # aggregation + tmp_values = values + delays_agg = torch.zeros_like(values).float() + for i in range(top_k): + pattern = torch.roll(tmp_values, -int(index[i]), -1) + delays_agg = delays_agg + pattern * \ + (tmp_corr[:, i].unsqueeze(1).unsqueeze(1).unsqueeze(1).repeat(1, head, channel, length)) + return delays_agg + + def time_delay_agg_inference(self, values, corr): + """ + SpeedUp version of Autocorrelation (a batch-normalization style design) + This is for the inference phase. + """ + batch = values.shape[0] + head = values.shape[1] + channel = values.shape[2] + length = values.shape[3] + # index init + init_index = torch.arange(length).unsqueeze(0).unsqueeze(0).unsqueeze(0).repeat(batch, head, channel, 1).to(values.device) + # find top k + top_k = int(self.factor * math.log(length)) + mean_value = torch.mean(torch.mean(corr, dim=1), dim=1) + weights, delay = torch.topk(mean_value, top_k, dim=-1) + # update corr + tmp_corr = torch.softmax(weights, dim=-1) + # aggregation + tmp_values = values.repeat(1, 1, 1, 2) + delays_agg = torch.zeros_like(values).float() + for i in range(top_k): + tmp_delay = init_index + delay[:, i].unsqueeze(1).unsqueeze(1).unsqueeze(1).repeat(1, head, channel, length) + pattern = torch.gather(tmp_values, dim=-1, index=tmp_delay) + delays_agg = delays_agg + pattern * \ + (tmp_corr[:, i].unsqueeze(1).unsqueeze(1).unsqueeze(1).repeat(1, head, channel, length)) + return delays_agg + + def time_delay_agg_full(self, values, corr): + """ + Standard version of Autocorrelation + """ + batch = values.shape[0] + head = values.shape[1] + channel = values.shape[2] + length = values.shape[3] + # index init + init_index = torch.arange(length).unsqueeze(0).unsqueeze(0).unsqueeze(0).repeat(batch, head, channel, 1).to(values.device) + # find top k + top_k = int(self.factor * math.log(length)) + weights, delay = torch.topk(corr, top_k, dim=-1) + # update corr + tmp_corr = torch.softmax(weights, dim=-1) + # aggregation + tmp_values = values.repeat(1, 1, 1, 2) + delays_agg = torch.zeros_like(values).float() + for i in range(top_k): + tmp_delay = init_index + delay[..., i].unsqueeze(-1) + pattern = torch.gather(tmp_values, dim=-1, index=tmp_delay) + delays_agg = delays_agg + pattern * (tmp_corr[..., i].unsqueeze(-1)) + return delays_agg + + def forward(self, queries, keys, values, attn_mask): + B, L, H, E = queries.shape + _, S, _, D = values.shape + if L > S: + zeros = torch.zeros_like(queries[:, :(L - S), :]).float() + values = torch.cat([values, zeros], dim=1) + keys = torch.cat([keys, zeros], dim=1) + else: + values = values[:, :L, :, :] + keys = keys[:, :L, :, :] + + # period-based dependencies + q_fft = torch.fft.rfft(queries.permute(0, 2, 3, 1).contiguous(), dim=-1) + k_fft = torch.fft.rfft(keys.permute(0, 2, 3, 1).contiguous(), dim=-1) + res = q_fft * torch.conj(k_fft) + corr = torch.fft.irfft(res, dim=-1) + + # time delay agg + if self.training: + V = self.time_delay_agg_training(values.permute(0, 2, 3, 1).contiguous(), corr).permute(0, 3, 1, 2) + else: + V = self.time_delay_agg_inference(values.permute(0, 2, 3, 1).contiguous(), corr).permute(0, 3, 1, 2) + + if self.output_attention: + return (V.contiguous(), corr.permute(0, 3, 1, 2)) + else: + return (V.contiguous(), None) + + +class AutoCorrelationLayer(nn.Module): + def __init__(self, correlation, d_model, n_heads, d_keys=None, + d_values=None): + super(AutoCorrelationLayer, self).__init__() + + d_keys = d_keys or (d_model // n_heads) + d_values = d_values or (d_model // n_heads) + + self.inner_correlation = correlation + self.query_projection = nn.Linear(d_model, d_keys * n_heads) + self.key_projection = nn.Linear(d_model, d_keys * n_heads) + self.value_projection = nn.Linear(d_model, d_values * n_heads) + self.out_projection = nn.Linear(d_values * n_heads, d_model) + self.n_heads = n_heads + + def forward(self, queries, keys, values, attn_mask): + B, L, _ = queries.shape + _, S, _ = keys.shape + H = self.n_heads + + queries = self.query_projection(queries).view(B, L, H, -1) + keys = self.key_projection(keys).view(B, S, H, -1) + values = self.value_projection(values).view(B, S, H, -1) + + out, attn = self.inner_correlation( + queries, + keys, + values, + attn_mask + ) + out = out.view(B, L, -1) + + return self.out_projection(out), attn diff --git a/layers/Autoformer_EncDec.py b/layers/Autoformer_EncDec.py new file mode 100644 index 0000000..6fce4bc --- /dev/null +++ b/layers/Autoformer_EncDec.py @@ -0,0 +1,203 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class my_Layernorm(nn.Module): + """ + Special designed layernorm for the seasonal part + """ + + def __init__(self, channels): + super(my_Layernorm, self).__init__() + self.layernorm = nn.LayerNorm(channels) + + def forward(self, x): + x_hat = self.layernorm(x) + bias = torch.mean(x_hat, dim=1).unsqueeze(1).repeat(1, x.shape[1], 1) + return x_hat - bias + + +class moving_avg(nn.Module): + """ + Moving average block to highlight the trend of time series + """ + + def __init__(self, kernel_size, stride): + super(moving_avg, self).__init__() + self.kernel_size = kernel_size + self.avg = nn.AvgPool1d(kernel_size=kernel_size, stride=stride, padding=0) + + def forward(self, x): + # padding on the both ends of time series + front = x[:, 0:1, :].repeat(1, (self.kernel_size - 1) // 2, 1) + end = x[:, -1:, :].repeat(1, (self.kernel_size - 1) // 2, 1) + x = torch.cat([front, x, end], dim=1) + x = self.avg(x.permute(0, 2, 1)) + x = x.permute(0, 2, 1) + return x + + +class series_decomp(nn.Module): + """ + Series decomposition block + """ + + def __init__(self, kernel_size): + super(series_decomp, self).__init__() + self.moving_avg = moving_avg(kernel_size, stride=1) + + def forward(self, x): + moving_mean = self.moving_avg(x) + res = x - moving_mean + return res, moving_mean + + +class series_decomp_multi(nn.Module): + """ + Multiple Series decomposition block from FEDformer + """ + + def __init__(self, kernel_size): + super(series_decomp_multi, self).__init__() + self.kernel_size = kernel_size + self.series_decomp = [series_decomp(kernel) for kernel in kernel_size] + + def forward(self, x): + moving_mean = [] + res = [] + for func in self.series_decomp: + sea, moving_avg = func(x) + moving_mean.append(moving_avg) + res.append(sea) + + sea = sum(res) / len(res) + moving_mean = sum(moving_mean) / len(moving_mean) + return sea, moving_mean + + +class EncoderLayer(nn.Module): + """ + Autoformer encoder layer with the progressive decomposition architecture + """ + + def __init__(self, attention, d_model, d_ff=None, moving_avg=25, dropout=0.1, activation="relu"): + super(EncoderLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.attention = attention + self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1, bias=False) + self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1, bias=False) + self.decomp1 = series_decomp(moving_avg) + self.decomp2 = series_decomp(moving_avg) + self.dropout = nn.Dropout(dropout) + self.activation = F.relu if activation == "relu" else F.gelu + + def forward(self, x, attn_mask=None): + new_x, attn = self.attention( + x, x, x, + attn_mask=attn_mask + ) + x = x + self.dropout(new_x) + x, _ = self.decomp1(x) + y = x + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + res, _ = self.decomp2(x + y) + return res, attn + + +class Encoder(nn.Module): + """ + Autoformer encoder + """ + + def __init__(self, attn_layers, conv_layers=None, norm_layer=None): + super(Encoder, self).__init__() + self.attn_layers = nn.ModuleList(attn_layers) + self.conv_layers = nn.ModuleList(conv_layers) if conv_layers is not None else None + self.norm = norm_layer + + def forward(self, x, attn_mask=None): + attns = [] + if self.conv_layers is not None: + for attn_layer, conv_layer in zip(self.attn_layers, self.conv_layers): + x, attn = attn_layer(x, attn_mask=attn_mask) + x = conv_layer(x) + attns.append(attn) + x, attn = self.attn_layers[-1](x) + attns.append(attn) + else: + for attn_layer in self.attn_layers: + x, attn = attn_layer(x, attn_mask=attn_mask) + attns.append(attn) + + if self.norm is not None: + x = self.norm(x) + + return x, attns + + +class DecoderLayer(nn.Module): + """ + Autoformer decoder layer with the progressive decomposition architecture + """ + + def __init__(self, self_attention, cross_attention, d_model, c_out, d_ff=None, + moving_avg=25, dropout=0.1, activation="relu"): + super(DecoderLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.self_attention = self_attention + self.cross_attention = cross_attention + self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1, bias=False) + self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1, bias=False) + self.decomp1 = series_decomp(moving_avg) + self.decomp2 = series_decomp(moving_avg) + self.decomp3 = series_decomp(moving_avg) + self.dropout = nn.Dropout(dropout) + self.projection = nn.Conv1d(in_channels=d_model, out_channels=c_out, kernel_size=3, stride=1, padding=1, + padding_mode='circular', bias=False) + self.activation = F.relu if activation == "relu" else F.gelu + + def forward(self, x, cross, x_mask=None, cross_mask=None): + x = x + self.dropout(self.self_attention( + x, x, x, + attn_mask=x_mask + )[0]) + x, trend1 = self.decomp1(x) + x = x + self.dropout(self.cross_attention( + x, cross, cross, + attn_mask=cross_mask + )[0]) + x, trend2 = self.decomp2(x) + y = x + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + x, trend3 = self.decomp3(x + y) + + residual_trend = trend1 + trend2 + trend3 + residual_trend = self.projection(residual_trend.permute(0, 2, 1)).transpose(1, 2) + return x, residual_trend + + +class Decoder(nn.Module): + """ + Autoformer encoder + """ + + def __init__(self, layers, norm_layer=None, projection=None): + super(Decoder, self).__init__() + self.layers = nn.ModuleList(layers) + self.norm = norm_layer + self.projection = projection + + def forward(self, x, cross, x_mask=None, cross_mask=None, trend=None): + for layer in self.layers: + x, residual_trend = layer(x, cross, x_mask=x_mask, cross_mask=cross_mask) + trend = trend + residual_trend + + if self.norm is not None: + x = self.norm(x) + + if self.projection is not None: + x = self.projection(x) + return x, trend diff --git a/layers/Conv_Blocks.py b/layers/Conv_Blocks.py new file mode 100644 index 0000000..8eddfa3 --- /dev/null +++ b/layers/Conv_Blocks.py @@ -0,0 +1,60 @@ +import torch +import torch.nn as nn + + +class Inception_Block_V1(nn.Module): + def __init__(self, in_channels, out_channels, num_kernels=6, init_weight=True): + super(Inception_Block_V1, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.num_kernels = num_kernels + kernels = [] + for i in range(self.num_kernels): + kernels.append(nn.Conv2d(in_channels, out_channels, kernel_size=2 * i + 1, padding=i)) + self.kernels = nn.ModuleList(kernels) + if init_weight: + self._initialize_weights() + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def forward(self, x): + res_list = [] + for i in range(self.num_kernels): + res_list.append(self.kernels[i](x)) + res = torch.stack(res_list, dim=-1).mean(-1) + return res + + +class Inception_Block_V2(nn.Module): + def __init__(self, in_channels, out_channels, num_kernels=6, init_weight=True): + super(Inception_Block_V2, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.num_kernels = num_kernels + kernels = [] + for i in range(self.num_kernels // 2): + kernels.append(nn.Conv2d(in_channels, out_channels, kernel_size=[1, 2 * i + 3], padding=[0, i + 1])) + kernels.append(nn.Conv2d(in_channels, out_channels, kernel_size=[2 * i + 3, 1], padding=[i + 1, 0])) + kernels.append(nn.Conv2d(in_channels, out_channels, kernel_size=1)) + self.kernels = nn.ModuleList(kernels) + if init_weight: + self._initialize_weights() + + def _initialize_weights(self): + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + if m.bias is not None: + nn.init.constant_(m.bias, 0) + + def forward(self, x): + res_list = [] + for i in range(self.num_kernels // 2 * 2 + 1): + res_list.append(self.kernels[i](x)) + res = torch.stack(res_list, dim=-1).mean(-1) + return res diff --git a/layers/Crossformer_EncDec.py b/layers/Crossformer_EncDec.py new file mode 100644 index 0000000..42fc322 --- /dev/null +++ b/layers/Crossformer_EncDec.py @@ -0,0 +1,131 @@ +import torch +import torch.nn as nn +from einops import rearrange, repeat +from layers.SelfAttention_Family import TwoStageAttentionLayer + + +class SegMerging(nn.Module): + def __init__(self, d_model, win_size, norm_layer=nn.LayerNorm): + super().__init__() + self.d_model = d_model + self.win_size = win_size + self.linear_trans = nn.Linear(win_size * d_model, d_model) + self.norm = norm_layer(win_size * d_model) + + def forward(self, x): + batch_size, ts_d, seg_num, d_model = x.shape + pad_num = seg_num % self.win_size + if pad_num != 0: + pad_num = self.win_size - pad_num + x = torch.cat((x, x[:, :, -pad_num:, :]), dim=-2) + + seg_to_merge = [] + for i in range(self.win_size): + seg_to_merge.append(x[:, :, i::self.win_size, :]) + x = torch.cat(seg_to_merge, -1) + + x = self.norm(x) + x = self.linear_trans(x) + + return x + + +class scale_block(nn.Module): + def __init__(self, configs, win_size, d_model, n_heads, d_ff, depth, dropout, \ + seg_num=10, factor=10): + super(scale_block, self).__init__() + + if win_size > 1: + self.merge_layer = SegMerging(d_model, win_size, nn.LayerNorm) + else: + self.merge_layer = None + + self.encode_layers = nn.ModuleList() + + for i in range(depth): + 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): + _, ts_dim, _, _ = x.shape + + if self.merge_layer is not None: + x = self.merge_layer(x) + + for layer in self.encode_layers: + x = layer(x) + + return x, None + + +class Encoder(nn.Module): + def __init__(self, attn_layers): + super(Encoder, self).__init__() + self.encode_blocks = nn.ModuleList(attn_layers) + + def forward(self, x): + encode_x = [] + encode_x.append(x) + + for block in self.encode_blocks: + x, attns = block(x) + encode_x.append(x) + + return encode_x, None + + +class DecoderLayer(nn.Module): + def __init__(self, self_attention, cross_attention, seg_len, d_model, d_ff=None, dropout=0.1): + super(DecoderLayer, self).__init__() + self.self_attention = self_attention + self.cross_attention = cross_attention + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.dropout = nn.Dropout(dropout) + self.MLP1 = nn.Sequential(nn.Linear(d_model, d_model), + nn.GELU(), + nn.Linear(d_model, d_model)) + self.linear_pred = nn.Linear(d_model, seg_len) + + def forward(self, x, cross): + batch = x.shape[0] + x = self.self_attention(x) + x = rearrange(x, 'b ts_d out_seg_num d_model -> (b ts_d) out_seg_num d_model') + + cross = rearrange(cross, 'b ts_d in_seg_num d_model -> (b ts_d) in_seg_num d_model') + tmp, attn = self.cross_attention(x, cross, cross, None, None, None,) + x = x + self.dropout(tmp) + y = x = self.norm1(x) + y = self.MLP1(y) + dec_output = self.norm2(x + y) + + dec_output = rearrange(dec_output, '(b ts_d) seg_dec_num d_model -> b ts_d seg_dec_num d_model', b=batch) + layer_predict = self.linear_pred(dec_output) + layer_predict = rearrange(layer_predict, 'b out_d seg_num seg_len -> b (out_d seg_num) seg_len') + + return dec_output, layer_predict + + +class Decoder(nn.Module): + def __init__(self, layers): + super(Decoder, self).__init__() + self.decode_layers = nn.ModuleList(layers) + + + def forward(self, x, cross): + final_predict = None + i = 0 + + ts_d = x.shape[1] + for layer in self.decode_layers: + cross_enc = cross[i] + x, layer_predict = layer(x, cross_enc) + if final_predict is None: + final_predict = layer_predict + else: + final_predict = final_predict + layer_predict + i += 1 + + final_predict = rearrange(final_predict, 'b (out_d seg_num) seg_len -> b (seg_num seg_len) out_d', out_d=ts_d) + + return final_predict diff --git a/layers/DECOMP.py b/layers/DECOMP.py new file mode 100644 index 0000000..e10a015 --- /dev/null +++ b/layers/DECOMP.py @@ -0,0 +1,22 @@ +import torch +from torch import nn +from layers.EMA import EMA +from layers.DEMA import DEMA + +class DECOMP(nn.Module): + """ + Series decomposition block using EMA/DEMA + """ + def __init__(self, ma_type, alpha, beta): + super(DECOMP, self).__init__() + if ma_type == 'ema': + self.ma = EMA(alpha) + elif ma_type == 'dema': + self.ma = DEMA(alpha, beta) + else: + raise ValueError(f"Unsupported ma_type: {ma_type}. Use 'ema' or 'dema'") + + def forward(self, x): + moving_average = self.ma(x) + res = x - moving_average + return res, moving_average \ No newline at end of file diff --git a/layers/DEMA.py b/layers/DEMA.py new file mode 100644 index 0000000..963f41f --- /dev/null +++ b/layers/DEMA.py @@ -0,0 +1,23 @@ +import torch +from torch import nn + +class DEMA(nn.Module): + """ + Double Exponential Moving Average (DEMA) block to highlight the trend of time series + """ + def __init__(self, alpha, beta): + super(DEMA, self).__init__() + self.alpha = alpha.to(device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')) + self.beta = beta.to(device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')) + + def forward(self, x): + s_prev = x[:, 0, :] + b = x[:, 1, :] - s_prev + res = [s_prev.unsqueeze(1)] + for t in range(1, x.shape[1]): + xt = x[:, t, :] + s = self.alpha * xt + (1 - self.alpha) * (s_prev + b) + b = self.beta * (s - s_prev) + (1 - self.beta) * b + s_prev = s + res.append(s.unsqueeze(1)) + return torch.cat(res, dim=1) \ No newline at end of file diff --git a/layers/DWT_Decomposition.py b/layers/DWT_Decomposition.py new file mode 100644 index 0000000..d21e9b1 --- /dev/null +++ b/layers/DWT_Decomposition.py @@ -0,0 +1,1268 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Jan 5 +@author: Murad +SISLab, USF +mmurad@usf.edu +https://github.com/Secure-and-Intelligent-Systems-Lab/WPMixer +""" + +import torch +import torch.nn as nn +import pywt +import numpy as np +import torch.nn.functional as F +from torch.autograd import Function + + +class Decomposition(nn.Module): + def __init__(self, + input_length=[], + pred_length=[], + wavelet_name=[], + level=[], + batch_size=[], + channel=[], + d_model=[], + tfactor=[], + dfactor=[], + device=[], + no_decomposition=[], + use_amp=[]): + super(Decomposition, self).__init__() + self.input_length = input_length + self.pred_length = pred_length + self.wavelet_name = wavelet_name + self.level = level + self.batch_size = batch_size + self.channel = channel + self.d_model = d_model + self.device = device + self.no_decomposition = no_decomposition + self.use_amp = use_amp + self.eps = 1e-5 + + self.dwt = DWT1DForward(wave=self.wavelet_name, J=self.level, + use_amp=self.use_amp).cuda() if self.device.type == 'cuda' else DWT1DForward( + wave=self.wavelet_name, J=self.level, use_amp=self.use_amp) + self.idwt = DWT1DInverse(wave=self.wavelet_name, + use_amp=self.use_amp).cuda() if self.device.type == 'cuda' else DWT1DInverse( + wave=self.wavelet_name, use_amp=self.use_amp) + + self.input_w_dim = self._dummy_forward(self.input_length) if not self.no_decomposition else [ + self.input_length] # length of the input seq after decompose + self.pred_w_dim = self._dummy_forward(self.pred_length) if not self.no_decomposition else [ + self.pred_length] # required length of the pred seq after decom + + self.tfactor = tfactor + self.dfactor = dfactor + ################################# + self.affine = False + ################################# + + if self.affine: + self._init_params() + + def transform(self, x): + # input: x shape: batch, channel, seq + if not self.no_decomposition: + yl, yh = self._wavelet_decompose(x) + else: + yl, yh = x, [] # no decompose: returning the same value in yl + return yl, yh + + def inv_transform(self, yl, yh): + if not self.no_decomposition: + x = self._wavelet_reverse_decompose(yl, yh) + else: + x = yl # no decompose: returning the same value in x + return x + + def _dummy_forward(self, input_length): + dummy_x = torch.ones((self.batch_size, self.channel, input_length)).to(self.device) + yl, yh = self.dwt(dummy_x) + l = [] + l.append(yl.shape[-1]) + for i in range(len(yh)): + l.append(yh[i].shape[-1]) + return l + + def _init_params(self): + self.affine_weight = nn.Parameter(torch.ones((self.level + 1, self.channel))) + self.affine_bias = nn.Parameter(torch.zeros((self.level + 1, self.channel))) + + def _wavelet_decompose(self, x): + # input: x shape: batch, channel, seq + yl, yh = self.dwt(x) + + if self.affine: + yl = yl.transpose(1, 2) # batch, seq, channel + yl = yl * self.affine_weight[0] + yl = yl + self.affine_bias[0] + yl = yl.transpose(1, 2) # batch, channel, seq + for i in range(self.level): + yh_ = yh[i].transpose(1, 2) # batch, seq, channel + yh_ = yh_ * self.affine_weight[i + 1] + yh_ = yh_ + self.affine_bias[i + 1] + yh[i] = yh_.transpose(1, 2) # batch, channel, seq + + return yl, yh + + def _wavelet_reverse_decompose(self, yl, yh): + if self.affine: + yl = yl.transpose(1, 2) # batch, seq, channel + yl = yl - self.affine_bias[0] + yl = yl / (self.affine_weight[0] + self.eps) + yl = yl.transpose(1, 2) # batch, channel, seq + for i in range(self.level): + yh_ = yh[i].transpose(1, 2) # batch, seq, channel + yh_ = yh_ - self.affine_bias[i + 1] + yh_ = yh_ / (self.affine_weight[i + 1] + self.eps) + yh[i] = yh_.transpose(1, 2) # batch, channel, seq + + x = self.idwt((yl, yh)) + return x # shape: batch, channel, seq + + +############################################################################################### +""" +Following codes are combined from https://github.com/fbcotter/pytorch_wavelets. +To use Wavelet decomposition, you do not need to modify any of the codes below this line, +we can just play with the class Decomposition(above) +""" + + +############################################################################################### + +class DWT1DForward(nn.Module): + """ Performs a 1d DWT Forward decomposition of an image + + Args: + J (int): Number of levels of decomposition + wave (str or pywt.Wavelet or tuple(ndarray)): Which wavelet to use. + Can be: + 1) a string to pass to pywt.Wavelet constructor + 2) a pywt.Wavelet class + 3) a tuple of numpy arrays (h0, h1) + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. The + padding scheme + """ + + def __init__(self, J=1, wave='db1', mode='zero', use_amp=False): + super().__init__() + self.use_amp = use_amp + if isinstance(wave, str): + wave = pywt.Wavelet(wave) + if isinstance(wave, pywt.Wavelet): + h0, h1 = wave.dec_lo, wave.dec_hi + else: + assert len(wave) == 2 + h0, h1 = wave[0], wave[1] + + # Prepare the filters - this makes them into column filters + filts = prep_filt_afb1d(h0, h1) + self.register_buffer('h0', filts[0]) + self.register_buffer('h1', filts[1]) + self.J = J + self.mode = mode + + def forward(self, x): + """ Forward pass of the DWT. + + Args: + x (tensor): Input of shape :math:`(N, C_{in}, L_{in})` + + Returns: + (yl, yh) + tuple of lowpass (yl) and bandpass (yh) coefficients. + yh is a list of length J with the first entry + being the finest scale coefficients. + """ + assert x.ndim == 3, "Can only handle 3d inputs (N, C, L)" + highs = [] + x0 = x + mode = mode_to_int(self.mode) + + # Do a multilevel transform + for j in range(self.J): + x0, x1 = AFB1D.apply(x0, self.h0, self.h1, mode, self.use_amp) + highs.append(x1) + + return x0, highs + + +class DWT1DInverse(nn.Module): + """ Performs a 1d DWT Inverse reconstruction of an image + + Args: + wave (str or pywt.Wavelet or tuple(ndarray)): Which wavelet to use. + Can be: + 1) a string to pass to pywt.Wavelet constructor + 2) a pywt.Wavelet class + 3) a tuple of numpy arrays (h0, h1) + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. The + padding scheme + """ + + def __init__(self, wave='db1', mode='zero', use_amp=False): + super().__init__() + self.use_amp = use_amp + if isinstance(wave, str): + wave = pywt.Wavelet(wave) + if isinstance(wave, pywt.Wavelet): + g0, g1 = wave.rec_lo, wave.rec_hi + else: + assert len(wave) == 2 + g0, g1 = wave[0], wave[1] + + # Prepare the filters + filts = prep_filt_sfb1d(g0, g1) + self.register_buffer('g0', filts[0]) + self.register_buffer('g1', filts[1]) + self.mode = mode + + def forward(self, coeffs): + """ + Args: + coeffs (yl, yh): tuple of lowpass and bandpass coefficients, should + match the format returned by DWT1DForward. + + Returns: + Reconstructed input of shape :math:`(N, C_{in}, L_{in})` + + Note: + Can have None for any of the highpass scales and will treat the + values as zeros (not in an efficient way though). + """ + x0, highs = coeffs + assert x0.ndim == 3, "Can only handle 3d inputs (N, C, L)" + mode = mode_to_int(self.mode) + # Do a multilevel inverse transform + for x1 in highs[::-1]: + if x1 is None: + x1 = torch.zeros_like(x0) + + # 'Unpad' added signal + if x0.shape[-1] > x1.shape[-1]: + x0 = x0[..., :-1] + x0 = SFB1D.apply(x0, x1, self.g0, self.g1, mode, self.use_amp) + return x0 + + +def roll(x, n, dim, make_even=False): + if n < 0: + n = x.shape[dim] + n + + if make_even and x.shape[dim] % 2 == 1: + end = 1 + else: + end = 0 + + if dim == 0: + return torch.cat((x[-n:], x[:-n + end]), dim=0) + elif dim == 1: + return torch.cat((x[:, -n:], x[:, :-n + end]), dim=1) + elif dim == 2 or dim == -2: + return torch.cat((x[:, :, -n:], x[:, :, :-n + end]), dim=2) + elif dim == 3 or dim == -1: + return torch.cat((x[:, :, :, -n:], x[:, :, :, :-n + end]), dim=3) + + +def mypad(x, pad, mode='constant', value=0): + """ Function to do numpy like padding on tensors. Only works for 2-D + padding. + + Inputs: + x (tensor): tensor to pad + pad (tuple): tuple of (left, right, top, bottom) pad sizes + mode (str): 'symmetric', 'wrap', 'constant, 'reflect', 'replicate', or + 'zero'. The padding technique. + """ + if mode == 'symmetric': + # Vertical only + if pad[0] == 0 and pad[1] == 0: + m1, m2 = pad[2], pad[3] + l = x.shape[-2] + xe = reflect(np.arange(-m1, l + m2, dtype='int32'), -0.5, l - 0.5) + return x[:, :, xe] + # horizontal only + elif pad[2] == 0 and pad[3] == 0: + m1, m2 = pad[0], pad[1] + l = x.shape[-1] + xe = reflect(np.arange(-m1, l + m2, dtype='int32'), -0.5, l - 0.5) + return x[:, :, :, xe] + # Both + else: + m1, m2 = pad[0], pad[1] + l1 = x.shape[-1] + xe_row = reflect(np.arange(-m1, l1 + m2, dtype='int32'), -0.5, l1 - 0.5) + m1, m2 = pad[2], pad[3] + l2 = x.shape[-2] + xe_col = reflect(np.arange(-m1, l2 + m2, dtype='int32'), -0.5, l2 - 0.5) + i = np.outer(xe_col, np.ones(xe_row.shape[0])) + j = np.outer(np.ones(xe_col.shape[0]), xe_row) + return x[:, :, i, j] + elif mode == 'periodic': + # Vertical only + if pad[0] == 0 and pad[1] == 0: + xe = np.arange(x.shape[-2]) + xe = np.pad(xe, (pad[2], pad[3]), mode='wrap') + return x[:, :, xe] + # Horizontal only + elif pad[2] == 0 and pad[3] == 0: + xe = np.arange(x.shape[-1]) + xe = np.pad(xe, (pad[0], pad[1]), mode='wrap') + return x[:, :, :, xe] + # Both + else: + xe_col = np.arange(x.shape[-2]) + xe_col = np.pad(xe_col, (pad[2], pad[3]), mode='wrap') + xe_row = np.arange(x.shape[-1]) + xe_row = np.pad(xe_row, (pad[0], pad[1]), mode='wrap') + i = np.outer(xe_col, np.ones(xe_row.shape[0])) + j = np.outer(np.ones(xe_col.shape[0]), xe_row) + return x[:, :, i, j] + + elif mode == 'constant' or mode == 'reflect' or mode == 'replicate': + return F.pad(x, pad, mode, value) + elif mode == 'zero': + return F.pad(x, pad) + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + +def afb1d(x, h0, h1, use_amp, mode='zero', dim=-1): + """ 1D analysis filter bank (along one dimension only) of an image + + Inputs: + x (tensor): 4D input with the last two dimensions the spatial input + h0 (tensor): 4D input for the lowpass filter. Should have shape (1, 1, + h, 1) or (1, 1, 1, w) + h1 (tensor): 4D input for the highpass filter. Should have shape (1, 1, + h, 1) or (1, 1, 1, w) + mode (str): padding method + dim (int) - dimension of filtering. d=2 is for a vertical filter (called + column filtering but filters across the rows). d=3 is for a + horizontal filter, (called row filtering but filters across the + columns). + + Returns: + lohi: lowpass and highpass subbands concatenated along the channel + dimension + """ + C = x.shape[1] + # Convert the dim to positive + d = dim % 4 + s = (2, 1) if d == 2 else (1, 2) + N = x.shape[d] + # If h0, h1 are not tensors, make them. If they are, then assume that they + # are in the right order + if not isinstance(h0, torch.Tensor): + h0 = torch.tensor(np.copy(np.array(h0).ravel()[::-1]), + dtype=torch.float, device=x.device) + if not isinstance(h1, torch.Tensor): + h1 = torch.tensor(np.copy(np.array(h1).ravel()[::-1]), + dtype=torch.float, device=x.device) + L = h0.numel() + L2 = L // 2 + shape = [1, 1, 1, 1] + shape[d] = L + # If h aren't in the right shape, make them so + if h0.shape != tuple(shape): + h0 = h0.reshape(*shape) + if h1.shape != tuple(shape): + h1 = h1.reshape(*shape) + h = torch.cat([h0, h1] * C, dim=0) + + if mode == 'per' or mode == 'periodization': + if x.shape[dim] % 2 == 1: + if d == 2: + x = torch.cat((x, x[:, :, -1:]), dim=2) + else: + x = torch.cat((x, x[:, :, :, -1:]), dim=3) + N += 1 + x = roll(x, -L2, dim=d) + pad = (L - 1, 0) if d == 2 else (0, L - 1) + if use_amp: + with torch.cuda.amp.autocast(): # for mixed precision + lohi = F.conv2d(x, h, padding=pad, stride=s, groups=C) + else: + lohi = F.conv2d(x, h, padding=pad, stride=s, groups=C) + N2 = N // 2 + if d == 2: + lohi[:, :, :L2] = lohi[:, :, :L2] + lohi[:, :, N2:N2 + L2] + lohi = lohi[:, :, :N2] + else: + lohi[:, :, :, :L2] = lohi[:, :, :, :L2] + lohi[:, :, :, N2:N2 + L2] + lohi = lohi[:, :, :, :N2] + else: + # Calculate the pad size + outsize = pywt.dwt_coeff_len(N, L, mode=mode) + p = 2 * (outsize - 1) - N + L + if mode == 'zero': + # Sadly, pytorch only allows for same padding before and after, if + # we need to do more padding after for odd length signals, have to + # prepad + if p % 2 == 1: + pad = (0, 0, 0, 1) if d == 2 else (0, 1, 0, 0) + x = F.pad(x, pad) + pad = (p // 2, 0) if d == 2 else (0, p // 2) + # Calculate the high and lowpass + if use_amp: + with torch.cuda.amp.autocast(): + lohi = F.conv2d(x, h, padding=pad, stride=s, groups=C) + else: + lohi = F.conv2d(x, h, padding=pad, stride=s, groups=C) + elif mode == 'symmetric' or mode == 'reflect' or mode == 'periodic': + pad = (0, 0, p // 2, (p + 1) // 2) if d == 2 else (p // 2, (p + 1) // 2, 0, 0) + x = mypad(x, pad=pad, mode=mode) + if use_amp: + with torch.cuda.amp.autocast(): + lohi = F.conv2d(x, h, stride=s, groups=C) + else: + lohi = F.conv2d(x, h, stride=s, groups=C) + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + return lohi + + +def afb1d_atrous(x, h0, h1, mode='periodic', dim=-1, dilation=1): + """ 1D analysis filter bank (along one dimension only) of an image without + downsampling. Does the a trous algorithm. + + Inputs: + x (tensor): 4D input with the last two dimensions the spatial input + h0 (tensor): 4D input for the lowpass filter. Should have shape (1, 1, + h, 1) or (1, 1, 1, w) + h1 (tensor): 4D input for the highpass filter. Should have shape (1, 1, + h, 1) or (1, 1, 1, w) + mode (str): padding method + dim (int) - dimension of filtering. d=2 is for a vertical filter (called + column filtering but filters across the rows). d=3 is for a + horizontal filter, (called row filtering but filters across the + columns). + dilation (int): dilation factor. Should be a power of 2. + + Returns: + lohi: lowpass and highpass subbands concatenated along the channel + dimension + """ + C = x.shape[1] + # Convert the dim to positive + d = dim % 4 + # If h0, h1 are not tensors, make them. If they are, then assume that they + # are in the right order + if not isinstance(h0, torch.Tensor): + h0 = torch.tensor(np.copy(np.array(h0).ravel()[::-1]), + dtype=torch.float, device=x.device) + if not isinstance(h1, torch.Tensor): + h1 = torch.tensor(np.copy(np.array(h1).ravel()[::-1]), + dtype=torch.float, device=x.device) + L = h0.numel() + shape = [1, 1, 1, 1] + shape[d] = L + # If h aren't in the right shape, make them so + if h0.shape != tuple(shape): + h0 = h0.reshape(*shape) + if h1.shape != tuple(shape): + h1 = h1.reshape(*shape) + h = torch.cat([h0, h1] * C, dim=0) + + # Calculate the pad size + L2 = (L * dilation) // 2 + pad = (0, 0, L2 - dilation, L2) if d == 2 else (L2 - dilation, L2, 0, 0) + x = mypad(x, pad=pad, mode=mode) + lohi = F.conv2d(x, h, groups=C, dilation=dilation) + + return lohi + + +def sfb1d(lo, hi, g0, g1, use_amp, mode='zero', dim=-1): + """ 1D synthesis filter bank of an image tensor + """ + C = lo.shape[1] + d = dim % 4 + # If g0, g1 are not tensors, make them. If they are, then assume that they + # are in the right order + if not isinstance(g0, torch.Tensor): + g0 = torch.tensor(np.copy(np.array(g0).ravel()), + dtype=torch.float, device=lo.device) + if not isinstance(g1, torch.Tensor): + g1 = torch.tensor(np.copy(np.array(g1).ravel()), + dtype=torch.float, device=lo.device) + L = g0.numel() + shape = [1, 1, 1, 1] + shape[d] = L + N = 2 * lo.shape[d] + # If g aren't in the right shape, make them so + if g0.shape != tuple(shape): + g0 = g0.reshape(*shape) + if g1.shape != tuple(shape): + g1 = g1.reshape(*shape) + + s = (2, 1) if d == 2 else (1, 2) + g0 = torch.cat([g0] * C, dim=0) + g1 = torch.cat([g1] * C, dim=0) + if mode == 'per' or mode == 'periodization': + if use_amp: + with torch.cuda.amp.autocast(): + y = F.conv_transpose2d(lo, g0, stride=s, groups=C) + \ + F.conv_transpose2d(hi, g1, stride=s, groups=C) + else: + y = F.conv_transpose2d(lo, g0, stride=s, groups=C) + \ + F.conv_transpose2d(hi, g1, stride=s, groups=C) + if d == 2: + y[:, :, :L - 2] = y[:, :, :L - 2] + y[:, :, N:N + L - 2] + y = y[:, :, :N] + else: + y[:, :, :, :L - 2] = y[:, :, :, :L - 2] + y[:, :, :, N:N + L - 2] + y = y[:, :, :, :N] + y = roll(y, 1 - L // 2, dim=dim) + else: + if mode == 'zero' or mode == 'symmetric' or mode == 'reflect' or \ + mode == 'periodic': + pad = (L - 2, 0) if d == 2 else (0, L - 2) + if use_amp: + with torch.cuda.amp.autocast(): + y = F.conv_transpose2d(lo, g0, stride=s, padding=pad, groups=C) + \ + F.conv_transpose2d(hi, g1, stride=s, padding=pad, groups=C) + else: + y = F.conv_transpose2d(lo, g0, stride=s, padding=pad, groups=C) + \ + F.conv_transpose2d(hi, g1, stride=s, padding=pad, groups=C) + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + return y + + +def mode_to_int(mode): + if mode == 'zero': + return 0 + elif mode == 'symmetric': + return 1 + elif mode == 'per' or mode == 'periodization': + return 2 + elif mode == 'constant': + return 3 + elif mode == 'reflect': + return 4 + elif mode == 'replicate': + return 5 + elif mode == 'periodic': + return 6 + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + +def int_to_mode(mode): + if mode == 0: + return 'zero' + elif mode == 1: + return 'symmetric' + elif mode == 2: + return 'periodization' + elif mode == 3: + return 'constant' + elif mode == 4: + return 'reflect' + elif mode == 5: + return 'replicate' + elif mode == 6: + return 'periodic' + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + +class AFB2D(Function): + """ Does a single level 2d wavelet decomposition of an input. Does separate + row and column filtering by two calls to + :py:func:`pytorch_wavelets.dwt.lowlevel.afb1d` + + Needs to have the tensors in the right form. Because this function defines + its own backward pass, saves on memory by not having to save the input + tensors. + + Inputs: + x (torch.Tensor): Input to decompose + h0_row: row lowpass + h1_row: row highpass + h0_col: col lowpass + h1_col: col highpass + mode (int): use mode_to_int to get the int code here + + We encode the mode as an integer rather than a string as gradcheck causes an + error when a string is provided. + + Returns: + y: Tensor of shape (N, C*4, H, W) + """ + + @staticmethod + def forward(ctx, x, h0_row, h1_row, h0_col, h1_col, mode): + ctx.save_for_backward(h0_row, h1_row, h0_col, h1_col) + ctx.shape = x.shape[-2:] + mode = int_to_mode(mode) + ctx.mode = mode + lohi = afb1d(x, h0_row, h1_row, mode=mode, dim=3) + y = afb1d(lohi, h0_col, h1_col, mode=mode, dim=2) + s = y.shape + y = y.reshape(s[0], -1, 4, s[-2], s[-1]) + low = y[:, :, 0].contiguous() + highs = y[:, :, 1:].contiguous() + return low, highs + + @staticmethod + def backward(ctx, low, highs): + dx = None + if ctx.needs_input_grad[0]: + mode = ctx.mode + h0_row, h1_row, h0_col, h1_col = ctx.saved_tensors + lh, hl, hh = torch.unbind(highs, dim=2) + lo = sfb1d(low, lh, h0_col, h1_col, mode=mode, dim=2) + hi = sfb1d(hl, hh, h0_col, h1_col, mode=mode, dim=2) + dx = sfb1d(lo, hi, h0_row, h1_row, mode=mode, dim=3) + if dx.shape[-2] > ctx.shape[-2] and dx.shape[-1] > ctx.shape[-1]: + dx = dx[:, :, :ctx.shape[-2], :ctx.shape[-1]] + elif dx.shape[-2] > ctx.shape[-2]: + dx = dx[:, :, :ctx.shape[-2]] + elif dx.shape[-1] > ctx.shape[-1]: + dx = dx[:, :, :, :ctx.shape[-1]] + return dx, None, None, None, None, None + + +class AFB1D(Function): + """ Does a single level 1d wavelet decomposition of an input. + + Needs to have the tensors in the right form. Because this function defines + its own backward pass, saves on memory by not having to save the input + tensors. + + Inputs: + x (torch.Tensor): Input to decompose + h0: lowpass + h1: highpass + mode (int): use mode_to_int to get the int code here + + We encode the mode as an integer rather than a string as gradcheck causes an + error when a string is provided. + + Returns: + x0: Tensor of shape (N, C, L') - lowpass + x1: Tensor of shape (N, C, L') - highpass + """ + + @staticmethod + def forward(ctx, x, h0, h1, mode, use_amp): + mode = int_to_mode(mode) + + # Make inputs 4d + x = x[:, :, None, :] + h0 = h0[:, :, None, :] + h1 = h1[:, :, None, :] + + # Save for backwards + ctx.save_for_backward(h0, h1) + ctx.shape = x.shape[3] + ctx.mode = mode + ctx.use_amp = use_amp + + lohi = afb1d(x, h0, h1, use_amp, mode=mode, dim=3) + x0 = lohi[:, ::2, 0].contiguous() + x1 = lohi[:, 1::2, 0].contiguous() + return x0, x1 + + @staticmethod + def backward(ctx, dx0, dx1): + dx = None + if ctx.needs_input_grad[0]: + mode = ctx.mode + h0, h1 = ctx.saved_tensors + use_amp = ctx.use_amp + + # Make grads 4d + dx0 = dx0[:, :, None, :] + dx1 = dx1[:, :, None, :] + + dx = sfb1d(dx0, dx1, h0, h1, use_amp, mode=mode, dim=3)[:, :, 0] + + # Check for odd input + if dx.shape[2] > ctx.shape: + dx = dx[:, :, :ctx.shape] + + return dx, None, None, None, None, None + + +def afb2d(x, filts, mode='zero'): + """ Does a single level 2d wavelet decomposition of an input. Does separate + row and column filtering by two calls to + :py:func:`pytorch_wavelets.dwt.lowlevel.afb1d` + + Inputs: + x (torch.Tensor): Input to decompose + filts (list of ndarray or torch.Tensor): If a list of tensors has been + given, this function assumes they are in the right form (the form + returned by + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_afb2d`). + Otherwise, this function will prepare the filters to be of the right + form by calling + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_afb2d`. + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. Which + padding to use. If periodization, the output size will be half the + input size. Otherwise, the output size will be slightly larger than + half. + + Returns: + y: Tensor of shape (N, C*4, H, W) + """ + tensorize = [not isinstance(f, torch.Tensor) for f in filts] + if len(filts) == 2: + h0, h1 = filts + if True in tensorize: + h0_col, h1_col, h0_row, h1_row = prep_filt_afb2d( + h0, h1, device=x.device) + else: + h0_col = h0 + h0_row = h0.transpose(2, 3) + h1_col = h1 + h1_row = h1.transpose(2, 3) + elif len(filts) == 4: + if True in tensorize: + h0_col, h1_col, h0_row, h1_row = prep_filt_afb2d( + *filts, device=x.device) + else: + h0_col, h1_col, h0_row, h1_row = filts + else: + raise ValueError("Unknown form for input filts") + + lohi = afb1d(x, h0_row, h1_row, mode=mode, dim=3) + y = afb1d(lohi, h0_col, h1_col, mode=mode, dim=2) + + return y + + +def afb2d_atrous(x, filts, mode='periodization', dilation=1): + """ Does a single level 2d wavelet decomposition of an input. Does separate + row and column filtering by two calls to + :py:func:`pytorch_wavelets.dwt.lowlevel.afb1d` + + Inputs: + x (torch.Tensor): Input to decompose + filts (list of ndarray or torch.Tensor): If a list of tensors has been + given, this function assumes they are in the right form (the form + returned by + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_afb2d`). + Otherwise, this function will prepare the filters to be of the right + form by calling + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_afb2d`. + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. Which + padding to use. If periodization, the output size will be half the + input size. Otherwise, the output size will be slightly larger than + half. + dilation (int): dilation factor for the filters. Should be 2**level + + Returns: + y: Tensor of shape (N, C, 4, H, W) + """ + tensorize = [not isinstance(f, torch.Tensor) for f in filts] + if len(filts) == 2: + h0, h1 = filts + if True in tensorize: + h0_col, h1_col, h0_row, h1_row = prep_filt_afb2d( + h0, h1, device=x.device) + else: + h0_col = h0 + h0_row = h0.transpose(2, 3) + h1_col = h1 + h1_row = h1.transpose(2, 3) + elif len(filts) == 4: + if True in tensorize: + h0_col, h1_col, h0_row, h1_row = prep_filt_afb2d( + *filts, device=x.device) + else: + h0_col, h1_col, h0_row, h1_row = filts + else: + raise ValueError("Unknown form for input filts") + + lohi = afb1d_atrous(x, h0_row, h1_row, mode=mode, dim=3, dilation=dilation) + y = afb1d_atrous(lohi, h0_col, h1_col, mode=mode, dim=2, dilation=dilation) + + return y + + +def afb2d_nonsep(x, filts, mode='zero'): + """ Does a 1 level 2d wavelet decomposition of an input. Doesn't do separate + row and column filtering. + + Inputs: + x (torch.Tensor): Input to decompose + filts (list or torch.Tensor): If a list is given, should be the low and + highpass filter banks. If a tensor is given, it should be of the + form created by + :py:func:`pytorch_wavelets.dwt.lowlevel.prep_filt_afb2d_nonsep` + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. Which + padding to use. If periodization, the output size will be half the + input size. Otherwise, the output size will be slightly larger than + half. + + Returns: + y: Tensor of shape (N, C, 4, H, W) + """ + C = x.shape[1] + Ny = x.shape[2] + Nx = x.shape[3] + + # Check the filter inputs + if isinstance(filts, (tuple, list)): + if len(filts) == 2: + filts = prep_filt_afb2d_nonsep(filts[0], filts[1], device=x.device) + else: + filts = prep_filt_afb2d_nonsep( + filts[0], filts[1], filts[2], filts[3], device=x.device) + f = torch.cat([filts] * C, dim=0) + Ly = f.shape[2] + Lx = f.shape[3] + + if mode == 'periodization' or mode == 'per': + if x.shape[2] % 2 == 1: + x = torch.cat((x, x[:, :, -1:]), dim=2) + Ny += 1 + if x.shape[3] % 2 == 1: + x = torch.cat((x, x[:, :, :, -1:]), dim=3) + Nx += 1 + pad = (Ly - 1, Lx - 1) + stride = (2, 2) + x = roll(roll(x, -Ly // 2, dim=2), -Lx // 2, dim=3) + y = F.conv2d(x, f, padding=pad, stride=stride, groups=C) + y[:, :, :Ly // 2] += y[:, :, Ny // 2:Ny // 2 + Ly // 2] + y[:, :, :, :Lx // 2] += y[:, :, :, Nx // 2:Nx // 2 + Lx // 2] + y = y[:, :, :Ny // 2, :Nx // 2] + elif mode == 'zero' or mode == 'symmetric' or mode == 'reflect': + # Calculate the pad size + out1 = pywt.dwt_coeff_len(Ny, Ly, mode=mode) + out2 = pywt.dwt_coeff_len(Nx, Lx, mode=mode) + p1 = 2 * (out1 - 1) - Ny + Ly + p2 = 2 * (out2 - 1) - Nx + Lx + if mode == 'zero': + # Sadly, pytorch only allows for same padding before and after, if + # we need to do more padding after for odd length signals, have to + # prepad + if p1 % 2 == 1 and p2 % 2 == 1: + x = F.pad(x, (0, 1, 0, 1)) + elif p1 % 2 == 1: + x = F.pad(x, (0, 0, 0, 1)) + elif p2 % 2 == 1: + x = F.pad(x, (0, 1, 0, 0)) + # Calculate the high and lowpass + y = F.conv2d( + x, f, padding=(p1 // 2, p2 // 2), stride=2, groups=C) + elif mode == 'symmetric' or mode == 'reflect' or mode == 'periodic': + pad = (p2 // 2, (p2 + 1) // 2, p1 // 2, (p1 + 1) // 2) + x = mypad(x, pad=pad, mode=mode) + y = F.conv2d(x, f, stride=2, groups=C) + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + return y + + +def sfb2d(ll, lh, hl, hh, filts, mode='zero'): + """ Does a single level 2d wavelet reconstruction of wavelet coefficients. + Does separate row and column filtering by two calls to + :py:func:`pytorch_wavelets.dwt.lowlevel.sfb1d` + + Inputs: + ll (torch.Tensor): lowpass coefficients + lh (torch.Tensor): horizontal coefficients + hl (torch.Tensor): vertical coefficients + hh (torch.Tensor): diagonal coefficients + filts (list of ndarray or torch.Tensor): If a list of tensors has been + given, this function assumes they are in the right form (the form + returned by + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_sfb2d`). + Otherwise, this function will prepare the filters to be of the right + form by calling + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_sfb2d`. + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. Which + padding to use. If periodization, the output size will be half the + input size. Otherwise, the output size will be slightly larger than + half. + """ + tensorize = [not isinstance(x, torch.Tensor) for x in filts] + if len(filts) == 2: + g0, g1 = filts + if True in tensorize: + g0_col, g1_col, g0_row, g1_row = prep_filt_sfb2d(g0, g1) + else: + g0_col = g0 + g0_row = g0.transpose(2, 3) + g1_col = g1 + g1_row = g1.transpose(2, 3) + elif len(filts) == 4: + if True in tensorize: + g0_col, g1_col, g0_row, g1_row = prep_filt_sfb2d(*filts) + else: + g0_col, g1_col, g0_row, g1_row = filts + else: + raise ValueError("Unknown form for input filts") + + lo = sfb1d(ll, lh, g0_col, g1_col, mode=mode, dim=2) + hi = sfb1d(hl, hh, g0_col, g1_col, mode=mode, dim=2) + y = sfb1d(lo, hi, g0_row, g1_row, mode=mode, dim=3) + + return y + + +class SFB2D(Function): + """ Does a single level 2d wavelet decomposition of an input. Does separate + row and column filtering by two calls to + :py:func:`pytorch_wavelets.dwt.lowlevel.afb1d` + + Needs to have the tensors in the right form. Because this function defines + its own backward pass, saves on memory by not having to save the input + tensors. + + Inputs: + x (torch.Tensor): Input to decompose + h0_row: row lowpass + h1_row: row highpass + h0_col: col lowpass + h1_col: col highpass + mode (int): use mode_to_int to get the int code here + + We encode the mode as an integer rather than a string as gradcheck causes an + error when a string is provided. + + Returns: + y: Tensor of shape (N, C*4, H, W) + """ + + @staticmethod + def forward(ctx, low, highs, g0_row, g1_row, g0_col, g1_col, mode): + mode = int_to_mode(mode) + ctx.mode = mode + ctx.save_for_backward(g0_row, g1_row, g0_col, g1_col) + + lh, hl, hh = torch.unbind(highs, dim=2) + lo = sfb1d(low, lh, g0_col, g1_col, mode=mode, dim=2) + hi = sfb1d(hl, hh, g0_col, g1_col, mode=mode, dim=2) + y = sfb1d(lo, hi, g0_row, g1_row, mode=mode, dim=3) + return y + + @staticmethod + def backward(ctx, dy): + dlow, dhigh = None, None + if ctx.needs_input_grad[0]: + mode = ctx.mode + g0_row, g1_row, g0_col, g1_col = ctx.saved_tensors + dx = afb1d(dy, g0_row, g1_row, mode=mode, dim=3) + dx = afb1d(dx, g0_col, g1_col, mode=mode, dim=2) + s = dx.shape + dx = dx.reshape(s[0], -1, 4, s[-2], s[-1]) + dlow = dx[:, :, 0].contiguous() + dhigh = dx[:, :, 1:].contiguous() + return dlow, dhigh, None, None, None, None, None + + +class SFB1D(Function): + """ Does a single level 1d wavelet decomposition of an input. + + Needs to have the tensors in the right form. Because this function defines + its own backward pass, saves on memory by not having to save the input + tensors. + + Inputs: + low (torch.Tensor): Lowpass to reconstruct of shape (N, C, L) + high (torch.Tensor): Highpass to reconstruct of shape (N, C, L) + g0: lowpass + g1: highpass + mode (int): use mode_to_int to get the int code here + + We encode the mode as an integer rather than a string as gradcheck causes an + error when a string is provided. + + Returns: + y: Tensor of shape (N, C*2, L') + """ + + @staticmethod + def forward(ctx, low, high, g0, g1, mode, use_amp): + mode = int_to_mode(mode) + # Make into a 2d tensor with 1 row + low = low[:, :, None, :] + high = high[:, :, None, :] + g0 = g0[:, :, None, :] + g1 = g1[:, :, None, :] + + ctx.mode = mode + ctx.save_for_backward(g0, g1) + ctx.use_amp = use_amp + + return sfb1d(low, high, g0, g1, use_amp, mode=mode, dim=3)[:, :, 0] + + @staticmethod + def backward(ctx, dy): + dlow, dhigh = None, None + if ctx.needs_input_grad[0]: + mode = ctx.mode + use_amp = ctx.use_amp + g0, g1, = ctx.saved_tensors + dy = dy[:, :, None, :] + + dx = afb1d(dy, g0, g1, use_amp, mode=mode, dim=3) + + dlow = dx[:, ::2, 0].contiguous() + dhigh = dx[:, 1::2, 0].contiguous() + return dlow, dhigh, None, None, None, None, None + + +def sfb2d_nonsep(coeffs, filts, mode='zero'): + """ Does a single level 2d wavelet reconstruction of wavelet coefficients. + Does not do separable filtering. + + Inputs: + coeffs (torch.Tensor): tensor of coefficients of shape (N, C, 4, H, W) + where the third dimension indexes across the (ll, lh, hl, hh) bands. + filts (list of ndarray or torch.Tensor): If a list of tensors has been + given, this function assumes they are in the right form (the form + returned by + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_sfb2d_nonsep`). + Otherwise, this function will prepare the filters to be of the right + form by calling + :py:func:`~pytorch_wavelets.dwt.lowlevel.prep_filt_sfb2d_nonsep`. + mode (str): 'zero', 'symmetric', 'reflect' or 'periodization'. Which + padding to use. If periodization, the output size will be half the + input size. Otherwise, the output size will be slightly larger than + half. + """ + C = coeffs.shape[1] + Ny = coeffs.shape[-2] + Nx = coeffs.shape[-1] + + # Check the filter inputs - should be in the form of a torch tensor, but if + # not, tensorize it here. + if isinstance(filts, (tuple, list)): + if len(filts) == 2: + filts = prep_filt_sfb2d_nonsep(filts[0], filts[1], + device=coeffs.device) + elif len(filts) == 4: + filts = prep_filt_sfb2d_nonsep( + filts[0], filts[1], filts[2], filts[3], device=coeffs.device) + else: + raise ValueError("Unkown form for input filts") + f = torch.cat([filts] * C, dim=0) + Ly = f.shape[2] + Lx = f.shape[3] + + x = coeffs.reshape(coeffs.shape[0], -1, coeffs.shape[-2], coeffs.shape[-1]) + if mode == 'periodization' or mode == 'per': + ll = F.conv_transpose2d(x, f, groups=C, stride=2) + ll[:, :, :Ly - 2] += ll[:, :, 2 * Ny:2 * Ny + Ly - 2] + ll[:, :, :, :Lx - 2] += ll[:, :, :, 2 * Nx:2 * Nx + Lx - 2] + ll = ll[:, :, :2 * Ny, :2 * Nx] + ll = roll(roll(ll, 1 - Ly // 2, dim=2), 1 - Lx // 2, dim=3) + elif mode == 'symmetric' or mode == 'zero' or mode == 'reflect' or \ + mode == 'periodic': + pad = (Ly - 2, Lx - 2) + ll = F.conv_transpose2d(x, f, padding=pad, groups=C, stride=2) + else: + raise ValueError("Unkown pad type: {}".format(mode)) + + return ll.contiguous() + + +def prep_filt_afb2d_nonsep(h0_col, h1_col, h0_row=None, h1_row=None, + device=None): + """ + Prepares the filters to be of the right form for the afb2d_nonsep function. + In particular, makes 2d point spread functions, and mirror images them in + preparation to do torch.conv2d. + + Inputs: + h0_col (array-like): low pass column filter bank + h1_col (array-like): high pass column filter bank + h0_row (array-like): low pass row filter bank. If none, will assume the + same as column filter + h1_row (array-like): high pass row filter bank. If none, will assume the + same as column filter + device: which device to put the tensors on to + + Returns: + filts: (4, 1, h, w) tensor ready to get the four subbands + """ + h0_col = np.array(h0_col).ravel() + h1_col = np.array(h1_col).ravel() + if h0_row is None: + h0_row = h0_col + if h1_row is None: + h1_row = h1_col + ll = np.outer(h0_col, h0_row) + lh = np.outer(h1_col, h0_row) + hl = np.outer(h0_col, h1_row) + hh = np.outer(h1_col, h1_row) + filts = np.stack([ll[None, ::-1, ::-1], lh[None, ::-1, ::-1], + hl[None, ::-1, ::-1], hh[None, ::-1, ::-1]], axis=0) + filts = torch.tensor(filts, dtype=torch.get_default_dtype(), device=device) + return filts + + +def prep_filt_sfb2d_nonsep(g0_col, g1_col, g0_row=None, g1_row=None, + device=None): + """ + Prepares the filters to be of the right form for the sfb2d_nonsep function. + In particular, makes 2d point spread functions. Does not mirror image them + as sfb2d_nonsep uses conv2d_transpose which acts like normal convolution. + + Inputs: + g0_col (array-like): low pass column filter bank + g1_col (array-like): high pass column filter bank + g0_row (array-like): low pass row filter bank. If none, will assume the + same as column filter + g1_row (array-like): high pass row filter bank. If none, will assume the + same as column filter + device: which device to put the tensors on to + + Returns: + filts: (4, 1, h, w) tensor ready to combine the four subbands + """ + g0_col = np.array(g0_col).ravel() + g1_col = np.array(g1_col).ravel() + if g0_row is None: + g0_row = g0_col + if g1_row is None: + g1_row = g1_col + ll = np.outer(g0_col, g0_row) + lh = np.outer(g1_col, g0_row) + hl = np.outer(g0_col, g1_row) + hh = np.outer(g1_col, g1_row) + filts = np.stack([ll[None], lh[None], hl[None], hh[None]], axis=0) + filts = torch.tensor(filts, dtype=torch.get_default_dtype(), device=device) + return filts + + +def prep_filt_sfb2d(g0_col, g1_col, g0_row=None, g1_row=None, device=None): + """ + Prepares the filters to be of the right form for the sfb2d function. In + particular, makes the tensors the right shape. It does not mirror image them + as as sfb2d uses conv2d_transpose which acts like normal convolution. + + Inputs: + g0_col (array-like): low pass column filter bank + g1_col (array-like): high pass column filter bank + g0_row (array-like): low pass row filter bank. If none, will assume the + same as column filter + g1_row (array-like): high pass row filter bank. If none, will assume the + same as column filter + device: which device to put the tensors on to + + Returns: + (g0_col, g1_col, g0_row, g1_row) + """ + g0_col, g1_col = prep_filt_sfb1d(g0_col, g1_col, device) + if g0_row is None: + g0_row, g1_row = g0_col, g1_col + else: + g0_row, g1_row = prep_filt_sfb1d(g0_row, g1_row, device) + + g0_col = g0_col.reshape((1, 1, -1, 1)) + g1_col = g1_col.reshape((1, 1, -1, 1)) + g0_row = g0_row.reshape((1, 1, 1, -1)) + g1_row = g1_row.reshape((1, 1, 1, -1)) + + return g0_col, g1_col, g0_row, g1_row + + +def prep_filt_sfb1d(g0, g1, device=None): + """ + Prepares the filters to be of the right form for the sfb1d function. In + particular, makes the tensors the right shape. It does not mirror image them + as as sfb2d uses conv2d_transpose which acts like normal convolution. + + Inputs: + g0 (array-like): low pass filter bank + g1 (array-like): high pass filter bank + device: which device to put the tensors on to + + Returns: + (g0, g1) + """ + g0 = np.array(g0).ravel() + g1 = np.array(g1).ravel() + t = torch.get_default_dtype() + g0 = torch.tensor(g0, device=device, dtype=t).reshape((1, 1, -1)) + g1 = torch.tensor(g1, device=device, dtype=t).reshape((1, 1, -1)) + + return g0, g1 + + +def prep_filt_afb2d(h0_col, h1_col, h0_row=None, h1_row=None, device=None): + """ + Prepares the filters to be of the right form for the afb2d function. In + particular, makes the tensors the right shape. It takes mirror images of + them as as afb2d uses conv2d which acts like normal correlation. + + Inputs: + h0_col (array-like): low pass column filter bank + h1_col (array-like): high pass column filter bank + h0_row (array-like): low pass row filter bank. If none, will assume the + same as column filter + h1_row (array-like): high pass row filter bank. If none, will assume the + same as column filter + device: which device to put the tensors on to + + Returns: + (h0_col, h1_col, h0_row, h1_row) + """ + h0_col, h1_col = prep_filt_afb1d(h0_col, h1_col, device) + if h0_row is None: + h0_row, h1_row = h0_col, h1_col + else: + h0_row, h1_row = prep_filt_afb1d(h0_row, h1_row, device) + + h0_col = h0_col.reshape((1, 1, -1, 1)) + h1_col = h1_col.reshape((1, 1, -1, 1)) + h0_row = h0_row.reshape((1, 1, 1, -1)) + h1_row = h1_row.reshape((1, 1, 1, -1)) + return h0_col, h1_col, h0_row, h1_row + + +def prep_filt_afb1d(h0, h1, device=None): + """ + Prepares the filters to be of the right form for the afb2d function. In + particular, makes the tensors the right shape. It takes mirror images of + them as as afb2d uses conv2d which acts like normal correlation. + + Inputs: + h0 (array-like): low pass column filter bank + h1 (array-like): high pass column filter bank + device: which device to put the tensors on to + + Returns: + (h0, h1) + """ + h0 = np.array(h0[::-1]).ravel() + h1 = np.array(h1[::-1]).ravel() + t = torch.get_default_dtype() + h0 = torch.tensor(h0, device=device, dtype=t).reshape((1, 1, -1)) + h1 = torch.tensor(h1, device=device, dtype=t).reshape((1, 1, -1)) + return h0, h1 + + +def reflect(x, minx, maxx): + """Reflect the values in matrix *x* about the scalar values *minx* and + *maxx*. Hence a vector *x* containing a long linearly increasing series is + converted into a waveform which ramps linearly up and down between *minx* + and *maxx*. If *x* contains integers and *minx* and *maxx* are (integers + + 0.5), the ramps will have repeated max and min samples. + + .. codeauthor:: Rich Wareham , Aug 2013 + .. codeauthor:: Nick Kingsbury, Cambridge University, January 1999. + + """ + x = np.asanyarray(x) + rng = maxx - minx + rng_by_2 = 2 * rng + mod = np.fmod(x - minx, rng_by_2) + normed_mod = np.where(mod < 0, mod + rng_by_2, mod) + out = np.where(normed_mod >= rng, rng_by_2 - normed_mod, normed_mod) + minx + return np.array(out, dtype=x.dtype) \ No newline at end of file diff --git a/layers/EMA.py b/layers/EMA.py new file mode 100644 index 0000000..577dd5e --- /dev/null +++ b/layers/EMA.py @@ -0,0 +1,23 @@ +import torch +from torch import nn + +class EMA(nn.Module): + """ + Exponential Moving Average (EMA) block to highlight the trend of time series + """ + def __init__(self, alpha): + super(EMA, self).__init__() + self.alpha = alpha + + def forward(self, x): + # x: [Batch, Input, Channel] + _, t, _ = x.shape + powers = torch.flip(torch.arange(t, dtype=torch.double), dims=(0,)) + weights = torch.pow((1 - self.alpha), powers).to(x.device) + divisor = weights.clone() + weights[1:] = weights[1:] * self.alpha + weights = weights.reshape(1, t, 1) + divisor = divisor.reshape(1, t, 1) + x = torch.cumsum(x * weights, dim=1) + x = torch.div(x, divisor) + return x.to(torch.float32) \ No newline at end of file diff --git a/layers/ETSformer_EncDec.py b/layers/ETSformer_EncDec.py new file mode 100644 index 0000000..a3c41ba --- /dev/null +++ b/layers/ETSformer_EncDec.py @@ -0,0 +1,334 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.fft as fft +from einops import rearrange, reduce, repeat +import math, random +from scipy.fftpack import next_fast_len + + +class Transform: + def __init__(self, sigma): + self.sigma = sigma + + @torch.no_grad() + def transform(self, x): + return self.jitter(self.shift(self.scale(x))) + + def jitter(self, x): + return x + (torch.randn(x.shape).to(x.device) * self.sigma) + + def scale(self, x): + return x * (torch.randn(x.size(-1)).to(x.device) * self.sigma + 1) + + def shift(self, x): + return x + (torch.randn(x.size(-1)).to(x.device) * self.sigma) + + +def conv1d_fft(f, g, dim=-1): + N = f.size(dim) + M = g.size(dim) + + fast_len = next_fast_len(N + M - 1) + + F_f = fft.rfft(f, fast_len, dim=dim) + F_g = fft.rfft(g, fast_len, dim=dim) + + F_fg = F_f * F_g.conj() + out = fft.irfft(F_fg, fast_len, dim=dim) + out = out.roll((-1,), dims=(dim,)) + idx = torch.as_tensor(range(fast_len - N, fast_len)).to(out.device) + out = out.index_select(dim, idx) + + return out + + +class ExponentialSmoothing(nn.Module): + + def __init__(self, dim, nhead, dropout=0.1, aux=False): + super().__init__() + self._smoothing_weight = nn.Parameter(torch.randn(nhead, 1)) + self.v0 = nn.Parameter(torch.randn(1, 1, nhead, dim)) + self.dropout = nn.Dropout(dropout) + if aux: + self.aux_dropout = nn.Dropout(dropout) + + def forward(self, values, aux_values=None): + b, t, h, d = values.shape + + init_weight, weight = self.get_exponential_weight(t) + output = conv1d_fft(self.dropout(values), weight, dim=1) + output = init_weight * self.v0 + output + + if aux_values is not None: + aux_weight = weight / (1 - self.weight) * self.weight + aux_output = conv1d_fft(self.aux_dropout(aux_values), aux_weight) + output = output + aux_output + + return output + + def get_exponential_weight(self, T): + # Generate array [0, 1, ..., T-1] + powers = torch.arange(T, dtype=torch.float, device=self.weight.device) + + # (1 - \alpha) * \alpha^t, for all t = T-1, T-2, ..., 0] + weight = (1 - self.weight) * (self.weight ** torch.flip(powers, dims=(0,))) + + # \alpha^t for all t = 1, 2, ..., T + init_weight = self.weight ** (powers + 1) + + return rearrange(init_weight, 'h t -> 1 t h 1'), \ + rearrange(weight, 'h t -> 1 t h 1') + + @property + def weight(self): + return torch.sigmoid(self._smoothing_weight) + + +class Feedforward(nn.Module): + def __init__(self, d_model, dim_feedforward, dropout=0.1, activation='sigmoid'): + # Implementation of Feedforward model + super().__init__() + self.linear1 = nn.Linear(d_model, dim_feedforward, bias=False) + self.dropout1 = nn.Dropout(dropout) + self.linear2 = nn.Linear(dim_feedforward, d_model, bias=False) + self.dropout2 = nn.Dropout(dropout) + self.activation = getattr(F, activation) + + def forward(self, x): + x = self.linear2(self.dropout1(self.activation(self.linear1(x)))) + return self.dropout2(x) + + +class GrowthLayer(nn.Module): + + def __init__(self, d_model, nhead, d_head=None, dropout=0.1): + super().__init__() + self.d_head = d_head or (d_model // nhead) + self.d_model = d_model + self.nhead = nhead + + self.z0 = nn.Parameter(torch.randn(self.nhead, self.d_head)) + self.in_proj = nn.Linear(self.d_model, self.d_head * self.nhead) + self.es = ExponentialSmoothing(self.d_head, self.nhead, dropout=dropout) + self.out_proj = nn.Linear(self.d_head * self.nhead, self.d_model) + + assert self.d_head * self.nhead == self.d_model, "d_model must be divisible by nhead" + + def forward(self, inputs): + """ + :param inputs: shape: (batch, seq_len, dim) + :return: shape: (batch, seq_len, dim) + """ + b, t, d = inputs.shape + values = self.in_proj(inputs).view(b, t, self.nhead, -1) + values = torch.cat([repeat(self.z0, 'h d -> b 1 h d', b=b), values], dim=1) + values = values[:, 1:] - values[:, :-1] + out = self.es(values) + out = torch.cat([repeat(self.es.v0, '1 1 h d -> b 1 h d', b=b), out], dim=1) + out = rearrange(out, 'b t h d -> b t (h d)') + return self.out_proj(out) + + +class FourierLayer(nn.Module): + + def __init__(self, d_model, pred_len, k=None, low_freq=1): + super().__init__() + self.d_model = d_model + self.pred_len = pred_len + self.k = k + self.low_freq = low_freq + + def forward(self, x): + """x: (b, t, d)""" + b, t, d = x.shape + x_freq = fft.rfft(x, dim=1) + + if t % 2 == 0: + x_freq = x_freq[:, self.low_freq:-1] + f = fft.rfftfreq(t)[self.low_freq:-1] + else: + x_freq = x_freq[:, self.low_freq:] + f = fft.rfftfreq(t)[self.low_freq:] + + x_freq, index_tuple = self.topk_freq(x_freq) + f = repeat(f, 'f -> b f d', b=x_freq.size(0), d=x_freq.size(2)) + f = rearrange(f[index_tuple], 'b f d -> b f () d').to(x_freq.device) + + return self.extrapolate(x_freq, f, t) + + def extrapolate(self, x_freq, f, t): + x_freq = torch.cat([x_freq, x_freq.conj()], dim=1) + f = torch.cat([f, -f], dim=1) + t_val = rearrange(torch.arange(t + self.pred_len, dtype=torch.float), + 't -> () () t ()').to(x_freq.device) + + amp = rearrange(x_freq.abs() / t, 'b f d -> b f () d') + phase = rearrange(x_freq.angle(), 'b f d -> b f () d') + + x_time = amp * torch.cos(2 * math.pi * f * t_val + phase) + + return reduce(x_time, 'b f t d -> b t d', 'sum') + + def topk_freq(self, x_freq): + values, indices = torch.topk(x_freq.abs(), self.k, dim=1, largest=True, sorted=True) + mesh_a, mesh_b = torch.meshgrid(torch.arange(x_freq.size(0)), torch.arange(x_freq.size(2))) + index_tuple = (mesh_a.unsqueeze(1).to(indices.device), indices, mesh_b.unsqueeze(1).to(indices.device)) + x_freq = x_freq[index_tuple] + + return x_freq, index_tuple + + +class LevelLayer(nn.Module): + + def __init__(self, d_model, c_out, dropout=0.1): + super().__init__() + self.d_model = d_model + self.c_out = c_out + + self.es = ExponentialSmoothing(1, self.c_out, dropout=dropout, aux=True) + self.growth_pred = nn.Linear(self.d_model, self.c_out) + self.season_pred = nn.Linear(self.d_model, self.c_out) + + def forward(self, level, growth, season): + b, t, _ = level.shape + growth = self.growth_pred(growth).view(b, t, self.c_out, 1) + season = self.season_pred(season).view(b, t, self.c_out, 1) + growth = growth.view(b, t, self.c_out, 1) + season = season.view(b, t, self.c_out, 1) + level = level.view(b, t, self.c_out, 1) + out = self.es(level - season, aux_values=growth) + out = rearrange(out, 'b t h d -> b t (h d)') + return out + + +class EncoderLayer(nn.Module): + + def __init__(self, d_model, nhead, c_out, seq_len, pred_len, k, dim_feedforward=None, dropout=0.1, + activation='sigmoid', layer_norm_eps=1e-5): + super().__init__() + self.d_model = d_model + self.nhead = nhead + self.c_out = c_out + self.seq_len = seq_len + self.pred_len = pred_len + dim_feedforward = dim_feedforward or 4 * d_model + self.dim_feedforward = dim_feedforward + + self.growth_layer = GrowthLayer(d_model, nhead, dropout=dropout) + self.seasonal_layer = FourierLayer(d_model, pred_len, k=k) + self.level_layer = LevelLayer(d_model, c_out, dropout=dropout) + + # Implementation of Feedforward model + self.ff = Feedforward(d_model, dim_feedforward, dropout=dropout, activation=activation) + self.norm1 = nn.LayerNorm(d_model, eps=layer_norm_eps) + self.norm2 = nn.LayerNorm(d_model, eps=layer_norm_eps) + + self.dropout1 = nn.Dropout(dropout) + self.dropout2 = nn.Dropout(dropout) + + def forward(self, res, level, attn_mask=None): + season = self._season_block(res) + res = res - season[:, :-self.pred_len] + growth = self._growth_block(res) + res = self.norm1(res - growth[:, 1:]) + res = self.norm2(res + self.ff(res)) + + level = self.level_layer(level, growth[:, :-1], season[:, :-self.pred_len]) + return res, level, growth, season + + def _growth_block(self, x): + x = self.growth_layer(x) + return self.dropout1(x) + + def _season_block(self, x): + x = self.seasonal_layer(x) + return self.dropout2(x) + + +class Encoder(nn.Module): + + def __init__(self, layers): + super().__init__() + self.layers = nn.ModuleList(layers) + + def forward(self, res, level, attn_mask=None): + growths = [] + seasons = [] + for layer in self.layers: + res, level, growth, season = layer(res, level, attn_mask=None) + growths.append(growth) + seasons.append(season) + + return level, growths, seasons + + +class DampingLayer(nn.Module): + + def __init__(self, pred_len, nhead, dropout=0.1): + super().__init__() + self.pred_len = pred_len + self.nhead = nhead + self._damping_factor = nn.Parameter(torch.randn(1, nhead)) + self.dropout = nn.Dropout(dropout) + + def forward(self, x): + x = repeat(x, 'b 1 d -> b t d', t=self.pred_len) + b, t, d = x.shape + + powers = torch.arange(self.pred_len).to(self._damping_factor.device) + 1 + powers = powers.view(self.pred_len, 1) + damping_factors = self.damping_factor ** powers + damping_factors = damping_factors.cumsum(dim=0) + x = x.view(b, t, self.nhead, -1) + x = self.dropout(x) * damping_factors.unsqueeze(-1) + return x.view(b, t, d) + + @property + def damping_factor(self): + return torch.sigmoid(self._damping_factor) + + +class DecoderLayer(nn.Module): + + def __init__(self, d_model, nhead, c_out, pred_len, dropout=0.1): + super().__init__() + self.d_model = d_model + self.nhead = nhead + self.c_out = c_out + self.pred_len = pred_len + + self.growth_damping = DampingLayer(pred_len, nhead, dropout=dropout) + self.dropout1 = nn.Dropout(dropout) + + def forward(self, growth, season): + growth_horizon = self.growth_damping(growth[:, -1:]) + growth_horizon = self.dropout1(growth_horizon) + + seasonal_horizon = season[:, -self.pred_len:] + return growth_horizon, seasonal_horizon + + +class Decoder(nn.Module): + + def __init__(self, layers): + super().__init__() + self.d_model = layers[0].d_model + self.c_out = layers[0].c_out + self.pred_len = layers[0].pred_len + self.nhead = layers[0].nhead + + self.layers = nn.ModuleList(layers) + self.pred = nn.Linear(self.d_model, self.c_out) + + def forward(self, growths, seasons): + growth_repr = [] + season_repr = [] + + for idx, layer in enumerate(self.layers): + growth_horizon, season_horizon = layer(growths[idx], seasons[idx]) + growth_repr.append(growth_horizon) + season_repr.append(season_horizon) + growth_repr = sum(growth_repr) + season_repr = sum(season_repr) + return self.pred(growth_repr), self.pred(season_repr) diff --git a/layers/Embed.py b/layers/Embed.py new file mode 100644 index 0000000..977e255 --- /dev/null +++ b/layers/Embed.py @@ -0,0 +1,190 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torch.nn.utils import weight_norm +import math + + +class PositionalEmbedding(nn.Module): + def __init__(self, d_model, max_len=5000): + super(PositionalEmbedding, self).__init__() + # Compute the positional encodings once in log space. + pe = torch.zeros(max_len, d_model).float() + pe.require_grad = False + + position = torch.arange(0, max_len).float().unsqueeze(1) + div_term = (torch.arange(0, d_model, 2).float() + * -(math.log(10000.0) / d_model)).exp() + + pe[:, 0::2] = torch.sin(position * div_term) + pe[:, 1::2] = torch.cos(position * div_term) + + pe = pe.unsqueeze(0) + self.register_buffer('pe', pe) + + def forward(self, x): + return self.pe[:, :x.size(1)] + + +class TokenEmbedding(nn.Module): + def __init__(self, c_in, d_model): + super(TokenEmbedding, self).__init__() + padding = 1 if torch.__version__ >= '1.5.0' else 2 + self.tokenConv = nn.Conv1d(in_channels=c_in, out_channels=d_model, + kernel_size=3, padding=padding, padding_mode='circular', bias=False) + for m in self.modules(): + if isinstance(m, nn.Conv1d): + nn.init.kaiming_normal_( + m.weight, mode='fan_in', nonlinearity='leaky_relu') + + def forward(self, x): + x = self.tokenConv(x.permute(0, 2, 1)).transpose(1, 2) + return x + + +class FixedEmbedding(nn.Module): + def __init__(self, c_in, d_model): + super(FixedEmbedding, self).__init__() + + w = torch.zeros(c_in, d_model).float() + w.require_grad = False + + position = torch.arange(0, c_in).float().unsqueeze(1) + div_term = (torch.arange(0, d_model, 2).float() + * -(math.log(10000.0) / d_model)).exp() + + w[:, 0::2] = torch.sin(position * div_term) + w[:, 1::2] = torch.cos(position * div_term) + + self.emb = nn.Embedding(c_in, d_model) + self.emb.weight = nn.Parameter(w, requires_grad=False) + + def forward(self, x): + return self.emb(x).detach() + + +class TemporalEmbedding(nn.Module): + def __init__(self, d_model, embed_type='fixed', freq='h'): + super(TemporalEmbedding, self).__init__() + + minute_size = 4 + hour_size = 24 + weekday_size = 7 + day_size = 32 + month_size = 13 + + Embed = FixedEmbedding if embed_type == 'fixed' else nn.Embedding + if freq == 't': + self.minute_embed = Embed(minute_size, d_model) + self.hour_embed = Embed(hour_size, d_model) + self.weekday_embed = Embed(weekday_size, d_model) + self.day_embed = Embed(day_size, d_model) + self.month_embed = Embed(month_size, d_model) + + def forward(self, x): + x = x.long() + minute_x = self.minute_embed(x[:, :, 4]) if hasattr( + self, 'minute_embed') else 0. + hour_x = self.hour_embed(x[:, :, 3]) + weekday_x = self.weekday_embed(x[:, :, 2]) + day_x = self.day_embed(x[:, :, 1]) + month_x = self.month_embed(x[:, :, 0]) + + return hour_x + weekday_x + day_x + month_x + minute_x + + +class TimeFeatureEmbedding(nn.Module): + def __init__(self, d_model, embed_type='timeF', freq='h'): + super(TimeFeatureEmbedding, self).__init__() + + freq_map = {'h': 4, 't': 5, 's': 6, + 'm': 1, 'a': 1, 'w': 2, 'd': 3, 'b': 3} + d_inp = freq_map[freq] + self.embed = nn.Linear(d_inp, d_model, bias=False) + + def forward(self, x): + return self.embed(x) + + +class DataEmbedding(nn.Module): + def __init__(self, c_in, d_model, embed_type='fixed', freq='h', dropout=0.1): + super(DataEmbedding, self).__init__() + + self.value_embedding = TokenEmbedding(c_in=c_in, d_model=d_model) + self.position_embedding = PositionalEmbedding(d_model=d_model) + self.temporal_embedding = TemporalEmbedding(d_model=d_model, embed_type=embed_type, + freq=freq) if embed_type != 'timeF' else TimeFeatureEmbedding( + d_model=d_model, embed_type=embed_type, freq=freq) + self.dropout = nn.Dropout(p=dropout) + + def forward(self, x, x_mark): + if x_mark is None: + x = self.value_embedding(x) + self.position_embedding(x) + else: + x = self.value_embedding( + x) + self.temporal_embedding(x_mark) + self.position_embedding(x) + return self.dropout(x) + + +class DataEmbedding_inverted(nn.Module): + def __init__(self, c_in, d_model, embed_type='fixed', freq='h', dropout=0.1): + super(DataEmbedding_inverted, self).__init__() + self.value_embedding = nn.Linear(c_in, d_model) + self.dropout = nn.Dropout(p=dropout) + + def forward(self, x, x_mark): + x = x.permute(0, 2, 1) + # x: [Batch Variate Time] + if x_mark is None: + x = self.value_embedding(x) + else: + x = self.value_embedding(torch.cat([x, x_mark.permute(0, 2, 1)], 1)) + # x: [Batch Variate d_model] + return self.dropout(x) + + +class DataEmbedding_wo_pos(nn.Module): + def __init__(self, c_in, d_model, embed_type='fixed', freq='h', dropout=0.1): + super(DataEmbedding_wo_pos, self).__init__() + + self.value_embedding = TokenEmbedding(c_in=c_in, d_model=d_model) + self.position_embedding = PositionalEmbedding(d_model=d_model) + self.temporal_embedding = TemporalEmbedding(d_model=d_model, embed_type=embed_type, + freq=freq) if embed_type != 'timeF' else TimeFeatureEmbedding( + d_model=d_model, embed_type=embed_type, freq=freq) + self.dropout = nn.Dropout(p=dropout) + + def forward(self, x, x_mark): + if x_mark is None: + x = self.value_embedding(x) + else: + x = self.value_embedding(x) + self.temporal_embedding(x_mark) + return self.dropout(x) + + +class PatchEmbedding(nn.Module): + def __init__(self, d_model, patch_len, stride, padding, dropout): + super(PatchEmbedding, self).__init__() + # Patching + self.patch_len = patch_len + self.stride = stride + self.padding_patch_layer = nn.ReplicationPad1d((0, padding)) + + # Backbone, Input encoding: projection of feature vectors onto a d-dim vector space + self.value_embedding = nn.Linear(patch_len, d_model, bias=False) + + # Positional embedding + self.position_embedding = PositionalEmbedding(d_model) + + # Residual dropout + self.dropout = nn.Dropout(dropout) + + def forward(self, x): + # do patching + n_vars = x.shape[1] + x = self.padding_patch_layer(x) + x = x.unfold(dimension=-1, size=self.patch_len, step=self.stride) + x = torch.reshape(x, (x.shape[0] * x.shape[1], x.shape[2], x.shape[3])) + # Input encoding + x = self.value_embedding(x) + self.position_embedding(x) + return self.dropout(x), n_vars diff --git a/layers/FourierCorrelation.py b/layers/FourierCorrelation.py new file mode 100644 index 0000000..6a8cbd4 --- /dev/null +++ b/layers/FourierCorrelation.py @@ -0,0 +1,162 @@ +# coding=utf-8 +# author=maziqing +# email=maziqing.mzq@alibaba-inc.com + +import numpy as np +import torch +import torch.nn as nn + + +def get_frequency_modes(seq_len, modes=64, mode_select_method='random'): + """ + get modes on frequency domain: + 'random' means sampling randomly; + 'else' means sampling the lowest modes; + """ + modes = min(modes, seq_len // 2) + if mode_select_method == 'random': + index = list(range(0, seq_len // 2)) + np.random.shuffle(index) + index = index[:modes] + else: + index = list(range(0, modes)) + index.sort() + return index + + +# ########## fourier layer ############# +class FourierBlock(nn.Module): + def __init__(self, in_channels, out_channels, n_heads, seq_len, modes=0, mode_select_method='random'): + super(FourierBlock, self).__init__() + print('fourier enhanced block used!') + """ + 1D Fourier block. It performs representation learning on frequency domain, + it does FFT, linear transform, and Inverse FFT. + """ + # get modes on frequency domain + self.index = get_frequency_modes(seq_len, modes=modes, mode_select_method=mode_select_method) + print('modes={}, index={}'.format(modes, self.index)) + + self.n_heads = n_heads + self.scale = (1 / (in_channels * out_channels)) + self.weights1 = nn.Parameter( + self.scale * torch.rand(self.n_heads, in_channels // self.n_heads, out_channels // self.n_heads, + len(self.index), dtype=torch.float)) + self.weights2 = nn.Parameter( + self.scale * torch.rand(self.n_heads, in_channels // self.n_heads, out_channels // self.n_heads, + len(self.index), dtype=torch.float)) + + # Complex multiplication + def compl_mul1d(self, order, x, weights): + x_flag = True + w_flag = True + if not torch.is_complex(x): + x_flag = False + x = torch.complex(x, torch.zeros_like(x).to(x.device)) + if not torch.is_complex(weights): + w_flag = False + weights = torch.complex(weights, torch.zeros_like(weights).to(weights.device)) + if x_flag or w_flag: + return torch.complex(torch.einsum(order, x.real, weights.real) - torch.einsum(order, x.imag, weights.imag), + torch.einsum(order, x.real, weights.imag) + torch.einsum(order, x.imag, weights.real)) + else: + return torch.einsum(order, x.real, weights.real) + + def forward(self, q, k, v, mask): + # size = [B, L, H, E] + B, L, H, E = q.shape + x = q.permute(0, 2, 3, 1) + # Compute Fourier coefficients + x_ft = torch.fft.rfft(x, dim=-1) + # Perform Fourier neural operations + out_ft = torch.zeros(B, H, E, L // 2 + 1, device=x.device, dtype=torch.cfloat) + for wi, i in enumerate(self.index): + if i >= x_ft.shape[3] or wi >= out_ft.shape[3]: + continue + out_ft[:, :, :, wi] = self.compl_mul1d("bhi,hio->bho", x_ft[:, :, :, i], + torch.complex(self.weights1, self.weights2)[:, :, :, wi]) + # Return to time domain + x = torch.fft.irfft(out_ft, n=x.size(-1)) + return (x, None) + +# ########## Fourier Cross Former #################### +class FourierCrossAttention(nn.Module): + def __init__(self, in_channels, out_channels, seq_len_q, seq_len_kv, modes=64, mode_select_method='random', + activation='tanh', policy=0, num_heads=8): + super(FourierCrossAttention, self).__init__() + print(' fourier enhanced cross attention used!') + """ + 1D Fourier Cross Attention layer. It does FFT, linear transform, attention mechanism and Inverse FFT. + """ + self.activation = activation + self.in_channels = in_channels + self.out_channels = out_channels + # get modes for queries and keys (& values) on frequency domain + self.index_q = get_frequency_modes(seq_len_q, modes=modes, mode_select_method=mode_select_method) + self.index_kv = get_frequency_modes(seq_len_kv, modes=modes, mode_select_method=mode_select_method) + + print('modes_q={}, index_q={}'.format(len(self.index_q), self.index_q)) + print('modes_kv={}, index_kv={}'.format(len(self.index_kv), self.index_kv)) + + self.scale = (1 / (in_channels * out_channels)) + self.weights1 = nn.Parameter( + self.scale * torch.rand(num_heads, in_channels // num_heads, out_channels // num_heads, len(self.index_q), dtype=torch.float)) + self.weights2 = nn.Parameter( + self.scale * torch.rand(num_heads, in_channels // num_heads, out_channels // num_heads, len(self.index_q), dtype=torch.float)) + + # Complex multiplication + def compl_mul1d(self, order, x, weights): + x_flag = True + w_flag = True + if not torch.is_complex(x): + x_flag = False + x = torch.complex(x, torch.zeros_like(x).to(x.device)) + if not torch.is_complex(weights): + w_flag = False + weights = torch.complex(weights, torch.zeros_like(weights).to(weights.device)) + if x_flag or w_flag: + return torch.complex(torch.einsum(order, x.real, weights.real) - torch.einsum(order, x.imag, weights.imag), + torch.einsum(order, x.real, weights.imag) + torch.einsum(order, x.imag, weights.real)) + else: + return torch.einsum(order, x.real, weights.real) + + def forward(self, q, k, v, mask): + # size = [B, L, H, E] + B, L, H, E = q.shape + xq = q.permute(0, 2, 3, 1) # size = [B, H, E, L] + xk = k.permute(0, 2, 3, 1) + xv = v.permute(0, 2, 3, 1) + + # Compute Fourier coefficients + xq_ft_ = torch.zeros(B, H, E, len(self.index_q), device=xq.device, dtype=torch.cfloat) + xq_ft = torch.fft.rfft(xq, dim=-1) + for i, j in enumerate(self.index_q): + if j >= xq_ft.shape[3]: + continue + xq_ft_[:, :, :, i] = xq_ft[:, :, :, j] + xk_ft_ = torch.zeros(B, H, E, len(self.index_kv), device=xq.device, dtype=torch.cfloat) + xk_ft = torch.fft.rfft(xk, dim=-1) + for i, j in enumerate(self.index_kv): + if j >= xk_ft.shape[3]: + continue + xk_ft_[:, :, :, i] = xk_ft[:, :, :, j] + + # perform attention mechanism on frequency domain + xqk_ft = (self.compl_mul1d("bhex,bhey->bhxy", xq_ft_, xk_ft_)) + if self.activation == 'tanh': + xqk_ft = torch.complex(xqk_ft.real.tanh(), xqk_ft.imag.tanh()) + elif self.activation == 'softmax': + xqk_ft = torch.softmax(abs(xqk_ft), dim=-1) + xqk_ft = torch.complex(xqk_ft, torch.zeros_like(xqk_ft)) + else: + raise Exception('{} actiation function is not implemented'.format(self.activation)) + xqkv_ft = self.compl_mul1d("bhxy,bhey->bhex", xqk_ft, xk_ft_) + xqkvw = self.compl_mul1d("bhex,heox->bhox", xqkv_ft, torch.complex(self.weights1, self.weights2)) + out_ft = torch.zeros(B, H, E, L // 2 + 1, device=xq.device, dtype=torch.cfloat) + for i, j in enumerate(self.index_q): + if i >= xqkvw.shape[3] or j >= out_ft.shape[3]: + continue + out_ft[:, :, :, j] = xqkvw[:, :, :, i] + # Return to time domain + out = torch.fft.irfft(out_ft / self.in_channels / self.out_channels, n=xq.size(-1)) + return (out, None) diff --git a/layers/GraphMixer.py b/layers/GraphMixer.py new file mode 100644 index 0000000..c900805 --- /dev/null +++ b/layers/GraphMixer.py @@ -0,0 +1,83 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math + +class HierarchicalGraphMixer(nn.Module): + """ + 分层图混合器,同时考虑宏观通道关系和微观 Patch 级别注意力。 + 输入 z : 形状为 [B, C, N, D] 的张量 + 输出 z_out : 形状同输入 + """ + def __init__(self, n_channel: int, dim: int, k: int = 5, tau: float = 0.2): + super().__init__() + self.k = k + self.tau = tau + + # Level 1: Channel Graph + self.A = nn.Parameter(torch.zeros(n_channel, n_channel)) + self.se = nn.Sequential( + nn.Linear(dim, dim // 4, bias=False), nn.ReLU(), + nn.Linear(dim // 4, 1, bias=False), nn.Sigmoid() + ) + + # Level 2: Patch Cross-Attention + self.q_proj = nn.Linear(dim, dim) + self.k_proj = nn.Linear(dim, dim) + self.v_proj = nn.Linear(dim, dim) + self.out_proj = nn.Linear(dim, dim) + self.norm = nn.LayerNorm(dim) + + def _row_sparse(self, logits: torch.Tensor) -> torch.Tensor: + """Gumbel-Softmax based sparse attention""" + g = -torch.empty_like(logits).exponential_().log() + y = (logits + g) / self.tau + probs = F.softmax(y, dim=-1) + + # Ensure k doesn't exceed the dimension size + k_actual = min(self.k, probs.size(-1)) + if k_actual <= 0: + return torch.zeros_like(probs) + + topk_val, _ = torch.topk(probs, k_actual, dim=-1) + thr = topk_val[..., -1].unsqueeze(-1) + sparse = torch.where(probs >= thr, probs, torch.zeros_like(probs)) + return sparse.detach() + probs - probs.detach() + + def forward(self, z): + # z 的形状: [B, C, N, D] + B, C, N, D = z.shape + + # --- Level 1: 计算宏观权重 --- + A_sparse = self._row_sparse(self.A) # 通道连接稀疏图 A_sparse: [C, C] + + # --- Level 2: 跨通道 Patch 交互 --- + out_z = torch.zeros_like(z) + for i in range(C): # 遍历每个目标通道 i + target_z = z[:, i, :, :] # [B, N, D] + + # 准备聚合来自其他通道的 patch 级别上下文 + aggregated_context = torch.zeros_like(target_z) + + for j in range(C): # 遍历每个源通道 j + if A_sparse[i, j] != 0: + source_z = z[:, j, :, :] # [B, N, D] + + # --- 执行交叉注意力 --- + Q = self.q_proj(target_z) # Query 来自目标通道 i + K = self.k_proj(source_z) # Key 来自源通道 j + V = self.v_proj(source_z) # Value 来自源通道 j + + attn_scores = torch.bmm(Q, K.transpose(1, 2)) / math.sqrt(D) + attn_probs = F.softmax(attn_scores, dim=-1) # [B, N, N] + + context = torch.bmm(attn_probs, V) # [B, N, D], 从 j 聚合到 i 的上下文 + + # 加权上下文 + weighted_context = A_sparse[i, j] * context + aggregated_context = aggregated_context + weighted_context + + # 将聚合后的上下文通过输出层,并与原始目标表示相加(残差连接) + out_z[:, i, :, :] = self.norm(target_z + self.out_proj(aggregated_context)) + + return out_z \ No newline at end of file diff --git a/layers/MultiWaveletCorrelation.py b/layers/MultiWaveletCorrelation.py new file mode 100644 index 0000000..b6feb59 --- /dev/null +++ b/layers/MultiWaveletCorrelation.py @@ -0,0 +1,587 @@ +import torch +import numpy as np +import torch.nn as nn +import torch.nn.functional as F +from torch import Tensor +from typing import List, Tuple +import math +from functools import partial +from torch import nn, einsum, diagonal +from math import log2, ceil +import pdb +from sympy import Poly, legendre, Symbol, chebyshevt +from scipy.special import eval_legendre + + +def legendreDer(k, x): + def _legendre(k, x): + return (2 * k + 1) * eval_legendre(k, x) + + out = 0 + for i in np.arange(k - 1, -1, -2): + out += _legendre(i, x) + return out + + +def phi_(phi_c, x, lb=0, ub=1): + mask = np.logical_or(x < lb, x > ub) * 1.0 + return np.polynomial.polynomial.Polynomial(phi_c)(x) * (1 - mask) + + +def get_phi_psi(k, base): + x = Symbol('x') + phi_coeff = np.zeros((k, k)) + phi_2x_coeff = np.zeros((k, k)) + if base == 'legendre': + for ki in range(k): + coeff_ = Poly(legendre(ki, 2 * x - 1), x).all_coeffs() + phi_coeff[ki, :ki + 1] = np.flip(np.sqrt(2 * ki + 1) * np.array(coeff_).astype(np.float64)) + coeff_ = Poly(legendre(ki, 4 * x - 1), x).all_coeffs() + phi_2x_coeff[ki, :ki + 1] = np.flip(np.sqrt(2) * np.sqrt(2 * ki + 1) * np.array(coeff_).astype(np.float64)) + + psi1_coeff = np.zeros((k, k)) + psi2_coeff = np.zeros((k, k)) + for ki in range(k): + psi1_coeff[ki, :] = phi_2x_coeff[ki, :] + for i in range(k): + a = phi_2x_coeff[ki, :ki + 1] + b = phi_coeff[i, :i + 1] + prod_ = np.convolve(a, b) + prod_[np.abs(prod_) < 1e-8] = 0 + proj_ = (prod_ * 1 / (np.arange(len(prod_)) + 1) * np.power(0.5, 1 + np.arange(len(prod_)))).sum() + psi1_coeff[ki, :] -= proj_ * phi_coeff[i, :] + psi2_coeff[ki, :] -= proj_ * phi_coeff[i, :] + for j in range(ki): + a = phi_2x_coeff[ki, :ki + 1] + b = psi1_coeff[j, :] + prod_ = np.convolve(a, b) + prod_[np.abs(prod_) < 1e-8] = 0 + proj_ = (prod_ * 1 / (np.arange(len(prod_)) + 1) * np.power(0.5, 1 + np.arange(len(prod_)))).sum() + psi1_coeff[ki, :] -= proj_ * psi1_coeff[j, :] + psi2_coeff[ki, :] -= proj_ * psi2_coeff[j, :] + + a = psi1_coeff[ki, :] + prod_ = np.convolve(a, a) + prod_[np.abs(prod_) < 1e-8] = 0 + norm1 = (prod_ * 1 / (np.arange(len(prod_)) + 1) * np.power(0.5, 1 + np.arange(len(prod_)))).sum() + + a = psi2_coeff[ki, :] + prod_ = np.convolve(a, a) + prod_[np.abs(prod_) < 1e-8] = 0 + norm2 = (prod_ * 1 / (np.arange(len(prod_)) + 1) * (1 - np.power(0.5, 1 + np.arange(len(prod_))))).sum() + norm_ = np.sqrt(norm1 + norm2) + psi1_coeff[ki, :] /= norm_ + psi2_coeff[ki, :] /= norm_ + psi1_coeff[np.abs(psi1_coeff) < 1e-8] = 0 + psi2_coeff[np.abs(psi2_coeff) < 1e-8] = 0 + + phi = [np.poly1d(np.flip(phi_coeff[i, :])) for i in range(k)] + psi1 = [np.poly1d(np.flip(psi1_coeff[i, :])) for i in range(k)] + psi2 = [np.poly1d(np.flip(psi2_coeff[i, :])) for i in range(k)] + + elif base == 'chebyshev': + for ki in range(k): + if ki == 0: + phi_coeff[ki, :ki + 1] = np.sqrt(2 / np.pi) + phi_2x_coeff[ki, :ki + 1] = np.sqrt(2 / np.pi) * np.sqrt(2) + else: + coeff_ = Poly(chebyshevt(ki, 2 * x - 1), x).all_coeffs() + phi_coeff[ki, :ki + 1] = np.flip(2 / np.sqrt(np.pi) * np.array(coeff_).astype(np.float64)) + coeff_ = Poly(chebyshevt(ki, 4 * x - 1), x).all_coeffs() + phi_2x_coeff[ki, :ki + 1] = np.flip( + np.sqrt(2) * 2 / np.sqrt(np.pi) * np.array(coeff_).astype(np.float64)) + + phi = [partial(phi_, phi_coeff[i, :]) for i in range(k)] + + x = Symbol('x') + kUse = 2 * k + roots = Poly(chebyshevt(kUse, 2 * x - 1)).all_roots() + x_m = np.array([rt.evalf(20) for rt in roots]).astype(np.float64) + # x_m[x_m==0.5] = 0.5 + 1e-8 # add small noise to avoid the case of 0.5 belonging to both phi(2x) and phi(2x-1) + # not needed for our purpose here, we use even k always to avoid + wm = np.pi / kUse / 2 + + psi1_coeff = np.zeros((k, k)) + psi2_coeff = np.zeros((k, k)) + + psi1 = [[] for _ in range(k)] + psi2 = [[] for _ in range(k)] + + for ki in range(k): + psi1_coeff[ki, :] = phi_2x_coeff[ki, :] + for i in range(k): + proj_ = (wm * phi[i](x_m) * np.sqrt(2) * phi[ki](2 * x_m)).sum() + psi1_coeff[ki, :] -= proj_ * phi_coeff[i, :] + psi2_coeff[ki, :] -= proj_ * phi_coeff[i, :] + + for j in range(ki): + proj_ = (wm * psi1[j](x_m) * np.sqrt(2) * phi[ki](2 * x_m)).sum() + psi1_coeff[ki, :] -= proj_ * psi1_coeff[j, :] + psi2_coeff[ki, :] -= proj_ * psi2_coeff[j, :] + + psi1[ki] = partial(phi_, psi1_coeff[ki, :], lb=0, ub=0.5) + psi2[ki] = partial(phi_, psi2_coeff[ki, :], lb=0.5, ub=1) + + norm1 = (wm * psi1[ki](x_m) * psi1[ki](x_m)).sum() + norm2 = (wm * psi2[ki](x_m) * psi2[ki](x_m)).sum() + + norm_ = np.sqrt(norm1 + norm2) + psi1_coeff[ki, :] /= norm_ + psi2_coeff[ki, :] /= norm_ + psi1_coeff[np.abs(psi1_coeff) < 1e-8] = 0 + psi2_coeff[np.abs(psi2_coeff) < 1e-8] = 0 + + psi1[ki] = partial(phi_, psi1_coeff[ki, :], lb=0, ub=0.5 + 1e-16) + psi2[ki] = partial(phi_, psi2_coeff[ki, :], lb=0.5 + 1e-16, ub=1) + + return phi, psi1, psi2 + + +def get_filter(base, k): + def psi(psi1, psi2, i, inp): + mask = (inp <= 0.5) * 1.0 + return psi1[i](inp) * mask + psi2[i](inp) * (1 - mask) + + if base not in ['legendre', 'chebyshev']: + raise Exception('Base not supported') + + x = Symbol('x') + H0 = np.zeros((k, k)) + H1 = np.zeros((k, k)) + G0 = np.zeros((k, k)) + G1 = np.zeros((k, k)) + PHI0 = np.zeros((k, k)) + PHI1 = np.zeros((k, k)) + phi, psi1, psi2 = get_phi_psi(k, base) + if base == 'legendre': + roots = Poly(legendre(k, 2 * x - 1)).all_roots() + x_m = np.array([rt.evalf(20) for rt in roots]).astype(np.float64) + wm = 1 / k / legendreDer(k, 2 * x_m - 1) / eval_legendre(k - 1, 2 * x_m - 1) + + for ki in range(k): + for kpi in range(k): + H0[ki, kpi] = 1 / np.sqrt(2) * (wm * phi[ki](x_m / 2) * phi[kpi](x_m)).sum() + G0[ki, kpi] = 1 / np.sqrt(2) * (wm * psi(psi1, psi2, ki, x_m / 2) * phi[kpi](x_m)).sum() + H1[ki, kpi] = 1 / np.sqrt(2) * (wm * phi[ki]((x_m + 1) / 2) * phi[kpi](x_m)).sum() + G1[ki, kpi] = 1 / np.sqrt(2) * (wm * psi(psi1, psi2, ki, (x_m + 1) / 2) * phi[kpi](x_m)).sum() + + PHI0 = np.eye(k) + PHI1 = np.eye(k) + + elif base == 'chebyshev': + x = Symbol('x') + kUse = 2 * k + roots = Poly(chebyshevt(kUse, 2 * x - 1)).all_roots() + x_m = np.array([rt.evalf(20) for rt in roots]).astype(np.float64) + # x_m[x_m==0.5] = 0.5 + 1e-8 # add small noise to avoid the case of 0.5 belonging to both phi(2x) and phi(2x-1) + # not needed for our purpose here, we use even k always to avoid + wm = np.pi / kUse / 2 + + for ki in range(k): + for kpi in range(k): + H0[ki, kpi] = 1 / np.sqrt(2) * (wm * phi[ki](x_m / 2) * phi[kpi](x_m)).sum() + G0[ki, kpi] = 1 / np.sqrt(2) * (wm * psi(psi1, psi2, ki, x_m / 2) * phi[kpi](x_m)).sum() + H1[ki, kpi] = 1 / np.sqrt(2) * (wm * phi[ki]((x_m + 1) / 2) * phi[kpi](x_m)).sum() + G1[ki, kpi] = 1 / np.sqrt(2) * (wm * psi(psi1, psi2, ki, (x_m + 1) / 2) * phi[kpi](x_m)).sum() + + PHI0[ki, kpi] = (wm * phi[ki](2 * x_m) * phi[kpi](2 * x_m)).sum() * 2 + PHI1[ki, kpi] = (wm * phi[ki](2 * x_m - 1) * phi[kpi](2 * x_m - 1)).sum() * 2 + + PHI0[np.abs(PHI0) < 1e-8] = 0 + PHI1[np.abs(PHI1) < 1e-8] = 0 + + H0[np.abs(H0) < 1e-8] = 0 + H1[np.abs(H1) < 1e-8] = 0 + G0[np.abs(G0) < 1e-8] = 0 + G1[np.abs(G1) < 1e-8] = 0 + + return H0, H1, G0, G1, PHI0, PHI1 + + +class MultiWaveletTransform(nn.Module): + """ + 1D multiwavelet block. + """ + + def __init__(self, ich=1, k=8, alpha=16, c=128, + nCZ=1, L=0, base='legendre', attention_dropout=0.1): + super(MultiWaveletTransform, self).__init__() + print('base', base) + self.k = k + self.c = c + self.L = L + self.nCZ = nCZ + self.Lk0 = nn.Linear(ich, c * k) + self.Lk1 = nn.Linear(c * k, ich) + self.ich = ich + self.MWT_CZ = nn.ModuleList(MWT_CZ1d(k, alpha, L, c, base) for i in range(nCZ)) + + def forward(self, queries, keys, values, attn_mask): + B, L, H, E = queries.shape + _, S, _, D = values.shape + if L > S: + zeros = torch.zeros_like(queries[:, :(L - S), :]).float() + values = torch.cat([values, zeros], dim=1) + keys = torch.cat([keys, zeros], dim=1) + else: + values = values[:, :L, :, :] + keys = keys[:, :L, :, :] + values = values.view(B, L, -1) + + V = self.Lk0(values).view(B, L, self.c, -1) + for i in range(self.nCZ): + V = self.MWT_CZ[i](V) + if i < self.nCZ - 1: + V = F.relu(V) + + V = self.Lk1(V.view(B, L, -1)) + V = V.view(B, L, -1, D) + return (V.contiguous(), None) + + +class MultiWaveletCross(nn.Module): + """ + 1D Multiwavelet Cross Attention layer. + """ + + def __init__(self, in_channels, out_channels, seq_len_q, seq_len_kv, modes, c=64, + k=8, ich=512, + L=0, + base='legendre', + mode_select_method='random', + initializer=None, activation='tanh', + **kwargs): + super(MultiWaveletCross, self).__init__() + print('base', base) + + self.c = c + self.k = k + self.L = L + H0, H1, G0, G1, PHI0, PHI1 = get_filter(base, k) + H0r = H0 @ PHI0 + G0r = G0 @ PHI0 + H1r = H1 @ PHI1 + G1r = G1 @ PHI1 + + H0r[np.abs(H0r) < 1e-8] = 0 + H1r[np.abs(H1r) < 1e-8] = 0 + G0r[np.abs(G0r) < 1e-8] = 0 + G1r[np.abs(G1r) < 1e-8] = 0 + self.max_item = 3 + + self.attn1 = FourierCrossAttentionW(in_channels=in_channels, out_channels=out_channels, seq_len_q=seq_len_q, + seq_len_kv=seq_len_kv, modes=modes, activation=activation, + mode_select_method=mode_select_method) + self.attn2 = FourierCrossAttentionW(in_channels=in_channels, out_channels=out_channels, seq_len_q=seq_len_q, + seq_len_kv=seq_len_kv, modes=modes, activation=activation, + mode_select_method=mode_select_method) + self.attn3 = FourierCrossAttentionW(in_channels=in_channels, out_channels=out_channels, seq_len_q=seq_len_q, + seq_len_kv=seq_len_kv, modes=modes, activation=activation, + mode_select_method=mode_select_method) + self.attn4 = FourierCrossAttentionW(in_channels=in_channels, out_channels=out_channels, seq_len_q=seq_len_q, + seq_len_kv=seq_len_kv, modes=modes, activation=activation, + mode_select_method=mode_select_method) + self.T0 = nn.Linear(k, k) + self.register_buffer('ec_s', torch.Tensor( + np.concatenate((H0.T, H1.T), axis=0))) + self.register_buffer('ec_d', torch.Tensor( + np.concatenate((G0.T, G1.T), axis=0))) + + self.register_buffer('rc_e', torch.Tensor( + np.concatenate((H0r, G0r), axis=0))) + self.register_buffer('rc_o', torch.Tensor( + np.concatenate((H1r, G1r), axis=0))) + + self.Lk = nn.Linear(ich, c * k) + self.Lq = nn.Linear(ich, c * k) + self.Lv = nn.Linear(ich, c * k) + self.out = nn.Linear(c * k, ich) + self.modes1 = modes + + def forward(self, q, k, v, mask=None): + B, N, H, E = q.shape # (B, N, H, E) torch.Size([3, 768, 8, 2]) + _, S, _, _ = k.shape # (B, S, H, E) torch.Size([3, 96, 8, 2]) + + q = q.view(q.shape[0], q.shape[1], -1) + k = k.view(k.shape[0], k.shape[1], -1) + v = v.view(v.shape[0], v.shape[1], -1) + q = self.Lq(q) + q = q.view(q.shape[0], q.shape[1], self.c, self.k) + k = self.Lk(k) + k = k.view(k.shape[0], k.shape[1], self.c, self.k) + v = self.Lv(v) + v = v.view(v.shape[0], v.shape[1], self.c, self.k) + + if N > S: + zeros = torch.zeros_like(q[:, :(N - S), :]).float() + v = torch.cat([v, zeros], dim=1) + k = torch.cat([k, zeros], dim=1) + else: + v = v[:, :N, :, :] + k = k[:, :N, :, :] + + ns = math.floor(np.log2(N)) + nl = pow(2, math.ceil(np.log2(N))) + extra_q = q[:, 0:nl - N, :, :] + extra_k = k[:, 0:nl - N, :, :] + extra_v = v[:, 0:nl - N, :, :] + q = torch.cat([q, extra_q], 1) + k = torch.cat([k, extra_k], 1) + v = torch.cat([v, extra_v], 1) + + Ud_q = torch.jit.annotate(List[Tuple[Tensor]], []) + Ud_k = torch.jit.annotate(List[Tuple[Tensor]], []) + Ud_v = torch.jit.annotate(List[Tuple[Tensor]], []) + + Us_q = torch.jit.annotate(List[Tensor], []) + Us_k = torch.jit.annotate(List[Tensor], []) + Us_v = torch.jit.annotate(List[Tensor], []) + + Ud = torch.jit.annotate(List[Tensor], []) + Us = torch.jit.annotate(List[Tensor], []) + + # decompose + for i in range(ns - self.L): + # print('q shape',q.shape) + d, q = self.wavelet_transform(q) + Ud_q += [tuple([d, q])] + Us_q += [d] + for i in range(ns - self.L): + d, k = self.wavelet_transform(k) + Ud_k += [tuple([d, k])] + Us_k += [d] + for i in range(ns - self.L): + d, v = self.wavelet_transform(v) + Ud_v += [tuple([d, v])] + Us_v += [d] + for i in range(ns - self.L): + dk, sk = Ud_k[i], Us_k[i] + dq, sq = Ud_q[i], Us_q[i] + dv, sv = Ud_v[i], Us_v[i] + Ud += [self.attn1(dq[0], dk[0], dv[0], mask)[0] + self.attn2(dq[1], dk[1], dv[1], mask)[0]] + Us += [self.attn3(sq, sk, sv, mask)[0]] + v = self.attn4(q, k, v, mask)[0] + + # reconstruct + for i in range(ns - 1 - self.L, -1, -1): + v = v + Us[i] + v = torch.cat((v, Ud[i]), -1) + v = self.evenOdd(v) + v = self.out(v[:, :N, :, :].contiguous().view(B, N, -1)) + return (v.contiguous(), None) + + def wavelet_transform(self, x): + xa = torch.cat([x[:, ::2, :, :], + x[:, 1::2, :, :], + ], -1) + d = torch.matmul(xa, self.ec_d) + s = torch.matmul(xa, self.ec_s) + return d, s + + def evenOdd(self, x): + B, N, c, ich = x.shape # (B, N, c, k) + assert ich == 2 * self.k + x_e = torch.matmul(x, self.rc_e) + x_o = torch.matmul(x, self.rc_o) + + x = torch.zeros(B, N * 2, c, self.k, + device=x.device) + x[..., ::2, :, :] = x_e + x[..., 1::2, :, :] = x_o + return x + + +class FourierCrossAttentionW(nn.Module): + def __init__(self, in_channels, out_channels, seq_len_q, seq_len_kv, modes=16, activation='tanh', + mode_select_method='random'): + super(FourierCrossAttentionW, self).__init__() + print('corss fourier correlation used!') + self.in_channels = in_channels + self.out_channels = out_channels + self.modes1 = modes + self.activation = activation + + def compl_mul1d(self, order, x, weights): + x_flag = True + w_flag = True + if not torch.is_complex(x): + x_flag = False + x = torch.complex(x, torch.zeros_like(x).to(x.device)) + if not torch.is_complex(weights): + w_flag = False + weights = torch.complex(weights, torch.zeros_like(weights).to(weights.device)) + if x_flag or w_flag: + return torch.complex(torch.einsum(order, x.real, weights.real) - torch.einsum(order, x.imag, weights.imag), + torch.einsum(order, x.real, weights.imag) + torch.einsum(order, x.imag, weights.real)) + else: + return torch.einsum(order, x.real, weights.real) + + def forward(self, q, k, v, mask): + B, L, E, H = q.shape + + xq = q.permute(0, 3, 2, 1) # size = [B, H, E, L] torch.Size([3, 8, 64, 512]) + xk = k.permute(0, 3, 2, 1) + xv = v.permute(0, 3, 2, 1) + self.index_q = list(range(0, min(int(L // 2), self.modes1))) + self.index_k_v = list(range(0, min(int(xv.shape[3] // 2), self.modes1))) + + # Compute Fourier coefficients + xq_ft_ = torch.zeros(B, H, E, len(self.index_q), device=xq.device, dtype=torch.cfloat) + xq_ft = torch.fft.rfft(xq, dim=-1) + for i, j in enumerate(self.index_q): + xq_ft_[:, :, :, i] = xq_ft[:, :, :, j] + + xk_ft_ = torch.zeros(B, H, E, len(self.index_k_v), device=xq.device, dtype=torch.cfloat) + xk_ft = torch.fft.rfft(xk, dim=-1) + for i, j in enumerate(self.index_k_v): + xk_ft_[:, :, :, i] = xk_ft[:, :, :, j] + xqk_ft = (self.compl_mul1d("bhex,bhey->bhxy", xq_ft_, xk_ft_)) + if self.activation == 'tanh': + xqk_ft = torch.complex(xqk_ft.real.tanh(), xqk_ft.imag.tanh()) + elif self.activation == 'softmax': + xqk_ft = torch.softmax(abs(xqk_ft), dim=-1) + xqk_ft = torch.complex(xqk_ft, torch.zeros_like(xqk_ft)) + else: + raise Exception('{} actiation function is not implemented'.format(self.activation)) + xqkv_ft = self.compl_mul1d("bhxy,bhey->bhex", xqk_ft, xk_ft_) + + xqkvw = xqkv_ft + out_ft = torch.zeros(B, H, E, L // 2 + 1, device=xq.device, dtype=torch.cfloat) + for i, j in enumerate(self.index_q): + out_ft[:, :, :, j] = xqkvw[:, :, :, i] + + out = torch.fft.irfft(out_ft / self.in_channels / self.out_channels, n=xq.size(-1)).permute(0, 3, 2, 1) + # size = [B, L, H, E] + return (out, None) + + +class sparseKernelFT1d(nn.Module): + def __init__(self, + k, alpha, c=1, + nl=1, + initializer=None, + **kwargs): + super(sparseKernelFT1d, self).__init__() + + self.modes1 = alpha + self.scale = (1 / (c * k * c * k)) + self.weights1 = nn.Parameter(self.scale * torch.rand(c * k, c * k, self.modes1, dtype=torch.float)) + self.weights2 = nn.Parameter(self.scale * torch.rand(c * k, c * k, self.modes1, dtype=torch.float)) + self.weights1.requires_grad = True + self.weights2.requires_grad = True + self.k = k + + def compl_mul1d(self, order, x, weights): + x_flag = True + w_flag = True + if not torch.is_complex(x): + x_flag = False + x = torch.complex(x, torch.zeros_like(x).to(x.device)) + if not torch.is_complex(weights): + w_flag = False + weights = torch.complex(weights, torch.zeros_like(weights).to(weights.device)) + if x_flag or w_flag: + return torch.complex(torch.einsum(order, x.real, weights.real) - torch.einsum(order, x.imag, weights.imag), + torch.einsum(order, x.real, weights.imag) + torch.einsum(order, x.imag, weights.real)) + else: + return torch.einsum(order, x.real, weights.real) + + def forward(self, x): + B, N, c, k = x.shape # (B, N, c, k) + + x = x.view(B, N, -1) + x = x.permute(0, 2, 1) + x_fft = torch.fft.rfft(x) + # Multiply relevant Fourier modes + l = min(self.modes1, N // 2 + 1) + out_ft = torch.zeros(B, c * k, N // 2 + 1, device=x.device, dtype=torch.cfloat) + out_ft[:, :, :l] = self.compl_mul1d("bix,iox->box", x_fft[:, :, :l], + torch.complex(self.weights1, self.weights2)[:, :, :l]) + x = torch.fft.irfft(out_ft, n=N) + x = x.permute(0, 2, 1).view(B, N, c, k) + return x + + +# ## +class MWT_CZ1d(nn.Module): + def __init__(self, + k=3, alpha=64, + L=0, c=1, + base='legendre', + initializer=None, + **kwargs): + super(MWT_CZ1d, self).__init__() + + self.k = k + self.L = L + H0, H1, G0, G1, PHI0, PHI1 = get_filter(base, k) + H0r = H0 @ PHI0 + G0r = G0 @ PHI0 + H1r = H1 @ PHI1 + G1r = G1 @ PHI1 + + H0r[np.abs(H0r) < 1e-8] = 0 + H1r[np.abs(H1r) < 1e-8] = 0 + G0r[np.abs(G0r) < 1e-8] = 0 + G1r[np.abs(G1r) < 1e-8] = 0 + self.max_item = 3 + + self.A = sparseKernelFT1d(k, alpha, c) + self.B = sparseKernelFT1d(k, alpha, c) + self.C = sparseKernelFT1d(k, alpha, c) + + self.T0 = nn.Linear(k, k) + + self.register_buffer('ec_s', torch.Tensor( + np.concatenate((H0.T, H1.T), axis=0))) + self.register_buffer('ec_d', torch.Tensor( + np.concatenate((G0.T, G1.T), axis=0))) + + self.register_buffer('rc_e', torch.Tensor( + np.concatenate((H0r, G0r), axis=0))) + self.register_buffer('rc_o', torch.Tensor( + np.concatenate((H1r, G1r), axis=0))) + + def forward(self, x): + B, N, c, k = x.shape # (B, N, k) + ns = math.floor(np.log2(N)) + nl = pow(2, math.ceil(np.log2(N))) + extra_x = x[:, 0:nl - N, :, :] + x = torch.cat([x, extra_x], 1) + Ud = torch.jit.annotate(List[Tensor], []) + Us = torch.jit.annotate(List[Tensor], []) + for i in range(ns - self.L): + d, x = self.wavelet_transform(x) + Ud += [self.A(d) + self.B(x)] + Us += [self.C(d)] + x = self.T0(x) # coarsest scale transform + + # reconstruct + for i in range(ns - 1 - self.L, -1, -1): + x = x + Us[i] + x = torch.cat((x, Ud[i]), -1) + x = self.evenOdd(x) + x = x[:, :N, :, :] + + return x + + def wavelet_transform(self, x): + xa = torch.cat([x[:, ::2, :, :], + x[:, 1::2, :, :], + ], -1) + d = torch.matmul(xa, self.ec_d) + s = torch.matmul(xa, self.ec_s) + return d, s + + def evenOdd(self, x): + + B, N, c, ich = x.shape # (B, N, c, k) + assert ich == 2 * self.k + x_e = torch.matmul(x, self.rc_e) + x_o = torch.matmul(x, self.rc_o) + + x = torch.zeros(B, N * 2, c, self.k, + device=x.device) + x[..., ::2, :, :] = x_e + x[..., 1::2, :, :] = x_o + return x diff --git a/layers/Pyraformer_EncDec.py b/layers/Pyraformer_EncDec.py new file mode 100644 index 0000000..1af1bf2 --- /dev/null +++ b/layers/Pyraformer_EncDec.py @@ -0,0 +1,218 @@ +import torch +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 +import math + + +def get_mask(input_size, window_size, inner_size): + """Get the attention mask of PAM-Naive""" + # Get the size of all layers + all_size = [] + all_size.append(input_size) + for i in range(len(window_size)): + layer_size = math.floor(all_size[i] / window_size[i]) + all_size.append(layer_size) + + seq_length = sum(all_size) + mask = torch.zeros(seq_length, seq_length) + + # get intra-scale mask + inner_window = inner_size // 2 + for layer_idx in range(len(all_size)): + start = sum(all_size[:layer_idx]) + for i in range(start, start + all_size[layer_idx]): + left_side = max(i - inner_window, start) + right_side = min(i + inner_window + 1, start + all_size[layer_idx]) + mask[i, left_side:right_side] = 1 + + # get inter-scale mask + for layer_idx in range(1, len(all_size)): + start = sum(all_size[:layer_idx]) + for i in range(start, start + all_size[layer_idx]): + left_side = (start - all_size[layer_idx - 1]) + \ + (i - start) * window_size[layer_idx - 1] + if i == (start + all_size[layer_idx] - 1): + right_side = start + else: + right_side = ( + start - all_size[layer_idx - 1]) + (i - start + 1) * window_size[layer_idx - 1] + mask[i, left_side:right_side] = 1 + mask[left_side:right_side, i] = 1 + + mask = (1 - mask).bool() + + return mask, all_size + + +def refer_points(all_sizes, window_size): + """Gather features from PAM's pyramid sequences""" + input_size = all_sizes[0] + indexes = torch.zeros(input_size, len(all_sizes)) + + for i in range(input_size): + indexes[i][0] = i + former_index = i + for j in range(1, len(all_sizes)): + start = sum(all_sizes[:j]) + inner_layer_idx = former_index - (start - all_sizes[j - 1]) + former_index = start + \ + min(inner_layer_idx // window_size[j - 1], all_sizes[j] - 1) + indexes[i][j] = former_index + + indexes = indexes.unsqueeze(0).unsqueeze(3) + + return indexes.long() + + +class RegularMask(): + def __init__(self, mask): + self._mask = mask.unsqueeze(1) + + @property + def mask(self): + return self._mask + + +class EncoderLayer(nn.Module): + """ Compose with two layers """ + + def __init__(self, d_model, d_inner, n_head, dropout=0.1, normalize_before=True): + super(EncoderLayer, self).__init__() + + self.slf_attn = AttentionLayer( + FullAttention(mask_flag=True, factor=0, + attention_dropout=dropout, output_attention=False), + d_model, n_head) + self.pos_ffn = PositionwiseFeedForward( + d_model, d_inner, dropout=dropout, normalize_before=normalize_before) + + def forward(self, enc_input, slf_attn_mask=None): + attn_mask = RegularMask(slf_attn_mask) + enc_output, _ = self.slf_attn( + enc_input, enc_input, enc_input, attn_mask=attn_mask) + enc_output = self.pos_ffn(enc_output) + return enc_output + + +class Encoder(nn.Module): + """ A encoder model with self attention mechanism. """ + + def __init__(self, configs, window_size, inner_size): + super().__init__() + + d_bottleneck = configs.d_model//4 + + self.mask, self.all_size = get_mask( + configs.seq_len, window_size, inner_size) + self.indexes = refer_points(self.all_size, window_size) + self.layers = nn.ModuleList([ + EncoderLayer(configs.d_model, configs.d_ff, configs.n_heads, dropout=configs.dropout, + normalize_before=False) for _ in range(configs.e_layers) + ]) # naive pyramid attention + + self.enc_embedding = DataEmbedding( + configs.enc_in, configs.d_model, configs.dropout) + self.conv_layers = Bottleneck_Construct( + configs.d_model, window_size, d_bottleneck) + + def forward(self, x_enc, x_mark_enc): + seq_enc = self.enc_embedding(x_enc, x_mark_enc) + + mask = self.mask.repeat(len(seq_enc), 1, 1).to(x_enc.device) + seq_enc = self.conv_layers(seq_enc) + + for i in range(len(self.layers)): + seq_enc = self.layers[i](seq_enc, mask) + + indexes = self.indexes.repeat(seq_enc.size( + 0), 1, 1, seq_enc.size(2)).to(seq_enc.device) + indexes = indexes.view(seq_enc.size(0), -1, seq_enc.size(2)) + all_enc = torch.gather(seq_enc, 1, indexes) + seq_enc = all_enc.view(seq_enc.size(0), self.all_size[0], -1) + + return seq_enc + + +class ConvLayer(nn.Module): + def __init__(self, c_in, window_size): + super(ConvLayer, self).__init__() + self.downConv = nn.Conv1d(in_channels=c_in, + out_channels=c_in, + kernel_size=window_size, + stride=window_size) + self.norm = nn.BatchNorm1d(c_in) + self.activation = nn.ELU() + + def forward(self, x): + x = self.downConv(x) + x = self.norm(x) + x = self.activation(x) + return x + + +class Bottleneck_Construct(nn.Module): + """Bottleneck convolution CSCM""" + + def __init__(self, d_model, window_size, d_inner): + super(Bottleneck_Construct, self).__init__() + if not isinstance(window_size, list): + self.conv_layers = nn.ModuleList([ + ConvLayer(d_inner, window_size), + ConvLayer(d_inner, window_size), + ConvLayer(d_inner, window_size) + ]) + else: + self.conv_layers = [] + for i in range(len(window_size)): + self.conv_layers.append(ConvLayer(d_inner, window_size[i])) + self.conv_layers = nn.ModuleList(self.conv_layers) + self.up = Linear(d_inner, d_model) + self.down = Linear(d_model, d_inner) + self.norm = nn.LayerNorm(d_model) + + def forward(self, enc_input): + temp_input = self.down(enc_input).permute(0, 2, 1) + all_inputs = [] + for i in range(len(self.conv_layers)): + temp_input = self.conv_layers[i](temp_input) + all_inputs.append(temp_input) + + all_inputs = torch.cat(all_inputs, dim=2).transpose(1, 2) + all_inputs = self.up(all_inputs) + all_inputs = torch.cat([enc_input, all_inputs], dim=1) + + all_inputs = self.norm(all_inputs) + return all_inputs + + +class PositionwiseFeedForward(nn.Module): + """ Two-layer position-wise feed-forward neural network. """ + + def __init__(self, d_in, d_hid, dropout=0.1, normalize_before=True): + super().__init__() + + self.normalize_before = normalize_before + + self.w_1 = nn.Linear(d_in, d_hid) + self.w_2 = nn.Linear(d_hid, d_in) + + self.layer_norm = nn.LayerNorm(d_in, eps=1e-6) + self.dropout = nn.Dropout(dropout) + + def forward(self, x): + residual = x + if self.normalize_before: + x = self.layer_norm(x) + + x = F.gelu(self.w_1(x)) + x = self.dropout(x) + x = self.w_2(x) + x = self.dropout(x) + x = x + residual + + if not self.normalize_before: + x = self.layer_norm(x) + return x diff --git a/layers/RevIN.py b/layers/RevIN.py new file mode 100644 index 0000000..a9d7e73 --- /dev/null +++ b/layers/RevIN.py @@ -0,0 +1,59 @@ +import torch +from torch import nn + +class RevIN(nn.Module): + """ + Reversible Instance Normalization + """ + def __init__(self, num_features: int, eps=1e-5, affine=True, subtract_last=False): + super(RevIN, self).__init__() + self.num_features = num_features + self.eps = eps + self.affine = affine + self.subtract_last = subtract_last + if self.affine: + self._init_params() + + def forward(self, x, mode: str): + if mode == 'norm': + self._get_statistics(x) + x = self._normalize(x) + elif mode == 'denorm': + x = self._denormalize(x) + else: + raise NotImplementedError + return x + + def _init_params(self): + self.affine_weight = nn.Parameter(torch.ones(self.num_features)) + self.affine_bias = nn.Parameter(torch.zeros(self.num_features)) + + def _get_statistics(self, x): + dim2reduce = tuple(range(1, x.ndim-1)) + if self.subtract_last: + self.last = x[:, -1, :].unsqueeze(1) + else: + self.mean = torch.mean(x, dim=dim2reduce, keepdim=True).detach() + self.stdev = torch.sqrt(torch.var(x, dim=dim2reduce, keepdim=True, unbiased=False) + self.eps).detach() + + def _normalize(self, x): + if self.subtract_last: + x = x - self.last + else: + x = x - self.mean + x = x / self.stdev + if self.affine: + x = x * self.affine_weight + x = x + self.affine_bias + return x + + def _denormalize(self, x): + if self.affine: + x = x - self.affine_bias + x = x / (self.affine_weight + self.eps * self.eps) + x = x * self.stdev + if self.subtract_last: + x = x + self.last + else: + x = x + self.mean + return x \ No newline at end of file diff --git a/layers/SeasonPatch.py b/layers/SeasonPatch.py new file mode 100644 index 0000000..3dd349e --- /dev/null +++ b/layers/SeasonPatch.py @@ -0,0 +1,67 @@ +""" +SeasonPatch = PatchTST (CI) + ChannelGraphMixer + Linear prediction head +Adapted for Time-Series-Library-main style +""" +import torch +import torch.nn as nn +from layers.TSTEncoder import TSTiEncoder +from layers.GraphMixer import HierarchicalGraphMixer + +class SeasonPatch(nn.Module): + def __init__(self, + c_in: int, + seq_len: int, + pred_len: int, + patch_len: int, + stride: int, + k_graph: int = 8, + d_model: int = 128, + n_layers: int = 3, + n_heads: int = 16): + super().__init__() + + # Store patch parameters + self.patch_len = patch_len + self.stride = stride + + # Calculate patch number + patch_num = (seq_len - patch_len) // stride + 1 + + # PatchTST encoder (channel independent) + self.encoder = TSTiEncoder( + c_in=c_in, + patch_num=patch_num, + patch_len=patch_len, + d_model=d_model, + n_layers=n_layers, + n_heads=n_heads + ) + + # Cross-channel mixer + self.mixer = HierarchicalGraphMixer(c_in, dim=d_model, k=k_graph) + + # Prediction head + self.head = nn.Linear(patch_num * d_model, pred_len) + + def forward(self, x): + # x: [B, L, C] + x = x.permute(0, 2, 1) # → [B, C, L] + + # Patch the input + x_patch = x.unfold(-1, self.patch_len, self.stride) # [B, C, patch_num, patch_len] + + # Encode patches + z = self.encoder(x_patch) # [B, C, d_model, patch_num] + + # z: [B, C, d_model, patch_num] → [B, C, patch_num, d_model] + B, C, D, N = z.shape + z = z.permute(0, 1, 3, 2) # [B, C, patch_num, d_model] + + # Cross-channel mixing + z_mix = self.mixer(z) # [B, C, patch_num, d_model] + + # Flatten and predict + z_mix = z_mix.view(B, C, N * D) # [B, C, patch_num * d_model] + y_pred = self.head(z_mix) # [B, C, pred_len] + + return y_pred \ No newline at end of file diff --git a/layers/SelfAttention_Family.py b/layers/SelfAttention_Family.py new file mode 100644 index 0000000..b151bff --- /dev/null +++ b/layers/SelfAttention_Family.py @@ -0,0 +1,302 @@ +import torch +import torch.nn as nn +import numpy as np +from math import sqrt +from utils.masking import TriangularCausalMask, ProbMask +from reformer_pytorch import LSHSelfAttention +from einops import rearrange, repeat + + +class DSAttention(nn.Module): + '''De-stationary Attention''' + + def __init__(self, mask_flag=True, factor=5, scale=None, attention_dropout=0.1, output_attention=False): + super(DSAttention, self).__init__() + self.scale = scale + self.mask_flag = mask_flag + self.output_attention = output_attention + self.dropout = nn.Dropout(attention_dropout) + + def forward(self, queries, keys, values, attn_mask, tau=None, delta=None): + B, L, H, E = queries.shape + _, S, _, D = values.shape + scale = self.scale or 1. / sqrt(E) + + tau = 1.0 if tau is None else tau.unsqueeze( + 1).unsqueeze(1) # B x 1 x 1 x 1 + delta = 0.0 if delta is None else delta.unsqueeze( + 1).unsqueeze(1) # B x 1 x 1 x S + + # De-stationary Attention, rescaling pre-softmax score with learned de-stationary factors + scores = torch.einsum("blhe,bshe->bhls", queries, keys) * tau + delta + + if self.mask_flag: + if attn_mask is None: + attn_mask = TriangularCausalMask(B, L, device=queries.device) + + scores.masked_fill_(attn_mask.mask, -np.inf) + + A = self.dropout(torch.softmax(scale * scores, dim=-1)) + V = torch.einsum("bhls,bshd->blhd", A, values) + + if self.output_attention: + return V.contiguous(), A + else: + return V.contiguous(), None + + +class FullAttention(nn.Module): + def __init__(self, mask_flag=True, factor=5, scale=None, attention_dropout=0.1, output_attention=False): + super(FullAttention, self).__init__() + self.scale = scale + self.mask_flag = mask_flag + self.output_attention = output_attention + self.dropout = nn.Dropout(attention_dropout) + + def forward(self, queries, keys, values, attn_mask, tau=None, delta=None): + B, L, H, E = queries.shape + _, S, _, D = values.shape + scale = self.scale or 1. / sqrt(E) + + scores = torch.einsum("blhe,bshe->bhls", queries, keys) + + if self.mask_flag: + if attn_mask is None: + attn_mask = TriangularCausalMask(B, L, device=queries.device) + + scores.masked_fill_(attn_mask.mask, -np.inf) + + A = self.dropout(torch.softmax(scale * scores, dim=-1)) + V = torch.einsum("bhls,bshd->blhd", A, values) + + if self.output_attention: + return V.contiguous(), A + else: + return V.contiguous(), None + + +class ProbAttention(nn.Module): + def __init__(self, mask_flag=True, factor=5, scale=None, attention_dropout=0.1, output_attention=False): + super(ProbAttention, self).__init__() + self.factor = factor + self.scale = scale + self.mask_flag = mask_flag + self.output_attention = output_attention + self.dropout = nn.Dropout(attention_dropout) + + def _prob_QK(self, Q, K, sample_k, n_top): # n_top: c*ln(L_q) + # Q [B, H, L, D] + B, H, L_K, E = K.shape + _, _, L_Q, _ = Q.shape + + # calculate the sampled Q_K + K_expand = K.unsqueeze(-3).expand(B, H, L_Q, L_K, E) + # real U = U_part(factor*ln(L_k))*L_q + index_sample = torch.randint(L_K, (L_Q, sample_k)) + K_sample = K_expand[:, :, torch.arange( + L_Q).unsqueeze(1), index_sample, :] + Q_K_sample = torch.matmul( + Q.unsqueeze(-2), K_sample.transpose(-2, -1)).squeeze() + + # find the Top_k query with sparisty measurement + M = Q_K_sample.max(-1)[0] - torch.div(Q_K_sample.sum(-1), L_K) + M_top = M.topk(n_top, sorted=False)[1] + + # 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) + Q_K = torch.matmul(Q_reduce, K.transpose(-2, -1)) # factor*ln(L_q)*L_k + + return Q_K, M_top + + def _get_initial_context(self, V, L_Q): + B, H, L_V, D = V.shape + if not self.mask_flag: + # V_sum = V.sum(dim=-2) + V_sum = V.mean(dim=-2) + contex = V_sum.unsqueeze(-2).expand(B, H, + L_Q, V_sum.shape[-1]).clone() + else: # use mask + # requires that L_Q == L_V, i.e. for self-attention only + assert (L_Q == L_V) + contex = V.cumsum(dim=-2) + return contex + + def _update_context(self, context_in, V, scores, index, L_Q, attn_mask): + B, H, L_V, D = V.shape + + if self.mask_flag: + attn_mask = ProbMask(B, H, L_Q, index, scores, device=V.device) + scores.masked_fill_(attn_mask.mask, -np.inf) + + 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) + 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 + return context_in, attns + else: + return context_in, None + + def forward(self, queries, keys, values, attn_mask, tau=None, delta=None): + B, L_Q, H, D = queries.shape + _, L_K, _, _ = keys.shape + + queries = queries.transpose(2, 1) + keys = keys.transpose(2, 1) + values = values.transpose(2, 1) + + U_part = self.factor * \ + 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) + + U_part = U_part if U_part < L_K else L_K + u = u if u < L_Q else L_Q + + scores_top, index = self._prob_QK( + queries, keys, sample_k=U_part, n_top=u) + + # add scale factor + scale = self.scale or 1. / sqrt(D) + if scale is not None: + scores_top = scores_top * scale + # get the context + context = self._get_initial_context(values, L_Q) + # update the context with selected top_k queries + context, attn = self._update_context( + context, values, scores_top, index, L_Q, attn_mask) + + return context.contiguous(), attn + + +class AttentionLayer(nn.Module): + def __init__(self, attention, d_model, n_heads, d_keys=None, + d_values=None): + super(AttentionLayer, self).__init__() + + d_keys = d_keys or (d_model // n_heads) + d_values = d_values or (d_model // n_heads) + + self.inner_attention = attention + self.query_projection = nn.Linear(d_model, d_keys * n_heads) + self.key_projection = nn.Linear(d_model, d_keys * n_heads) + self.value_projection = nn.Linear(d_model, d_values * n_heads) + self.out_projection = nn.Linear(d_values * n_heads, d_model) + self.n_heads = n_heads + + def forward(self, queries, keys, values, attn_mask, tau=None, delta=None): + B, L, _ = queries.shape + _, S, _ = keys.shape + H = self.n_heads + + queries = self.query_projection(queries).view(B, L, H, -1) + keys = self.key_projection(keys).view(B, S, H, -1) + values = self.value_projection(values).view(B, S, H, -1) + + out, attn = self.inner_attention( + queries, + keys, + values, + attn_mask, + tau=tau, + delta=delta + ) + out = out.view(B, L, -1) + + return self.out_projection(out), attn + + +class ReformerLayer(nn.Module): + def __init__(self, attention, d_model, n_heads, d_keys=None, + d_values=None, causal=False, bucket_size=4, n_hashes=4): + super().__init__() + self.bucket_size = bucket_size + self.attn = LSHSelfAttention( + dim=d_model, + heads=n_heads, + bucket_size=bucket_size, + n_hashes=n_hashes, + causal=causal + ) + + def fit_length(self, queries): + # inside reformer: assert N % (bucket_size * 2) == 0 + B, N, C = queries.shape + if N % (self.bucket_size * 2) == 0: + return queries + else: + # fill the time series + fill_len = (self.bucket_size * 2) - (N % (self.bucket_size * 2)) + return torch.cat([queries, torch.zeros([B, fill_len, C]).to(queries.device)], dim=1) + + def forward(self, queries, keys, values, attn_mask, tau, delta): + # in Reformer: defalut queries=keys + B, N, C = queries.shape + queries = self.attn(self.fit_length(queries))[:, :N, :] + return queries, None + + +class TwoStageAttentionLayer(nn.Module): + ''' + The Two Stage Attention (TSA) Layer + input/output shape: [batch_size, Data_dim(D), Seg_num(L), d_model] + ''' + + def __init__(self, configs, + seg_num, factor, d_model, n_heads, d_ff=None, dropout=0.1): + super(TwoStageAttentionLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.time_attention = AttentionLayer(FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), d_model, n_heads) + self.dim_sender = AttentionLayer(FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), d_model, n_heads) + self.dim_receiver = AttentionLayer(FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), d_model, n_heads) + self.router = nn.Parameter(torch.randn(seg_num, factor, d_model)) + + self.dropout = nn.Dropout(dropout) + + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + self.norm4 = nn.LayerNorm(d_model) + + self.MLP1 = nn.Sequential(nn.Linear(d_model, d_ff), + nn.GELU(), + nn.Linear(d_ff, d_model)) + self.MLP2 = nn.Sequential(nn.Linear(d_model, d_ff), + nn.GELU(), + nn.Linear(d_ff, d_model)) + + def forward(self, x, attn_mask=None, tau=None, delta=None): + # Cross Time Stage: Directly apply MSA to each dimension + batch = x.shape[0] + time_in = rearrange(x, 'b ts_d seg_num d_model -> (b ts_d) seg_num d_model') + time_enc, attn = self.time_attention( + time_in, time_in, time_in, attn_mask=None, tau=None, delta=None + ) + dim_in = time_in + self.dropout(time_enc) + dim_in = self.norm1(dim_in) + 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 + 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) + dim_receive, attn = self.dim_receiver(dim_send, dim_buffer, dim_buffer, attn_mask=None, tau=None, delta=None) + dim_enc = dim_send + self.dropout(dim_receive) + dim_enc = self.norm3(dim_enc) + dim_enc = dim_enc + self.dropout(self.MLP2(dim_enc)) + dim_enc = self.norm4(dim_enc) + + final_out = rearrange(dim_enc, '(b seg_num) ts_d d_model -> b ts_d seg_num d_model', b=batch) + + return final_out diff --git a/layers/StandardNorm.py b/layers/StandardNorm.py new file mode 100755 index 0000000..990d0fd --- /dev/null +++ b/layers/StandardNorm.py @@ -0,0 +1,68 @@ +import torch +import torch.nn as nn + + +class Normalize(nn.Module): + def __init__(self, num_features: int, eps=1e-5, affine=False, subtract_last=False, non_norm=False): + """ + :param num_features: the number of features or channels + :param eps: a value added for numerical stability + :param affine: if True, RevIN has learnable affine parameters + """ + super(Normalize, self).__init__() + self.num_features = num_features + self.eps = eps + self.affine = affine + self.subtract_last = subtract_last + self.non_norm = non_norm + if self.affine: + self._init_params() + + def forward(self, x, mode: str): + if mode == 'norm': + self._get_statistics(x) + x = self._normalize(x) + elif mode == 'denorm': + x = self._denormalize(x) + else: + raise NotImplementedError + return x + + def _init_params(self): + # initialize RevIN params: (C,) + self.affine_weight = nn.Parameter(torch.ones(self.num_features)) + self.affine_bias = nn.Parameter(torch.zeros(self.num_features)) + + def _get_statistics(self, x): + dim2reduce = tuple(range(1, x.ndim - 1)) + if self.subtract_last: + self.last = x[:, -1, :].unsqueeze(1) + else: + self.mean = torch.mean(x, dim=dim2reduce, keepdim=True).detach() + self.stdev = torch.sqrt(torch.var(x, dim=dim2reduce, keepdim=True, unbiased=False) + self.eps).detach() + + def _normalize(self, x): + if self.non_norm: + return x + if self.subtract_last: + x = x - self.last + else: + x = x - self.mean + x = x / self.stdev + if self.affine: + x = x * self.affine_weight + x = x + self.affine_bias + return x + + def _denormalize(self, x): + if self.non_norm: + return x + if self.affine: + x = x - self.affine_bias + x = x / (self.affine_weight + self.eps * self.eps) + x = x * self.stdev + if self.subtract_last: + x = x + self.last + else: + x = x + self.mean + return x diff --git a/layers/TSTEncoder.py b/layers/TSTEncoder.py new file mode 100644 index 0000000..d03fe6b --- /dev/null +++ b/layers/TSTEncoder.py @@ -0,0 +1,91 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from layers.Embed import PositionalEmbedding +from layers.SelfAttention_Family import FullAttention, AttentionLayer +from layers.Transformer_EncDec import EncoderLayer + +class TSTEncoder(nn.Module): + """ + Transformer encoder for PatchTST, adapted for Time-Series-Library-main style + """ + def __init__(self, q_len, d_model, n_heads, d_k=None, d_v=None, d_ff=None, + norm='BatchNorm', attn_dropout=0., dropout=0., activation='gelu', + n_layers=1): + super().__init__() + + d_k = d_model // n_heads if d_k is None else d_k + d_v = d_model // n_heads if d_v is None else d_v + d_ff = d_model * 4 if d_ff is None else d_ff + + self.layers = nn.ModuleList([ + EncoderLayer( + AttentionLayer( + FullAttention(False, attention_dropout=attn_dropout), + d_model, n_heads + ), + d_model, + d_ff, + dropout=dropout, + activation=activation + ) for i in range(n_layers) + ]) + + def forward(self, src, attn_mask=None): + output = src + attns = [] + for layer in self.layers: + output, attn = layer(output, attn_mask) + attns.append(attn) + return output, attns + + +class TSTiEncoder(nn.Module): + """ + Channel-independent TST Encoder adapted for Time-Series-Library-main + """ + def __init__(self, c_in, patch_num, patch_len, max_seq_len=1024, + n_layers=3, d_model=128, n_heads=16, d_k=None, d_v=None, + d_ff=256, norm='BatchNorm', attn_dropout=0., dropout=0., + activation="gelu"): + super().__init__() + + self.patch_num = patch_num + self.patch_len = patch_len + + # Input encoding - projection of feature vectors onto a d-dim vector space + self.W_P = nn.Linear(patch_len, d_model) + + # Positional encoding using Time-Series-Library-main's PositionalEmbedding + self.pos_embedding = PositionalEmbedding(d_model, max_len=max_seq_len) + + # Residual dropout + self.dropout = nn.Dropout(dropout) + + # Encoder + self.encoder = TSTEncoder(patch_num, d_model, n_heads, d_k=d_k, d_v=d_v, + d_ff=d_ff, norm=norm, attn_dropout=attn_dropout, + dropout=dropout, activation=activation, n_layers=n_layers) + + def forward(self, x): + # x: [bs x nvars x patch_num x patch_len] + bs, n_vars, patch_num, patch_len = x.shape + + # Input encoding: project patch_len to d_model + x = self.W_P(x) # x: [bs x nvars x patch_num x d_model] + + # Reshape for attention: combine batch and channel dimensions + u = torch.reshape(x, (bs * n_vars, patch_num, x.shape[-1])) # u: [bs * nvars x patch_num x d_model] + + # Add positional encoding + pos = self.pos_embedding(u) # Get positional encoding [bs*nvars x patch_num x d_model] + u = self.dropout(u + pos[:, :patch_num, :]) # Add positional encoding + + # Encoder + z, attns = self.encoder(u) # z: [bs * nvars x patch_num x d_model] + + # Reshape back to separate batch and channel dimensions + z = torch.reshape(z, (bs, n_vars, patch_num, z.shape[-1])) # z: [bs x nvars x patch_num x d_model] + z = z.permute(0, 1, 3, 2) # z: [bs x nvars x d_model x patch_num] + + return z \ No newline at end of file diff --git a/layers/Transformer_EncDec.py b/layers/Transformer_EncDec.py new file mode 100644 index 0000000..dabf4c2 --- /dev/null +++ b/layers/Transformer_EncDec.py @@ -0,0 +1,135 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class ConvLayer(nn.Module): + def __init__(self, c_in): + super(ConvLayer, self).__init__() + self.downConv = nn.Conv1d(in_channels=c_in, + out_channels=c_in, + kernel_size=3, + padding=2, + padding_mode='circular') + self.norm = nn.BatchNorm1d(c_in) + self.activation = nn.ELU() + self.maxPool = nn.MaxPool1d(kernel_size=3, stride=2, padding=1) + + def forward(self, x): + x = self.downConv(x.permute(0, 2, 1)) + x = self.norm(x) + x = self.activation(x) + x = self.maxPool(x) + x = x.transpose(1, 2) + return x + + +class EncoderLayer(nn.Module): + def __init__(self, attention, d_model, d_ff=None, dropout=0.1, activation="relu"): + super(EncoderLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.attention = attention + self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1) + self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1) + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.dropout = nn.Dropout(dropout) + self.activation = F.relu if activation == "relu" else F.gelu + + def forward(self, x, attn_mask=None, tau=None, delta=None): + new_x, attn = self.attention( + x, x, x, + attn_mask=attn_mask, + tau=tau, delta=delta + ) + x = x + self.dropout(new_x) + + y = x = self.norm1(x) + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + + return self.norm2(x + y), attn + + +class Encoder(nn.Module): + def __init__(self, attn_layers, conv_layers=None, norm_layer=None): + super(Encoder, self).__init__() + self.attn_layers = nn.ModuleList(attn_layers) + self.conv_layers = nn.ModuleList(conv_layers) if conv_layers is not None else None + self.norm = norm_layer + + def forward(self, x, attn_mask=None, tau=None, delta=None): + # x [B, L, D] + attns = [] + if self.conv_layers is not None: + for i, (attn_layer, conv_layer) in enumerate(zip(self.attn_layers, self.conv_layers)): + delta = delta if i == 0 else None + x, attn = attn_layer(x, attn_mask=attn_mask, tau=tau, delta=delta) + x = conv_layer(x) + attns.append(attn) + x, attn = self.attn_layers[-1](x, tau=tau, delta=None) + attns.append(attn) + else: + for attn_layer in self.attn_layers: + x, attn = attn_layer(x, attn_mask=attn_mask, tau=tau, delta=delta) + attns.append(attn) + + if self.norm is not None: + x = self.norm(x) + + return x, attns + + +class DecoderLayer(nn.Module): + def __init__(self, self_attention, cross_attention, d_model, d_ff=None, + dropout=0.1, activation="relu"): + super(DecoderLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.self_attention = self_attention + self.cross_attention = cross_attention + self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1) + self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1) + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + self.dropout = nn.Dropout(dropout) + self.activation = F.relu if activation == "relu" else F.gelu + + def forward(self, x, cross, x_mask=None, cross_mask=None, tau=None, delta=None): + x = x + self.dropout(self.self_attention( + x, x, x, + attn_mask=x_mask, + tau=tau, delta=None + )[0]) + x = self.norm1(x) + + x = x + self.dropout(self.cross_attention( + x, cross, cross, + attn_mask=cross_mask, + tau=tau, delta=delta + )[0]) + + y = x = self.norm2(x) + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + + return self.norm3(x + y) + + +class Decoder(nn.Module): + def __init__(self, layers, norm_layer=None, projection=None): + super(Decoder, self).__init__() + self.layers = nn.ModuleList(layers) + self.norm = norm_layer + self.projection = projection + + def forward(self, x, cross, x_mask=None, cross_mask=None, tau=None, delta=None): + for layer in self.layers: + x = layer(x, cross, x_mask=x_mask, cross_mask=cross_mask, tau=tau, delta=delta) + + if self.norm is not None: + x = self.norm(x) + + if self.projection is not None: + x = self.projection(x) + return x diff --git a/layers/__init__.py b/layers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/Autoformer.py b/models/Autoformer.py new file mode 100644 index 0000000..fb0cd52 --- /dev/null +++ b/models/Autoformer.py @@ -0,0 +1,157 @@ +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 +import math +import numpy as np + + +class Model(nn.Module): + """ + Autoformer is the first method to achieve the series-wise connection, + with inherent O(LlogL) complexity + Paper link: https://openreview.net/pdf?id=I55UqU-M11y + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.pred_len + + # Decomp + kernel_size = configs.moving_avg + self.decomp = series_decomp(kernel_size) + + # Embedding + self.enc_embedding = DataEmbedding_wo_pos(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AutoCorrelationLayer( + AutoCorrelation(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + moving_avg=configs.moving_avg, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + norm_layer=my_Layernorm(configs.d_model) + ) + # Decoder + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.dec_embedding = DataEmbedding_wo_pos(configs.dec_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + self.decoder = Decoder( + [ + DecoderLayer( + AutoCorrelationLayer( + AutoCorrelation(True, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + AutoCorrelationLayer( + AutoCorrelation(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.c_out, + configs.d_ff, + moving_avg=configs.moving_avg, + dropout=configs.dropout, + activation=configs.activation, + ) + for l in range(configs.d_layers) + ], + norm_layer=my_Layernorm(configs.d_model), + projection=nn.Linear(configs.d_model, configs.c_out, bias=True) + ) + if self.task_name == 'imputation': + self.projection = nn.Linear( + configs.d_model, configs.c_out, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear( + configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear( + configs.d_model * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # decomp init + mean = torch.mean(x_enc, dim=1).unsqueeze( + 1).repeat(1, self.pred_len, 1) + zeros = torch.zeros([x_dec.shape[0], self.pred_len, + x_dec.shape[2]], device=x_enc.device) + seasonal_init, trend_init = self.decomp(x_enc) + # decoder input + trend_init = torch.cat( + [trend_init[:, -self.label_len:, :], mean], dim=1) + seasonal_init = torch.cat( + [seasonal_init[:, -self.label_len:, :], zeros], dim=1) + # enc + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # dec + dec_out = self.dec_embedding(seasonal_init, x_mark_dec) + seasonal_part, trend_part = self.decoder(dec_out, enc_out, x_mask=None, cross_mask=None, + trend=trend_init) + # final + dec_out = trend_part + seasonal_part + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # enc + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # final + dec_out = self.projection(enc_out) + return dec_out + + def anomaly_detection(self, x_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # final + dec_out = self.projection(enc_out) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + # Output + # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.act(enc_out) + output = self.dropout(output) + # zero-out padding embeddings + output = output * x_mark_enc.unsqueeze(-1) + # (batch_size, seq_length * d_model) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation( + x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/Crossformer.py b/models/Crossformer.py new file mode 100644 index 0000000..7757d34 --- /dev/null +++ b/models/Crossformer.py @@ -0,0 +1,145 @@ +import torch +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 math import ceil + + +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 + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.seg_len = 12 + self.win_size = 2 + self.task_name = configs.task_name + + # The padding operation to handle invisible sgemnet length + self.pad_in_len = ceil(1.0 * configs.seq_len / self.seg_len) * self.seg_len + self.pad_out_len = ceil(1.0 * configs.pred_len / self.seg_len) * self.seg_len + self.in_seg_num = self.pad_in_len // self.seg_len + self.out_seg_num = ceil(self.in_seg_num / (self.win_size ** (configs.e_layers - 1))) + 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_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) + + # Encoder + self.encoder = Encoder( + [ + scale_block(configs, 1 if l == 0 else self.win_size, configs.d_model, configs.n_heads, configs.d_ff, + 1, configs.dropout, + self.in_seg_num if l == 0 else ceil(self.in_seg_num / self.win_size ** l), configs.factor + ) for l in range(configs.e_layers) + ] + ) + # Decoder + self.dec_pos_embedding = nn.Parameter( + torch.randn(1, configs.enc_in, (self.pad_out_len // self.seg_len), configs.d_model)) + + self.decoder = Decoder( + [ + DecoderLayer( + TwoStageAttentionLayer(configs, (self.pad_out_len // self.seg_len), configs.factor, configs.d_model, configs.n_heads, + configs.d_ff, configs.dropout), + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + self.seg_len, + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + # activation=configs.activation, + ) + for l in range(configs.e_layers + 1) + ], + ) + if self.task_name == 'imputation' or self.task_name == 'anomaly_detection': + self.head = FlattenHead(configs.enc_in, self.head_nf, configs.seq_len, + head_dropout=configs.dropout) + elif self.task_name == 'classification': + self.flatten = nn.Flatten(start_dim=-2) + self.dropout = nn.Dropout(configs.dropout) + 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 += self.enc_pos_embedding + x_enc = self.pre_norm(x_enc) + enc_out, attns = self.encoder(x_enc) + + dec_in = repeat(self.dec_pos_embedding, 'b ts_d l d -> (repeat b) ts_d l d', repeat=x_enc.shape[0]) + dec_out = self.decoder(dec_in, enc_out) + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # 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 += self.enc_pos_embedding + x_enc = self.pre_norm(x_enc) + enc_out, attns = self.encoder(x_enc) + + dec_out = self.head(enc_out[-1].permute(0, 1, 3, 2)).permute(0, 2, 1) + + return dec_out + + def anomaly_detection(self, x_enc): + # 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 += self.enc_pos_embedding + x_enc = self.pre_norm(x_enc) + enc_out, attns = self.encoder(x_enc) + + dec_out = self.head(enc_out[-1].permute(0, 1, 3, 2)).permute(0, 2, 1) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # 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 += self.enc_pos_embedding + x_enc = self.pre_norm(x_enc) + enc_out, attns = self.encoder(x_enc) + # Output from Non-stationary Transformer + output = self.flatten(enc_out[-1].permute(0, 1, 3, 2)) + output = self.dropout(output) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + 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 diff --git a/models/DLinear.py b/models/DLinear.py new file mode 100644 index 0000000..3f4d666 --- /dev/null +++ b/models/DLinear.py @@ -0,0 +1,110 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from layers.Autoformer_EncDec import series_decomp + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/pdf/2205.13504.pdf + """ + + def __init__(self, configs, individual=False): + """ + individual: Bool, whether shared model among different variates. + """ + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + if self.task_name == 'classification' or self.task_name == 'anomaly_detection' or self.task_name == 'imputation': + self.pred_len = configs.seq_len + else: + self.pred_len = configs.pred_len + # Series decomposition block from Autoformer + self.decompsition = series_decomp(configs.moving_avg) + self.individual = individual + self.channels = configs.enc_in + + if self.individual: + self.Linear_Seasonal = nn.ModuleList() + self.Linear_Trend = nn.ModuleList() + + for i in range(self.channels): + self.Linear_Seasonal.append( + nn.Linear(self.seq_len, self.pred_len)) + self.Linear_Trend.append( + nn.Linear(self.seq_len, self.pred_len)) + + self.Linear_Seasonal[i].weight = nn.Parameter( + (1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len])) + self.Linear_Trend[i].weight = nn.Parameter( + (1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len])) + else: + self.Linear_Seasonal = nn.Linear(self.seq_len, self.pred_len) + self.Linear_Trend = nn.Linear(self.seq_len, self.pred_len) + + self.Linear_Seasonal.weight = nn.Parameter( + (1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len])) + self.Linear_Trend.weight = nn.Parameter( + (1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len])) + + if self.task_name == 'classification': + self.projection = nn.Linear( + configs.enc_in * configs.seq_len, configs.num_class) + + def encoder(self, x): + seasonal_init, trend_init = self.decompsition(x) + seasonal_init, trend_init = seasonal_init.permute( + 0, 2, 1), trend_init.permute(0, 2, 1) + if self.individual: + seasonal_output = torch.zeros([seasonal_init.size(0), seasonal_init.size(1), self.pred_len], + dtype=seasonal_init.dtype).to(seasonal_init.device) + trend_output = torch.zeros([trend_init.size(0), trend_init.size(1), self.pred_len], + dtype=trend_init.dtype).to(trend_init.device) + for i in range(self.channels): + seasonal_output[:, i, :] = self.Linear_Seasonal[i]( + seasonal_init[:, i, :]) + trend_output[:, i, :] = self.Linear_Trend[i]( + trend_init[:, i, :]) + else: + seasonal_output = self.Linear_Seasonal(seasonal_init) + trend_output = self.Linear_Trend(trend_init) + x = seasonal_output + trend_output + return x.permute(0, 2, 1) + + def forecast(self, x_enc): + # Encoder + return self.encoder(x_enc) + + def imputation(self, x_enc): + # Encoder + return self.encoder(x_enc) + + def anomaly_detection(self, x_enc): + # Encoder + return self.encoder(x_enc) + + def classification(self, x_enc): + # Encoder + enc_out = self.encoder(x_enc) + # Output + # (batch_size, seq_length * d_model) + output = enc_out.reshape(enc_out.shape[0], -1) + # (batch_size, num_classes) + output = self.projection(output) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc) + return dec_out # [B, N] + return None diff --git a/models/ETSformer.py b/models/ETSformer.py new file mode 100644 index 0000000..a79b3da --- /dev/null +++ b/models/ETSformer.py @@ -0,0 +1,110 @@ +import torch +import torch.nn as nn +from layers.Embed import DataEmbedding +from layers.ETSformer_EncDec import EncoderLayer, Encoder, DecoderLayer, Decoder, Transform + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/abs/2202.01381 + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + if self.task_name == 'classification' or self.task_name == 'anomaly_detection' or self.task_name == 'imputation': + self.pred_len = configs.seq_len + else: + self.pred_len = configs.pred_len + + assert configs.e_layers == configs.d_layers, "Encoder and decoder layers must be equal" + + # Embedding + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + configs.d_model, configs.n_heads, configs.enc_in, configs.seq_len, self.pred_len, configs.top_k, + dim_feedforward=configs.d_ff, + dropout=configs.dropout, + activation=configs.activation, + ) for _ in range(configs.e_layers) + ] + ) + # Decoder + self.decoder = Decoder( + [ + DecoderLayer( + configs.d_model, configs.n_heads, configs.c_out, self.pred_len, + dropout=configs.dropout, + ) for _ in range(configs.d_layers) + ], + ) + self.transform = Transform(sigma=0.2) + + if self.task_name == 'classification': + self.act = torch.nn.functional.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.d_model * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + with torch.no_grad(): + if self.training: + x_enc = self.transform.transform(x_enc) + res = self.enc_embedding(x_enc, x_mark_enc) + level, growths, seasons = self.encoder(res, x_enc, attn_mask=None) + + growth, season = self.decoder(growths, seasons) + preds = level[:, -1:] + growth + season + return preds + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + res = self.enc_embedding(x_enc, x_mark_enc) + level, growths, seasons = self.encoder(res, x_enc, attn_mask=None) + growth, season = self.decoder(growths, seasons) + preds = level[:, -1:] + growth + season + return preds + + def anomaly_detection(self, x_enc): + res = self.enc_embedding(x_enc, None) + level, growths, seasons = self.encoder(res, x_enc, attn_mask=None) + growth, season = self.decoder(growths, seasons) + preds = level[:, -1:] + growth + season + return preds + + def classification(self, x_enc, x_mark_enc): + res = self.enc_embedding(x_enc, None) + _, growths, seasons = self.encoder(res, x_enc, attn_mask=None) + + growths = torch.sum(torch.stack(growths, 0), 0)[:, :self.seq_len, :] + seasons = torch.sum(torch.stack(seasons, 0), 0)[:, :self.seq_len, :] + + enc_out = growths + seasons + output = self.act(enc_out) # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.dropout(output) + + # Output + output = output * x_mark_enc.unsqueeze(-1) # zero-out padding embeddings + output = output.reshape(output.shape[0], -1) # (batch_size, seq_length * d_model) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/FEDformer.py b/models/FEDformer.py new file mode 100644 index 0000000..726eb4a --- /dev/null +++ b/models/FEDformer.py @@ -0,0 +1,178 @@ +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 + + +class Model(nn.Module): + """ + FEDformer performs the attention mechanism on frequency domain and achieved O(N) complexity + Paper link: https://proceedings.mlr.press/v162/zhou22g.html + """ + + def __init__(self, configs, version='fourier', mode_select='random', modes=32): + """ + version: str, for FEDformer, there are two versions to choose, options: [Fourier, Wavelets]. + mode_select: str, for FEDformer, there are two mode selection method, options: [random, low]. + modes: int, modes to be selected. + """ + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.pred_len + + self.version = version + self.mode_select = mode_select + self.modes = modes + + # Decomp + self.decomp = series_decomp(configs.moving_avg) + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + self.dec_embedding = DataEmbedding(configs.dec_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + if self.version == 'Wavelets': + encoder_self_att = MultiWaveletTransform(ich=configs.d_model, L=1, base='legendre') + decoder_self_att = MultiWaveletTransform(ich=configs.d_model, L=1, base='legendre') + decoder_cross_att = MultiWaveletCross(in_channels=configs.d_model, + out_channels=configs.d_model, + seq_len_q=self.seq_len // 2 + self.pred_len, + seq_len_kv=self.seq_len, + modes=self.modes, + ich=configs.d_model, + base='legendre', + activation='tanh') + else: + encoder_self_att = FourierBlock(in_channels=configs.d_model, + out_channels=configs.d_model, + n_heads=configs.n_heads, + seq_len=self.seq_len, + modes=self.modes, + mode_select_method=self.mode_select) + decoder_self_att = FourierBlock(in_channels=configs.d_model, + out_channels=configs.d_model, + n_heads=configs.n_heads, + seq_len=self.seq_len // 2 + self.pred_len, + modes=self.modes, + mode_select_method=self.mode_select) + decoder_cross_att = FourierCrossAttention(in_channels=configs.d_model, + out_channels=configs.d_model, + seq_len_q=self.seq_len // 2 + self.pred_len, + seq_len_kv=self.seq_len, + modes=self.modes, + mode_select_method=self.mode_select, + num_heads=configs.n_heads) + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AutoCorrelationLayer( + encoder_self_att, # instead of multi-head attention in transformer + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + moving_avg=configs.moving_avg, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + norm_layer=my_Layernorm(configs.d_model) + ) + # Decoder + self.decoder = Decoder( + [ + DecoderLayer( + AutoCorrelationLayer( + decoder_self_att, + configs.d_model, configs.n_heads), + AutoCorrelationLayer( + decoder_cross_att, + configs.d_model, configs.n_heads), + configs.d_model, + configs.c_out, + configs.d_ff, + moving_avg=configs.moving_avg, + dropout=configs.dropout, + activation=configs.activation, + ) + for l in range(configs.d_layers) + ], + norm_layer=my_Layernorm(configs.d_model), + projection=nn.Linear(configs.d_model, configs.c_out, bias=True) + ) + + if self.task_name == 'imputation': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.d_model * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # decomp init + mean = torch.mean(x_enc, dim=1).unsqueeze(1).repeat(1, self.pred_len, 1) + seasonal_init, trend_init = self.decomp(x_enc) # x - moving_avg, moving_avg + # decoder input + trend_init = torch.cat([trend_init[:, -self.label_len:, :], mean], dim=1) + seasonal_init = F.pad(seasonal_init[:, -self.label_len:, :], (0, 0, 0, self.pred_len)) + # enc + enc_out = self.enc_embedding(x_enc, x_mark_enc) + dec_out = self.dec_embedding(seasonal_init, x_mark_dec) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # dec + seasonal_part, trend_part = self.decoder(dec_out, enc_out, x_mask=None, cross_mask=None, trend=trend_init) + # final + dec_out = trend_part + seasonal_part + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # enc + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # final + dec_out = self.projection(enc_out) + return dec_out + + def anomaly_detection(self, x_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # final + dec_out = self.projection(enc_out) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + # Output + output = self.act(enc_out) + output = self.dropout(output) + output = output * x_mark_enc.unsqueeze(-1) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/FiLM.py b/models/FiLM.py new file mode 100644 index 0000000..1240e37 --- /dev/null +++ b/models/FiLM.py @@ -0,0 +1,268 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np +from scipy import signal +from scipy import special as ss + +device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + +def transition(N): + Q = np.arange(N, dtype=np.float64) + R = (2 * Q + 1)[:, None] # / theta + j, i = np.meshgrid(Q, Q) + A = np.where(i < j, -1, (-1.) ** (i - j + 1)) * R + B = (-1.) ** Q[:, None] * R + return A, B + + +class HiPPO_LegT(nn.Module): + def __init__(self, N, dt=1.0, discretization='bilinear'): + """ + N: the order of the HiPPO projection + dt: discretization step size - should be roughly inverse to the length of the sequence + """ + super(HiPPO_LegT, self).__init__() + self.N = N + A, B = transition(N) + C = np.ones((1, N)) + D = np.zeros((1,)) + A, B, _, _, _ = signal.cont2discrete((A, B, C, D), dt=dt, method=discretization) + + B = B.squeeze(-1) + + self.register_buffer('A', torch.Tensor(A).to(device)) + self.register_buffer('B', torch.Tensor(B).to(device)) + vals = np.arange(0.0, 1.0, dt) + self.register_buffer('eval_matrix', torch.Tensor( + ss.eval_legendre(np.arange(N)[:, None], 1 - 2 * vals).T).to(device)) + + def forward(self, inputs): + """ + inputs : (length, ...) + output : (length, ..., N) where N is the order of the HiPPO projection + """ + c = torch.zeros(inputs.shape[:-1] + tuple([self.N])).to(device) + cs = [] + for f in inputs.permute([-1, 0, 1]): + f = f.unsqueeze(-1) + new = f @ self.B.unsqueeze(0) + c = F.linear(c, self.A) + new + cs.append(c) + return torch.stack(cs, dim=0) + + def reconstruct(self, c): + return (self.eval_matrix @ c.unsqueeze(-1)).squeeze(-1) + + +class SpectralConv1d(nn.Module): + def __init__(self, in_channels, out_channels, seq_len, ratio=0.5): + """ + 1D Fourier layer. It does FFT, linear transform, and Inverse FFT. + """ + super(SpectralConv1d, self).__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.ratio = ratio + self.modes = min(32, seq_len // 2) + self.index = list(range(0, self.modes)) + + self.scale = (1 / (in_channels * out_channels)) + self.weights_real = nn.Parameter( + self.scale * torch.rand(in_channels, out_channels, len(self.index), dtype=torch.float)) + self.weights_imag = nn.Parameter( + self.scale * torch.rand(in_channels, out_channels, len(self.index), dtype=torch.float)) + + def compl_mul1d(self, order, x, weights_real, weights_imag): + return torch.complex(torch.einsum(order, x.real, weights_real) - torch.einsum(order, x.imag, weights_imag), + torch.einsum(order, x.real, weights_imag) + torch.einsum(order, x.imag, weights_real)) + + def forward(self, x): + B, H, E, N = x.shape + x_ft = torch.fft.rfft(x) + out_ft = torch.zeros(B, H, self.out_channels, x.size(-1) // 2 + 1, device=x.device, dtype=torch.cfloat) + a = x_ft[:, :, :, :self.modes] + out_ft[:, :, :, :self.modes] = self.compl_mul1d("bjix,iox->bjox", a, self.weights_real, self.weights_imag) + x = torch.fft.irfft(out_ft, n=x.size(-1)) + return x + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/abs/2205.08897 + """ + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.configs = configs + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.seq_len if configs.pred_len == 0 else configs.pred_len + + self.seq_len_all = self.seq_len + self.label_len + + self.layers = configs.e_layers + self.enc_in = configs.enc_in + self.e_layers = configs.e_layers + # b, s, f means b, f + self.affine_weight = nn.Parameter(torch.ones(1, 1, configs.enc_in)) + self.affine_bias = nn.Parameter(torch.zeros(1, 1, configs.enc_in)) + + self.multiscale = [1, 2, 4] + self.window_size = [256] + configs.ratio = 0.5 + self.legts = nn.ModuleList( + [HiPPO_LegT(N=n, dt=1. / self.pred_len / i) for n in self.window_size for i in self.multiscale]) + self.spec_conv_1 = nn.ModuleList([SpectralConv1d(in_channels=n, out_channels=n, + seq_len=min(self.pred_len, self.seq_len), + ratio=configs.ratio) for n in + self.window_size for _ in range(len(self.multiscale))]) + self.mlp = nn.Linear(len(self.multiscale) * len(self.window_size), 1) + + if self.task_name == 'imputation' or self.task_name == 'anomaly_detection': + self.projection = nn.Linear( + configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear( + configs.enc_in * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec_true, x_mark_dec): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() + x_enc /= stdev + + x_enc = x_enc * self.affine_weight + self.affine_bias + x_decs = [] + jump_dist = 0 + for i in range(0, len(self.multiscale) * len(self.window_size)): + x_in_len = self.multiscale[i % len(self.multiscale)] * self.pred_len + x_in = x_enc[:, -x_in_len:] + legt = self.legts[i] + x_in_c = legt(x_in.transpose(1, 2)).permute([1, 2, 3, 0])[:, :, :, jump_dist:] + out1 = self.spec_conv_1[i](x_in_c) + if self.seq_len >= self.pred_len: + x_dec_c = out1.transpose(2, 3)[:, :, self.pred_len - 1 - jump_dist, :] + else: + x_dec_c = out1.transpose(2, 3)[:, :, -1, :] + x_dec = x_dec_c @ legt.eval_matrix[-self.pred_len:, :].T + x_decs.append(x_dec) + x_dec = torch.stack(x_decs, dim=-1) + x_dec = self.mlp(x_dec).squeeze(-1).permute(0, 2, 1) + + # De-Normalization from Non-stationary Transformer + x_dec = x_dec - self.affine_bias + x_dec = x_dec / (self.affine_weight + 1e-10) + x_dec = x_dec * stdev + x_dec = x_dec + means + return x_dec + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() + x_enc /= stdev + + x_enc = x_enc * self.affine_weight + self.affine_bias + x_decs = [] + jump_dist = 0 + for i in range(0, len(self.multiscale) * len(self.window_size)): + x_in_len = self.multiscale[i % len(self.multiscale)] * self.pred_len + x_in = x_enc[:, -x_in_len:] + legt = self.legts[i] + x_in_c = legt(x_in.transpose(1, 2)).permute([1, 2, 3, 0])[:, :, :, jump_dist:] + out1 = self.spec_conv_1[i](x_in_c) + if self.seq_len >= self.pred_len: + x_dec_c = out1.transpose(2, 3)[:, :, self.pred_len - 1 - jump_dist, :] + else: + x_dec_c = out1.transpose(2, 3)[:, :, -1, :] + x_dec = x_dec_c @ legt.eval_matrix[-self.pred_len:, :].T + x_decs.append(x_dec) + x_dec = torch.stack(x_decs, dim=-1) + x_dec = self.mlp(x_dec).squeeze(-1).permute(0, 2, 1) + + # De-Normalization from Non-stationary Transformer + x_dec = x_dec - self.affine_bias + x_dec = x_dec / (self.affine_weight + 1e-10) + x_dec = x_dec * stdev + x_dec = x_dec + means + return x_dec + + def anomaly_detection(self, x_enc): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() + x_enc /= stdev + + x_enc = x_enc * self.affine_weight + self.affine_bias + x_decs = [] + jump_dist = 0 + for i in range(0, len(self.multiscale) * len(self.window_size)): + x_in_len = self.multiscale[i % len(self.multiscale)] * self.pred_len + x_in = x_enc[:, -x_in_len:] + legt = self.legts[i] + x_in_c = legt(x_in.transpose(1, 2)).permute([1, 2, 3, 0])[:, :, :, jump_dist:] + out1 = self.spec_conv_1[i](x_in_c) + if self.seq_len >= self.pred_len: + x_dec_c = out1.transpose(2, 3)[:, :, self.pred_len - 1 - jump_dist, :] + else: + x_dec_c = out1.transpose(2, 3)[:, :, -1, :] + x_dec = x_dec_c @ legt.eval_matrix[-self.pred_len:, :].T + x_decs.append(x_dec) + x_dec = torch.stack(x_decs, dim=-1) + x_dec = self.mlp(x_dec).squeeze(-1).permute(0, 2, 1) + + # De-Normalization from Non-stationary Transformer + x_dec = x_dec - self.affine_bias + x_dec = x_dec / (self.affine_weight + 1e-10) + x_dec = x_dec * stdev + x_dec = x_dec + means + return x_dec + + def classification(self, x_enc, x_mark_enc): + x_enc = x_enc * self.affine_weight + self.affine_bias + x_decs = [] + jump_dist = 0 + for i in range(0, len(self.multiscale) * len(self.window_size)): + x_in_len = self.multiscale[i % len(self.multiscale)] * self.pred_len + x_in = x_enc[:, -x_in_len:] + legt = self.legts[i] + x_in_c = legt(x_in.transpose(1, 2)).permute([1, 2, 3, 0])[:, :, :, jump_dist:] + out1 = self.spec_conv_1[i](x_in_c) + if self.seq_len >= self.pred_len: + x_dec_c = out1.transpose(2, 3)[:, :, self.pred_len - 1 - jump_dist, :] + else: + x_dec_c = out1.transpose(2, 3)[:, :, -1, :] + x_dec = x_dec_c @ legt.eval_matrix[-self.pred_len:, :].T + x_decs.append(x_dec) + x_dec = torch.stack(x_decs, dim=-1) + x_dec = self.mlp(x_dec).squeeze(-1).permute(0, 2, 1) + + # Output from Non-stationary Transformer + output = self.act(x_dec) + output = self.dropout(output) + output = output * x_mark_enc.unsqueeze(-1) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/FreTS.py b/models/FreTS.py new file mode 100644 index 0000000..ca4e0b6 --- /dev/null +++ b/models/FreTS.py @@ -0,0 +1,118 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/pdf/2311.06184.pdf + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + if self.task_name == 'classification' or self.task_name == 'anomaly_detection' or self.task_name == 'imputation': + self.pred_len = configs.seq_len + else: + self.pred_len = configs.pred_len + self.embed_size = 128 # embed_size + self.hidden_size = 256 # hidden_size + self.pred_len = configs.pred_len + self.feature_size = configs.enc_in # channels + self.seq_len = configs.seq_len + self.channel_independence = configs.channel_independence + self.sparsity_threshold = 0.01 + self.scale = 0.02 + self.embeddings = nn.Parameter(torch.randn(1, self.embed_size)) + self.r1 = nn.Parameter(self.scale * torch.randn(self.embed_size, self.embed_size)) + self.i1 = nn.Parameter(self.scale * torch.randn(self.embed_size, self.embed_size)) + self.rb1 = nn.Parameter(self.scale * torch.randn(self.embed_size)) + self.ib1 = nn.Parameter(self.scale * torch.randn(self.embed_size)) + self.r2 = nn.Parameter(self.scale * torch.randn(self.embed_size, self.embed_size)) + self.i2 = nn.Parameter(self.scale * torch.randn(self.embed_size, self.embed_size)) + self.rb2 = nn.Parameter(self.scale * torch.randn(self.embed_size)) + self.ib2 = nn.Parameter(self.scale * torch.randn(self.embed_size)) + + self.fc = nn.Sequential( + nn.Linear(self.seq_len * self.embed_size, self.hidden_size), + nn.LeakyReLU(), + nn.Linear(self.hidden_size, self.pred_len) + ) + + # dimension extension + def tokenEmb(self, x): + # x: [Batch, Input length, Channel] + x = x.permute(0, 2, 1) + x = x.unsqueeze(3) + # N*T*1 x 1*D = N*T*D + y = self.embeddings + return x * y + + # frequency temporal learner + def MLP_temporal(self, x, B, N, L): + # [B, N, T, D] + x = torch.fft.rfft(x, dim=2, norm='ortho') # FFT on L dimension + y = self.FreMLP(B, N, L, x, self.r2, self.i2, self.rb2, self.ib2) + x = torch.fft.irfft(y, n=self.seq_len, dim=2, norm="ortho") + return x + + # frequency channel learner + def MLP_channel(self, x, B, N, L): + # [B, N, T, D] + x = x.permute(0, 2, 1, 3) + # [B, T, N, D] + x = torch.fft.rfft(x, dim=2, norm='ortho') # FFT on N dimension + y = self.FreMLP(B, L, N, x, self.r1, self.i1, self.rb1, self.ib1) + x = torch.fft.irfft(y, n=self.feature_size, dim=2, norm="ortho") + x = x.permute(0, 2, 1, 3) + # [B, N, T, D] + return x + + # frequency-domain MLPs + # dimension: FFT along the dimension, r: the real part of weights, i: the imaginary part of weights + # rb: the real part of bias, ib: the imaginary part of bias + def FreMLP(self, B, nd, dimension, x, r, i, rb, ib): + o1_real = torch.zeros([B, nd, dimension // 2 + 1, self.embed_size], + device=x.device) + o1_imag = torch.zeros([B, nd, dimension // 2 + 1, self.embed_size], + device=x.device) + + o1_real = F.relu( + torch.einsum('bijd,dd->bijd', x.real, r) - \ + torch.einsum('bijd,dd->bijd', x.imag, i) + \ + rb + ) + + o1_imag = F.relu( + torch.einsum('bijd,dd->bijd', x.imag, r) + \ + torch.einsum('bijd,dd->bijd', x.real, i) + \ + ib + ) + + y = torch.stack([o1_real, o1_imag], dim=-1) + y = F.softshrink(y, lambd=self.sparsity_threshold) + y = torch.view_as_complex(y) + return y + + def forecast(self, x_enc): + # x: [Batch, Input length, Channel] + B, T, N = x_enc.shape + # embedding x: [B, N, T, D] + x = self.tokenEmb(x_enc) + bias = x + # [B, N, T, D] + if self.channel_independence == '0': + x = self.MLP_channel(x, B, N, T) + # [B, N, T, D] + x = self.MLP_temporal(x, B, N, T) + x = x + bias + x = self.fc(x.reshape(B, N, -1)).permute(0, 2, 1) + return x + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + else: + raise ValueError('Only forecast tasks implemented yet') diff --git a/models/Informer.py b/models/Informer.py new file mode 100644 index 0000000..1c22cfc --- /dev/null +++ b/models/Informer.py @@ -0,0 +1,147 @@ +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 + + +class Model(nn.Module): + """ + Informer with Propspare attention in O(LlogL) complexity + Paper link: https://ojs.aaai.org/index.php/AAAI/article/view/17325/17132 + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.pred_len = configs.pred_len + self.label_len = configs.label_len + + # Embedding + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + self.dec_embedding = DataEmbedding(configs.dec_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + ProbAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + [ + ConvLayer( + configs.d_model + ) for l in range(configs.e_layers - 1) + ] if configs.distil and ('forecast' in configs.task_name) else None, + norm_layer=torch.nn.LayerNorm(configs.d_model) + ) + # Decoder + self.decoder = Decoder( + [ + DecoderLayer( + AttentionLayer( + ProbAttention(True, configs.factor, attention_dropout=configs.dropout, output_attention=False), + configs.d_model, configs.n_heads), + AttentionLayer( + ProbAttention(False, configs.factor, attention_dropout=configs.dropout, output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation, + ) + for l in range(configs.d_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model), + projection=nn.Linear(configs.d_model, configs.c_out, bias=True) + ) + if self.task_name == 'imputation': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.d_model * configs.seq_len, configs.num_class) + + def long_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + enc_out = self.enc_embedding(x_enc, x_mark_enc) + dec_out = self.dec_embedding(x_dec, x_mark_dec) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + 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 + x_enc = x_enc - mean_enc + std_enc = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() # B x 1 x E + x_enc = x_enc / std_enc + + enc_out = self.enc_embedding(x_enc, x_mark_enc) + dec_out = self.dec_embedding(x_dec, x_mark_dec) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.decoder(dec_out, enc_out, x_mask=None, cross_mask=None) + + dec_out = dec_out * std_enc + mean_enc + return dec_out # [B, L, D] + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # enc + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # final + dec_out = self.projection(enc_out) + return dec_out + + def anomaly_detection(self, x_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + # final + dec_out = self.projection(enc_out) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + # Output + output = self.act(enc_out) # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.dropout(output) + output = output * x_mark_enc.unsqueeze(-1) # zero-out padding embeddings + output = output.reshape(output.shape[0], -1) # (batch_size, seq_length * d_model) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast': + dec_out = self.long_forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'short_term_forecast': + dec_out = self.short_forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/Koopa.py b/models/Koopa.py new file mode 100644 index 0000000..0eea941 --- /dev/null +++ b/models/Koopa.py @@ -0,0 +1,337 @@ +import math +import torch +import torch.nn as nn +from 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_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, + dropout=0.05, + activation='tanh'): + super(MLP, self).__init__() + self.f_in = f_in + self.f_out = f_out + self.hidden_dim = hidden_dim + self.hidden_layers = hidden_layers + self.dropout = dropout + if activation == 'relu': + self.activation = nn.ReLU() + elif activation == 'tanh': + self.activation = nn.Tanh() + else: + raise NotImplementedError + + layers = [nn.Linear(self.f_in, self.hidden_dim), + self.activation, nn.Dropout(self.dropout)] + 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) + + def forward(self, x): + # x: B x S x f_in + # 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): + super(KPLayer, self).__init__() + + self.K = None # B E E + + def one_step_forward(self, z, return_rec=False, return_K=False): + B, input_len, E = z.shape + assert input_len > 1, 'snapshots number should be larger than 1' + x, y = z[:, :-1], z[:, 1:] + + # solve linear system + 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_pred = torch.bmm(z[:, -1:], self.K) + if return_rec: + z_rec = torch.cat((z[:, :1], torch.bmm(x, self.K)), dim=1) + 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_preds = [z_pred] + for i in range(1, pred_len): + z_pred = torch.bmm(z_pred, self.K) + z_preds.append(z_pred) + z_preds = torch.cat(z_preds, dim=1) + return z_rec, z_preds + + +class KPLayerApprox(nn.Module): + """ + Find koopman transition of linear system by DMD with multistep K approximation + """ + def __init__(self): + super(KPLayerApprox, self).__init__() + + 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 + # z_rec: B L E, reconstructed representation + # z_pred: B S E, forecasting representation + B, input_len, E = z.shape + assert input_len > 1, 'snapshots number should be larger than 1' + x, y = z[:, :-1], z[:, 1:] + + # solve linear system + 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 + + if pred_len <= input_len: + self.K_step = torch.linalg.matrix_power(self.K, pred_len) + if torch.isnan(self.K_step).any(): + print('Encounter multistep K with nan, replace it by identity matrix') + self.K_step = torch.eye(self.K_step.shape[1]).to(self.K_step.device).unsqueeze(0).repeat(B, 1, 1) + z_pred = torch.bmm(z[:, -pred_len:, :], self.K_step) + else: + self.K_step = torch.linalg.matrix_power(self.K, input_len) + if torch.isnan(self.K_step).any(): + print('Encounter multistep K with nan, replace it by identity matrix') + self.K_step = torch.eye(self.K_step.shape[1]).to(self.K_step.device).unsqueeze(0).repeat(B, 1, 1) + temp_z_pred, all_pred = z, [] + for _ in range(math.ceil(pred_len / input_len)): + temp_z_pred = torch.bmm(temp_z_pred, self.K_step) + all_pred.append(temp_z_pred) + 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, + pred_len=96, + seg_len=24, + dynamic_dim=128, + encoder=None, + decoder=None, + multistep=False, + ): + super(TimeVarKP, self).__init__() + self.input_len = input_len + self.pred_len = pred_len + self.enc_in = enc_in + self.seg_len = seg_len + self.dynamic_dim = dynamic_dim + self.multistep = multistep + 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() + + 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 = 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 + + 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 + + return x_rec, x_pred + + +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, + dynamic_dim=128, + encoder=None, + decoder=None): + super(TimeInvKP, self).__init__() + self.dynamic_dim = dynamic_dim + self.input_len = input_len + self.pred_len = pred_len + self.encoder = encoder + self.decoder = decoder + + K_init = torch.randn(self.dynamic_dim, self.dynamic_dim) + 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 + + return res + + +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 + seg_len: int, segment length of time series + dynamic_dim: int, latent dimension of koopman embedding + hidden_dim: int, hidden dimension of en/decoder + hidden_layers: int, number of hidden layers of en/decoder + num_blocks: int, number of Koopa blocks + multistep: bool, whether to use approximation for multistep K + alpha: float, spectrum filter ratio + """ + super(Model, self).__init__() + self.task_name = configs.task_name + self.enc_in = configs.enc_in + self.input_len = configs.seq_len + self.pred_len = configs.pred_len + + self.seg_len = self.pred_len + self.num_blocks = num_blocks + self.dynamic_dim = dynamic_dim + self.hidden_dim = hidden_dim + self.hidden_layers = hidden_layers + self.multistep = multistep + self.alpha = 0.2 + self.mask_spectrum = self._get_mask_spectrum(configs) + + self.disentanglement = FourierFilter(self.mask_spectrum) + + # 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) + 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) + 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)]) + + # 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_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)]) + + def _get_mask_spectrum(self, configs): + """ + get shared frequency spectrums + """ + train_data, train_loader = data_provider(configs, 'train') + amps = 0.0 + 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 + + def forecast(self, x_enc): + # Series Stationarization adopted from NSformer + 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 + + # Koopman Forecasting + residual, forecast = x_enc, None + for i in range(self.num_blocks): + time_var_input, time_inv_input = self.disentanglement(residual) + time_inv_output = self.time_inv_kps[i](time_inv_input) + time_var_backcast, time_var_output = self.time_var_kps[i](time_var_input) + residual = residual - time_var_backcast + if forecast is None: + forecast = (time_inv_output + time_var_output) + else: + forecast += (time_inv_output + time_var_output) + + # Series Stationarization adopted from NSformer + res = forecast * std_enc + mean_enc + + 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] diff --git a/models/LightTS.py b/models/LightTS.py new file mode 100644 index 0000000..a2051e4 --- /dev/null +++ b/models/LightTS.py @@ -0,0 +1,165 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class IEBlock(nn.Module): + def __init__(self, input_dim, hid_dim, output_dim, num_node): + super(IEBlock, self).__init__() + + self.input_dim = input_dim + self.hid_dim = hid_dim + self.output_dim = output_dim + self.num_node = num_node + + self._build() + + def _build(self): + self.spatial_proj = nn.Sequential( + nn.Linear(self.input_dim, self.hid_dim), + nn.LeakyReLU(), + nn.Linear(self.hid_dim, self.hid_dim // 4) + ) + + self.channel_proj = nn.Linear(self.num_node, self.num_node) + torch.nn.init.eye_(self.channel_proj.weight) + + self.output_proj = nn.Linear(self.hid_dim // 4, self.output_dim) + + def forward(self, x): + x = self.spatial_proj(x.permute(0, 2, 1)) + x = x.permute(0, 2, 1) + self.channel_proj(x.permute(0, 2, 1)) + x = self.output_proj(x.permute(0, 2, 1)) + + x = x.permute(0, 2, 1) + + return x + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/abs/2207.01186 + """ + + def __init__(self, configs, chunk_size=24): + """ + chunk_size: int, reshape T into [num_chunks, chunk_size] + """ + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + if self.task_name == 'classification' or self.task_name == 'anomaly_detection' or self.task_name == 'imputation': + self.pred_len = configs.seq_len + else: + self.pred_len = configs.pred_len + + if configs.task_name == 'long_term_forecast' or configs.task_name == 'short_term_forecast': + self.chunk_size = min(configs.pred_len, configs.seq_len, chunk_size) + else: + self.chunk_size = min(configs.seq_len, chunk_size) + # assert (self.seq_len % self.chunk_size == 0) + if self.seq_len % self.chunk_size != 0: + self.seq_len += (self.chunk_size - self.seq_len % self.chunk_size) # padding in order to ensure complete division + self.num_chunks = self.seq_len // self.chunk_size + + self.d_model = configs.d_model + self.enc_in = configs.enc_in + self.dropout = configs.dropout + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.enc_in * configs.seq_len, configs.num_class) + self._build() + + def _build(self): + self.layer_1 = IEBlock( + input_dim=self.chunk_size, + hid_dim=self.d_model // 4, + output_dim=self.d_model // 4, + num_node=self.num_chunks + ) + + self.chunk_proj_1 = nn.Linear(self.num_chunks, 1) + + self.layer_2 = IEBlock( + input_dim=self.chunk_size, + hid_dim=self.d_model // 4, + output_dim=self.d_model // 4, + num_node=self.num_chunks + ) + + self.chunk_proj_2 = nn.Linear(self.num_chunks, 1) + + self.layer_3 = IEBlock( + input_dim=self.d_model // 2, + hid_dim=self.d_model // 2, + output_dim=self.pred_len, + num_node=self.enc_in + ) + + self.ar = nn.Linear(self.seq_len, self.pred_len) + + def encoder(self, x): + B, T, N = x.size() + + # padding + x = torch.cat([x, torch.zeros((B, self.seq_len - T, N)).to(x.device)], dim=1) + + highway = self.ar(x.permute(0, 2, 1)) + highway = highway.permute(0, 2, 1) + + # continuous sampling + x1 = x.reshape(B, self.num_chunks, self.chunk_size, N) + x1 = x1.permute(0, 3, 2, 1) + x1 = x1.reshape(-1, self.chunk_size, self.num_chunks) + x1 = self.layer_1(x1) + x1 = self.chunk_proj_1(x1).squeeze(dim=-1) + + # interval sampling + x2 = x.reshape(B, self.chunk_size, self.num_chunks, N) + x2 = x2.permute(0, 3, 1, 2) + x2 = x2.reshape(-1, self.chunk_size, self.num_chunks) + x2 = self.layer_2(x2) + x2 = self.chunk_proj_2(x2).squeeze(dim=-1) + + x3 = torch.cat([x1, x2], dim=-1) + + x3 = x3.reshape(B, N, -1) + x3 = x3.permute(0, 2, 1) + + out = self.layer_3(x3) + + out = out + highway + return out + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + return self.encoder(x_enc) + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + return self.encoder(x_enc) + + def anomaly_detection(self, x_enc): + return self.encoder(x_enc) + + def classification(self, x_enc, x_mark_enc): + enc_out = self.encoder(x_enc) + + # Output + output = enc_out.reshape(enc_out.shape[0], -1) # (batch_size, seq_length * d_model) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/MICN.py b/models/MICN.py new file mode 100644 index 0000000..4d79f64 --- /dev/null +++ b/models/MICN.py @@ -0,0 +1,222 @@ +import torch +import torch.nn as nn +from layers.Embed import DataEmbedding +from layers.Autoformer_EncDec import series_decomp, series_decomp_multi +import torch.nn.functional as F + + +class MIC(nn.Module): + """ + MIC layer to extract local and global features + """ + + def __init__(self, feature_size=512, n_heads=8, dropout=0.05, decomp_kernel=[32], conv_kernel=[24], + isometric_kernel=[18, 6], device='cuda'): + super(MIC, self).__init__() + self.conv_kernel = conv_kernel + self.device = device + + # isometric convolution + self.isometric_conv = nn.ModuleList([nn.Conv1d(in_channels=feature_size, out_channels=feature_size, + kernel_size=i, padding=0, stride=1) + for i in isometric_kernel]) + + # downsampling convolution: padding=i//2, stride=i + self.conv = nn.ModuleList([nn.Conv1d(in_channels=feature_size, out_channels=feature_size, + kernel_size=i, padding=i // 2, stride=i) + for i in conv_kernel]) + + # upsampling convolution + self.conv_trans = nn.ModuleList([nn.ConvTranspose1d(in_channels=feature_size, out_channels=feature_size, + kernel_size=i, padding=0, stride=i) + for i in conv_kernel]) + + self.decomp = nn.ModuleList([series_decomp(k) for k in decomp_kernel]) + self.merge = torch.nn.Conv2d(in_channels=feature_size, out_channels=feature_size, + kernel_size=(len(self.conv_kernel), 1)) + + # feedforward network + self.conv1 = nn.Conv1d(in_channels=feature_size, out_channels=feature_size * 4, kernel_size=1) + self.conv2 = nn.Conv1d(in_channels=feature_size * 4, out_channels=feature_size, kernel_size=1) + self.norm1 = nn.LayerNorm(feature_size) + self.norm2 = nn.LayerNorm(feature_size) + + self.norm = torch.nn.LayerNorm(feature_size) + self.act = torch.nn.Tanh() + self.drop = torch.nn.Dropout(0.05) + + def conv_trans_conv(self, input, conv1d, conv1d_trans, isometric): + batch, seq_len, channel = input.shape + x = input.permute(0, 2, 1) + + # downsampling convolution + x1 = self.drop(self.act(conv1d(x))) + x = x1 + + # isometric convolution + zeros = torch.zeros((x.shape[0], x.shape[1], x.shape[2] - 1), device=self.device) + x = torch.cat((zeros, x), dim=-1) + x = self.drop(self.act(isometric(x))) + x = self.norm((x + x1).permute(0, 2, 1)).permute(0, 2, 1) + + # upsampling convolution + x = self.drop(self.act(conv1d_trans(x))) + x = x[:, :, :seq_len] # truncate + + x = self.norm(x.permute(0, 2, 1) + input) + return x + + def forward(self, src): + self.device = src.device + # multi-scale + multi = [] + for i in range(len(self.conv_kernel)): + src_out, trend1 = self.decomp[i](src) + src_out = self.conv_trans_conv(src_out, self.conv[i], self.conv_trans[i], self.isometric_conv[i]) + multi.append(src_out) + + # merge + mg = torch.tensor([], device=self.device) + for i in range(len(self.conv_kernel)): + mg = torch.cat((mg, multi[i].unsqueeze(1).to(self.device)), dim=1) + mg = self.merge(mg.permute(0, 3, 1, 2)).squeeze(-2).permute(0, 2, 1) + + y = self.norm1(mg) + y = self.conv2(self.conv1(y.transpose(-1, 1))).transpose(-1, 1) + + return self.norm2(mg + y) + + +class SeasonalPrediction(nn.Module): + def __init__(self, embedding_size=512, n_heads=8, dropout=0.05, d_layers=1, decomp_kernel=[32], c_out=1, + conv_kernel=[2, 4], isometric_kernel=[18, 6], device='cuda'): + super(SeasonalPrediction, self).__init__() + + self.mic = nn.ModuleList([MIC(feature_size=embedding_size, n_heads=n_heads, + decomp_kernel=decomp_kernel, conv_kernel=conv_kernel, + isometric_kernel=isometric_kernel, device=device) + for i in range(d_layers)]) + + self.projection = nn.Linear(embedding_size, c_out) + + def forward(self, dec): + for mic_layer in self.mic: + dec = mic_layer(dec) + return self.projection(dec) + + +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 + """ + super(Model, self).__init__() + + decomp_kernel = [] # kernel of decomposition operation + isometric_kernel = [] # kernel of isometric convolution + for ii in conv_kernel: + if ii % 2 == 0: # the kernel of decomposition operation must be odd + decomp_kernel.append(ii + 1) + isometric_kernel.append((configs.seq_len + configs.pred_len + ii) // ii) + else: + decomp_kernel.append(ii) + isometric_kernel.append((configs.seq_len + configs.pred_len + ii - 1) // ii) + + self.task_name = configs.task_name + self.pred_len = configs.pred_len + self.seq_len = configs.seq_len + + # Multiple Series decomposition block from FEDformer + self.decomp_multi = series_decomp_multi(decomp_kernel) + + # embedding + self.dec_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + self.conv_trans = SeasonalPrediction(embedding_size=configs.d_model, n_heads=configs.n_heads, + dropout=configs.dropout, + d_layers=configs.d_layers, decomp_kernel=decomp_kernel, + c_out=configs.c_out, conv_kernel=conv_kernel, + isometric_kernel=isometric_kernel, device=torch.device('cuda:0')) + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + # refer to DLinear + self.regression = nn.Linear(configs.seq_len, configs.pred_len) + self.regression.weight = nn.Parameter( + (1 / configs.pred_len) * torch.ones([configs.pred_len, configs.seq_len]), + requires_grad=True) + if self.task_name == 'imputation': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.c_out * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Multi-scale Hybrid Decomposition + seasonal_init_enc, trend = self.decomp_multi(x_enc) + trend = self.regression(trend.permute(0, 2, 1)).permute(0, 2, 1) + + # embedding + zeros = torch.zeros([x_dec.shape[0], self.pred_len, x_dec.shape[2]], device=x_enc.device) + seasonal_init_dec = torch.cat([seasonal_init_enc[:, -self.seq_len:, :], zeros], dim=1) + dec_out = self.dec_embedding(seasonal_init_dec, x_mark_dec) + dec_out = self.conv_trans(dec_out) + dec_out = dec_out[:, -self.pred_len:, :] + trend[:, -self.pred_len:, :] + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # Multi-scale Hybrid Decomposition + seasonal_init_enc, trend = self.decomp_multi(x_enc) + + # embedding + dec_out = self.dec_embedding(seasonal_init_enc, x_mark_dec) + dec_out = self.conv_trans(dec_out) + dec_out = dec_out + trend + return dec_out + + def anomaly_detection(self, x_enc): + # Multi-scale Hybrid Decomposition + seasonal_init_enc, trend = self.decomp_multi(x_enc) + + # embedding + dec_out = self.dec_embedding(seasonal_init_enc, None) + dec_out = self.conv_trans(dec_out) + dec_out = dec_out + trend + return dec_out + + def classification(self, x_enc, x_mark_enc): + # Multi-scale Hybrid Decomposition + seasonal_init_enc, trend = self.decomp_multi(x_enc) + # embedding + dec_out = self.dec_embedding(seasonal_init_enc, None) + dec_out = self.conv_trans(dec_out) + dec_out = dec_out + trend + + # Output from Non-stationary Transformer + output = self.act(dec_out) # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.dropout(output) + output = output * x_mark_enc.unsqueeze(-1) # zero-out padding embeddings + output = output.reshape(output.shape[0], -1) # (batch_size, seq_length * d_model) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation( + x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/Mamba.py b/models/Mamba.py new file mode 100644 index 0000000..edece42 --- /dev/null +++ b/models/Mamba.py @@ -0,0 +1,50 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F + +from mamba_ssm import Mamba + +from 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.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, + ) + + self.out_layer = nn.Linear(configs.d_model, configs.c_out, bias=False) + + def forecast(self, x_enc, x_mark_enc): + mean_enc = x_enc.mean(1, keepdim=True).detach() + 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 + + x = self.embedding(x_enc, x_mark_enc) + x = self.mamba(x) + x_out = self.out_layer(x) + + x_out = x_out * std_enc + mean_enc + return x_out + + 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 \ No newline at end of file diff --git a/models/MambaSimple.py b/models/MambaSimple.py new file mode 100644 index 0000000..a81e664 --- /dev/null +++ b/models/MambaSimple.py @@ -0,0 +1,162 @@ +import math + +import torch +import torch.nn as nn +import torch.nn.functional as F +from einops import rearrange, repeat, einsum + +from layers.Embed import DataEmbedding + + +class Model(nn.Module): + """ + Mamba, linear-time sequence modeling with selective state spaces O(L) + Paper link: https://arxiv.org/abs/2312.00752 + Implementation refernce: https://github.com/johnma2006/mamba-minimal/ + """ + + 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) + + 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.norm = RMSNorm(configs.d_model) + + self.out_layer = nn.Linear(configs.d_model, configs.c_out, bias=False) + + def forecast(self, x_enc, x_mark_enc): + mean_enc = x_enc.mean(1, keepdim=True).detach() + 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 + + x = self.embedding(x_enc, x_mark_enc) + for layer in self.layers: + x = layer(x) + + x = self.norm(x) + x_out = self.out_layer(x) + + x_out = x_out * std_enc + mean_enc + return x_out + + 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:, :] + + +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) + + 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__() + self.d_inner = d_inner + 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 + ) + + # takes in x and outputs the input-specific delta, B, C + self.x_proj = nn.Linear(self.d_inner, self.dt_rank + configs.d_ff * 2, bias=False) + + # projects delta + self.dt_proj = nn.Linear(self.dt_rank, self.d_inner, bias=True) + + A = repeat(torch.arange(1, configs.d_ff + 1), "n -> d n", d=self.d_inner).float() + self.A_log = nn.Parameter(torch.log(A)) + self.D = nn.Parameter(torch.ones(self.d_inner)) + + self.out_proj = nn.Linear(self.d_inner, configs.d_model, bias=False) + + def forward(self, x): + """ + Figure 3 in Section 3.4 in the paper + """ + (b, l, d) = x.shape + + 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") + x = self.conv1d(x)[:, :, :l] + x = rearrange(x, "b d l -> b l d") + + x = F.silu(x) + + y = self.ssm(x) + y = y * F.silu(res) + + 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] + + 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 + + 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" + + # selective scan, sequential instead of parallel + x = torch.zeros((b, d_in, n), device=deltaA.device) + ys = [] + for i in range(l): + x = deltaA[:, i] * x + deltaB_u[:, i] + 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 = y + u * D + + return y + +class RMSNorm(nn.Module): + def __init__(self, d_model, eps=1e-5): + super(RMSNorm, self).__init__() + self.eps = eps + self.weight = nn.Parameter(torch.ones(d_model)) + + def forward(self, x): + output = x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps) * self.weight + return output diff --git a/models/MultiPatchFormer.py b/models/MultiPatchFormer.py new file mode 100644 index 0000000..84acf88 --- /dev/null +++ b/models/MultiPatchFormer.py @@ -0,0 +1,365 @@ +import torch +import torch.nn as nn +import math +from einops import rearrange + +from layers.SelfAttention_Family import AttentionLayer, FullAttention + + +class FeedForward(nn.Module): + def __init__(self, d_model: int, d_hidden: int = 512): + super(FeedForward, self).__init__() + + self.linear_1 = torch.nn.Linear(d_model, d_hidden) + self.linear_2 = torch.nn.Linear(d_hidden, d_model) + self.activation = torch.nn.GELU() + + def forward(self, x): + x = self.linear_1(x) + x = self.activation(x) + x = self.linear_2(x) + + return x + + +class Encoder(nn.Module): + def __init__( + self, + d_model: int, + mha: AttentionLayer, + d_hidden: int, + dropout: float = 0, + channel_wise=False, + ): + super(Encoder, self).__init__() + + self.channel_wise = channel_wise + if self.channel_wise: + self.conv = torch.nn.Conv1d( + in_channels=d_model, + out_channels=d_model, + kernel_size=1, + stride=1, + padding=0, + padding_mode="reflect", + ) + self.MHA = mha + self.feedforward = FeedForward(d_model=d_model, d_hidden=d_hidden) + self.dropout = torch.nn.Dropout(p=dropout) + self.layerNormal_1 = torch.nn.LayerNorm(d_model) + self.layerNormal_2 = torch.nn.LayerNorm(d_model) + + def forward(self, x): + residual = x + q = residual + if self.channel_wise: + x_r = self.conv(x.permute(0, 2, 1)).transpose(1, 2) + k = x_r + v = x_r + else: + k = residual + v = residual + x, score = self.MHA(q, k, v, attn_mask=None) + x = self.dropout(x) + x = self.layerNormal_1(x + residual) + + residual = x + x = self.feedforward(residual) + x = self.dropout(x) + x = self.layerNormal_2(x + residual) + + return x, score + + +class Model(nn.Module): + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.d_channel = configs.enc_in + self.N = configs.e_layers + # Embedding + self.d_model = configs.d_model + self.d_hidden = configs.d_ff + self.n_heads = configs.n_heads + self.mask = True + self.dropout = configs.dropout + + self.stride1 = 8 + self.patch_len1 = 8 + self.stride2 = 8 + self.patch_len2 = 16 + self.stride3 = 7 + self.patch_len3 = 24 + self.stride4 = 6 + self.patch_len4 = 32 + self.patch_num1 = int((self.seq_len - self.patch_len2) // self.stride2) + 2 + self.padding_patch_layer1 = nn.ReplicationPad1d((0, self.stride1)) + self.padding_patch_layer2 = nn.ReplicationPad1d((0, self.stride2)) + self.padding_patch_layer3 = nn.ReplicationPad1d((0, self.stride3)) + self.padding_patch_layer4 = nn.ReplicationPad1d((0, self.stride4)) + + self.shared_MHA = nn.ModuleList( + [ + AttentionLayer( + FullAttention(mask_flag=self.mask), + d_model=self.d_model, + n_heads=self.n_heads, + ) + for _ in range(self.N) + ] + ) + + self.shared_MHA_ch = nn.ModuleList( + [ + AttentionLayer( + FullAttention(mask_flag=self.mask), + d_model=self.d_model, + n_heads=self.n_heads, + ) + for _ in range(self.N) + ] + ) + + self.encoder_list = nn.ModuleList( + [ + Encoder( + d_model=self.d_model, + mha=self.shared_MHA[ll], + d_hidden=self.d_hidden, + dropout=self.dropout, + channel_wise=False, + ) + for ll in range(self.N) + ] + ) + + self.encoder_list_ch = nn.ModuleList( + [ + Encoder( + d_model=self.d_model, + mha=self.shared_MHA_ch[0], + d_hidden=self.d_hidden, + dropout=self.dropout, + channel_wise=True, + ) + for ll in range(self.N) + ] + ) + + pe = torch.zeros(self.patch_num1, self.d_model) + for pos in range(self.patch_num1): + for i in range(0, self.d_model, 2): + wavelength = 10000 ** ((2 * i) / self.d_model) + pe[pos, i] = math.sin(pos / wavelength) + pe[pos, i + 1] = math.cos(pos / wavelength) + pe = pe.unsqueeze(0) # add a batch dimention to your pe matrix + self.register_buffer("pe", pe) + + self.embedding_channel = nn.Conv1d( + in_channels=self.d_model * self.patch_num1, + out_channels=self.d_model, + kernel_size=1, + ) + + self.embedding_patch_1 = torch.nn.Conv1d( + in_channels=1, + out_channels=self.d_model // 4, + kernel_size=self.patch_len1, + stride=self.stride1, + ) + self.embedding_patch_2 = torch.nn.Conv1d( + in_channels=1, + out_channels=self.d_model // 4, + kernel_size=self.patch_len2, + stride=self.stride2, + ) + self.embedding_patch_3 = torch.nn.Conv1d( + in_channels=1, + out_channels=self.d_model // 4, + kernel_size=self.patch_len3, + stride=self.stride3, + ) + self.embedding_patch_4 = torch.nn.Conv1d( + in_channels=1, + out_channels=self.d_model // 4, + kernel_size=self.patch_len4, + stride=self.stride4, + ) + + self.out_linear_1 = torch.nn.Linear(self.d_model, self.pred_len // 8) + self.out_linear_2 = torch.nn.Linear( + self.d_model + self.pred_len // 8, self.pred_len // 8 + ) + self.out_linear_3 = torch.nn.Linear( + self.d_model + 2 * self.pred_len // 8, self.pred_len // 8 + ) + self.out_linear_4 = torch.nn.Linear( + self.d_model + 3 * self.pred_len // 8, self.pred_len // 8 + ) + self.out_linear_5 = torch.nn.Linear( + self.d_model + self.pred_len // 2, self.pred_len // 8 + ) + self.out_linear_6 = torch.nn.Linear( + self.d_model + 5 * self.pred_len // 8, self.pred_len // 8 + ) + self.out_linear_7 = torch.nn.Linear( + self.d_model + 6 * self.pred_len // 8, self.pred_len // 8 + ) + self.out_linear_8 = torch.nn.Linear( + self.d_model + 7 * self.pred_len // 8, + self.pred_len - 7 * (self.pred_len // 8), + ) + + self.remap = torch.nn.Linear(self.d_model, self.seq_len) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Normalization + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + # Multi-scale embedding + x_i = x_enc.permute(0, 2, 1) + + x_i_p1 = x_i + x_i_p2 = self.padding_patch_layer2(x_i) + x_i_p3 = self.padding_patch_layer3(x_i) + x_i_p4 = self.padding_patch_layer4(x_i) + encoding_patch1 = self.embedding_patch_1( + rearrange(x_i_p1, "b c l -> (b c) l").unsqueeze(-1).permute(0, 2, 1) + ).permute(0, 2, 1) + encoding_patch2 = self.embedding_patch_2( + rearrange(x_i_p2, "b c l -> (b c) l").unsqueeze(-1).permute(0, 2, 1) + ).permute(0, 2, 1) + encoding_patch3 = self.embedding_patch_3( + rearrange(x_i_p3, "b c l -> (b c) l").unsqueeze(-1).permute(0, 2, 1) + ).permute(0, 2, 1) + encoding_patch4 = self.embedding_patch_4( + rearrange(x_i_p4, "b c l -> (b c) l").unsqueeze(-1).permute(0, 2, 1) + ).permute(0, 2, 1) + + encoding_patch = ( + torch.cat( + (encoding_patch1, encoding_patch2, encoding_patch3, encoding_patch4), + dim=-1, + ) + + self.pe + ) + # Temporal encoding + for i in range(self.N): + encoding_patch = self.encoder_list[i](encoding_patch)[0] + + # Channel-wise encoding + x_patch_c = rearrange( + encoding_patch, "(b c) p d -> b c (p d)", b=x_enc.shape[0], c=self.d_channel + ) + x_ch = self.embedding_channel(x_patch_c.permute(0, 2, 1)).transpose( + 1, 2 + ) # [b c d] + + encoding_1_ch = self.encoder_list_ch[0](x_ch)[0] + + # Semi Auto-regressive + forecast_ch1 = self.out_linear_1(encoding_1_ch) + forecast_ch2 = self.out_linear_2( + torch.cat((encoding_1_ch, forecast_ch1), dim=-1) + ) + forecast_ch3 = self.out_linear_3( + torch.cat((encoding_1_ch, forecast_ch1, forecast_ch2), dim=-1) + ) + forecast_ch4 = self.out_linear_4( + torch.cat((encoding_1_ch, forecast_ch1, forecast_ch2, forecast_ch3), dim=-1) + ) + forecast_ch5 = self.out_linear_5( + torch.cat( + (encoding_1_ch, forecast_ch1, forecast_ch2, forecast_ch3, forecast_ch4), + dim=-1, + ) + ) + forecast_ch6 = self.out_linear_6( + torch.cat( + ( + encoding_1_ch, + forecast_ch1, + forecast_ch2, + forecast_ch3, + forecast_ch4, + forecast_ch5, + ), + dim=-1, + ) + ) + forecast_ch7 = self.out_linear_7( + torch.cat( + ( + encoding_1_ch, + forecast_ch1, + forecast_ch2, + forecast_ch3, + forecast_ch4, + forecast_ch5, + forecast_ch6, + ), + dim=-1, + ) + ) + forecast_ch8 = self.out_linear_8( + torch.cat( + ( + encoding_1_ch, + forecast_ch1, + forecast_ch2, + forecast_ch3, + forecast_ch4, + forecast_ch5, + forecast_ch6, + forecast_ch7, + ), + dim=-1, + ) + ) + + final_forecast = torch.cat( + ( + forecast_ch1, + forecast_ch2, + forecast_ch3, + forecast_ch4, + forecast_ch5, + forecast_ch6, + forecast_ch7, + forecast_ch8, + ), + dim=-1, + ).permute(0, 2, 1) + + # De-Normalization + dec_out = final_forecast * ( + stdev[:, 0].unsqueeze(1).repeat(1, self.pred_len, 1) + ) + dec_out = dec_out + (means[:, 0].unsqueeze(1).repeat(1, self.pred_len, 1)) + return dec_out + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if ( + self.task_name == "long_term_forecast" + or self.task_name == "short_term_forecast" + ): + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len :, :] # [B, L, D] + if self.task_name == "imputation": + raise NotImplementedError( + "Task imputation for WPMixer is temporarily not supported" + ) + if self.task_name == "anomaly_detection": + raise NotImplementedError( + "Task anomaly_detection for WPMixer is temporarily not supported" + ) + if self.task_name == "classification": + raise NotImplementedError( + "Task classification for WPMixer is temporarily not supported" + ) + return None diff --git a/models/Nonstationary_Transformer.py b/models/Nonstationary_Transformer.py new file mode 100644 index 0000000..211e8b8 --- /dev/null +++ b/models/Nonstationary_Transformer.py @@ -0,0 +1,230 @@ +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 +import torch.nn.functional as F + + +class Projector(nn.Module): + ''' + MLP to learn the De-stationary factors + Paper link: https://openreview.net/pdf?id=ucNDIDRNjjv + ''' + + def __init__(self, enc_in, seq_len, hidden_dims, hidden_layers, output_dim, kernel_size=3): + super(Projector, self).__init__() + + padding = 1 if torch.__version__ >= '1.5.0' else 2 + self.series_conv = nn.Conv1d(in_channels=seq_len, out_channels=1, kernel_size=kernel_size, padding=padding, + padding_mode='circular', bias=False) + + layers = [nn.Linear(2 * enc_in, hidden_dims[0]), nn.ReLU()] + for i in range(hidden_layers - 1): + layers += [nn.Linear(hidden_dims[i], hidden_dims[i + 1]), nn.ReLU()] + + layers += [nn.Linear(hidden_dims[-1], output_dim, bias=False)] + self.backbone = nn.Sequential(*layers) + + def forward(self, x, stats): + # x: B x S x E + # stats: B x 1 x E + # y: B x O + batch_size = x.shape[0] + x = self.series_conv(x) # B x 1 x E + x = torch.cat([x, stats], dim=1) # B x 2 x E + x = x.view(batch_size, -1) # B x 2E + y = self.backbone(x) # B x O + + return y + + +class Model(nn.Module): + """ + Paper link: https://openreview.net/pdf?id=ucNDIDRNjjv + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.pred_len = configs.pred_len + self.seq_len = configs.seq_len + self.label_len = configs.label_len + + # Embedding + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + DSAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model) + ) + # Decoder + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.dec_embedding = DataEmbedding(configs.dec_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + self.decoder = Decoder( + [ + DecoderLayer( + AttentionLayer( + DSAttention(True, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + AttentionLayer( + DSAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation, + ) + for l in range(configs.d_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model), + projection=nn.Linear(configs.d_model, configs.c_out, bias=True) + ) + if self.task_name == 'imputation': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.d_model * configs.seq_len, configs.num_class) + + self.tau_learner = Projector(enc_in=configs.enc_in, seq_len=configs.seq_len, hidden_dims=configs.p_hidden_dims, + hidden_layers=configs.p_hidden_layers, output_dim=1) + self.delta_learner = Projector(enc_in=configs.enc_in, seq_len=configs.seq_len, + hidden_dims=configs.p_hidden_dims, hidden_layers=configs.p_hidden_layers, + output_dim=configs.seq_len) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + x_raw = x_enc.clone().detach() + + # Normalization + 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() # B x 1 x E + x_enc = x_enc / std_enc + # B x S x E, B x 1 x E -> B x 1, positive scalar + tau = self.tau_learner(x_raw, std_enc) + threshold = 80.0 + tau_clamped = torch.clamp(tau, max=threshold) # avoid numerical overflow + tau = tau_clamped.exp() + # B x S x E, B x 1 x E -> B x S + delta = self.delta_learner(x_raw, mean_enc) + + x_dec_new = torch.cat([x_enc[:, -self.label_len:, :], torch.zeros_like(x_dec[:, -self.pred_len:, :])], + dim=1).to(x_enc.device).clone() + + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None, tau=tau, delta=delta) + + dec_out = self.dec_embedding(x_dec_new, x_mark_dec) + dec_out = self.decoder(dec_out, enc_out, x_mask=None, cross_mask=None, tau=tau, delta=delta) + dec_out = dec_out * std_enc + mean_enc + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + x_raw = x_enc.clone().detach() + + # Normalization + mean_enc = torch.sum(x_enc, dim=1) / torch.sum(mask == 1, dim=1) + mean_enc = mean_enc.unsqueeze(1).detach() + x_enc = x_enc - mean_enc + x_enc = x_enc.masked_fill(mask == 0, 0) + std_enc = torch.sqrt(torch.sum(x_enc * x_enc, dim=1) / torch.sum(mask == 1, dim=1) + 1e-5) + std_enc = std_enc.unsqueeze(1).detach() + x_enc /= std_enc + # B x S x E, B x 1 x E -> B x 1, positive scalar + tau = self.tau_learner(x_raw, std_enc) + threshold = 80.0 + tau_clamped = torch.clamp(tau, max=threshold) # avoid numerical overflow + tau = tau_clamped.exp() + # B x S x E, B x 1 x E -> B x S + delta = self.delta_learner(x_raw, mean_enc) + + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None, tau=tau, delta=delta) + + dec_out = self.projection(enc_out) + dec_out = dec_out * std_enc + mean_enc + return dec_out + + def anomaly_detection(self, x_enc): + x_raw = x_enc.clone().detach() + + # Normalization + 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() # B x 1 x E + x_enc = x_enc / std_enc + # B x S x E, B x 1 x E -> B x 1, positive scalar + tau = self.tau_learner(x_raw, std_enc) + threshold = 80.0 + tau_clamped = torch.clamp(tau, max=threshold) # avoid numerical overflow + tau = tau_clamped.exp() + # B x S x E, B x 1 x E -> B x S + delta = self.delta_learner(x_raw, mean_enc) + # embedding + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None, tau=tau, delta=delta) + + dec_out = self.projection(enc_out) + dec_out = dec_out * std_enc + mean_enc + return dec_out + + def classification(self, x_enc, x_mark_enc): + x_raw = x_enc.clone().detach() + + # Normalization + mean_enc = x_enc.mean(1, keepdim=True).detach() # B x 1 x E + std_enc = torch.sqrt( + torch.var(x_enc - mean_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() # B x 1 x E + # B x S x E, B x 1 x E -> B x 1, positive scalar + tau = self.tau_learner(x_raw, std_enc) + threshold = 80.0 + tau_clamped = torch.clamp(tau, max=threshold) # avoid numerical overflow + tau = tau_clamped.exp() + # B x S x E, B x 1 x E -> B x S + delta = self.delta_learner(x_raw, mean_enc) + # embedding + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None, tau=tau, delta=delta) + + # Output + output = self.act(enc_out) # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.dropout(output) + output = output * x_mark_enc.unsqueeze(-1) # zero-out padding embeddings + # (batch_size, seq_length * d_model) + output = output.reshape(output.shape[0], -1) + # (batch_size, num_classes) + output = self.projection(output) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, L, D] + return None diff --git a/models/PAttn.py b/models/PAttn.py new file mode 100644 index 0000000..b6f4634 --- /dev/null +++ b/models/PAttn.py @@ -0,0 +1,62 @@ +import torch +import torch.nn as nn +from layers.Transformer_EncDec import Encoder, EncoderLayer +from layers.SelfAttention_Family import FullAttention, AttentionLayer +from einops import rearrange + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/abs/2406.16964 + """ + def __init__(self, configs, patch_len=16, stride=8): + super().__init__() + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.patch_size = patch_len + self.stride = stride + + self.d_model = configs.d_model + + self.patch_num = (configs.seq_len - self.patch_size) // self.stride + 2 + self.padding_patch_layer = nn.ReplicationPad1d((0, self.stride)) + self.in_layer = nn.Linear(self.patch_size, self.d_model) + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(1) + ], + norm_layer=nn.LayerNorm(configs.d_model) + ) + self.out_layer = nn.Linear(self.d_model * self.patch_num, configs.pred_len) + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt( + torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + B, _, C = x_enc.shape + x_enc = x_enc.permute(0, 2, 1) + x_enc = self.padding_patch_layer(x_enc) + x_enc = x_enc.unfold(dimension=-1, size=self.patch_size, step=self.stride) + enc_out = self.in_layer(x_enc) + enc_out = rearrange(enc_out, 'b c m l -> (b c) m l') + dec_out, _ = self.encoder(enc_out) + dec_out = rearrange(dec_out, '(b c) m l -> b c (m l)' , b=B , c=C) + dec_out = self.out_layer(dec_out) + dec_out = dec_out.permute(0, 2, 1) + + dec_out = dec_out * \ + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + dec_out = dec_out + \ + (means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + return dec_out \ No newline at end of file diff --git a/models/PatchTST.py b/models/PatchTST.py new file mode 100644 index 0000000..085efd8 --- /dev/null +++ b/models/PatchTST.py @@ -0,0 +1,227 @@ +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 + +class Transpose(nn.Module): + 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) + + +class FlattenHead(nn.Module): + def __init__(self, n_vars, nf, target_window, head_dropout=0): + super().__init__() + self.n_vars = n_vars + self.flatten = nn.Flatten(start_dim=-2) + self.linear = nn.Linear(nf, target_window) + self.dropout = nn.Dropout(head_dropout) + + def forward(self, x): # x: [bs x nvars x d_model x patch_num] + x = self.flatten(x) + x = self.linear(x) + x = self.dropout(x) + return x + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/pdf/2211.14730.pdf + """ + + def __init__(self, configs, patch_len=16, stride=8): + """ + patch_len: int, patch len for patch_embedding + stride: int, stride for patch_embedding + """ + super().__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + padding = stride + + # patching and embedding + self.patch_embedding = PatchEmbedding( + configs.d_model, patch_len, stride, padding, configs.dropout) + + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + 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)) + ) + + # Prediction Head + self.head_nf = configs.d_model * \ + 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) + elif self.task_name == 'imputation' or self.task_name == 'anomaly_detection': + self.head = FlattenHead(configs.enc_in, self.head_nf, configs.seq_len, + head_dropout=configs.dropout) + elif self.task_name == 'classification': + self.flatten = nn.Flatten(start_dim=-2) + self.dropout = nn.Dropout(configs.dropout) + 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): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt( + torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + # do patching and embedding + x_enc = x_enc.permute(0, 2, 1) + # u: [bs * nvars x patch_num x d_model] + enc_out, n_vars = self.patch_embedding(x_enc) + + # Encoder + # z: [bs * nvars x patch_num x d_model] + enc_out, attns = self.encoder(enc_out) + # z: [bs x nvars x patch_num x d_model] + enc_out = torch.reshape( + enc_out, (-1, n_vars, enc_out.shape[-2], enc_out.shape[-1])) + # z: [bs x nvars x d_model x patch_num] + enc_out = enc_out.permute(0, 1, 3, 2) + + # Decoder + dec_out = self.head(enc_out) # z: [bs x nvars x target_window] + dec_out = dec_out.permute(0, 2, 1) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * \ + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + dec_out = dec_out + \ + (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): + # Normalization from Non-stationary Transformer + means = torch.sum(x_enc, dim=1) / torch.sum(mask == 1, dim=1) + means = means.unsqueeze(1).detach() + x_enc = x_enc - means + x_enc = x_enc.masked_fill(mask == 0, 0) + stdev = torch.sqrt(torch.sum(x_enc * x_enc, dim=1) / + torch.sum(mask == 1, dim=1) + 1e-5) + stdev = stdev.unsqueeze(1).detach() + x_enc /= stdev + + # do patching and embedding + x_enc = x_enc.permute(0, 2, 1) + # u: [bs * nvars x patch_num x d_model] + enc_out, n_vars = self.patch_embedding(x_enc) + + # Encoder + # z: [bs * nvars x patch_num x d_model] + enc_out, attns = self.encoder(enc_out) + # z: [bs x nvars x patch_num x d_model] + enc_out = torch.reshape( + enc_out, (-1, n_vars, enc_out.shape[-2], enc_out.shape[-1])) + # z: [bs x nvars x d_model x patch_num] + enc_out = enc_out.permute(0, 1, 3, 2) + + # Decoder + dec_out = self.head(enc_out) # z: [bs x nvars x target_window] + dec_out = dec_out.permute(0, 2, 1) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * \ + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + dec_out = dec_out + \ + (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + return dec_out + + def anomaly_detection(self, x_enc): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt( + torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + # do patching and embedding + x_enc = x_enc.permute(0, 2, 1) + # u: [bs * nvars x patch_num x d_model] + enc_out, n_vars = self.patch_embedding(x_enc) + + # Encoder + # z: [bs * nvars x patch_num x d_model] + enc_out, attns = self.encoder(enc_out) + # z: [bs x nvars x patch_num x d_model] + enc_out = torch.reshape( + enc_out, (-1, n_vars, enc_out.shape[-2], enc_out.shape[-1])) + # z: [bs x nvars x d_model x patch_num] + enc_out = enc_out.permute(0, 1, 3, 2) + + # Decoder + dec_out = self.head(enc_out) # z: [bs x nvars x target_window] + dec_out = dec_out.permute(0, 2, 1) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * \ + (stdev[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + dec_out = dec_out + \ + (means[:, 0, :].unsqueeze(1).repeat(1, self.seq_len, 1)) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt( + torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + # do patching and embedding + x_enc = x_enc.permute(0, 2, 1) + # u: [bs * nvars x patch_num x d_model] + enc_out, n_vars = self.patch_embedding(x_enc) + + # Encoder + # z: [bs * nvars x patch_num x d_model] + enc_out, attns = self.encoder(enc_out) + # z: [bs x nvars x patch_num x d_model] + enc_out = torch.reshape( + enc_out, (-1, n_vars, enc_out.shape[-2], enc_out.shape[-1])) + # z: [bs x nvars x d_model x patch_num] + enc_out = enc_out.permute(0, 1, 3, 2) + + # Decoder + output = self.flatten(enc_out) + output = self.dropout(output) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation( + x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/Pyraformer.py b/models/Pyraformer.py new file mode 100644 index 0000000..d92693c --- /dev/null +++ b/models/Pyraformer.py @@ -0,0 +1,101 @@ +import torch +import torch.nn as nn +from 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): + """ + window_size: list, the downsample window size in pyramidal attention. + inner_size: int, the size of neighbour attention + """ + super().__init__() + self.task_name = configs.task_name + self.pred_len = configs.pred_len + self.d_model = configs.d_model + + if self.task_name == 'short_term_forecast': + 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) + 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) + 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) + + 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 + x_enc = x_enc - mean_enc + std_enc = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() # B x 1 x E + x_enc = x_enc / std_enc + + 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 + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + enc_out = self.encoder(x_enc, x_mark_enc) + dec_out = self.projection(enc_out) + return dec_out + + def anomaly_detection(self, x_enc, x_mark_enc): + enc_out = self.encoder(x_enc, x_mark_enc) + dec_out = self.projection(enc_out) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # enc + enc_out = self.encoder(x_enc, x_mark_enc=None) + + # Output + # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.act(enc_out) + output = self.dropout(output) + # zero-out padding embeddings + output = output * x_mark_enc.unsqueeze(-1) + # (batch_size, seq_length * d_model) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) # (batch_size, num_classes) + + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast': + dec_out = self.long_forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'short_term_forecast': + dec_out = self.short_forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation( + x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc, x_mark_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/Reformer.py b/models/Reformer.py new file mode 100644 index 0000000..b29336c --- /dev/null +++ b/models/Reformer.py @@ -0,0 +1,132 @@ +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 + + +class Model(nn.Module): + """ + Reformer with O(LlogL) complexity + Paper link: https://openreview.net/forum?id=rkgNKkHtvB + """ + + def __init__(self, configs, bucket_size=4, n_hashes=4): + """ + bucket_size: int, + n_hashes: int, + """ + super(Model, self).__init__() + self.task_name = configs.task_name + self.pred_len = configs.pred_len + self.seq_len = configs.seq_len + + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + ReformerLayer(None, configs.d_model, configs.n_heads, + bucket_size=bucket_size, n_hashes=n_hashes), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model) + ) + + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear( + configs.d_model * configs.seq_len, configs.num_class) + else: + self.projection = nn.Linear( + configs.d_model, configs.c_out, bias=True) + + def long_forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # add placeholder + x_enc = torch.cat([x_enc, x_dec[:, -self.pred_len:, :]], dim=1) + if x_mark_enc is not None: + x_mark_enc = torch.cat( + [x_mark_enc, x_mark_dec[:, -self.pred_len:, :]], dim=1) + + enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C] + enc_out, attns = self.encoder(enc_out, attn_mask=None) + 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 + x_enc = x_enc - mean_enc + std_enc = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5).detach() # B x 1 x E + x_enc = x_enc / std_enc + + # add placeholder + x_enc = torch.cat([x_enc, x_dec[:, -self.pred_len:, :]], dim=1) + if x_mark_enc is not None: + x_mark_enc = torch.cat( + [x_mark_enc, x_mark_dec[:, -self.pred_len:, :]], dim=1) + + enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C] + enc_out, attns = self.encoder(enc_out, attn_mask=None) + dec_out = self.projection(enc_out) + + dec_out = dec_out * std_enc + mean_enc + return dec_out # [B, L, D] + + def imputation(self, x_enc, x_mark_enc): + enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C] + + enc_out, attns = self.encoder(enc_out) + enc_out = self.projection(enc_out) + + return enc_out # [B, L, D] + + def anomaly_detection(self, x_enc): + enc_out = self.enc_embedding(x_enc, None) # [B,T,C] + + enc_out, attns = self.encoder(enc_out) + enc_out = self.projection(enc_out) + + return enc_out # [B, L, D] + + def classification(self, x_enc, x_mark_enc): + # enc + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out) + + # Output + # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.act(enc_out) + output = self.dropout(output) + # zero-out padding embeddings + output = output * x_mark_enc.unsqueeze(-1) + # (batch_size, seq_length * d_model) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast': + dec_out = self.long_forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'short_term_forecast': + dec_out = self.short_forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/SCINet.py b/models/SCINet.py new file mode 100644 index 0000000..740d0f7 --- /dev/null +++ b/models/SCINet.py @@ -0,0 +1,188 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math + +class Splitting(nn.Module): + def __init__(self): + super(Splitting, self).__init__() + + def even(self, x): + return x[:, ::2, :] + + def odd(self, x): + return x[:, 1::2, :] + + def forward(self, x): + # return the odd and even part + return self.even(x), self.odd(x) + + +class CausalConvBlock(nn.Module): + def __init__(self, d_model, kernel_size=5, dropout=0.0): + super(CausalConvBlock, self).__init__() + module_list = [ + nn.ReplicationPad1d((kernel_size - 1, kernel_size - 1)), + + nn.Conv1d(d_model, d_model, + kernel_size=kernel_size), + nn.LeakyReLU(negative_slope=0.01, inplace=True), + + nn.Dropout(dropout), + nn.Conv1d(d_model, d_model, + kernel_size=kernel_size), + nn.Tanh() + ] + self.causal_conv = nn.Sequential(*module_list) + + def forward(self, x): + return self.causal_conv(x) # return value is the same as input dimension + + +class SCIBlock(nn.Module): + def __init__(self, d_model, kernel_size=5, dropout=0.0): + super(SCIBlock, self).__init__() + self.splitting = Splitting() + self.modules_even, self.modules_odd, self.interactor_even, self.interactor_odd = [CausalConvBlock(d_model) for _ in range(4)] + + def forward(self, x): + x_even, x_odd = self.splitting(x) + x_even = x_even.permute(0, 2, 1) + x_odd = x_odd.permute(0, 2, 1) + + x_even_temp = x_even.mul(torch.exp(self.modules_even(x_odd))) + x_odd_temp = x_odd.mul(torch.exp(self.modules_odd(x_even))) + + x_even_update = x_even_temp + self.interactor_even(x_odd_temp) + x_odd_update = x_odd_temp - self.interactor_odd(x_even_temp) + + return x_even_update.permute(0, 2, 1), x_odd_update.permute(0, 2, 1) + + +class SCINet(nn.Module): + def __init__(self, d_model, current_level=3, kernel_size=5, dropout=0.0): + super(SCINet, self).__init__() + self.current_level = current_level + self.working_block = SCIBlock(d_model, kernel_size, dropout) + + if current_level != 0: + self.SCINet_Tree_odd = SCINet(d_model, current_level-1, kernel_size, dropout) + self.SCINet_Tree_even = SCINet(d_model, current_level-1, kernel_size, dropout) + + def forward(self, x): + odd_flag = False + if x.shape[1] % 2 == 1: + odd_flag = True + x = torch.cat((x, x[:, -1:, :]), dim=1) + x_even_update, x_odd_update = self.working_block(x) + if odd_flag: + x_odd_update = x_odd_update[:, :-1] + + if self.current_level == 0: + return self.zip_up_the_pants(x_even_update, x_odd_update) + else: + return self.zip_up_the_pants(self.SCINet_Tree_even(x_even_update), self.SCINet_Tree_odd(x_odd_update)) + + def zip_up_the_pants(self, even, odd): + even = even.permute(1, 0, 2) + odd = odd.permute(1, 0, 2) + even_len = even.shape[0] + odd_len = odd.shape[0] + min_len = min(even_len, odd_len) + + zipped_data = [] + for i in range(min_len): + zipped_data.append(even[i].unsqueeze(0)) + zipped_data.append(odd[i].unsqueeze(0)) + if even_len > odd_len: + zipped_data.append(even[-1].unsqueeze(0)) + return torch.cat(zipped_data,0).permute(1, 0, 2) + + +class Model(nn.Module): + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.pred_len + + # You can set the number of SCINet stacks by argument "d_layers", but should choose 1 or 2. + self.num_stacks = configs.d_layers + if self.num_stacks == 1: + self.sci_net_1 = SCINet(configs.enc_in, dropout=configs.dropout) + self.projection_1 = nn.Conv1d(self.seq_len, self.seq_len + self.pred_len, kernel_size=1, stride=1, bias=False) + else: + self.sci_net_1, self.sci_net_2 = [SCINet(configs.enc_in, dropout=configs.dropout) for _ in range(2)] + self.projection_1 = nn.Conv1d(self.seq_len, self.pred_len, kernel_size=1, stride=1, bias=False) + self.projection_2 = nn.Conv1d(self.seq_len+self.pred_len, self.seq_len+self.pred_len, + kernel_size = 1, bias = False) + + # For positional encoding + self.pe_hidden_size = configs.enc_in + if self.pe_hidden_size % 2 == 1: + self.pe_hidden_size += 1 + + num_timescales = self.pe_hidden_size // 2 + max_timescale = 10000.0 + min_timescale = 1.0 + + log_timescale_increment = ( + math.log(float(max_timescale) / float(min_timescale)) / + max(num_timescales - 1, 1)) + inv_timescales = min_timescale * torch.exp( + torch.arange(num_timescales, dtype=torch.float32) * + -log_timescale_increment) + self.register_buffer('inv_timescales', inv_timescales) + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + 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 + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + # position-encoding + pe = self.get_position_encoding(x_enc) + if pe.shape[2] > x_enc.shape[2]: + x_enc += pe[:, :, :-1] + else: + x_enc += self.get_position_encoding(x_enc) + + # SCINet + dec_out = self.sci_net_1(x_enc) + dec_out += x_enc + dec_out = self.projection_1(dec_out) + if self.num_stacks != 1: + dec_out = torch.cat((x_enc, dec_out), dim=1) + temp = dec_out + dec_out = self.sci_net_2(dec_out) + dec_out += temp + dec_out = self.projection_2(dec_out) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * \ + (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)) + return dec_out + + def get_position_encoding(self, x): + max_length = x.size()[1] + position = torch.arange(max_length, dtype=torch.float32, + device=x.device) # tensor([0., 1., 2., 3., 4.], device='cuda:0') + scaled_time = position.unsqueeze(1) * self.inv_timescales.unsqueeze(0) # 5 256 + signal = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], dim=1) # [T, C] + signal = F.pad(signal, (0, 0, 0, self.pe_hidden_size % 2)) + signal = signal.view(1, max_length, self.pe_hidden_size) + + return signal \ No newline at end of file diff --git a/models/SegRNN.py b/models/SegRNN.py new file mode 100644 index 0000000..afff1bc --- /dev/null +++ b/models/SegRNN.py @@ -0,0 +1,119 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from layers.Autoformer_EncDec import series_decomp + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/abs/2308.11200.pdf + """ + + def __init__(self, configs): + super(Model, self).__init__() + + # get parameters + self.seq_len = configs.seq_len + self.enc_in = configs.enc_in + self.d_model = configs.d_model + self.dropout = configs.dropout + + self.task_name = configs.task_name + if self.task_name == 'classification' or self.task_name == 'anomaly_detection' or self.task_name == 'imputation': + self.pred_len = configs.seq_len + else: + self.pred_len = configs.pred_len + + self.seg_len = configs.seg_len + self.seg_num_x = self.seq_len // self.seg_len + self.seg_num_y = self.pred_len // self.seg_len + + # building model + self.valueEmbedding = nn.Sequential( + nn.Linear(self.seg_len, self.d_model), + 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) + 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)) + + self.predict = nn.Sequential( + nn.Dropout(self.dropout), + nn.Linear(self.d_model, self.seg_len) + ) + + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear( + configs.enc_in * configs.seq_len, configs.num_class) + + def encoder(self, x): + # b:batch_size c:channel_size s:seq_len s:seq_len + # d:d_model w:seg_len n:seg_num_x m:seg_num_y + batch_size = x.size(0) + + # 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 + + # 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 + + # m,d//2 -> 1,m,d//2 -> c,m,d//2 + # c,d//2 -> c,1,d//2 -> c,m,d//2 + # c,m,d -> cm,1,d -> bcm, 1, d + 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) + + _, 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) + + # permute and denorm + y = y.permute(0, 2, 1) + seq_last + return y + + def forecast(self, x_enc): + # Encoder + return self.encoder(x_enc) + + def imputation(self, x_enc): + # Encoder + return self.encoder(x_enc) + + def anomaly_detection(self, x_enc): + # Encoder + return self.encoder(x_enc) + + def classification(self, x_enc): + # Encoder + enc_out = self.encoder(x_enc) + # Output + # (batch_size, seq_length * d_model) + output = enc_out.reshape(enc_out.shape[0], -1) + # (batch_size, num_classes) + output = self.projection(output) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc) + return dec_out # [B, N] + return None diff --git a/models/TSMixer.py b/models/TSMixer.py new file mode 100644 index 0000000..76884d4 --- /dev/null +++ b/models/TSMixer.py @@ -0,0 +1,54 @@ +import torch.nn as nn + + +class ResBlock(nn.Module): + def __init__(self, configs): + super(ResBlock, self).__init__() + + self.temporal = nn.Sequential( + nn.Linear(configs.seq_len, configs.d_model), + nn.ReLU(), + nn.Linear(configs.d_model, configs.seq_len), + nn.Dropout(configs.dropout) + ) + + self.channel = nn.Sequential( + nn.Linear(configs.enc_in, configs.d_model), + nn.ReLU(), + nn.Linear(configs.d_model, configs.enc_in), + nn.Dropout(configs.dropout) + ) + + def forward(self, x): + # x: [B, L, D] + x = x + self.temporal(x.transpose(1, 2)).transpose(1, 2) + x = x + self.channel(x) + + return x + + +class Model(nn.Module): + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.layer = configs.e_layers + self.model = nn.ModuleList([ResBlock(configs) + for _ in range(configs.e_layers)]) + self.pred_len = configs.pred_len + self.projection = nn.Linear(configs.seq_len, configs.pred_len) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + + # x: [B, L, D] + for i in range(self.layer): + x_enc = self.model[i](x_enc) + enc_out = self.projection(x_enc.transpose(1, 2)).transpose(1, 2) + + return enc_out + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + else: + raise ValueError('Only forecast tasks implemented yet') diff --git a/models/TemporalFusionTransformer.py b/models/TemporalFusionTransformer.py new file mode 100644 index 0000000..564c835 --- /dev/null +++ b/models/TemporalFusionTransformer.py @@ -0,0 +1,309 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from layers.Embed import DataEmbedding, TemporalEmbedding +from torch import Tensor +from typing import Optional +from collections import namedtuple + +# static: time-independent features +# observed: time features of the past(e.g. predicted targets) +# known: known information about the past and future(i.e. time stamp) +TypePos = namedtuple('TypePos', ['static', 'observed']) + +# When you want to use new dataset, please add the index of 'static, observed' columns here. +# 'known' columns needn't be added, because 'known' inputs are automatically judged and provided by the program. +datatype_dict = {'ETTh1': TypePos([], [x for x in range(7)]), + 'ETTm1': TypePos([], [x for x in range(7)])} + + +def get_known_len(embed_type, freq): + if embed_type != 'timeF': + if freq == 't': + return 5 + else: + return 4 + else: + freq_map = {'h': 4, 't': 5, 's': 6, + 'm': 1, 'a': 1, 'w': 2, 'd': 3, 'b': 3} + return freq_map[freq] + + +class TFTTemporalEmbedding(TemporalEmbedding): + def __init__(self, d_model, embed_type='fixed', freq='h'): + super(TFTTemporalEmbedding, self).__init__(d_model, embed_type, freq) + + def forward(self, x): + x = x.long() + minute_x = self.minute_embed(x[:, :, 4]) if hasattr( + self, 'minute_embed') else 0. + hour_x = self.hour_embed(x[:, :, 3]) + weekday_x = self.weekday_embed(x[:, :, 2]) + day_x = self.day_embed(x[:, :, 1]) + month_x = self.month_embed(x[:, :, 0]) + + embedding_x = torch.stack([month_x, day_x, weekday_x, hour_x, minute_x], dim=-2) if hasattr( + self, 'minute_embed') else torch.stack([month_x, day_x, weekday_x, hour_x], dim=-2) + return embedding_x + + +class TFTTimeFeatureEmbedding(nn.Module): + def __init__(self, d_model, embed_type='timeF', freq='h'): + super(TFTTimeFeatureEmbedding, self).__init__() + d_inp = get_known_len(embed_type, freq) + 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) + + +class TFTEmbedding(nn.Module): + def __init__(self, configs): + super(TFTEmbedding, self).__init__() + self.pred_len = configs.pred_len + self.static_pos = datatype_dict[configs.data].static + self.observed_pos = datatype_dict[configs.data].observed + 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)]) \ + 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.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) + 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) + + 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) + + return static_input, observed_input, known_input + + +class GLU(nn.Module): + def __init__(self, input_size, output_size): + super().__init__() + self.fc1 = nn.Linear(input_size, output_size) + self.fc2 = nn.Linear(input_size, output_size) + self.glu = nn.GLU() + + def forward(self, x): + a = self.fc1(x) + b = self.fc2(x) + return self.glu(torch.cat([a, b], dim=-1)) + + +class GateAddNorm(nn.Module): + def __init__(self, input_size, output_size): + super(GateAddNorm, self).__init__() + self.glu = GLU(input_size, input_size) + self.projection = nn.Linear(input_size, output_size) if input_size != output_size else nn.Identity() + self.layer_norm = nn.LayerNorm(output_size) + + def forward(self, x, skip_a): + x = self.glu(x) + x = x + skip_a + return self.layer_norm(self.projection(x)) + + +class GRN(nn.Module): + def __init__(self, input_size, output_size, hidden_size=None, context_size=None, dropout=0.0): + super(GRN, self).__init__() + hidden_size = input_size if hidden_size is None else hidden_size + self.lin_a = nn.Linear(input_size, hidden_size) + self.lin_c = nn.Linear(context_size, hidden_size) if context_size is not None else None + self.lin_i = nn.Linear(hidden_size, hidden_size) + self.dropout = nn.Dropout(dropout) + self.project_a = nn.Linear(input_size, hidden_size) if hidden_size != input_size else nn.Identity() + self.gate = GateAddNorm(hidden_size, output_size) + + def forward(self, a: Tensor, c: Optional[Tensor] = None): + # a: [B,T,d], c: [B,d] + x = self.lin_a(a) + if c is not None: + x = x + self.lin_c(c).unsqueeze(1) + x = F.elu(x) + x = self.lin_i(x) + x = self.dropout(x) + return self.gate(x, self.project_a(a)) + + +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.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): + # x: [B,T,C,d] or [B,C,d] + # selection_weights: [B,T,C] or [B,C] + # x_processed: [B,T,d,C] or [B,d,C] + # selection_result: [B,T,d] or [B,d] + x_flattened = torch.flatten(x, start_dim=-2) + 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) + + selection_result = torch.matmul(x_processed, selection_weights.unsqueeze(-1)).squeeze(-1) + return selection_result + + +class StaticCovariateEncoder(nn.Module): + def __init__(self, d_model, static_len, dropout=0.0): + super(StaticCovariateEncoder, self).__init__() + self.static_vsn = VariableSelectionNetwork(d_model, static_len) if static_len else None + self.grns = nn.ModuleList([GRN(d_model, d_model, dropout=dropout) for _ in range(4)]) + + def forward(self, static_input): + # static_input: [B,C,d] + if static_input is not None: + static_features = self.static_vsn(static_input) + return [grn(static_features) for grn in self.grns] + else: + return [None] * 4 + + +class InterpretableMultiHeadAttention(nn.Module): + def __init__(self, configs): + super(InterpretableMultiHeadAttention, self).__init__() + self.n_heads = configs.n_heads + assert configs.d_model % configs.n_heads == 0 + self.d_head = configs.d_model // configs.n_heads + self.qkv_linears = nn.Linear(configs.d_model, (2 * self.n_heads + 1) * self.d_head, bias=False) + self.out_projection = nn.Linear(self.d_head, configs.d_model, bias=False) + self.out_dropout = nn.Dropout(configs.dropout) + self.scale = self.d_head ** -0.5 + example_len = configs.seq_len + configs.pred_len + self.register_buffer("mask", torch.triu(torch.full((example_len, example_len), float('-inf')), 1)) + + def forward(self, x): + # Q,K,V are all from x + B, T, d_model = x.shape + qkv = self.qkv_linears(x) + q, k, v = qkv.split((self.n_heads * self.d_head, self.n_heads * self.d_head, self.d_head), dim=-1) + q = q.view(B, T, self.n_heads, self.d_head) + k = k.view(B, T, self.n_heads, self.d_head) + v = v.view(B, T, self.d_head) + + attention_score = torch.matmul(q.permute((0, 2, 1, 3)), k.permute((0, 2, 3, 1))) # [B,n,T,T] + attention_score.mul_(self.scale) + attention_score = attention_score + self.mask + attention_prob = F.softmax(attention_score, dim=3) # [B,n,T,T] + + attention_out = torch.matmul(attention_prob, v.unsqueeze(1)) # [B,n,T,d] + attention_out = torch.mean(attention_out, dim=1) # [B,T,d] + out = self.out_projection(attention_out) + out = self.out_dropout(out) # [B,T,d] + return out + + +class TemporalFusionDecoder(nn.Module): + def __init__(self, configs): + super(TemporalFusionDecoder, self).__init__() + self.pred_len = configs.pred_len + + 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.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) + self.gate_final = GateAddNorm(configs.d_model, configs.d_model) + self.out_projection = nn.Linear(configs.d_model, configs.c_out) + + def forward(self, history_input, future_input, c_c, c_h, c_e): + # history_input, future_input: [B,T,d] + # c_c, c_h, c_e: [B,d] + # LSTM + c = (c_c.unsqueeze(0), c_h.unsqueeze(0)) if c_c is not None and c_h is not None else None + historical_features, state = self.history_encoder(history_input, c) + future_features, _ = self.future_encoder(future_input, state) + + # Skip connection + temporal_input = torch.cat([history_input, future_input], dim=1) + temporal_features = torch.cat([historical_features, future_features], dim=1) + temporal_features = self.gate_after_lstm(temporal_features, temporal_input) # [B,T,d] + + # Static enrichment + enriched_features = self.enrichment_grn(temporal_features, c_e) # [B,T,d] + + # 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:]) + + # 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:]) + return self.out_projection(out) + + +class Model(nn.Module): + def __init__(self, configs): + super(Model, self).__init__() + self.configs = configs + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.pred_len + + # Number of variables + self.static_len = len(datatype_dict[configs.data].static) + self.observed_len = len(datatype_dict[configs.data].observed) + self.known_len = get_known_len(configs.embed, configs.freq) + + self.embedding = TFTEmbedding(configs) + self.static_encoder = StaticCovariateEncoder(configs.d_model, self.static_len) + self.history_vsn = VariableSelectionNetwork(configs.d_model, self.observed_len + self.known_len) + self.future_vsn = VariableSelectionNetwork(configs.d_model, self.known_len) + self.temporal_fusion_decoder = TemporalFusionDecoder(configs) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + # Data embedding + # static_input: [B,C,d], observed_input:[B,T,C,d], known_input: [B,T,C,d] + static_input, observed_input, known_input = self.embedding(x_enc, x_mark_enc, x_dec, x_mark_dec) + + # Static context + # c_s,...,c_e: [B,d] + 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 = self.history_vsn(history_input, c_s) + future_input = self.future_vsn(future_input, c_s) + + # TFT main procedure after variable selection + # history_input: [B,T,d], future_input: [B,T,d] + dec_out = self.temporal_fusion_decoder(history_input, future_input, c_c, c_h, c_e) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + dec_out = dec_out + (means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + return dec_out + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + 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 diff --git a/models/TiDE.py b/models/TiDE.py new file mode 100644 index 0000000..0fbb98e --- /dev/null +++ b/models/TiDE.py @@ -0,0 +1,145 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + + +class LayerNorm(nn.Module): + """ LayerNorm but with an optional bias. PyTorch doesn't support simply bias=False """ + + def __init__(self, ndim, bias): + super().__init__() + self.weight = nn.Parameter(torch.ones(ndim)) + self.bias = nn.Parameter(torch.zeros(ndim)) if bias else None + + def forward(self, input): + return F.layer_norm(input, self.weight.shape, self.weight, self.bias, 1e-5) + + + +class ResBlock(nn.Module): + def __init__(self, input_dim, hidden_dim, output_dim, dropout=0.1, bias=True): + super().__init__() + + self.fc1 = nn.Linear(input_dim, hidden_dim, bias=bias) + self.fc2 = nn.Linear(hidden_dim, output_dim, bias=bias) + self.fc3 = nn.Linear(input_dim, output_dim, bias=bias) + self.dropout = nn.Dropout(dropout) + self.relu = nn.ReLU() + self.ln = LayerNorm(output_dim, bias=bias) + + def forward(self, x): + + out = self.fc1(x) + out = self.relu(out) + out = self.fc2(out) + out = self.dropout(out) + out = out + self.fc3(x) + out = self.ln(out) + return out + + +#TiDE +class Model(nn.Module): + """ + paper: https://arxiv.org/pdf/2304.08424.pdf + """ + def __init__(self, configs, bias=True, feature_encode_dim=2): + super(Model, self).__init__() + self.configs = configs + self.task_name = configs.task_name + self.seq_len = configs.seq_len #L + self.label_len = configs.label_len + self.pred_len = configs.pred_len #H + self.hidden_dim=configs.d_model + self.res_hidden=configs.d_model + self.encoder_num=configs.e_layers + self.decoder_num=configs.d_layers + self.freq=configs.freq + self.feature_encode_dim=feature_encode_dim + self.decode_dim = configs.c_out + self.temporalDecoderHidden=configs.d_ff + dropout=configs.dropout + + + freq_map = {'h': 4, 't': 5, 's': 6, + 'm': 1, 'a': 1, 'w': 2, 'd': 3, 'b': 3} + + self.feature_dim=freq_map[self.freq] + + + flatten_dim = self.seq_len + (self.seq_len + self.pred_len) * self.feature_encode_dim + + self.feature_encoder = ResBlock(self.feature_dim, self.res_hidden, self.feature_encode_dim, dropout, bias) + self.encoders = nn.Sequential(ResBlock(flatten_dim, self.res_hidden, self.hidden_dim, dropout, bias),*([ ResBlock(self.hidden_dim, self.res_hidden, self.hidden_dim, dropout, bias)]*(self.encoder_num-1))) + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.decoders = nn.Sequential(*([ ResBlock(self.hidden_dim, self.res_hidden, self.hidden_dim, dropout, bias)]*(self.decoder_num-1)),ResBlock(self.hidden_dim, self.res_hidden, self.decode_dim * self.pred_len, dropout, bias)) + self.temporalDecoder = ResBlock(self.decode_dim + self.feature_encode_dim, self.temporalDecoderHidden, 1, dropout, bias) + self.residual_proj = nn.Linear(self.seq_len, self.pred_len, bias=bias) + if self.task_name == 'imputation': + self.decoders = nn.Sequential(*([ ResBlock(self.hidden_dim, self.res_hidden, self.hidden_dim, dropout, bias)]*(self.decoder_num-1)),ResBlock(self.hidden_dim, self.res_hidden, self.decode_dim * self.seq_len, dropout, bias)) + self.temporalDecoder = ResBlock(self.decode_dim + self.feature_encode_dim, self.temporalDecoderHidden, 1, dropout, bias) + self.residual_proj = nn.Linear(self.seq_len, self.seq_len, bias=bias) + if self.task_name == 'anomaly_detection': + self.decoders = nn.Sequential(*([ ResBlock(self.hidden_dim, self.res_hidden, self.hidden_dim, dropout, bias)]*(self.decoder_num-1)),ResBlock(self.hidden_dim, self.res_hidden, self.decode_dim * self.seq_len, dropout, bias)) + self.temporalDecoder = ResBlock(self.decode_dim + self.feature_encode_dim, self.temporalDecoderHidden, 1, dropout, bias) + self.residual_proj = nn.Linear(self.seq_len, self.seq_len, bias=bias) + + + def forecast(self, x_enc, x_mark_enc, x_dec, batch_y_mark): + # Normalization + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + feature = self.feature_encoder(batch_y_mark) + hidden = self.encoders(torch.cat([x_enc, feature.reshape(feature.shape[0], -1)], dim=-1)) + decoded = self.decoders(hidden).reshape(hidden.shape[0], self.pred_len, self.decode_dim) + dec_out = self.temporalDecoder(torch.cat([feature[:,self.seq_len:], decoded], dim=-1)).squeeze(-1) + self.residual_proj(x_enc) + + + # De-Normalization + dec_out = dec_out * (stdev[:, 0].unsqueeze(1).repeat(1, self.pred_len)) + dec_out = dec_out + (means[:, 0].unsqueeze(1).repeat(1, self.pred_len)) + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, batch_y_mark, mask): + # Normalization + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + feature = self.feature_encoder(x_mark_enc) + hidden = self.encoders(torch.cat([x_enc, feature.reshape(feature.shape[0], -1)], dim=-1)) + decoded = self.decoders(hidden).reshape(hidden.shape[0], self.seq_len, self.decode_dim) + dec_out = self.temporalDecoder(torch.cat([feature[:,:self.seq_len], decoded], dim=-1)).squeeze(-1) + self.residual_proj(x_enc) + + # De-Normalization + dec_out = dec_out * (stdev[:, 0].unsqueeze(1).repeat(1, self.seq_len)) + dec_out = dec_out + (means[:, 0].unsqueeze(1).repeat(1, self.seq_len)) + return dec_out + + + def forward(self, x_enc, x_mark_enc, x_dec, batch_y_mark, mask=None): + '''x_mark_enc is the exogenous dynamic feature described in the original paper''' + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + if batch_y_mark is None: + batch_y_mark = torch.zeros((x_enc.shape[0], self.seq_len+self.pred_len, self.feature_dim)).to(x_enc.device).detach() + else: + batch_y_mark = torch.concat([x_mark_enc, batch_y_mark[:, -self.pred_len:, :]],dim=1) + dec_out = torch.stack([self.forecast(x_enc[:, :, feature], x_mark_enc, x_dec, batch_y_mark) for feature in range(x_enc.shape[-1])],dim=-1) + return dec_out # [B, L, D] + if self.task_name == 'imputation': + dec_out = torch.stack([self.imputation(x_enc[:, :, feature], x_mark_enc, x_dec, batch_y_mark, mask) for feature in range(x_enc.shape[-1])],dim=-1) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + raise NotImplementedError("Task anomaly_detection for Tide is temporarily not supported") + if self.task_name == 'classification': + raise NotImplementedError("Task classification for Tide is temporarily not supported") + return None + + + + + diff --git a/models/TimeMixer.py b/models/TimeMixer.py new file mode 100755 index 0000000..bd488ea --- /dev/null +++ b/models/TimeMixer.py @@ -0,0 +1,516 @@ +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 + + +class DFT_series_decomp(nn.Module): + """ + Series decomposition block + """ + + def __init__(self, top_k: int = 5): + super(DFT_series_decomp, self).__init__() + self.top_k = top_k + + def forward(self, x): + xf = torch.fft.rfft(x) + freq = abs(xf) + freq[0] = 0 + top_k_freq, top_list = torch.topk(freq, k=self.top_k) + xf[freq <= top_k_freq.min()] = 0 + x_season = torch.fft.irfft(xf) + x_trend = x - x_season + return x_season, x_trend + + +class MultiScaleSeasonMixing(nn.Module): + """ + Bottom-up mixing season pattern + """ + + def __init__(self, configs): + super(MultiScaleSeasonMixing, self).__init__() + + self.down_sampling_layers = torch.nn.ModuleList( + [ + nn.Sequential( + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** i), + configs.seq_len // (configs.down_sampling_window ** (i + 1)), + ), + nn.GELU(), + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** (i + 1)), + configs.seq_len // (configs.down_sampling_window ** (i + 1)), + ), + + ) + for i in range(configs.down_sampling_layers) + ] + ) + + def forward(self, season_list): + + # mixing high->low + out_high = season_list[0] + out_low = season_list[1] + out_season_list = [out_high.permute(0, 2, 1)] + + for i in range(len(season_list) - 1): + out_low_res = self.down_sampling_layers[i](out_high) + out_low = out_low + out_low_res + out_high = out_low + if i + 2 <= len(season_list) - 1: + out_low = season_list[i + 2] + out_season_list.append(out_high.permute(0, 2, 1)) + + return out_season_list + + +class MultiScaleTrendMixing(nn.Module): + """ + Top-down mixing trend pattern + """ + + def __init__(self, configs): + super(MultiScaleTrendMixing, self).__init__() + + self.up_sampling_layers = torch.nn.ModuleList( + [ + nn.Sequential( + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** (i + 1)), + configs.seq_len // (configs.down_sampling_window ** i), + ), + nn.GELU(), + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** i), + configs.seq_len // (configs.down_sampling_window ** i), + ), + ) + for i in reversed(range(configs.down_sampling_layers)) + ]) + + def forward(self, trend_list): + + # mixing low->high + trend_list_reverse = trend_list.copy() + trend_list_reverse.reverse() + out_low = trend_list_reverse[0] + out_high = trend_list_reverse[1] + out_trend_list = [out_low.permute(0, 2, 1)] + + for i in range(len(trend_list_reverse) - 1): + out_high_res = self.up_sampling_layers[i](out_low) + out_high = out_high + out_high_res + out_low = out_high + if i + 2 <= len(trend_list_reverse) - 1: + out_high = trend_list_reverse[i + 2] + out_trend_list.append(out_low.permute(0, 2, 1)) + + out_trend_list.reverse() + return out_trend_list + + +class PastDecomposableMixing(nn.Module): + def __init__(self, configs): + super(PastDecomposableMixing, self).__init__() + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.down_sampling_window = configs.down_sampling_window + + self.layer_norm = nn.LayerNorm(configs.d_model) + self.dropout = nn.Dropout(configs.dropout) + self.channel_independence = configs.channel_independence + + if configs.decomp_method == 'moving_avg': + self.decompsition = series_decomp(configs.moving_avg) + elif configs.decomp_method == "dft_decomp": + self.decompsition = DFT_series_decomp(configs.top_k) + else: + raise ValueError('decompsition is error') + + if not configs.channel_independence: + self.cross_layer = nn.Sequential( + nn.Linear(in_features=configs.d_model, out_features=configs.d_ff), + nn.GELU(), + nn.Linear(in_features=configs.d_ff, out_features=configs.d_model), + ) + + # Mixing season + self.mixing_multi_scale_season = MultiScaleSeasonMixing(configs) + + # Mxing trend + self.mixing_multi_scale_trend = MultiScaleTrendMixing(configs) + + self.out_cross_layer = nn.Sequential( + nn.Linear(in_features=configs.d_model, out_features=configs.d_ff), + nn.GELU(), + nn.Linear(in_features=configs.d_ff, out_features=configs.d_model), + ) + + def forward(self, x_list): + length_list = [] + for x in x_list: + _, T, _ = x.size() + length_list.append(T) + + # Decompose to obtain the season and trend + season_list = [] + trend_list = [] + for x in x_list: + season, trend = self.decompsition(x) + if not self.channel_independence: + season = self.cross_layer(season) + trend = self.cross_layer(trend) + season_list.append(season.permute(0, 2, 1)) + trend_list.append(trend.permute(0, 2, 1)) + + # bottom-up season mixing + out_season_list = self.mixing_multi_scale_season(season_list) + # top-down trend mixing + out_trend_list = self.mixing_multi_scale_trend(trend_list) + + out_list = [] + for ori, out_season, out_trend, length in zip(x_list, out_season_list, out_trend_list, + length_list): + out = out_season + out_trend + if self.channel_independence: + out = ori + self.out_cross_layer(out) + out_list.append(out[:, :length, :]) + return out_list + + +class Model(nn.Module): + + def __init__(self, configs): + super(Model, self).__init__() + self.configs = configs + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.pred_len + self.down_sampling_window = configs.down_sampling_window + self.channel_independence = configs.channel_independence + self.pdm_blocks = nn.ModuleList([PastDecomposableMixing(configs) + for _ in range(configs.e_layers)]) + + self.preprocess = series_decomp(configs.moving_avg) + self.enc_in = configs.enc_in + + if self.channel_independence: + self.enc_embedding = DataEmbedding_wo_pos(1, configs.d_model, configs.embed, configs.freq, + configs.dropout) + else: + self.enc_embedding = DataEmbedding_wo_pos(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + self.layer = configs.e_layers + + self.normalize_layers = torch.nn.ModuleList( + [ + Normalize(self.configs.enc_in, affine=True, non_norm=True if configs.use_norm == 0 else False) + for i in range(configs.down_sampling_layers + 1) + ] + ) + + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.predict_layers = torch.nn.ModuleList( + [ + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** i), + configs.pred_len, + ) + for i in range(configs.down_sampling_layers + 1) + ] + ) + + if self.channel_independence: + self.projection_layer = nn.Linear( + configs.d_model, 1, bias=True) + else: + self.projection_layer = nn.Linear( + configs.d_model, configs.c_out, bias=True) + + self.out_res_layers = torch.nn.ModuleList([ + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** i), + configs.seq_len // (configs.down_sampling_window ** i), + ) + for i in range(configs.down_sampling_layers + 1) + ]) + + self.regression_layers = torch.nn.ModuleList( + [ + torch.nn.Linear( + configs.seq_len // (configs.down_sampling_window ** i), + configs.pred_len, + ) + for i in range(configs.down_sampling_layers + 1) + ] + ) + + if self.task_name == 'imputation' or self.task_name == 'anomaly_detection': + if self.channel_independence: + self.projection_layer = nn.Linear( + configs.d_model, 1, bias=True) + else: + self.projection_layer = nn.Linear( + configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear( + configs.d_model * configs.seq_len, configs.num_class) + + def out_projection(self, dec_out, i, out_res): + dec_out = self.projection_layer(dec_out) + out_res = out_res.permute(0, 2, 1) + out_res = self.out_res_layers[i](out_res) + out_res = self.regression_layers[i](out_res).permute(0, 2, 1) + dec_out = dec_out + out_res + return dec_out + + def pre_enc(self, x_list): + if self.channel_independence: + return (x_list, None) + else: + out1_list = [] + out2_list = [] + for x in x_list: + x_1, x_2 = self.preprocess(x) + out1_list.append(x_1) + out2_list.append(x_2) + return (out1_list, out2_list) + + def __multi_scale_process_inputs(self, x_enc, x_mark_enc): + if self.configs.down_sampling_method == 'max': + down_pool = torch.nn.MaxPool1d(self.configs.down_sampling_window, return_indices=False) + elif self.configs.down_sampling_method == 'avg': + down_pool = torch.nn.AvgPool1d(self.configs.down_sampling_window) + elif self.configs.down_sampling_method == 'conv': + padding = 1 if torch.__version__ >= '1.5.0' else 2 + down_pool = nn.Conv1d(in_channels=self.configs.enc_in, out_channels=self.configs.enc_in, + kernel_size=3, padding=padding, + stride=self.configs.down_sampling_window, + padding_mode='circular', + bias=False) + else: + return x_enc, x_mark_enc + # B,T,C -> B,C,T + x_enc = x_enc.permute(0, 2, 1) + + x_enc_ori = x_enc + x_mark_enc_mark_ori = x_mark_enc + + x_enc_sampling_list = [] + x_mark_sampling_list = [] + x_enc_sampling_list.append(x_enc.permute(0, 2, 1)) + x_mark_sampling_list.append(x_mark_enc) + + for i in range(self.configs.down_sampling_layers): + x_enc_sampling = down_pool(x_enc_ori) + + x_enc_sampling_list.append(x_enc_sampling.permute(0, 2, 1)) + x_enc_ori = x_enc_sampling + + if x_mark_enc is not None: + x_mark_sampling_list.append(x_mark_enc_mark_ori[:, ::self.configs.down_sampling_window, :]) + x_mark_enc_mark_ori = x_mark_enc_mark_ori[:, ::self.configs.down_sampling_window, :] + + x_enc = x_enc_sampling_list + x_mark_enc = x_mark_sampling_list if x_mark_enc is not None else None + + return x_enc, x_mark_enc + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + + x_enc, x_mark_enc = self.__multi_scale_process_inputs(x_enc, x_mark_enc) + + x_list = [] + x_mark_list = [] + if x_mark_enc is not None: + for i, x, x_mark in zip(range(len(x_enc)), x_enc, x_mark_enc): + B, T, N = x.size() + x = self.normalize_layers[i](x, 'norm') + if self.channel_independence: + x = x.permute(0, 2, 1).contiguous().reshape(B * N, T, 1) + x_list.append(x) + x_mark = x_mark.repeat(N, 1, 1) + x_mark_list.append(x_mark) + else: + x_list.append(x) + x_mark_list.append(x_mark) + else: + for i, x in zip(range(len(x_enc)), x_enc, ): + B, T, N = x.size() + x = self.normalize_layers[i](x, 'norm') + if self.channel_independence: + x = x.permute(0, 2, 1).contiguous().reshape(B * N, T, 1) + x_list.append(x) + + # embedding + enc_out_list = [] + x_list = self.pre_enc(x_list) + if x_mark_enc is not None: + for i, x, x_mark in zip(range(len(x_list[0])), x_list[0], x_mark_list): + enc_out = self.enc_embedding(x, x_mark) # [B,T,C] + enc_out_list.append(enc_out) + else: + for i, x in zip(range(len(x_list[0])), x_list[0]): + enc_out = self.enc_embedding(x, None) # [B,T,C] + enc_out_list.append(enc_out) + + # Past Decomposable Mixing as encoder for past + for i in range(self.layer): + enc_out_list = self.pdm_blocks[i](enc_out_list) + + # Future Multipredictor Mixing as decoder for future + dec_out_list = self.future_multi_mixing(B, enc_out_list, x_list) + + dec_out = torch.stack(dec_out_list, dim=-1).sum(-1) + dec_out = self.normalize_layers[0](dec_out, 'denorm') + return dec_out + + def future_multi_mixing(self, B, enc_out_list, x_list): + dec_out_list = [] + if self.channel_independence: + x_list = x_list[0] + for i, enc_out in zip(range(len(x_list)), enc_out_list): + dec_out = self.predict_layers[i](enc_out.permute(0, 2, 1)).permute( + 0, 2, 1) # align temporal dimension + dec_out = self.projection_layer(dec_out) + dec_out = dec_out.reshape(B, self.configs.c_out, self.pred_len).permute(0, 2, 1).contiguous() + dec_out_list.append(dec_out) + + else: + for i, enc_out, out_res in zip(range(len(x_list[0])), enc_out_list, x_list[1]): + dec_out = self.predict_layers[i](enc_out.permute(0, 2, 1)).permute( + 0, 2, 1) # align temporal dimension + dec_out = self.out_projection(dec_out, i, out_res) + dec_out_list.append(dec_out) + + return dec_out_list + + def classification(self, x_enc, x_mark_enc): + x_enc, _ = self.__multi_scale_process_inputs(x_enc, None) + x_list = x_enc + + # embedding + enc_out_list = [] + for x in x_list: + enc_out = self.enc_embedding(x, None) # [B,T,C] + enc_out_list.append(enc_out) + + # MultiScale-CrissCrossAttention as encoder for past + for i in range(self.layer): + enc_out_list = self.pdm_blocks[i](enc_out_list) + + enc_out = enc_out_list[0] + # Output + # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.act(enc_out) + output = self.dropout(output) + # zero-out padding embeddings + output = output * x_mark_enc.unsqueeze(-1) + # (batch_size, seq_length * d_model) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) # (batch_size, num_classes) + return output + + def anomaly_detection(self, x_enc): + B, T, N = x_enc.size() + x_enc, _ = self.__multi_scale_process_inputs(x_enc, None) + + x_list = [] + + for i, x in zip(range(len(x_enc)), x_enc, ): + B, T, N = x.size() + x = self.normalize_layers[i](x, 'norm') + if self.channel_independence: + x = x.permute(0, 2, 1).contiguous().reshape(B * N, T, 1) + x_list.append(x) + + # embedding + enc_out_list = [] + for x in x_list: + enc_out = self.enc_embedding(x, None) # [B,T,C] + enc_out_list.append(enc_out) + + # MultiScale-CrissCrossAttention as encoder for past + for i in range(self.layer): + enc_out_list = self.pdm_blocks[i](enc_out_list) + + dec_out = self.projection_layer(enc_out_list[0]) + dec_out = dec_out.reshape(B, self.configs.c_out, -1).permute(0, 2, 1).contiguous() + + dec_out = self.normalize_layers[0](dec_out, 'denorm') + return dec_out + + def imputation(self, x_enc, x_mark_enc, mask): + means = torch.sum(x_enc, dim=1) / torch.sum(mask == 1, dim=1) + means = means.unsqueeze(1).detach() + x_enc = x_enc - means + x_enc = x_enc.masked_fill(mask == 0, 0) + stdev = torch.sqrt(torch.sum(x_enc * x_enc, dim=1) / + torch.sum(mask == 1, dim=1) + 1e-5) + stdev = stdev.unsqueeze(1).detach() + x_enc /= stdev + + B, T, N = x_enc.size() + x_enc, x_mark_enc = self.__multi_scale_process_inputs(x_enc, x_mark_enc) + + x_list = [] + x_mark_list = [] + if x_mark_enc is not None: + for i, x, x_mark in zip(range(len(x_enc)), x_enc, x_mark_enc): + B, T, N = x.size() + if self.channel_independence: + x = x.permute(0, 2, 1).contiguous().reshape(B * N, T, 1) + x_list.append(x) + x_mark = x_mark.repeat(N, 1, 1) + x_mark_list.append(x_mark) + else: + for i, x in zip(range(len(x_enc)), x_enc, ): + B, T, N = x.size() + if self.channel_independence: + x = x.permute(0, 2, 1).contiguous().reshape(B * N, T, 1) + x_list.append(x) + + # embedding + enc_out_list = [] + for x in x_list: + enc_out = self.enc_embedding(x, None) # [B,T,C] + enc_out_list.append(enc_out) + + # MultiScale-CrissCrossAttention as encoder for past + for i in range(self.layer): + enc_out_list = self.pdm_blocks[i](enc_out_list) + + dec_out = self.projection_layer(enc_out_list[0]) + 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)) + dec_out = dec_out + \ + (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): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + else: + raise ValueError('Other tasks implemented yet') diff --git a/models/TimeXer.py b/models/TimeXer.py new file mode 100644 index 0000000..c8026b7 --- /dev/null +++ b/models/TimeXer.py @@ -0,0 +1,225 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from layers.SelfAttention_Family import FullAttention, AttentionLayer +from layers.Embed import DataEmbedding_inverted, PositionalEmbedding +import numpy as np + + +class FlattenHead(nn.Module): + def __init__(self, n_vars, nf, target_window, head_dropout=0): + super().__init__() + self.n_vars = n_vars + self.flatten = nn.Flatten(start_dim=-2) + self.linear = nn.Linear(nf, target_window) + self.dropout = nn.Dropout(head_dropout) + + def forward(self, x): # x: [bs x nvars x d_model x patch_num] + x = self.flatten(x) + x = self.linear(x) + x = self.dropout(x) + return x + + +class EnEmbedding(nn.Module): + def __init__(self, n_vars, d_model, patch_len, dropout): + super(EnEmbedding, self).__init__() + # Patching + self.patch_len = patch_len + + self.value_embedding = nn.Linear(patch_len, d_model, bias=False) + self.glb_token = nn.Parameter(torch.randn(1, n_vars, 1, d_model)) + self.position_embedding = PositionalEmbedding(d_model) + + self.dropout = nn.Dropout(dropout) + + def forward(self, x): + # do patching + n_vars = x.shape[1] + glb = self.glb_token.repeat((x.shape[0], 1, 1, 1)) + + x = x.unfold(dimension=-1, size=self.patch_len, step=self.patch_len) + x = torch.reshape(x, (x.shape[0] * x.shape[1], x.shape[2], x.shape[3])) + # Input encoding + x = self.value_embedding(x) + self.position_embedding(x) + x = torch.reshape(x, (-1, n_vars, x.shape[-2], x.shape[-1])) + x = torch.cat([x, glb], dim=2) + x = torch.reshape(x, (x.shape[0] * x.shape[1], x.shape[2], x.shape[3])) + return self.dropout(x), n_vars + + +class Encoder(nn.Module): + def __init__(self, layers, norm_layer=None, projection=None): + super(Encoder, self).__init__() + self.layers = nn.ModuleList(layers) + self.norm = norm_layer + self.projection = projection + + def forward(self, x, cross, x_mask=None, cross_mask=None, tau=None, delta=None): + for layer in self.layers: + x = layer(x, cross, x_mask=x_mask, cross_mask=cross_mask, tau=tau, delta=delta) + + if self.norm is not None: + x = self.norm(x) + + if self.projection is not None: + x = self.projection(x) + return x + + +class EncoderLayer(nn.Module): + def __init__(self, self_attention, cross_attention, d_model, d_ff=None, + dropout=0.1, activation="relu"): + super(EncoderLayer, self).__init__() + d_ff = d_ff or 4 * d_model + self.self_attention = self_attention + self.cross_attention = cross_attention + self.conv1 = nn.Conv1d(in_channels=d_model, out_channels=d_ff, kernel_size=1) + self.conv2 = nn.Conv1d(in_channels=d_ff, out_channels=d_model, kernel_size=1) + self.norm1 = nn.LayerNorm(d_model) + self.norm2 = nn.LayerNorm(d_model) + self.norm3 = nn.LayerNorm(d_model) + self.dropout = nn.Dropout(dropout) + self.activation = F.relu if activation == "relu" else F.gelu + + def forward(self, x, cross, x_mask=None, cross_mask=None, tau=None, delta=None): + B, L, D = cross.shape + x = x + self.dropout(self.self_attention( + x, x, x, + attn_mask=x_mask, + tau=tau, delta=None + )[0]) + x = self.norm1(x) + + x_glb_ori = x[:, -1, :].unsqueeze(1) + x_glb = torch.reshape(x_glb_ori, (B, -1, D)) + x_glb_attn = self.dropout(self.cross_attention( + x_glb, cross, cross, + attn_mask=cross_mask, + tau=tau, delta=delta + )[0]) + x_glb_attn = torch.reshape(x_glb_attn, + (x_glb_attn.shape[0] * x_glb_attn.shape[1], x_glb_attn.shape[2])).unsqueeze(1) + x_glb = x_glb_ori + x_glb_attn + x_glb = self.norm2(x_glb) + + y = x = torch.cat([x[:, :-1, :], x_glb], dim=1) + + y = self.dropout(self.activation(self.conv1(y.transpose(-1, 1)))) + y = self.dropout(self.conv2(y).transpose(-1, 1)) + + return self.norm3(x + y) + + +class Model(nn.Module): + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.features = configs.features + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.use_norm = configs.use_norm + self.patch_len = configs.patch_len + self.patch_num = int(configs.seq_len // configs.patch_len) + self.n_vars = 1 if configs.features == 'MS' else configs.enc_in + # Embedding + self.en_embedding = EnEmbedding(self.n_vars, configs.d_model, self.patch_len, configs.dropout) + + self.ex_embedding = DataEmbedding_inverted(configs.seq_len, configs.d_model, configs.embed, configs.freq, + configs.dropout) + + # Encoder-only architecture + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation, + ) + for l in range(configs.e_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model) + ) + self.head_nf = configs.d_model * (self.patch_num + 1) + self.head = FlattenHead(configs.enc_in, self.head_nf, configs.pred_len, + head_dropout=configs.dropout) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + if self.use_norm: + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + _, _, N = x_enc.shape + + en_embed, n_vars = self.en_embedding(x_enc[:, :, -1].unsqueeze(-1).permute(0, 2, 1)) + ex_embed = self.ex_embedding(x_enc[:, :, :-1], x_mark_enc) + + enc_out = self.encoder(en_embed, ex_embed) + enc_out = torch.reshape( + enc_out, (-1, n_vars, enc_out.shape[-2], enc_out.shape[-1])) + # z: [bs x nvars x d_model x patch_num] + enc_out = enc_out.permute(0, 1, 3, 2) + + dec_out = self.head(enc_out) # z: [bs x nvars x target_window] + dec_out = dec_out.permute(0, 2, 1) + + if self.use_norm: + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * (stdev[:, 0, -1:].unsqueeze(1).repeat(1, self.pred_len, 1)) + dec_out = dec_out + (means[:, 0, -1:].unsqueeze(1).repeat(1, self.pred_len, 1)) + + return dec_out + + + def forecast_multi(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + if self.use_norm: + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + _, _, N = x_enc.shape + + en_embed, n_vars = self.en_embedding(x_enc.permute(0, 2, 1)) + ex_embed = self.ex_embedding(x_enc, x_mark_enc) + + enc_out = self.encoder(en_embed, ex_embed) + enc_out = torch.reshape( + enc_out, (-1, n_vars, enc_out.shape[-2], enc_out.shape[-1])) + # z: [bs x nvars x d_model x patch_num] + enc_out = enc_out.permute(0, 1, 3, 2) + + dec_out = self.head(enc_out) # z: [bs x nvars x target_window] + dec_out = dec_out.permute(0, 2, 1) + + if self.use_norm: + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + dec_out = dec_out + (means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + + return dec_out + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + if self.features == 'M': + dec_out = self.forecast_multi(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + else: + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + else: + return None \ No newline at end of file diff --git a/models/TimesNet.py b/models/TimesNet.py new file mode 100644 index 0000000..8977428 --- /dev/null +++ b/models/TimesNet.py @@ -0,0 +1,215 @@ +import torch +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 + + +def FFT_for_Period(x, k=2): + # [B, T, C] + xf = torch.fft.rfft(x, dim=1) + # find period by amplitudes + frequency_list = abs(xf).mean(0).mean(-1) + frequency_list[0] = 0 + _, top_list = torch.topk(frequency_list, k) + top_list = top_list.detach().cpu().numpy() + period = x.shape[1] // top_list + return period, abs(xf).mean(-1)[:, top_list] + + +class TimesBlock(nn.Module): + def __init__(self, configs): + super(TimesBlock, self).__init__() + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.k = configs.top_k + # parameter-efficient design + self.conv = nn.Sequential( + Inception_Block_V1(configs.d_model, configs.d_ff, + num_kernels=configs.num_kernels), + nn.GELU(), + Inception_Block_V1(configs.d_ff, configs.d_model, + num_kernels=configs.num_kernels) + ) + + def forward(self, x): + B, T, N = x.size() + period_list, period_weight = FFT_for_Period(x, self.k) + + res = [] + for i in range(self.k): + period = period_list[i] + # padding + if (self.seq_len + self.pred_len) % period != 0: + length = ( + ((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: + length = (self.seq_len + self.pred_len) + out = x + # reshape + out = out.reshape(B, length // period, period, + N).permute(0, 3, 1, 2).contiguous() + # 2D conv: from 1d Variation to 2d Variation + out = self.conv(out) + # reshape back + out = out.permute(0, 2, 3, 1).reshape(B, -1, N) + res.append(out[:, :(self.seq_len + self.pred_len), :]) + res = torch.stack(res, dim=-1) + # adaptive aggregation + period_weight = F.softmax(period_weight, dim=1) + period_weight = period_weight.unsqueeze( + 1).unsqueeze(1).repeat(1, T, N, 1) + res = torch.sum(res * period_weight, -1) + # residual connection + res = res + x + return res + + +class Model(nn.Module): + """ + Paper link: https://openreview.net/pdf?id=ju_Uqw384Oq + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.configs = configs + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.label_len = configs.label_len + self.pred_len = configs.pred_len + self.model = nn.ModuleList([TimesBlock(configs) + for _ in range(configs.e_layers)]) + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + self.layer = configs.e_layers + self.layer_norm = nn.LayerNorm(configs.d_model) + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.predict_linear = nn.Linear( + self.seq_len, self.pred_len + self.seq_len) + self.projection = nn.Linear( + configs.d_model, configs.c_out, bias=True) + if self.task_name == 'imputation' or self.task_name == 'anomaly_detection': + self.projection = nn.Linear( + configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear( + configs.d_model * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc.sub(means) + stdev = torch.sqrt( + torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc = x_enc.div(stdev) + + # embedding + enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C] + enc_out = self.predict_linear(enc_out.permute(0, 2, 1)).permute( + 0, 2, 1) # align temporal dimension + # TimesNet + for i in range(self.layer): + enc_out = self.layer_norm(self.model[i](enc_out)) + # project back + dec_out = self.projection(enc_out) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out.mul( + (stdev[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1))) + dec_out = dec_out.add( + (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): + # Normalization from Non-stationary Transformer + means = torch.sum(x_enc, dim=1) / torch.sum(mask == 1, dim=1) + means = means.unsqueeze(1).detach() + x_enc = x_enc.sub(means) + x_enc = x_enc.masked_fill(mask == 0, 0) + stdev = torch.sqrt(torch.sum(x_enc * x_enc, dim=1) / + torch.sum(mask == 1, dim=1) + 1e-5) + stdev = stdev.unsqueeze(1).detach() + x_enc = x_enc.div(stdev) + + # embedding + enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C] + # TimesNet + for i in range(self.layer): + enc_out = self.layer_norm(self.model[i](enc_out)) + # project back + dec_out = self.projection(enc_out) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out.mul( + (stdev[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1))) + dec_out = dec_out.add( + (means[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1))) + return dec_out + + def anomaly_detection(self, x_enc): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc.sub(means) + stdev = torch.sqrt( + torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc = x_enc.div(stdev) + + # embedding + enc_out = self.enc_embedding(x_enc, None) # [B,T,C] + # TimesNet + for i in range(self.layer): + enc_out = self.layer_norm(self.model[i](enc_out)) + # project back + dec_out = self.projection(enc_out) + + # De-Normalization from Non-stationary Transformer + dec_out = dec_out.mul( + (stdev[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1))) + dec_out = dec_out.add( + (means[:, 0, :].unsqueeze(1).repeat( + 1, self.pred_len + self.seq_len, 1))) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # embedding + enc_out = self.enc_embedding(x_enc, None) # [B,T,C] + # TimesNet + for i in range(self.layer): + enc_out = self.layer_norm(self.model[i](enc_out)) + + # Output + # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.act(enc_out) + output = self.dropout(output) + # zero-out padding embeddings + output = output * x_mark_enc.unsqueeze(-1) + # (batch_size, seq_length * d_model) + output = output.reshape(output.shape[0], -1) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation( + x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/Transformer.py b/models/Transformer.py new file mode 100644 index 0000000..3ecae52 --- /dev/null +++ b/models/Transformer.py @@ -0,0 +1,124 @@ +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 +import numpy as np + + +class Model(nn.Module): + """ + Vanilla Transformer + with O(L^2) complexity + Paper link: https://proceedings.neurips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.pred_len = configs.pred_len + # Embedding + self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model) + ) + # Decoder + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.dec_embedding = DataEmbedding(configs.dec_in, configs.d_model, configs.embed, configs.freq, + configs.dropout) + self.decoder = Decoder( + [ + DecoderLayer( + AttentionLayer( + FullAttention(True, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), + configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation, + ) + for l in range(configs.d_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model), + projection=nn.Linear(configs.d_model, configs.c_out, bias=True) + ) + if self.task_name == 'imputation': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear(configs.d_model, configs.c_out, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.d_model * configs.seq_len, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Embedding + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.dec_embedding(x_dec, x_mark_dec) + dec_out = self.decoder(dec_out, enc_out, x_mask=None, cross_mask=None) + return dec_out + + def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask): + # Embedding + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.projection(enc_out) + return dec_out + + def anomaly_detection(self, x_enc): + # Embedding + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.projection(enc_out) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # Embedding + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + # Output + output = self.act(enc_out) # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.dropout(output) + output = output * x_mark_enc.unsqueeze(-1) # zero-out padding embeddings + output = output.reshape(output.shape[0], -1) # (batch_size, seq_length * d_model) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/WPMixer.py b/models/WPMixer.py new file mode 100644 index 0000000..9271b2b --- /dev/null +++ b/models/WPMixer.py @@ -0,0 +1,319 @@ +# -*- coding: utf-8 -*- +""" +Created on Sun Jan 5 16:10:01 2025 +@author: Murad +SISLab, USF +mmurad@usf.edu +https://github.com/Secure-and-Intelligent-Systems-Lab/WPMixer +""" + +import torch.nn as nn +import torch +from layers.DWT_Decomposition import Decomposition + + +class TokenMixer(nn.Module): + def __init__(self, input_seq=[], batch_size=[], channel=[], pred_seq=[], dropout=[], factor=[], d_model=[]): + super(TokenMixer, self).__init__() + self.input_seq = input_seq + self.batch_size = batch_size + self.channel = channel + self.pred_seq = pred_seq + self.dropout = dropout + self.factor = factor + self.d_model = d_model + + self.dropoutLayer = nn.Dropout(self.dropout) + self.layers = nn.Sequential(nn.Linear(self.input_seq, self.pred_seq * self.factor), + nn.GELU(), + nn.Dropout(self.dropout), + nn.Linear(self.pred_seq * self.factor, self.pred_seq) + ) + + def forward(self, x): + x = x.transpose(1, 2) + x = self.layers(x) + x = x.transpose(1, 2) + return x + + +class Mixer(nn.Module): + def __init__(self, + input_seq=[], + out_seq=[], + batch_size=[], + channel=[], + d_model=[], + dropout=[], + tfactor=[], + dfactor=[]): + super(Mixer, self).__init__() + self.input_seq = input_seq + self.pred_seq = out_seq + self.batch_size = batch_size + self.channel = channel + self.d_model = d_model + self.dropout = dropout + self.tfactor = tfactor # expansion factor for patch mixer + self.dfactor = dfactor # expansion factor for embedding mixer + + self.tMixer = TokenMixer(input_seq=self.input_seq, batch_size=self.batch_size, channel=self.channel, + pred_seq=self.pred_seq, dropout=self.dropout, factor=self.tfactor, + d_model=self.d_model) + self.dropoutLayer = nn.Dropout(self.dropout) + self.norm1 = nn.BatchNorm2d(self.channel) + self.norm2 = nn.BatchNorm2d(self.channel) + + self.embeddingMixer = nn.Sequential(nn.Linear(self.d_model, self.d_model * self.dfactor), + nn.GELU(), + nn.Dropout(self.dropout), + nn.Linear(self.d_model * self.dfactor, self.d_model)) + + def forward(self, x): + ''' + Parameters + ---------- + x : input: [Batch, Channel, Patch_number, d_model] + + Returns + ------- + x: output: [Batch, Channel, Patch_number, d_model] + + ''' + x = self.norm1(x) + x = x.permute(0, 3, 1, 2) + x = self.dropoutLayer(self.tMixer(x)) + x = x.permute(0, 2, 3, 1) + x = self.norm2(x) + x = x + self.dropoutLayer(self.embeddingMixer(x)) + return x + + +class ResolutionBranch(nn.Module): + def __init__(self, + input_seq=[], + pred_seq=[], + batch_size=[], + channel=[], + d_model=[], + dropout=[], + embedding_dropout=[], + tfactor=[], + dfactor=[], + patch_len=[], + patch_stride=[]): + super(ResolutionBranch, self).__init__() + self.input_seq = input_seq + self.pred_seq = pred_seq + self.batch_size = batch_size + self.channel = channel + self.d_model = d_model + self.dropout = dropout + self.embedding_dropout = embedding_dropout + self.tfactor = tfactor + self.dfactor = dfactor + self.patch_len = patch_len + self.patch_stride = patch_stride + self.patch_num = int((self.input_seq - self.patch_len) / self.patch_stride + 2) + + self.patch_norm = nn.BatchNorm2d(self.channel) + self.patch_embedding_layer = nn.Linear(self.patch_len, self.d_model) # shared among all channels + self.mixer1 = Mixer(input_seq=self.patch_num, + out_seq=self.patch_num, + batch_size=self.batch_size, + channel=self.channel, + d_model=self.d_model, + dropout=self.dropout, + tfactor=self.tfactor, + dfactor=self.dfactor) + self.mixer2 = Mixer(input_seq=self.patch_num, + out_seq=self.patch_num, + batch_size=self.batch_size, + channel=self.channel, + d_model=self.d_model, + dropout=self.dropout, + tfactor=self.tfactor, + dfactor=self.dfactor) + self.norm = nn.BatchNorm2d(self.channel) + self.dropoutLayer = nn.Dropout(self.embedding_dropout) + self.head = nn.Sequential(nn.Flatten(start_dim=-2, end_dim=-1), + nn.Linear(self.patch_num * self.d_model, self.pred_seq)) + + def forward(self, x): + ''' + Parameters + ---------- + x : input coefficient series: [Batch, channel, length_of_coefficient_series] + + Returns + ------- + out : predicted coefficient series: [Batch, channel, length_of_pred_coeff_series] + ''' + + x_patch = self.do_patching(x) + x_patch = self.patch_norm(x_patch) + x_emb = self.dropoutLayer(self.patch_embedding_layer(x_patch)) + + out = self.mixer1(x_emb) + res = out + out = res + self.mixer2(out) + out = self.norm(out) + + out = self.head(out) + return out + + def do_patching(self, x): + x_end = x[:, :, -1:] + x_padding = x_end.repeat(1, 1, self.patch_stride) + x_new = torch.cat((x, x_padding), dim=-1) + x_patch = x_new.unfold(dimension=-1, size=self.patch_len, step=self.patch_stride) + return x_patch + + +class WPMixerCore(nn.Module): + def __init__(self, + input_length=[], + pred_length=[], + wavelet_name=[], + level=[], + batch_size=[], + channel=[], + d_model=[], + dropout=[], + embedding_dropout=[], + tfactor=[], + dfactor=[], + device=[], + patch_len=[], + patch_stride=[], + no_decomposition=[], + use_amp=[]): + super(WPMixerCore, self).__init__() + self.input_length = input_length + self.pred_length = pred_length + self.wavelet_name = wavelet_name + self.level = level + self.batch_size = batch_size + self.channel = channel + self.d_model = d_model + self.dropout = dropout + self.embedding_dropout = embedding_dropout + self.device = device + self.no_decomposition = no_decomposition + self.tfactor = tfactor + self.dfactor = dfactor + self.use_amp = use_amp + + self.Decomposition_model = Decomposition(input_length=self.input_length, + pred_length=self.pred_length, + wavelet_name=self.wavelet_name, + level=self.level, + batch_size=self.batch_size, + channel=self.channel, + d_model=self.d_model, + tfactor=self.tfactor, + dfactor=self.dfactor, + device=self.device, + no_decomposition=self.no_decomposition, + use_amp=self.use_amp) + + self.input_w_dim = self.Decomposition_model.input_w_dim # list of the length of the input coefficient series + self.pred_w_dim = self.Decomposition_model.pred_w_dim # list of the length of the predicted coefficient series + + self.patch_len = patch_len + self.patch_stride = patch_stride + + # (m+1) number of resolutionBranch + self.resolutionBranch = nn.ModuleList([ResolutionBranch(input_seq=self.input_w_dim[i], + pred_seq=self.pred_w_dim[i], + batch_size=self.batch_size, + channel=self.channel, + d_model=self.d_model, + dropout=self.dropout, + embedding_dropout=self.embedding_dropout, + tfactor=self.tfactor, + dfactor=self.dfactor, + patch_len=self.patch_len, + patch_stride=self.patch_stride) for i in + range(len(self.input_w_dim))]) + + def forward(self, xL): + ''' + Parameters + ---------- + xL : Look back window: [Batch, look_back_length, channel] + + Returns + ------- + xT : Prediction time series: [Batch, prediction_length, output_channel] + ''' + x = xL.transpose(1, 2) # [batch, channel, look_back_length] + + # xA: approximation coefficient series, + # xD: detail coefficient series + # yA: predicted approximation coefficient series + # yD: predicted detail coefficient series + + xA, xD = self.Decomposition_model.transform(x) + + yA = self.resolutionBranch[0](xA) + yD = [] + for i in range(len(xD)): + yD_i = self.resolutionBranch[i + 1](xD[i]) + yD.append(yD_i) + + y = self.Decomposition_model.inv_transform(yA, yD) + y = y.transpose(1, 2) + xT = y[:, -self.pred_length:, :] # decomposition output is always even, but pred length can be odd + + return xT + + +class Model(nn.Module): + def __init__(self, args, tfactor=5, dfactor=5, wavelet='db2', level=1, stride=8, no_decomposition=False): + super(Model, self).__init__() + self.args = args + self.task_name = args.task_name + self.wpmixerCore = WPMixerCore(input_length=self.args.seq_len, + pred_length=self.args.pred_len, + wavelet_name=wavelet, + level=level, + batch_size=self.args.batch_size, + channel=self.args.c_out, + d_model=self.args.d_model, + dropout=self.args.dropout, + embedding_dropout=self.args.dropout, + tfactor=tfactor, + dfactor=dfactor, + device=self.args.device, + patch_len=self.args.patch_len, + patch_stride=stride, + no_decomposition=no_decomposition, + use_amp=self.args.use_amp) + + def forecast(self, x_enc, x_mark_enc, x_dec, batch_y_mark): + # Normalization + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + pred = self.wpmixerCore(x_enc) + pred = pred[:, :, -self.args.c_out:] + + # De-Normalization + dec_out = pred * (stdev[:, 0].unsqueeze(1).repeat(1, self.args.pred_len, 1)) + dec_out = dec_out + (means[:, 0].unsqueeze(1).repeat(1, self.args.pred_len, 1)) + return dec_out + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out # [B, L, D] + if self.task_name == 'imputation': + raise NotImplementedError("Task imputation for WPMixer is temporarily not supported") + if self.task_name == 'anomaly_detection': + raise NotImplementedError("Task anomaly_detection for WPMixer is temporarily not supported") + if self.task_name == 'classification': + raise NotImplementedError("Task classification for WPMixer is temporarily not supported") + return None diff --git a/models/__init__.py b/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/models/iTransformer.py b/models/iTransformer.py new file mode 100644 index 0000000..4833a69 --- /dev/null +++ b/models/iTransformer.py @@ -0,0 +1,132 @@ +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 +import numpy as np + + +class Model(nn.Module): + """ + Paper link: https://arxiv.org/abs/2310.06625 + """ + + def __init__(self, configs): + super(Model, self).__init__() + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + # Embedding + self.enc_embedding = DataEmbedding_inverted(configs.seq_len, configs.d_model, configs.embed, configs.freq, + configs.dropout) + # Encoder + self.encoder = Encoder( + [ + EncoderLayer( + AttentionLayer( + FullAttention(False, configs.factor, attention_dropout=configs.dropout, + output_attention=False), configs.d_model, configs.n_heads), + configs.d_model, + configs.d_ff, + dropout=configs.dropout, + activation=configs.activation + ) for l in range(configs.e_layers) + ], + norm_layer=torch.nn.LayerNorm(configs.d_model) + ) + # Decoder + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.projection = nn.Linear(configs.d_model, configs.pred_len, bias=True) + if self.task_name == 'imputation': + self.projection = nn.Linear(configs.d_model, configs.seq_len, bias=True) + if self.task_name == 'anomaly_detection': + self.projection = nn.Linear(configs.d_model, configs.seq_len, bias=True) + if self.task_name == 'classification': + self.act = F.gelu + self.dropout = nn.Dropout(configs.dropout) + self.projection = nn.Linear(configs.d_model * configs.enc_in, configs.num_class) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + _, _, N = x_enc.shape + + # Embedding + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.projection(enc_out).permute(0, 2, 1)[:, :, :N] + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * (stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)) + dec_out = dec_out + (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): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + _, L, N = x_enc.shape + + # Embedding + enc_out = self.enc_embedding(x_enc, x_mark_enc) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.projection(enc_out).permute(0, 2, 1)[:, :, :N] + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * (stdev[:, 0, :].unsqueeze(1).repeat(1, L, 1)) + dec_out = dec_out + (means[:, 0, :].unsqueeze(1).repeat(1, L, 1)) + return dec_out + + def anomaly_detection(self, x_enc): + # Normalization from Non-stationary Transformer + means = x_enc.mean(1, keepdim=True).detach() + x_enc = x_enc - means + stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5) + x_enc /= stdev + + _, L, N = x_enc.shape + + # Embedding + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + dec_out = self.projection(enc_out).permute(0, 2, 1)[:, :, :N] + # De-Normalization from Non-stationary Transformer + dec_out = dec_out * (stdev[:, 0, :].unsqueeze(1).repeat(1, L, 1)) + dec_out = dec_out + (means[:, 0, :].unsqueeze(1).repeat(1, L, 1)) + return dec_out + + def classification(self, x_enc, x_mark_enc): + # Embedding + enc_out = self.enc_embedding(x_enc, None) + enc_out, attns = self.encoder(enc_out, attn_mask=None) + + # Output + output = self.act(enc_out) # the output transformer encoder/decoder embeddings don't include non-linearity + output = self.dropout(output) + output = output.reshape(output.shape[0], -1) # (batch_size, c_in * d_model) + output = self.projection(output) # (batch_size, num_classes) + return output + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + if self.task_name == 'imputation': + dec_out = self.imputation(x_enc, x_mark_enc, x_dec, x_mark_dec, mask) + return dec_out # [B, L, D] + if self.task_name == 'anomaly_detection': + dec_out = self.anomaly_detection(x_enc) + return dec_out # [B, L, D] + if self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + return None diff --git a/models/xPatch_SparseChannel.py b/models/xPatch_SparseChannel.py new file mode 100644 index 0000000..ea3862f --- /dev/null +++ b/models/xPatch_SparseChannel.py @@ -0,0 +1,166 @@ +""" +xPatch_SparseChannel model adapted for Time-Series-Library-main +Supports both long-term forecasting and classification tasks +""" +import torch +import torch.nn as nn +from layers.DECOMP import DECOMP +from layers.SeasonPatch import SeasonPatch +from layers.RevIN import RevIN + +class Model(nn.Module): + """ + xPatch SparseChannel Model + """ + + def __init__(self, configs): + super(Model, self).__init__() + + # Model configuration + self.task_name = configs.task_name + self.seq_len = configs.seq_len + self.pred_len = configs.pred_len + self.enc_in = configs.enc_in + + # Model parameters + self.patch_len = getattr(configs, 'patch_len', 16) + self.stride = getattr(configs, 'stride', 8) + + # Normalization + self.revin = getattr(configs, 'revin', True) + if self.revin: + self.revin_layer = RevIN(self.enc_in, affine=True, subtract_last=False) + + # Decomposition using original DECOMP with EMA/DEMA + ma_type = getattr(configs, 'ma_type', 'ema') + alpha = getattr(configs, 'alpha', torch.tensor(0.1)) + beta = getattr(configs, 'beta', torch.tensor(0.1)) + self.decomp = DECOMP(ma_type, alpha, beta) + + # Season network (PatchTST + Graph Mixer) + self.season_net = SeasonPatch( + c_in=self.enc_in, + seq_len=self.seq_len, + pred_len=self.pred_len, + patch_len=self.patch_len, + stride=self.stride, + k_graph=getattr(configs, 'k_graph', 8), + d_model=getattr(configs, 'd_model', 128), + n_layers=getattr(configs, 'e_layers', 3), + n_heads=getattr(configs, 'n_heads', 16) + ) + + # Trend network (MLP) + self.fc5 = nn.Linear(self.seq_len, self.pred_len * 4) + self.avgpool1 = nn.AvgPool1d(kernel_size=2) + self.ln1 = nn.LayerNorm(self.pred_len * 2) + self.fc6 = nn.Linear(self.pred_len * 2, self.pred_len) + self.avgpool2 = nn.AvgPool1d(kernel_size=2) + self.ln2 = nn.LayerNorm(self.pred_len // 2) + self.fc7 = nn.Linear(self.pred_len // 2, self.pred_len) + + # Task-specific heads + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + self.fc_final = nn.Linear(self.pred_len * 2, self.pred_len) + elif self.task_name == 'classification': + self.season_attention = nn.Sequential( + nn.Linear(self.pred_len, 64), + nn.Tanh(), + nn.Linear(64, 1) + ) + self.trend_attention = nn.Sequential( + nn.Linear(self.pred_len, 64), + nn.Tanh(), + nn.Linear(64, 1) + ) + self.classifier = nn.Sequential( + nn.Linear(self.enc_in * 2, 128), + nn.ReLU(), + nn.Dropout(getattr(configs, 'dropout', 0.1)), + nn.Linear(128, configs.num_class) + ) + + def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec): + """Long-term forecasting""" + # Normalization + if self.revin: + x_enc = self.revin_layer(x_enc, 'norm') + + # Decomposition + seasonal_init, trend_init = self.decomp(x_enc) + + # Season stream + y_season = self.season_net(seasonal_init) # [B, C, pred_len] + + # Trend stream + B, L, C = trend_init.shape + trend = trend_init.permute(0, 2, 1).reshape(B * C, L) # [B*C, L] + trend = self.fc5(trend) + trend = self.avgpool1(trend) + trend = self.ln1(trend) + trend = self.fc6(trend) + trend = self.avgpool2(trend) + trend = self.ln2(trend) + trend = self.fc7(trend) # [B*C, pred_len] + y_trend = trend.view(B, C, -1) # [B, C, pred_len] + + # Combine streams + y = torch.cat([y_season, y_trend], dim=-1) # [B, C, 2*pred_len] + y = self.fc_final(y) # [B, C, pred_len] + y = y.permute(0, 2, 1) # [B, pred_len, C] + + # Denormalization + if self.revin: + y = self.revin_layer(y, 'denorm') + + return y + + def classification(self, x_enc, x_mark_enc): + """Classification task""" + # Normalization + #if self.revin: + # x_enc = self.revin_layer(x_enc, 'norm') + + # Decomposition + seasonal_init, trend_init = self.decomp(x_enc) + + # Season stream + y_season = self.season_net(seasonal_init) # [B, C, pred_len] + + # print("shape:", trend_init.shape) + # Trend stream + B, L, C = trend_init.shape + trend = trend_init.permute(0, 2, 1).reshape(B * C, L) # [B*C, L] + trend = self.fc5(trend) + trend = self.avgpool1(trend) + trend = self.ln1(trend) + trend = self.fc6(trend) + trend = self.avgpool2(trend) + trend = self.ln2(trend) + trend = self.fc7(trend) # [B*C, pred_len] + y_trend = trend.view(B, C, -1) # [B, C, pred_len] + + # Attention-based pooling for classification + season_attn_weights = torch.softmax(y_season, dim=-1) + season_pooled = (y_season * season_attn_weights).sum(dim=-1) # [B, C] + + trend_attn_weights = torch.softmax(y_trend, dim=-1) # 时间维 + trend_pooled = (y_trend * trend_attn_weights).sum(dim=-1) # [B, C] + + # Combine features + features = torch.cat([season_pooled, trend_pooled], dim=-1) # [B, 2*C] + + # Classification + logits = self.classifier(features) # [B, num_classes] + return logits + + def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None): + """Forward pass dispatching to task-specific methods""" + if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast': + dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec) + return dec_out[:, -self.pred_len:, :] # [B, L, D] + elif self.task_name == 'classification': + dec_out = self.classification(x_enc, x_mark_enc) + return dec_out # [B, N] + else: + raise ValueError(f'Task {self.task_name} not supported by xPatch_SparseChannel') \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b4ae9ec --- /dev/null +++ b/requirements.txt @@ -0,0 +1,14 @@ +einops +local-attention +matplotlib +numpy +pandas +patool +reformer-pytorch +scikit-learn +scipy +sktime +sympy +torch +tqdm +PyWavelets diff --git a/run.py b/run.py new file mode 100644 index 0000000..d3d4ca1 --- /dev/null +++ b/run.py @@ -0,0 +1,261 @@ +import argparse +import os +import torch +import torch.backends +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 +import random +import numpy as np + +if __name__ == '__main__': + fix_seed = 2021 + random.seed(fix_seed) + torch.manual_seed(fix_seed) + np.random.seed(fix_seed) + + parser = argparse.ArgumentParser(description='TimesNet') + + # basic config + parser.add_argument('--task_name', type=str, required=True, default='long_term_forecast', + help='task name, options:[long_term_forecast, short_term_forecast, imputation, classification, anomaly_detection]') + parser.add_argument('--is_training', type=int, required=True, default=1, help='status') + parser.add_argument('--model_id', type=str, required=True, default='test', help='model id') + parser.add_argument('--model', type=str, required=True, default='Autoformer', + help='model name, options: [Autoformer, Transformer, TimesNet]') + + # data loader + parser.add_argument('--data', type=str, required=True, default='ETTh1', help='dataset type') + parser.add_argument('--root_path', type=str, default='./data/ETT/', help='root path of the data file') + parser.add_argument('--data_path', type=str, default='ETTh1.csv', help='data file') + parser.add_argument('--features', type=str, default='M', + help='forecasting task, options:[M, S, MS]; M:multivariate predict multivariate, S:univariate predict univariate, MS:multivariate predict univariate') + parser.add_argument('--target', type=str, default='OT', help='target feature in S or MS task') + parser.add_argument('--freq', type=str, default='h', + help='freq for time features encoding, options:[s:secondly, t:minutely, h:hourly, d:daily, b:business days, w:weekly, m:monthly], you can also use more detailed freq like 15min or 3h') + parser.add_argument('--checkpoints', type=str, default='./checkpoints/', help='location of model checkpoints') + + # forecasting task + parser.add_argument('--seq_len', type=int, default=96, help='input sequence length') + parser.add_argument('--label_len', type=int, default=48, help='start token length') + parser.add_argument('--pred_len', type=int, default=96, help='prediction sequence length') + parser.add_argument('--seasonal_patterns', type=str, default='Monthly', help='subset for M4') + parser.add_argument('--inverse', action='store_true', help='inverse output data', default=False) + + # inputation task + parser.add_argument('--mask_rate', type=float, default=0.25, help='mask ratio') + + # anomaly detection task + parser.add_argument('--anomaly_ratio', type=float, default=0.25, help='prior anomaly ratio (%%)') + + # model define + parser.add_argument('--expand', type=int, default=2, help='expansion factor for Mamba') + parser.add_argument('--d_conv', type=int, default=4, help='conv kernel size for Mamba') + parser.add_argument('--top_k', type=int, default=5, help='for TimesBlock') + parser.add_argument('--num_kernels', type=int, default=6, help='for Inception') + parser.add_argument('--enc_in', type=int, default=7, help='encoder input size') + parser.add_argument('--dec_in', type=int, default=7, help='decoder input size') + parser.add_argument('--c_out', type=int, default=7, help='output size') + parser.add_argument('--d_model', type=int, default=512, help='dimension of model') + parser.add_argument('--n_heads', type=int, default=8, help='num of heads') + parser.add_argument('--e_layers', type=int, default=2, help='num of encoder layers') + parser.add_argument('--d_layers', type=int, default=1, help='num of decoder layers') + parser.add_argument('--d_ff', type=int, default=2048, help='dimension of fcn') + parser.add_argument('--moving_avg', type=int, default=25, help='window size of moving average') + parser.add_argument('--factor', type=int, default=1, help='attn factor') + parser.add_argument('--distil', action='store_false', + help='whether to use distilling in encoder, using this argument means not using distilling', + default=True) + parser.add_argument('--dropout', type=float, default=0.1, help='dropout') + parser.add_argument('--embed', type=str, default='timeF', + help='time features encoding, options:[timeF, fixed, learned]') + parser.add_argument('--activation', type=str, default='gelu', help='activation') + parser.add_argument('--channel_independence', type=int, default=1, + help='0: channel dependence 1: channel independence for FreTS model') + parser.add_argument('--decomp_method', type=str, default='moving_avg', + help='method of series decompsition, only support moving_avg or dft_decomp') + parser.add_argument('--use_norm', type=int, default=1, help='whether to use normalize; True 1 False 0') + parser.add_argument('--down_sampling_layers', type=int, default=0, help='num of down sampling layers') + parser.add_argument('--down_sampling_window', type=int, default=1, help='down sampling window size') + parser.add_argument('--down_sampling_method', type=str, default=None, + help='down sampling method, only support avg, max, conv') + parser.add_argument('--seg_len', type=int, default=96, + help='the length of segmen-wise iteration of SegRNN') + + # optimization + parser.add_argument('--num_workers', type=int, default=10, help='data loader num workers') + parser.add_argument('--itr', type=int, default=1, help='experiments times') + parser.add_argument('--train_epochs', type=int, default=10, help='train epochs') + parser.add_argument('--batch_size', type=int, default=32, help='batch size of train input data') + parser.add_argument('--patience', type=int, default=3, help='early stopping patience') + parser.add_argument('--learning_rate', type=float, default=0.0001, help='optimizer learning rate') + parser.add_argument('--des', type=str, default='test', help='exp description') + parser.add_argument('--loss', type=str, default='MSE', help='loss function') + parser.add_argument('--lradj', type=str, default='type1', help='adjust learning rate') + parser.add_argument('--use_amp', action='store_true', help='use automatic mixed precision training', default=False) + + # GPU + parser.add_argument('--use_gpu', type=bool, default=True, help='use gpu') + parser.add_argument('--gpu', type=int, default=0, help='gpu') + parser.add_argument('--gpu_type', type=str, default='cuda', help='gpu type') # cuda or mps + parser.add_argument('--use_multi_gpu', action='store_true', help='use multiple gpus', default=False) + parser.add_argument('--devices', type=str, default='0,1,2,3', help='device ids of multile gpus') + + # de-stationary projector params + parser.add_argument('--p_hidden_dims', type=int, nargs='+', default=[128, 128], + help='hidden layer dimensions of projector (List)') + parser.add_argument('--p_hidden_layers', type=int, default=2, help='number of hidden layers in projector') + + # metrics (dtw) + parser.add_argument('--use_dtw', type=bool, default=False, + help='the controller of using dtw metric (dtw is time consuming, not suggested unless necessary)') + + # Augmentation + parser.add_argument('--augmentation_ratio', type=int, default=0, help="How many times to augment") + parser.add_argument('--seed', type=int, default=2, help="Randomization seed") + parser.add_argument('--jitter', default=False, action="store_true", help="Jitter preset augmentation") + parser.add_argument('--scaling', default=False, action="store_true", help="Scaling preset augmentation") + parser.add_argument('--permutation', default=False, action="store_true", + help="Equal Length Permutation preset augmentation") + parser.add_argument('--randompermutation', default=False, action="store_true", + help="Random Length Permutation preset augmentation") + parser.add_argument('--magwarp', default=False, action="store_true", help="Magnitude warp preset augmentation") + parser.add_argument('--timewarp', default=False, action="store_true", help="Time warp preset augmentation") + parser.add_argument('--windowslice', default=False, action="store_true", help="Window slice preset augmentation") + parser.add_argument('--windowwarp', default=False, action="store_true", help="Window warp preset augmentation") + parser.add_argument('--rotation', default=False, action="store_true", help="Rotation preset augmentation") + parser.add_argument('--spawner', default=False, action="store_true", help="SPAWNER preset augmentation") + parser.add_argument('--dtwwarp', default=False, action="store_true", help="DTW warp preset augmentation") + parser.add_argument('--shapedtwwarp', default=False, action="store_true", help="Shape DTW warp preset augmentation") + parser.add_argument('--wdba', default=False, action="store_true", help="Weighted DBA preset augmentation") + parser.add_argument('--discdtw', default=False, action="store_true", + help="Discrimitive DTW warp preset augmentation") + parser.add_argument('--discsdtw', default=False, action="store_true", + help="Discrimitive shapeDTW warp preset augmentation") + parser.add_argument('--extra_tag', type=str, default="", help="Anything extra") + + # TimeXer + parser.add_argument('--patch_len', type=int, default=16, help='patch length') + + args, unknown = parser.parse_known_args() + + # Parse unknown arguments dynamically + for i in range(0, len(unknown), 2): + if i + 1 < len(unknown) and unknown[i].startswith('--'): + param_name = unknown[i][2:] # Remove '--' prefix + param_value = unknown[i + 1] + + # Smart type conversion + if param_value.isdigit() or (param_value.startswith('-') and param_value[1:].isdigit()): + param_value = int(param_value) + elif param_value.replace('.', '', 1).replace('-', '', 1).isdigit(): + param_value = float(param_value) + elif param_value.lower() in ['true', 'yes', '1']: + param_value = True + elif param_value.lower() in ['false', 'no', '0']: + param_value = False + + setattr(args, param_name, param_value) + print(f"Dynamic parameter: --{param_name} = {param_value} ({type(param_value).__name__})") + + if unknown: + print(f"Parsed {len(unknown)//2} dynamic parameters") + if torch.cuda.is_available() and args.use_gpu: + args.device = torch.device('cuda:{}'.format(args.gpu)) + print('Using GPU') + else: + if hasattr(torch.backends, "mps"): + args.device = torch.device("mps") if torch.backends.mps.is_available() else torch.device("cpu") + else: + args.device = torch.device("cpu") + print('Using cpu or mps') + + if args.use_gpu and args.use_multi_gpu: + args.devices = args.devices.replace(' ', '') + device_ids = args.devices.split(',') + args.device_ids = [int(id_) for id_ in device_ids] + args.gpu = args.device_ids[0] + + print('Args in experiment:') + print_args(args) + + if args.task_name == 'long_term_forecast': + Exp = Exp_Long_Term_Forecast + elif args.task_name == 'short_term_forecast': + Exp = Exp_Short_Term_Forecast + elif args.task_name == 'imputation': + Exp = Exp_Imputation + elif args.task_name == 'anomaly_detection': + Exp = Exp_Anomaly_Detection + elif args.task_name == 'classification': + Exp = Exp_Classification + else: + Exp = Exp_Long_Term_Forecast + + if args.is_training: + for ii in range(args.itr): + # setting record of experiments + exp = Exp(args) # set experiments + setting = '{}_{}_{}_{}_ft{}_sl{}_ll{}_pl{}_dm{}_nh{}_el{}_dl{}_df{}_expand{}_dc{}_fc{}_eb{}_dt{}_{}_{}'.format( + args.task_name, + args.model_id, + args.model, + args.data, + args.features, + args.seq_len, + args.label_len, + args.pred_len, + args.d_model, + args.n_heads, + args.e_layers, + args.d_layers, + args.d_ff, + args.expand, + args.d_conv, + args.factor, + args.embed, + args.distil, + args.des, ii) + + print('>>>>>>>start training : {}>>>>>>>>>>>>>>>>>>>>>>>>>>'.format(setting)) + exp.train(setting) + + print('>>>>>>>testing : {}<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'.format(setting)) + exp.test(setting) + if args.gpu_type == 'mps': + torch.backends.mps.empty_cache() + elif args.gpu_type == 'cuda': + torch.cuda.empty_cache() + else: + exp = Exp(args) # set experiments + ii = 0 + setting = '{}_{}_{}_{}_ft{}_sl{}_ll{}_pl{}_dm{}_nh{}_el{}_dl{}_df{}_expand{}_dc{}_fc{}_eb{}_dt{}_{}_{}'.format( + args.task_name, + args.model_id, + args.model, + args.data, + args.features, + args.seq_len, + args.label_len, + args.pred_len, + args.d_model, + args.n_heads, + args.e_layers, + args.d_layers, + args.d_ff, + args.expand, + args.d_conv, + args.factor, + args.embed, + args.distil, + args.des, ii) + + print('>>>>>>>testing : {}<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'.format(setting)) + exp.test(setting, test=1) + if args.gpu_type == 'mps': + torch.backends.mps.empty_cache() + elif args.gpu_type == 'cuda': + torch.cuda.empty_cache() diff --git a/scripts/anomaly_detection/MSL/Autoformer.sh b/scripts/anomaly_detection/MSL/Autoformer.sh new file mode 100644 index 0000000..583ddf9 --- /dev/null +++ b/scripts/anomaly_detection/MSL/Autoformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model Autoformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/Crossformer.sh b/scripts/anomaly_detection/MSL/Crossformer.sh new file mode 100644 index 0000000..39d6c8b --- /dev/null +++ b/scripts/anomaly_detection/MSL/Crossformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model Crossformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/DLinear.sh b/scripts/anomaly_detection/MSL/DLinear.sh new file mode 100644 index 0000000..d0e2b27 --- /dev/null +++ b/scripts/anomaly_detection/MSL/DLinear.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model DLinear \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 100 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/ETSformer.sh b/scripts/anomaly_detection/MSL/ETSformer.sh new file mode 100644 index 0000000..6400458 --- /dev/null +++ b/scripts/anomaly_detection/MSL/ETSformer.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model ETSformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 100 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --d_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/FEDformer.sh b/scripts/anomaly_detection/MSL/FEDformer.sh new file mode 100644 index 0000000..a3e69bb --- /dev/null +++ b/scripts/anomaly_detection/MSL/FEDformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model FEDformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/FiLM.sh b/scripts/anomaly_detection/MSL/FiLM.sh new file mode 100644 index 0000000..92ed6ed --- /dev/null +++ b/scripts/anomaly_detection/MSL/FiLM.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=6 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model FiLM \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 100 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 32 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/Informer.sh b/scripts/anomaly_detection/MSL/Informer.sh new file mode 100644 index 0000000..6e3f0b0 --- /dev/null +++ b/scripts/anomaly_detection/MSL/Informer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model Informer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/LightTS.sh b/scripts/anomaly_detection/MSL/LightTS.sh new file mode 100644 index 0000000..2a2439e --- /dev/null +++ b/scripts/anomaly_detection/MSL/LightTS.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model LightTS \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/MICN.sh b/scripts/anomaly_detection/MSL/MICN.sh new file mode 100644 index 0000000..80ab7e9 --- /dev/null +++ b/scripts/anomaly_detection/MSL/MICN.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=1 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model MICN \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/Pyraformer.sh b/scripts/anomaly_detection/MSL/Pyraformer.sh new file mode 100644 index 0000000..c729ac8 --- /dev/null +++ b/scripts/anomaly_detection/MSL/Pyraformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model Pyraformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/Reformer.sh b/scripts/anomaly_detection/MSL/Reformer.sh new file mode 100644 index 0000000..09507c3 --- /dev/null +++ b/scripts/anomaly_detection/MSL/Reformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model Reformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/TimesNet.sh b/scripts/anomaly_detection/MSL/TimesNet.sh new file mode 100644 index 0000000..d6e4e11 --- /dev/null +++ b/scripts/anomaly_detection/MSL/TimesNet.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=2 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model TimesNet \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 8 \ + --d_ff 16 \ + --e_layers 1 \ + --enc_in 55 \ + --c_out 55 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 1 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/Transformer.sh b/scripts/anomaly_detection/MSL/Transformer.sh new file mode 100644 index 0000000..fd0d820 --- /dev/null +++ b/scripts/anomaly_detection/MSL/Transformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=1 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model Transformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/MSL/iTransformer.sh b/scripts/anomaly_detection/MSL/iTransformer.sh new file mode 100644 index 0000000..1dafe12 --- /dev/null +++ b/scripts/anomaly_detection/MSL/iTransformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/MSL \ + --model_id MSL \ + --model iTransformer \ + --data MSL \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 55 \ + --c_out 55 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/PSM/Autoformer.sh b/scripts/anomaly_detection/PSM/Autoformer.sh new file mode 100644 index 0000000..887ac1a --- /dev/null +++ b/scripts/anomaly_detection/PSM/Autoformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=6 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/PSM \ + --model_id PSM \ + --model Autoformer \ + --data PSM \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 25 \ + --c_out 25 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/PSM/DLinear.sh b/scripts/anomaly_detection/PSM/DLinear.sh new file mode 100644 index 0000000..d531bf0 --- /dev/null +++ b/scripts/anomaly_detection/PSM/DLinear.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=6 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/PSM \ + --model_id PSM \ + --model DLinear \ + --data PSM \ + --features M \ + --seq_len 100 \ + --pred_len 100 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 25 \ + --c_out 25 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/PSM/TimesNet.sh b/scripts/anomaly_detection/PSM/TimesNet.sh new file mode 100644 index 0000000..e972e61 --- /dev/null +++ b/scripts/anomaly_detection/PSM/TimesNet.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=6 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/PSM \ + --model_id PSM \ + --model TimesNet \ + --data PSM \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 64 \ + --d_ff 64 \ + --e_layers 2 \ + --enc_in 25 \ + --c_out 25 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/PSM/Transformer.sh b/scripts/anomaly_detection/PSM/Transformer.sh new file mode 100644 index 0000000..ae765c8 --- /dev/null +++ b/scripts/anomaly_detection/PSM/Transformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=6 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/PSM \ + --model_id PSM \ + --model Transformer \ + --data PSM \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 25 \ + --c_out 25 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/SMAP/Autoformer.sh b/scripts/anomaly_detection/SMAP/Autoformer.sh new file mode 100644 index 0000000..90d3e96 --- /dev/null +++ b/scripts/anomaly_detection/SMAP/Autoformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=7 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SMAP \ + --model_id SMAP \ + --model Autoformer \ + --data SMAP \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 25 \ + --c_out 25 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/SMAP/TimesNet.sh b/scripts/anomaly_detection/SMAP/TimesNet.sh new file mode 100644 index 0000000..5e0bfa5 --- /dev/null +++ b/scripts/anomaly_detection/SMAP/TimesNet.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=0 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SMAP \ + --model_id SMAP \ + --model TimesNet \ + --data SMAP \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 25 \ + --c_out 25 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/SMAP/Transformer.sh b/scripts/anomaly_detection/SMAP/Transformer.sh new file mode 100644 index 0000000..029d25c --- /dev/null +++ b/scripts/anomaly_detection/SMAP/Transformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=7 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SMAP \ + --model_id SMAP \ + --model Transformer \ + --data SMAP \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 25 \ + --c_out 25 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/SMD/Autoformer.sh b/scripts/anomaly_detection/SMD/Autoformer.sh new file mode 100644 index 0000000..b17c459 --- /dev/null +++ b/scripts/anomaly_detection/SMD/Autoformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=2 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SMD \ + --model_id SMD \ + --model Autoformer \ + --data SMD \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 38 \ + --c_out 38 \ + --anomaly_ratio 0.5 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/SMD/TimesNet.sh b/scripts/anomaly_detection/SMD/TimesNet.sh new file mode 100644 index 0000000..0064211 --- /dev/null +++ b/scripts/anomaly_detection/SMD/TimesNet.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=2 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SMD \ + --model_id SMD \ + --model TimesNet \ + --data SMD \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 64 \ + --d_ff 64 \ + --e_layers 2 \ + --enc_in 38 \ + --c_out 38 \ + --top_k 5 \ + --anomaly_ratio 0.5 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/SMD/Transformer.sh b/scripts/anomaly_detection/SMD/Transformer.sh new file mode 100644 index 0000000..dc695ae --- /dev/null +++ b/scripts/anomaly_detection/SMD/Transformer.sh @@ -0,0 +1,20 @@ +export CUDA_VISIBLE_DEVICES=2 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SMD \ + --model_id SMD \ + --model Transformer \ + --data SMD \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 38 \ + --c_out 38 \ + --anomaly_ratio 0.5 \ + --batch_size 128 \ + --train_epochs 10 \ No newline at end of file diff --git a/scripts/anomaly_detection/SWAT/Autoformer.sh b/scripts/anomaly_detection/SWAT/Autoformer.sh new file mode 100644 index 0000000..a279913 --- /dev/null +++ b/scripts/anomaly_detection/SWAT/Autoformer.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=1 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model Autoformer \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/SWAT/TimesNet.sh b/scripts/anomaly_detection/SWAT/TimesNet.sh new file mode 100644 index 0000000..98e00ac --- /dev/null +++ b/scripts/anomaly_detection/SWAT/TimesNet.sh @@ -0,0 +1,161 @@ +export CUDA_VISIBLE_DEVICES=1 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 8 \ + --d_ff 8 \ + --e_layers 3 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 16 \ + --d_ff 16 \ + --e_layers 3 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 32 \ + --d_ff 32 \ + --e_layers 3 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 64 \ + --d_ff 64 \ + --e_layers 3 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 8 \ + --d_ff 8 \ + --e_layers 2 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 16 \ + --d_ff 16 \ + --e_layers 2 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 32 \ + --d_ff 32 \ + --e_layers 2 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model TimesNet \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 64 \ + --d_ff 64 \ + --e_layers 2 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/anomaly_detection/SWAT/Transformer.sh b/scripts/anomaly_detection/SWAT/Transformer.sh new file mode 100644 index 0000000..5ae6209 --- /dev/null +++ b/scripts/anomaly_detection/SWAT/Transformer.sh @@ -0,0 +1,21 @@ +export CUDA_VISIBLE_DEVICES=1 + +python -u run.py \ + --task_name anomaly_detection \ + --is_training 1 \ + --root_path ./dataset/SWaT \ + --model_id SWAT \ + --model Transformer \ + --data SWAT \ + --features M \ + --seq_len 100 \ + --pred_len 0 \ + --d_model 128 \ + --d_ff 128 \ + --e_layers 3 \ + --enc_in 51 \ + --c_out 51 \ + --top_k 3 \ + --anomaly_ratio 1 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/classification/Autoformer.sh b/scripts/classification/Autoformer.sh new file mode 100644 index 0000000..84f4a7a --- /dev/null +++ b/scripts/classification/Autoformer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Autoformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/Crossformer.sh b/scripts/classification/Crossformer.sh new file mode 100644 index 0000000..c99a414 --- /dev/null +++ b/scripts/classification/Crossformer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=Crossformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/DLinear.sh b/scripts/classification/DLinear.sh new file mode 100644 index 0000000..662dd1d --- /dev/null +++ b/scripts/classification/DLinear.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=DLinear + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/ETSformer.sh b/scripts/classification/ETSformer.sh new file mode 100644 index 0000000..7b281b3 --- /dev/null +++ b/scripts/classification/ETSformer.sh @@ -0,0 +1,193 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=ETSformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --d_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/FEDformer.sh b/scripts/classification/FEDformer.sh new file mode 100644 index 0000000..0ad0192 --- /dev/null +++ b/scripts/classification/FEDformer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=FEDformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/FiLM.sh b/scripts/classification/FiLM.sh new file mode 100644 index 0000000..421f8b0 --- /dev/null +++ b/scripts/classification/FiLM.sh @@ -0,0 +1,185 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=FiLM + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --seq_len 1751 \ + --pred_len 1751 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/Informer.sh b/scripts/classification/Informer.sh new file mode 100644 index 0000000..cf84a5a --- /dev/null +++ b/scripts/classification/Informer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Informer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/LightTS.sh b/scripts/classification/LightTS.sh new file mode 100644 index 0000000..c47a011 --- /dev/null +++ b/scripts/classification/LightTS.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=LightTS + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/MICN.sh b/scripts/classification/MICN.sh new file mode 100644 index 0000000..dbb32ad --- /dev/null +++ b/scripts/classification/MICN.sh @@ -0,0 +1,184 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=MICN + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --c_out 3 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/PatchTST.sh b/scripts/classification/PatchTST.sh new file mode 100644 index 0000000..333ce8d --- /dev/null +++ b/scripts/classification/PatchTST.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=PatchTST + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/Pyraformer.sh b/scripts/classification/Pyraformer.sh new file mode 100644 index 0000000..d1a775e --- /dev/null +++ b/scripts/classification/Pyraformer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Pyraformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 4 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/Reformer.sh b/scripts/classification/Reformer.sh new file mode 100644 index 0000000..1b0bd9e --- /dev/null +++ b/scripts/classification/Reformer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Reformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/TimesNet.sh b/scripts/classification/TimesNet.sh new file mode 100644 index 0000000..7d55dd6 --- /dev/null +++ b/scripts/classification/TimesNet.sh @@ -0,0 +1,182 @@ +export CUDA_VISIBLE_DEVICES=3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model TimesNet \ + --data UEA \ + --e_layers 2 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model TimesNet \ + --data UEA \ + --e_layers 2 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 256 \ + --top_k 3 \ + --num_kernels 4 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python run.py \ +--task_name classification \ +--is_training 1 \ +--root_path ./dataset/Handwriting/ \ +--model_id Handwriting \ +--model TimesNet \ +--data UEA \ +--e_layers 2 \ +--batch_size 16 \ +--d_model 32 \ +--d_ff 64 \ +--top_k 3 \ +--des 'Exp' \ +--itr 1 \ +--learning_rate 0.001 \ +--train_epochs 30 \ +--patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model TimesNet \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 1 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model TimesNet \ + --data UEA \ + --e_layers 2 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 60 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model TimesNet \ + --data UEA \ + --e_layers 6 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model TimesNet \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model TimesNet \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model TimesNet \ + --data UEA \ + --e_layers 2 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 2 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model TimesNet \ + --data UEA \ + --e_layers 2 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 64 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 30 \ + --patience 10 diff --git a/scripts/classification/Transformer.sh b/scripts/classification/Transformer.sh new file mode 100644 index 0000000..677bf0d --- /dev/null +++ b/scripts/classification/Transformer.sh @@ -0,0 +1,183 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Transformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 diff --git a/scripts/classification/iTransformer.sh b/scripts/classification/iTransformer.sh new file mode 100644 index 0000000..2534e63 --- /dev/null +++ b/scripts/classification/iTransformer.sh @@ -0,0 +1,193 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 2048 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Handwriting/ \ + --model_id Handwriting \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/Heartbeat/ \ + --model_id Heartbeat \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/JapaneseVowels/ \ + --model_id JapaneseVowels \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/PEMS-SF/ \ + --model_id PEMS-SF \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP1/ \ + --model_id SelfRegulationSCP1 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SelfRegulationSCP2/ \ + --model_id SelfRegulationSCP2 \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/SpokenArabicDigits/ \ + --model_id SpokenArabicDigits \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/UWaveGestureLibrary/ \ + --model_id UWaveGestureLibrary \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --enc_in 3 diff --git a/scripts/classification/xPatch_SparseChannel.sh b/scripts/classification/xPatch_SparseChannel.sh new file mode 100644 index 0000000..544a4a5 --- /dev/null +++ b/scripts/classification/xPatch_SparseChannel.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# xPatch_SparseChannel Classification Training Script for FaceDetection Dataset +export CUDA_VISIBLE_DEVICES=0 + +model_name=xPatch_SparseChannel + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/FaceDetection/ \ + --model_id FaceDetection \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 64 \ + --seq_len 62 \ + --enc_in 144 \ + --d_model 128 \ + --d_ff 256 \ + --n_heads 8 \ + --patch_len 16 \ + --stride 8 \ + --moving_avg 25 \ + --dropout 0.1 \ + --des 'xPatch_SparseChannel_FaceDetection' \ + --itr 1 \ + --learning_rate 0.0005 \ + --train_epochs 100 \ + --patience 5 \ + --revin 1 \ + --k_graph 8 \ No newline at end of file diff --git a/scripts/exogenous_forecast/ECL/TimeXer.sh b/scripts/exogenous_forecast/ECL/TimeXer.sh new file mode 100644 index 0000000..53f9a28 --- /dev/null +++ b/scripts/exogenous_forecast/ECL/TimeXer.sh @@ -0,0 +1,89 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=TimeXer +des='Timexer-MS' + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des $des \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des $des \ + --batch_size 32 \ + --itr 1 + + python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des $des \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des $des \ + --d_model 512 \ + --itr 1 diff --git a/scripts/exogenous_forecast/EPF/TimeXer.sh b/scripts/exogenous_forecast/EPF/TimeXer.sh new file mode 100644 index 0000000..e7fcf3a --- /dev/null +++ b/scripts/exogenous_forecast/EPF/TimeXer.sh @@ -0,0 +1,114 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer +des='Timexer-MS' +patch_len=24 + + +python -u run.py \ + --is_training 1 \ + --task_name long_term_forecast \ + --root_path ./dataset/EPF/ \ + --data_path NP.csv \ + --model_id NP_168_24 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 168 \ + --pred_len 24 \ + --e_layers 3 \ + --enc_in 3 \ + --dec_in 3 \ + --c_out 1 \ + --des $des \ + --patch_len $patch_len \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --is_training 1 \ + --task_name long_term_forecast \ + --root_path ./dataset/EPF/ \ + --data_path PJM.csv \ + --model_id PJM_168_24 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 168 \ + --pred_len 24 \ + --e_layers 3 \ + --enc_in 3 \ + --dec_in 3 \ + --c_out 1 \ + --des $des \ + --patch_len $patch_len \ + --d_model 512 \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --is_training 1 \ + --task_name long_term_forecast \ + --root_path ./dataset/EPF/ \ + --data_path BE.csv \ + --model_id BE_168_24 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 168 \ + --pred_len 24 \ + --e_layers 2 \ + --enc_in 3 \ + --dec_in 3 \ + --c_out 1 \ + --des $des \ + --patch_len $patch_len \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --itr 1 + + +python -u run.py \ + --is_training 1 \ + --task_name long_term_forecast \ + --root_path ./dataset/EPF/ \ + --data_path FR.csv \ + --model_id FR_168_24 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 168 \ + --pred_len 24 \ + --e_layers 2 \ + --enc_in 3 \ + --dec_in 3 \ + --c_out 1 \ + --des $des \ + --patch_len $patch_len \ + --batch_size 16 \ + --d_model 512 \ + --itr 1 + +python -u run.py \ + --is_training 1 \ + --task_name long_term_forecast \ + --root_path ./dataset/EPF/ \ + --data_path DE.csv \ + --model_id DE_168_24 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 168 \ + --pred_len 24 \ + --e_layers 1 \ + --enc_in 3 \ + --dec_in 3 \ + --c_out 1 \ + --des $des \ + --patch_len $patch_len \ + --batch_size 4 \ + --d_model 512 \ + --itr 1 diff --git a/scripts/exogenous_forecast/ETTh1/TimeXer.sh b/scripts/exogenous_forecast/ETTh1/TimeXer.sh new file mode 100644 index 0000000..545a2af --- /dev/null +++ b/scripts/exogenous_forecast/ETTh1/TimeXer.sh @@ -0,0 +1,94 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=TimeXer +des='Timexer-MS' + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 512 \ + --d_ff 512 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --d_ff 128 \ + --batch_size 4 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 32 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 512 \ + --batch_size 128 \ + --des $des \ + --itr 1 diff --git a/scripts/exogenous_forecast/ETTh2/TimeXer.sh b/scripts/exogenous_forecast/ETTh2/TimeXer.sh new file mode 100644 index 0000000..95aa938 --- /dev/null +++ b/scripts/exogenous_forecast/ETTh2/TimeXer.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=TimeXer +des='Timexer-MS' + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --d_ff 128 \ + --batch_size 128 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --d_ff 512 \ + --batch_size 128 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --d_ff 256 \ + --batch_size 16 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des $des \ + --itr 1 \ No newline at end of file diff --git a/scripts/exogenous_forecast/ETTm1/TimeXer.sh b/scripts/exogenous_forecast/ETTm1/TimeXer.sh new file mode 100644 index 0000000..b6ba806 --- /dev/null +++ b/scripts/exogenous_forecast/ETTm1/TimeXer.sh @@ -0,0 +1,92 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TimeXer +des='Timexer-MS' + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --batch_size 128 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --batch_size 128 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --batch_size 128 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --batch_size 128 \ + --des $des \ + --itr 1 \ No newline at end of file diff --git a/scripts/exogenous_forecast/ETTm2/TimeXer.sh b/scripts/exogenous_forecast/ETTm2/TimeXer.sh new file mode 100644 index 0000000..f014b71 --- /dev/null +++ b/scripts/exogenous_forecast/ETTm2/TimeXer.sh @@ -0,0 +1,92 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TimeXer +des='Timexer-MS' + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 512 \ + --batch_size 16 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --batch_size 4 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --batch_size 128 \ + --des $des \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 128 \ + --batch_size 128 \ + --des $des \ + --itr 1 diff --git a/scripts/exogenous_forecast/Traffic/TimeXer.sh b/scripts/exogenous_forecast/Traffic/TimeXer.sh new file mode 100644 index 0000000..831025a --- /dev/null +++ b/scripts/exogenous_forecast/Traffic/TimeXer.sh @@ -0,0 +1,96 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer +des='Timexer-MS' + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --des $des \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --des $des \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --des $des \ + --batch_size 4 \ + --itr 1 diff --git a/scripts/exogenous_forecast/Weather/TimeXer.sh b/scripts/exogenous_forecast/Weather/TimeXer.sh new file mode 100644 index 0000000..30a285f --- /dev/null +++ b/scripts/exogenous_forecast/Weather/TimeXer.sh @@ -0,0 +1,89 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=TimeXer +des='Timexer-MS' + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des $des \ + --d_model 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des $des \ + --d_model 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des $des \ + --d_model 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features MS \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des $des \ + --d_model 128 \ + --itr 1 \ No newline at end of file diff --git a/scripts/imputation/ECL_script/Autoformer.sh b/scripts/imputation/ECL_script/Autoformer.sh new file mode 100644 index 0000000..fedd575 --- /dev/null +++ b/scripts/imputation/ECL_script/Autoformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Autoformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/DLinear.sh b/scripts/imputation/ECL_script/DLinear.sh new file mode 100644 index 0000000..2a95e50 --- /dev/null +++ b/scripts/imputation/ECL_script/DLinear.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=DLinear + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/ETSformer.sh b/scripts/imputation/ECL_script/ETSformer.sh new file mode 100644 index 0000000..36a4cdd --- /dev/null +++ b/scripts/imputation/ECL_script/ETSformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=ETSformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/FEDformer.sh b/scripts/imputation/ECL_script/FEDformer.sh new file mode 100644 index 0000000..57b2f5b --- /dev/null +++ b/scripts/imputation/ECL_script/FEDformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=FEDformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/Informer.sh b/scripts/imputation/ECL_script/Informer.sh new file mode 100644 index 0000000..cfd6264 --- /dev/null +++ b/scripts/imputation/ECL_script/Informer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Informer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/LightTS.sh b/scripts/imputation/ECL_script/LightTS.sh new file mode 100644 index 0000000..a7bffa0 --- /dev/null +++ b/scripts/imputation/ECL_script/LightTS.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=LightTS + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/Pyraformer.sh b/scripts/imputation/ECL_script/Pyraformer.sh new file mode 100644 index 0000000..93a36e3 --- /dev/null +++ b/scripts/imputation/ECL_script/Pyraformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Pyraformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/Reformer.sh b/scripts/imputation/ECL_script/Reformer.sh new file mode 100644 index 0000000..7f50b92 --- /dev/null +++ b/scripts/imputation/ECL_script/Reformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Reformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/TimesNet.sh b/scripts/imputation/ECL_script/TimesNet.sh new file mode 100644 index 0000000..f1930ab --- /dev/null +++ b/scripts/imputation/ECL_script/TimesNet.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=TimesNet + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/Transformer.sh b/scripts/imputation/ECL_script/Transformer.sh new file mode 100644 index 0000000..78559ec --- /dev/null +++ b/scripts/imputation/ECL_script/Transformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ECL_script/iTransformer.sh b/scripts/imputation/ECL_script/iTransformer.sh new file mode 100644 index 0000000..93eb2d2 --- /dev/null +++ b/scripts/imputation/ECL_script/iTransformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Autoformer_ETTh1.sh b/scripts/imputation/ETT_script/Autoformer_ETTh1.sh new file mode 100644 index 0000000..d71dc2d --- /dev/null +++ b/scripts/imputation/ETT_script/Autoformer_ETTh1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Autoformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Autoformer_ETTh2.sh b/scripts/imputation/ETT_script/Autoformer_ETTh2.sh new file mode 100644 index 0000000..ebdee51 --- /dev/null +++ b/scripts/imputation/ETT_script/Autoformer_ETTh2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Autoformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Autoformer_ETTm1.sh b/scripts/imputation/ETT_script/Autoformer_ETTm1.sh new file mode 100644 index 0000000..6210df7 --- /dev/null +++ b/scripts/imputation/ETT_script/Autoformer_ETTm1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Autoformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Autoformer_ETTm2.sh b/scripts/imputation/ETT_script/Autoformer_ETTm2.sh new file mode 100644 index 0000000..a16e618 --- /dev/null +++ b/scripts/imputation/ETT_script/Autoformer_ETTm2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Autoformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Crossformer_ETTh1.sh b/scripts/imputation/ETT_script/Crossformer_ETTh1.sh new file mode 100644 index 0000000..a271a1f --- /dev/null +++ b/scripts/imputation/ETT_script/Crossformer_ETTh1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Crossformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/DLinear_ETTh1.sh b/scripts/imputation/ETT_script/DLinear_ETTh1.sh new file mode 100644 index 0000000..5a9da75 --- /dev/null +++ b/scripts/imputation/ETT_script/DLinear_ETTh1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=DLinear + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/FiLM_ETTh1.sh b/scripts/imputation/ETT_script/FiLM_ETTh1.sh new file mode 100644 index 0000000..d811908 --- /dev/null +++ b/scripts/imputation/ETT_script/FiLM_ETTh1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=FiLM + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/MICN_ETTh1.sh b/scripts/imputation/ETT_script/MICN_ETTh1.sh new file mode 100644 index 0000000..5c742b5 --- /dev/null +++ b/scripts/imputation/ETT_script/MICN_ETTh1.sh @@ -0,0 +1,115 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MICN + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --conv_kernel 12 16 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --conv_kernel 12 16 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --conv_kernel 12 16 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --conv_kernel 12 16 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Nonstationary_Transformer_ETTh1.sh b/scripts/imputation/ETT_script/Nonstationary_Transformer_ETTh1.sh new file mode 100644 index 0000000..ec6bb59 --- /dev/null +++ b/scripts/imputation/ETT_script/Nonstationary_Transformer_ETTh1.sh @@ -0,0 +1,119 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 diff --git a/scripts/imputation/ETT_script/TiDE_ETTh1.sh b/scripts/imputation/ETT_script/TiDE_ETTh1.sh new file mode 100644 index 0000000..bb92069 --- /dev/null +++ b/scripts/imputation/ETT_script/TiDE_ETTh1.sh @@ -0,0 +1,110 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TiDE + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 2 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 256 \ + --d_ff 256 \ + --dropout 0.3 \ + --learning_rate 0.1 \ + --patience 5 \ + --train_epochs 10 \ + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/TimesNet_ETTh1.sh b/scripts/imputation/ETT_script/TimesNet_ETTh1.sh new file mode 100644 index 0000000..6b5af0c --- /dev/null +++ b/scripts/imputation/ETT_script/TimesNet_ETTh1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimesNet + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/TimesNet_ETTh2.sh b/scripts/imputation/ETT_script/TimesNet_ETTh2.sh new file mode 100644 index 0000000..2780552 --- /dev/null +++ b/scripts/imputation/ETT_script/TimesNet_ETTh2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=TimesNet + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/TimesNet_ETTm1.sh b/scripts/imputation/ETT_script/TimesNet_ETTm1.sh new file mode 100644 index 0000000..5250313 --- /dev/null +++ b/scripts/imputation/ETT_script/TimesNet_ETTm1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TimesNet + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/TimesNet_ETTm2.sh b/scripts/imputation/ETT_script/TimesNet_ETTm2.sh new file mode 100644 index 0000000..e1e8e5d --- /dev/null +++ b/scripts/imputation/ETT_script/TimesNet_ETTm2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=TimesNet + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Transformer_ETTh1.sh b/scripts/imputation/ETT_script/Transformer_ETTh1.sh new file mode 100644 index 0000000..eb64ee3 --- /dev/null +++ b/scripts/imputation/ETT_script/Transformer_ETTh1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Transformer_ETTh2.sh b/scripts/imputation/ETT_script/Transformer_ETTh2.sh new file mode 100644 index 0000000..f5b7e43 --- /dev/null +++ b/scripts/imputation/ETT_script/Transformer_ETTh2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Transformer_ETTm1.sh b/scripts/imputation/ETT_script/Transformer_ETTm1.sh new file mode 100644 index 0000000..dd8523d --- /dev/null +++ b/scripts/imputation/ETT_script/Transformer_ETTm1.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/Transformer_ETTm2.sh b/scripts/imputation/ETT_script/Transformer_ETTm2.sh new file mode 100644 index 0000000..ec27338 --- /dev/null +++ b/scripts/imputation/ETT_script/Transformer_ETTm2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/ETT_script/iTransformer_ETTh2.sh b/scripts/imputation/ETT_script/iTransformer_ETTh2.sh new file mode 100644 index 0000000..cc8a92b --- /dev/null +++ b/scripts/imputation/ETT_script/iTransformer_ETTh2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/Weather_script/Autoformer.sh b/scripts/imputation/Weather_script/Autoformer.sh new file mode 100644 index 0000000..4c96108 --- /dev/null +++ b/scripts/imputation/Weather_script/Autoformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Autoformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/imputation/Weather_script/TimesNet.sh b/scripts/imputation/Weather_script/TimesNet.sh new file mode 100644 index 0000000..6bb14e0 --- /dev/null +++ b/scripts/imputation/Weather_script/TimesNet.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=TimesNet + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --top_k 3 \ + --learning_rate 0.001 diff --git a/scripts/imputation/Weather_script/Transformer.sh b/scripts/imputation/Weather_script/Transformer.sh new file mode 100644 index 0000000..8020234 --- /dev/null +++ b/scripts/imputation/Weather_script/Transformer.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.125 \ + --mask_rate 0.125 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.25 \ + --mask_rate 0.25 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.375 \ + --mask_rate 0.375 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 + +python -u run.py \ + --task_name imputation \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_mask_0.5 \ + --mask_rate 0.5 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 0 \ + --pred_len 0 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 128 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 \ + --learning_rate 0.001 diff --git a/scripts/long_term_forecast/AugmentSample/Classification/PatchTST.sh b/scripts/long_term_forecast/AugmentSample/Classification/PatchTST.sh new file mode 100644 index 0000000..016ca15 --- /dev/null +++ b/scripts/long_term_forecast/AugmentSample/Classification/PatchTST.sh @@ -0,0 +1,28 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=PatchTST + +for aug in jitter scaling permutation magwarp timewarp windowslice windowwarp rotation spawner dtwwarp shapedtwwarp wdba discdtw discsdtw +do +echo using augmentation: ${aug} + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --augmentation_ratio 1 \ + --${aug} + done \ No newline at end of file diff --git a/scripts/long_term_forecast/AugmentSample/Forecasting/PatchTST.sh b/scripts/long_term_forecast/AugmentSample/Forecasting/PatchTST.sh new file mode 100644 index 0000000..af41d5a --- /dev/null +++ b/scripts/long_term_forecast/AugmentSample/Forecasting/PatchTST.sh @@ -0,0 +1,33 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=PatchTST +for aug in jitter scaling permutation magwarp timewarp windowslice windowwarp rotation spawner dtwwarp shapedtwwarp discdtw discsdtw +do +for pred_len in 96 192 336 720 +do +echo using augmentation: ${aug} + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_${pred_len} \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len ${pred_len} \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --augmentation_ratio 1 \ + --${aug} +done +done \ No newline at end of file diff --git a/scripts/long_term_forecast/AugmentSample/ReadMe.md b/scripts/long_term_forecast/AugmentSample/ReadMe.md new file mode 100644 index 0000000..6a2f89e --- /dev/null +++ b/scripts/long_term_forecast/AugmentSample/ReadMe.md @@ -0,0 +1,97 @@ +# Augmentation Feature Roadbook + +Hi there! For those who are interested in testing +augmentation techniques in `Time-Series-Library`. + +For now, we have embedded several augmentation methods +in this repo. We are still collecting publicly available +augmentation algorithms, and we appreciate your valuable +advice! + +``` +The Implemented Augmentation Methods +1. jitter +2. scaling +3. permutation +4. magwarp +5. timewarp +6. windowslice +7. windowwarp +8. rotation +9. spawner +10. dtwwarp +11. shapedtwwarp +12. wdba (Specially Designed for Classification tasks) +13. discdtw +``` + +## Usage + +In this folder, we present two sample of shell scripts +doing augmentation in `Forecasting` and `Classification` +tasks. + +Take `Forecasting` task for example, we test multiple +augmentation algorithms on `EthanolConcentration` dataset +(a subset of the popular classification benchmark `UEA`) +using `PatchTST` model. + +```shell +export CUDA_VISIBLE_DEVICES=0 + +model_name=PatchTST + +for aug in jitter scaling permutation magwarp timewarp windowslice windowwarp rotation spawner dtwwarp shapedtwwarp wdba discdtw discsdtw +do +echo using augmentation: ${aug} + +python -u run.py \ + --task_name classification \ + --is_training 1 \ + --root_path ./dataset/EthanolConcentration/ \ + --model_id EthanolConcentration \ + --model $model_name \ + --data UEA \ + --e_layers 3 \ + --batch_size 16 \ + --d_model 128 \ + --d_ff 256 \ + --top_k 3 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --train_epochs 100 \ + --patience 10 \ + --augmentation_ratio 1 \ + --${aug} + done +``` + +Here, parameter `augmentation_ratio` represents how many +times do we want to perform our augmentation method. +Parameter `${aug}` represents a string of augmentation +type label. + +The example here only perform augmentation once, so we +can set `augmentation_ratio` to `1`, followed by one +augmentation type label. Trivially, you can set +`augmentation_ratio` to an integer `num` followed by +`num` augmentation type labels. + +The augmentation code obeys the same prototype of +`Time-Series-Library`. If you want to adjust other +training parameters, feel free to add arguments to the +shell scripts and play around. The full list of parameters +can be seen in `run.py`. + +## Contact Us! + +This piece of code is written and maintained by +[Yunzhong Qiu](https://github.com/DigitalLifeYZQiu). +We thank [Haixu Wu](https://github.com/wuhaixu2016) and +[Jiaxiang Dong](https://github.com/dongjiaxiang) for +insightful discussion and solid support. + +If you have difficulties or find bugs in our code, please +contact us: +- Email: qiuyz24@mails.tsinghua.edu.cn \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Autoformer.sh b/scripts/long_term_forecast/ECL_script/Autoformer.sh new file mode 100644 index 0000000..d34e6d4 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Autoformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Crossformer.sh b/scripts/long_term_forecast/ECL_script/Crossformer.sh new file mode 100644 index 0000000..e88befd --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Crossformer.sh @@ -0,0 +1,103 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/DLinear.sh b/scripts/long_term_forecast/ECL_script/DLinear.sh new file mode 100644 index 0000000..4fb44f7 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/DLinear.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=DLinear + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/ETSformer.sh b/scripts/long_term_forecast/ECL_script/ETSformer.sh new file mode 100644 index 0000000..087f72c --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/ETSformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=ETSformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/FEDformer.sh b/scripts/long_term_forecast/ECL_script/FEDformer.sh new file mode 100644 index 0000000..a748d46 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/FEDformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=FEDformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/ECL_script/FiLM.sh b/scripts/long_term_forecast/ECL_script/FiLM.sh new file mode 100644 index 0000000..dac33da --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/FiLM.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 192 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 192 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 192 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 192 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Informer.sh b/scripts/long_term_forecast/ECL_script/Informer.sh new file mode 100644 index 0000000..e2a36e6 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Informer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Informer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Koopa.sh b/scripts/long_term_forecast/ECL_script/Koopa.sh new file mode 100644 index 0000000..a8da551 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Koopa.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_192_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_288_144 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_384_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/LightTS.sh b/scripts/long_term_forecast/ECL_script/LightTS.sh new file mode 100644 index 0000000..8704692 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/LightTS.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=LightTS + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/MICN.sh b/scripts/long_term_forecast/ECL_script/MICN.sh new file mode 100644 index 0000000..6bbf035 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/MICN.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Mamba.sh b/scripts/long_term_forecast/ECL_script/Mamba.sh new file mode 100644 index 0000000..931a1b7 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Mamba.sh @@ -0,0 +1,30 @@ +model_name=Mamba + +for pred_len in 96 192 336 720 +# for pred_len in 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_$pred_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 321 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 321 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done diff --git a/scripts/long_term_forecast/ECL_script/MultiPatchFormer.sh b/scripts/long_term_forecast/ECL_script/MultiPatchFormer.sh new file mode 100644 index 0000000..6d94d4b --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/MultiPatchFormer.sh @@ -0,0 +1,98 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MultiPatchFormer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Nonstationary_Transformer.sh b/scripts/long_term_forecast/ECL_script/Nonstationary_Transformer.sh new file mode 100644 index 0000000..28799ef --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Nonstationary_Transformer.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 2048 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 2048 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 2048 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 2048 diff --git a/scripts/long_term_forecast/ECL_script/PatchTST.sh b/scripts/long_term_forecast/ECL_script/PatchTST.sh new file mode 100644 index 0000000..b9b9863 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/PatchTST.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 16 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Pyraformer.sh b/scripts/long_term_forecast/ECL_script/Pyraformer.sh new file mode 100644 index 0000000..44bf3ba --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Pyraformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Reformer.sh b/scripts/long_term_forecast/ECL_script/Reformer.sh new file mode 100644 index 0000000..e37a55f --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Reformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Reformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/SegRNN.sh b/scripts/long_term_forecast/ECL_script/SegRNN.sh new file mode 100644 index 0000000..8284e0c --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/SegRNN.sh @@ -0,0 +1,27 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_$seq_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 24 \ + --enc_in 321 \ + --d_model 512 \ + --dropout 0 \ + --learning_rate 0.001 \ + --des 'Exp' \ + --itr 1 +done + diff --git a/scripts/long_term_forecast/ECL_script/TSMixer.sh b/scripts/long_term_forecast/ECL_script/TSMixer.sh new file mode 100755 index 0000000..07de434 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/TSMixer.sh @@ -0,0 +1,98 @@ + +model_name=TSMixer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/TimeMixer.sh b/scripts/long_term_forecast/ECL_script/TimeMixer.sh new file mode 100755 index 0000000..1e21206 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/TimeMixer.sh @@ -0,0 +1,134 @@ +#export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=3 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=16 +d_ff=32 +batch_size=32 +train_epochs=20 +patience=10 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_$seq_len'_'96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_$seq_len'_'192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_$seq_len'_'336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_$seq_len'_'720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/TimeXer.sh b/scripts/long_term_forecast/ECL_script/TimeXer.sh new file mode 100644 index 0000000..8c63f1a --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/TimeXer.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 4 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --d_ff 512 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 4 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 diff --git a/scripts/long_term_forecast/ECL_script/TimesNet.sh b/scripts/long_term_forecast/ECL_script/TimesNet.sh new file mode 100644 index 0000000..e265dfb --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/TimesNet.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --d_model 256 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/Transformer.sh b/scripts/long_term_forecast/ECL_script/Transformer.sh new file mode 100644 index 0000000..c2253f5 --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/Transformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features S \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ECL_script/WPMixer.sh b/scripts/long_term_forecast/ECL_script/WPMixer.sh new file mode 100644 index 0000000..ce0284e --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/WPMixer.sh @@ -0,0 +1,49 @@ + +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=electricity +seq_lens=(512 512 512 512) +pred_lens=(96 192 336 720) +learning_rates=(0.00328086 0.000493286 0.002505375 0.001977516) +batches=(32 32 32 32) +epochs=(100 100 100 100) +dropouts=(0.1 0.1 0.2 0.1) +patch_lens=(16 16 16 16) +lradjs=(type3 type3 type3 type3) +d_models=(32 32 32 32) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(sym3 coif5 sym4 db2) +levels=(2 3 1 2) +tfactors=(3 7 5 7) +dfactors=(5 5 7 8) +strides=(8 8 8 8) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/electricity/ \ + --data_path electricity.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/ECL_script/iTransformer.sh b/scripts/long_term_forecast/ECL_script/iTransformer.sh new file mode 100644 index 0000000..579ffbe --- /dev/null +++ b/scripts/long_term_forecast/ECL_script/iTransformer.sh @@ -0,0 +1,105 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.0005 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.0005 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.0005 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/electricity/ \ + --data_path electricity.csv \ + --model_id ECL_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 321 \ + --dec_in 321 \ + --c_out 321 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.0005 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Autoformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Autoformer_ETTh1.sh new file mode 100644 index 0000000..50c7f2f --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Autoformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Autoformer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Autoformer_ETTh2.sh new file mode 100644 index 0000000..8a24405 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Autoformer_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Autoformer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Autoformer_ETTm1.sh new file mode 100644 index 0000000..323e0a3 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Autoformer_ETTm1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Autoformer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Autoformer_ETTm2.sh new file mode 100644 index 0000000..88170f9 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Autoformer_ETTm2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Crossformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Crossformer_ETTh1.sh new file mode 100644 index 0000000..dc213fe --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Crossformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Crossformer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Crossformer_ETTh2.sh new file mode 100644 index 0000000..e327500 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Crossformer_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Crossformer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Crossformer_ETTm1.sh new file mode 100644 index 0000000..526494a --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Crossformer_ETTm1.sh @@ -0,0 +1,83 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Crossformer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Crossformer_ETTm2.sh new file mode 100644 index 0000000..83e4721 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Crossformer_ETTm2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/DLinear_ETTh1.sh b/scripts/long_term_forecast/ETT_script/DLinear_ETTh1.sh new file mode 100644 index 0000000..466776c --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/DLinear_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=DLinear + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/ETSformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/ETSformer_ETTh1.sh new file mode 100644 index 0000000..7c59d59 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/ETSformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=ETSformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/FEDformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/FEDformer_ETTh1.sh new file mode 100644 index 0000000..a33faf5 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/FEDformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=FEDformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/FiLM_ETTh1.sh b/scripts/long_term_forecast/ETT_script/FiLM_ETTh1.sh new file mode 100644 index 0000000..224af9d --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/FiLM_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 336 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 336 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 336 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 336 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/FiLM_ETTh2.sh b/scripts/long_term_forecast/ETT_script/FiLM_ETTh2.sh new file mode 100644 index 0000000..23591a8 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/FiLM_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 168 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 168 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 168 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 168 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/FiLM_ETTm1.sh b/scripts/long_term_forecast/ETT_script/FiLM_ETTm1.sh new file mode 100644 index 0000000..c131881 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/FiLM_ETTm1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/FiLM_ETTm2.sh b/scripts/long_term_forecast/ETT_script/FiLM_ETTm2.sh new file mode 100644 index 0000000..164749d --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/FiLM_ETTm2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Informer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Informer_ETTh1.sh new file mode 100644 index 0000000..0412bef --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Informer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Informer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Koopa_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Koopa_ETTh1.sh new file mode 100644 index 0000000..2c97a52 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Koopa_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_48 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_192_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_288_144 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_384_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Koopa_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Koopa_ETTh2.sh new file mode 100644 index 0000000..f4d1f32 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Koopa_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_48 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_192_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_288_144 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_384_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Koopa_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Koopa_ETTm1.sh new file mode 100644 index 0000000..d1dfbd4 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Koopa_ETTm1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_48 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_192_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_288_144 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_384_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Koopa_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Koopa_ETTm2.sh new file mode 100644 index 0000000..8f6439d --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Koopa_ETTm2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_48 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_192_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_288_144 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_384_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/LightTS_ETTh1.sh b/scripts/long_term_forecast/ETT_script/LightTS_ETTh1.sh new file mode 100644 index 0000000..f14f27c --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/LightTS_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=LightTS + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/MICN_ETTh1.sh b/scripts/long_term_forecast/ETT_script/MICN_ETTh1.sh new file mode 100644 index 0000000..77764b9 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MICN_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/ETT_script/MICN_ETTh2.sh b/scripts/long_term_forecast/ETT_script/MICN_ETTh2.sh new file mode 100644 index 0000000..a137e66 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MICN_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/ETT_script/MICN_ETTm1.sh b/scripts/long_term_forecast/ETT_script/MICN_ETTm1.sh new file mode 100644 index 0000000..ac57040 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MICN_ETTm1.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/MICN_ETTm2.sh b/scripts/long_term_forecast/ETT_script/MICN_ETTm2.sh new file mode 100644 index 0000000..d70b8df --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MICN_ETTm2.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --top_k 5 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/MambaSimple_ETTh1.sh b/scripts/long_term_forecast/ETT_script/MambaSimple_ETTh1.sh new file mode 100644 index 0000000..5e6606a --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MambaSimple_ETTh1.sh @@ -0,0 +1,29 @@ +model_name=MambaSimple + +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_$pred_len'_'$pred_len \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 7 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Mamba_ETT_all.sh b/scripts/long_term_forecast/ETT_script/Mamba_ETT_all.sh new file mode 100644 index 0000000..18558d6 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Mamba_ETT_all.sh @@ -0,0 +1,4 @@ +./scripts/long_term_forecast/ETT_script/Mamba_ETTh1.sh | tee mamba_ett.txt +./scripts/long_term_forecast/ETT_script/Mamba_ETTh2.sh | tee mamba_ett.txt -a +./scripts/long_term_forecast/ETT_script/Mamba_ETTm1.sh | tee mamba_ett.txt -a +./scripts/long_term_forecast/ETT_script/Mamba_ETTm2.sh | tee mamba_ett.txt -a \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Mamba_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Mamba_ETTh1.sh new file mode 100644 index 0000000..9f29ac3 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Mamba_ETTh1.sh @@ -0,0 +1,28 @@ +model_name=Mamba +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_$pred_len'_'$pred_len \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 7 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Mamba_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Mamba_ETTh2.sh new file mode 100644 index 0000000..4c61ce7 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Mamba_ETTh2.sh @@ -0,0 +1,28 @@ +model_name=Mamba + +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_$pred_len'_'$pred_len \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --enc_in 7 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 7 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Mamba_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Mamba_ETTm1.sh new file mode 100644 index 0000000..eefff6f --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Mamba_ETTm1.sh @@ -0,0 +1,28 @@ +model_name=Mamba + +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_$pred_len'_'$pred_len \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --enc_in 7 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 7 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Mamba_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Mamba_ETTm2.sh new file mode 100644 index 0000000..2a4458c --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Mamba_ETTm2.sh @@ -0,0 +1,28 @@ +model_name=Mamba + +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_$pred_len'_'$pred_len \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --enc_in 7 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 7 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTh1.sh new file mode 100644 index 0000000..44edfdd --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTh1.sh @@ -0,0 +1,90 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MultiPatchFormer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTm1.sh new file mode 100644 index 0000000..bc8b3e5 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/MultiPatchFormer_ETTm1.sh @@ -0,0 +1,98 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MultiPatchFormer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh1.sh new file mode 100644 index 0000000..a0e9f7a --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh1.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 128 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 128 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 128 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + --d_model 128 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh2.sh new file mode 100644 index 0000000..022a0a0 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTh2.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 256 256 \ + --p_hidden_layers 4 \ + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ diff --git a/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm1.sh new file mode 100644 index 0000000..9550195 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm1.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 16 16 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 16 16 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 16 16 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 16 16 \ + --p_hidden_layers 4 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm2.sh new file mode 100644 index 0000000..31b3adc --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Nonstationary_Transformer_ETTm2.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 256 256 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 256 256 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 16 16 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 16 16 \ + --p_hidden_layers 4 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/PAttn_ETTh1.sh b/scripts/long_term_forecast/ETT_script/PAttn_ETTh1.sh new file mode 100644 index 0000000..c213b44 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/PAttn_ETTh1.sh @@ -0,0 +1,83 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=PAttn + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 2 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 8 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 8 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 16 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/PatchTST_ETTh1.sh b/scripts/long_term_forecast/ETT_script/PatchTST_ETTh1.sh new file mode 100644 index 0000000..b7bda80 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/PatchTST_ETTh1.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 2 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 8 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 8 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 16 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/PatchTST_ETTh2.sh b/scripts/long_term_forecast/ETT_script/PatchTST_ETTh2.sh new file mode 100644 index 0000000..ba25fc1 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/PatchTST_ETTh2.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/PatchTST_ETTm1.sh b/scripts/long_term_forecast/ETT_script/PatchTST_ETTm1.sh new file mode 100644 index 0000000..a7cfe0d --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/PatchTST_ETTm1.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --batch_size 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --batch_size 128 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/PatchTST_ETTm2.sh b/scripts/long_term_forecast/ETT_script/PatchTST_ETTm2.sh new file mode 100644 index 0000000..d48553d --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/PatchTST_ETTm2.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 16 \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --batch_size 128 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Pyraformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTh1.sh new file mode 100644 index 0000000..5976c8c --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Pyraformer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTh2.sh new file mode 100644 index 0000000..0a08129 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Pyraformer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTm1.sh new file mode 100644 index 0000000..b26c54f --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTm1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Pyraformer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTm2.sh new file mode 100644 index 0000000..2e31c20 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Pyraformer_ETTm2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Reformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Reformer_ETTh1.sh new file mode 100644 index 0000000..cbe5833 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Reformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Reformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/SegRNN_ETTh1.sh b/scripts/long_term_forecast/ETT_script/SegRNN_ETTh1.sh new file mode 100644 index 0000000..3d7527a --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/SegRNN_ETTh1.sh @@ -0,0 +1,26 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_$seq_len'_'$pred_len \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 24 \ + --enc_in 7 \ + --d_model 512 \ + --dropout 0.5 \ + --learning_rate 0.0001 \ + --des 'Exp' \ + --itr 1 +done diff --git a/scripts/long_term_forecast/ETT_script/SegRNN_ETTh2.sh b/scripts/long_term_forecast/ETT_script/SegRNN_ETTh2.sh new file mode 100644 index 0000000..e761708 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/SegRNN_ETTh2.sh @@ -0,0 +1,26 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_$seq_len'_'$pred_len \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 24 \ + --enc_in 7 \ + --d_model 512 \ + --dropout 0.5 \ + --learning_rate 0.0001 \ + --des 'Exp' \ + --itr 1 +done diff --git a/scripts/long_term_forecast/ETT_script/SegRNN_ETTm1.sh b/scripts/long_term_forecast/ETT_script/SegRNN_ETTm1.sh new file mode 100644 index 0000000..be406c4 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/SegRNN_ETTm1.sh @@ -0,0 +1,26 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_$seq_len'_'$pred_len \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 48 \ + --enc_in 7 \ + --d_model 512 \ + --dropout 0.5 \ + --learning_rate 0.0001 \ + --des 'Exp' \ + --itr 1 +done diff --git a/scripts/long_term_forecast/ETT_script/SegRNN_ETTm2.sh b/scripts/long_term_forecast/ETT_script/SegRNN_ETTm2.sh new file mode 100644 index 0000000..756decb --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/SegRNN_ETTm2.sh @@ -0,0 +1,26 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_$seq_len'_'$pred_len \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 48 \ + --enc_in 7 \ + --d_model 512 \ + --dropout 0.5 \ + --learning_rate 0.0001 \ + --des 'Exp' \ + --itr 1 +done diff --git a/scripts/long_term_forecast/ETT_script/TSMixer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/TSMixer_ETTh1.sh new file mode 100755 index 0000000..57e2f49 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TSMixer_ETTh1.sh @@ -0,0 +1,86 @@ + +model_name=TSMixer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TSMixer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/TSMixer_ETTh2.sh new file mode 100755 index 0000000..6c33b0c --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TSMixer_ETTh2.sh @@ -0,0 +1,86 @@ + +model_name=TSMixer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TSMixer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/TSMixer_ETTm1.sh new file mode 100755 index 0000000..7fbd15d --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TSMixer_ETTm1.sh @@ -0,0 +1,86 @@ + +model_name=TSMixer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TSMixer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/TSMixer_ETTm2.sh new file mode 100755 index 0000000..709b589 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TSMixer_ETTm2.sh @@ -0,0 +1,86 @@ + +model_name=TSMixer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TiDE_ETTh1.sh b/scripts/long_term_forecast/ETT_script/TiDE_ETTh1.sh new file mode 100644 index 0000000..31f56ce --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TiDE_ETTh1.sh @@ -0,0 +1,112 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TiDE + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 2 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 8 \ + --d_model 256 \ + --d_ff 256 \ + --dropout 0.3 \ + --batch_size 512 \ + --learning_rate 0.1 \ + --patience 5 \ + --train_epochs 10 \ + + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 2 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 8 \ + --d_model 256 \ + --d_ff 256 \ + --dropout 0.3 \ + --batch_size 512 \ + --learning_rate 0.1 \ + --patience 5 \ + --train_epochs 10 \ + + + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 2 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 8 \ + --d_model 256 \ + --d_ff 256 \ + --dropout 0.3 \ + --batch_size 512 \ + --learning_rate 0.1 \ + --patience 5 \ + --train_epochs 10 \ + + + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 2 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 8 \ + --d_model 256 \ + --d_ff 256 \ + --dropout 0.3 \ + --batch_size 512 \ + --learning_rate 0.1 \ + --patience 5 \ + --train_epochs 10 \ + diff --git a/scripts/long_term_forecast/ETT_script/TimeMixer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTh1.sh new file mode 100755 index 0000000..b0f447f --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTh1.sh @@ -0,0 +1,125 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=2 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=16 +d_ff=32 +train_epochs=10 +patience=10 +batch_size=16 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/\ + --data_path ETTh1.csv \ + --model_id ETTh1_$seq_len'_'96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --batch_size 128 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_$seq_len'_'192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --batch_size 128 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_$seq_len'_'336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --batch_size 128 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_$seq_len'_'720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --batch_size 128 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window diff --git a/scripts/long_term_forecast/ETT_script/TimeMixer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTh2.sh new file mode 100755 index 0000000..54492a4 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTh2.sh @@ -0,0 +1,111 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=2 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=16 +d_ff=32 +batch_size=16 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/\ + --data_path ETTh2.csv \ + --model_id ETTh2_$seq_len'_'96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_$seq_len'_'192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_$seq_len'_'336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_$seq_len'_'720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window diff --git a/scripts/long_term_forecast/ETT_script/TimeMixer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTm1.sh new file mode 100755 index 0000000..d26fa42 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTm1.sh @@ -0,0 +1,115 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=2 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=16 +d_ff=32 +batch_size=16 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/\ + --data_path ETTm1.csv \ + --model_id ETTm1_$seq_len'_'96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_$seq_len'_'192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_$seq_len'_'336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_$seq_len'_'720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window diff --git a/scripts/long_term_forecast/ETT_script/TimeMixer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTm2.sh new file mode 100755 index 0000000..c53df60 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeMixer_ETTm2.sh @@ -0,0 +1,115 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=2 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=32 +d_ff=32 +batch_size=16 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/\ + --data_path ETTm2.csv \ + --model_id ETTm2_$seq_len'_'96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_$seq_len'_'192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_$seq_len'_'336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_$seq_len'_'720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --enc_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window diff --git a/scripts/long_term_forecast/ETT_script/TimeXer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/TimeXer_ETTh1.sh new file mode 100644 index 0000000..928b679 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeXer_ETTh1.sh @@ -0,0 +1,94 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --batch_size 4 \ + --des 'exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 128 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 1024 \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 256 \ + --d_ff 1024 \ + --batch_size 16 \ + --itr 1 diff --git a/scripts/long_term_forecast/ETT_script/TimeXer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/TimeXer_ETTh2.sh new file mode 100644 index 0000000..cc29628 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeXer_ETTh2.sh @@ -0,0 +1,94 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 256 \ + --d_ff 1024 \ + --batch_size 16 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 256 \ + --d_ff 1024 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 1024 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 256 \ + --d_ff 1024 \ + --batch_size 16 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TimeXer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/TimeXer_ETTm1.sh new file mode 100644 index 0000000..95f20d1 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeXer_ETTm1.sh @@ -0,0 +1,94 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --batch_size 4 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 256 \ + --batch_size 4 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 1024 \ + --batch_size 4 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 512 \ + --batch_size 4 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TimeXer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/TimeXer_ETTm2.sh new file mode 100644 index 0000000..9261199 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimeXer_ETTm2.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 256 \ + --d_ff 1024 \ + --batch_size 16 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 512 \ + --d_ff 1024 \ + --des 'Exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TimesNet_ETTh1.sh b/scripts/long_term_forecast/ETT_script/TimesNet_ETTh1.sh new file mode 100644 index 0000000..6a03e5f --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimesNet_ETTh1.sh @@ -0,0 +1,102 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 16 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --top_k 5 diff --git a/scripts/long_term_forecast/ETT_script/TimesNet_ETTh2.sh b/scripts/long_term_forecast/ETT_script/TimesNet_ETTh2.sh new file mode 100644 index 0000000..1741642 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimesNet_ETTh2.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/ETT_script/TimesNet_ETTm1.sh b/scripts/long_term_forecast/ETT_script/TimesNet_ETTm1.sh new file mode 100644 index 0000000..7aea983 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimesNet_ETTm1.sh @@ -0,0 +1,100 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/TimesNet_ETTm2.sh b/scripts/long_term_forecast/ETT_script/TimesNet_ETTm2.sh new file mode 100644 index 0000000..4c5f8d1 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/TimesNet_ETTm2.sh @@ -0,0 +1,101 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --itr 1 \ + --train_epochs 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Transformer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/Transformer_ETTh1.sh new file mode 100644 index 0000000..57eece1 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Transformer_ETTh1.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_96 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_192 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_336 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh1.csv \ + --model_id ETTh1_96_720 \ + --model $model_name \ + --data ETTh1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Transformer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/Transformer_ETTh2.sh new file mode 100644 index 0000000..1228b03 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Transformer_ETTh2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Transformer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/Transformer_ETTm1.sh new file mode 100644 index 0000000..7966a93 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Transformer_ETTm1.sh @@ -0,0 +1,83 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_96 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_192 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_336 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm1.csv \ + --model_id ETTm1_96_720 \ + --model $model_name \ + --data ETTm1 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/Transformer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/Transformer_ETTm2.sh new file mode 100644 index 0000000..ce6fd1f --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/Transformer_ETTm2.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=2 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_96 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_192 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_336 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTm2.csv \ + --model_id ETTm2_96_720 \ + --model $model_name \ + --data ETTm2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 1 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ETT_script/WPMixer_ETTh1.sh b/scripts/long_term_forecast/ETT_script/WPMixer_ETTh1.sh new file mode 100644 index 0000000..0f4c07c --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/WPMixer_ETTh1.sh @@ -0,0 +1,50 @@ + +# Set the GPU to use +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=ETTh1 +seq_lens=(512 512 512 512) +pred_lens=(96 192 336 720) +learning_rates=(0.000242438 0.000201437 0.000132929 0.000239762) +batches=(256 256 256 256) +epochs=(30 30 30 30) +dropouts=(0.4 0.05 0.0 0.2) +patch_lens=(16 16 16 16) +lradjs=(type3 type3 type3 type3) +d_models=(256 256 256 128) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(db2 db3 db2 db2) +levels=(2 2 1 1) +tfactors=(5 5 3 5) +dfactors=(8 5 3 3) +strides=(8 8 8 8) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/ETT/ \ + --data_path ETTh1.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/ETT_script/WPMixer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/WPMixer_ETTh2.sh new file mode 100644 index 0000000..7195138 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/WPMixer_ETTh2.sh @@ -0,0 +1,49 @@ + +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=ETTh2 +seq_lens=(512 512 512 512) +pred_lens=(96 192 336 720) +learning_rates=(0.000466278 0.000294929 0.000617476 0.000810205) +batches=(256 256 256 256) +epochs=(30 30 30 30) +dropouts=(0.0 0.0 0.1 0.4) +patch_lens=(16 16 16 16) +lradjs=(type3 type3 type3 type3) +d_models=(256 256 128 128) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(db2 db2 db2 db2) +levels=(2 3 5 5) +tfactors=(5 3 5 5) +dfactors=(5 8 3 5) +strides=(8 8 8 8) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/ETT/ \ + --data_path ETTh2.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/ETT_script/WPMixer_ETTm1.sh b/scripts/long_term_forecast/ETT_script/WPMixer_ETTm1.sh new file mode 100644 index 0000000..31c3c0e --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/WPMixer_ETTm1.sh @@ -0,0 +1,49 @@ + +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=ETTm1 +seq_lens=(512 512 512 512) +pred_lens=(96 192 336 720) +learning_rates=(0.001277976 0.002415901 0.001594735 0.002011441) +batches=(256 256 256 256) +epochs=(80 80 80 80) +dropouts=(0.4 0.4 0.4 0.4) +patch_lens=(48 48 48 48) +lradjs=(type3 type3 type3 type3) +d_models=(256 128 256 128) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(db2 db3 db5 db5) +levels=(1 1 1 4) +tfactors=(5 3 7 3) +dfactors=(3 7 7 8) +strides=(24 24 24 24) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/ETT/ \ + --data_path ETTm1.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/ETT_script/WPMixer_ETTm2.sh b/scripts/long_term_forecast/ETT_script/WPMixer_ETTm2.sh new file mode 100644 index 0000000..56093cf --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/WPMixer_ETTm2.sh @@ -0,0 +1,50 @@ + +# Set the GPU to use +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=ETTm2 +seq_lens=(512 512 512 512) +pred_lens=(96 192 336 720) +learning_rates=(0.00076587 0.000275775 0.000234608 0.001039536) +batches=(256 256 256 256) +epochs=(80 80 80 80) +dropouts=(0.4 0.2 0.4 0.4) +patch_lens=(48 48 48 48) +lradjs=(type3 type3 type3 type3) +d_models=(256 256 256 256) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(bior3.1 db2 db2 db2) +levels=(1 1 1 1) +tfactors=(3 3 3 3) +dfactors=(8 7 5 8) +strides=(24 24 24 24) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/ETT/ \ + --data_path ETTm2.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/ETT_script/iTransformer_ETTh2.sh b/scripts/long_term_forecast/ETT_script/iTransformer_ETTh2.sh new file mode 100644 index 0000000..e1a58e9 --- /dev/null +++ b/scripts/long_term_forecast/ETT_script/iTransformer_ETTh2.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_96 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 128 \ + --d_ff 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_192 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 128 \ + --d_ff 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_336 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 128 \ + --d_ff 128 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/ETT-small/ \ + --data_path ETTh2.csv \ + --model_id ETTh2_96_720 \ + --model $model_name \ + --data ETTh2 \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --d_model 128 \ + --d_ff 128 \ + --itr 1 diff --git a/scripts/long_term_forecast/Exchange_script/Autoformer.sh b/scripts/long_term_forecast/Exchange_script/Autoformer.sh new file mode 100644 index 0000000..a7de6f5 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Autoformer.sh @@ -0,0 +1,89 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Exchange_script/Crossformer.sh b/scripts/long_term_forecast/Exchange_script/Crossformer.sh new file mode 100644 index 0000000..5e3c62e --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Crossformer.sh @@ -0,0 +1,101 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 diff --git a/scripts/long_term_forecast/Exchange_script/FiLM.sh b/scripts/long_term_forecast/Exchange_script/FiLM.sh new file mode 100644 index 0000000..6e0b082 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/FiLM.sh @@ -0,0 +1,92 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 384 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 384 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/Exchange_script/Koopa.sh b/scripts/long_term_forecast/Exchange_script/Koopa.sh new file mode 100644 index 0000000..953ce92 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Koopa.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_192_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_288_144 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_384_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Exchange_script/MICN.sh b/scripts/long_term_forecast/Exchange_script/MICN.sh new file mode 100644 index 0000000..97c6881 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/MICN.sh @@ -0,0 +1,101 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 diff --git a/scripts/long_term_forecast/Exchange_script/Mamba.sh b/scripts/long_term_forecast/Exchange_script/Mamba.sh new file mode 100644 index 0000000..5a72e3f --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Mamba.sh @@ -0,0 +1,28 @@ +model_name=Mamba +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_$pred_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 8 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 8 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/Exchange_script/Nonstationary_Transformer.sh b/scripts/long_term_forecast/Exchange_script/Nonstationary_Transformer.sh new file mode 100644 index 0000000..ed3af30 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Nonstationary_Transformer.sh @@ -0,0 +1,96 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 64 64 64 64 \ + --p_hidden_layers 4 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ No newline at end of file diff --git a/scripts/long_term_forecast/Exchange_script/PatchTST.sh b/scripts/long_term_forecast/Exchange_script/PatchTST.sh new file mode 100644 index 0000000..9727816 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/PatchTST.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Exchange_script/Pyraformer.sh b/scripts/long_term_forecast/Exchange_script/Pyraformer.sh new file mode 100644 index 0000000..87d7d34 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Pyraformer.sh @@ -0,0 +1,89 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Exchange_script/TimesNet.sh b/scripts/long_term_forecast/Exchange_script/TimesNet.sh new file mode 100644 index 0000000..6a7e1a8 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/TimesNet.sh @@ -0,0 +1,101 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 diff --git a/scripts/long_term_forecast/Exchange_script/Transformer.sh b/scripts/long_term_forecast/Exchange_script/Transformer.sh new file mode 100644 index 0000000..8f41145 --- /dev/null +++ b/scripts/long_term_forecast/Exchange_script/Transformer.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/exchange_rate/ \ + --data_path exchange_rate.csv \ + --model_id Exchange_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 8 \ + --dec_in 8 \ + --c_out 8 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/Autoformer.sh b/scripts/long_term_forecast/ILI_script/Autoformer.sh new file mode 100644 index 0000000..8934462 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/Autoformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/Crossformer.sh b/scripts/long_term_forecast/ILI_script/Crossformer.sh new file mode 100644 index 0000000..eaca4ed --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/Crossformer.sh @@ -0,0 +1,103 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --dropout 0.6 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + -dropout 0.6 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + -dropout 0.6 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + -dropout 0.6 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/FiLM.sh b/scripts/long_term_forecast/ILI_script/FiLM.sh new file mode 100644 index 0000000..f8fe4ed --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/FiLM.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=5 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 60 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 60 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 60 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 60 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/Koopa.sh b/scripts/long_term_forecast/ILI_script/Koopa.sh new file mode 100644 index 0000000..e3df787 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/Koopa.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_48_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 48 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_72_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 72 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_96_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_120_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 120 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/MICN.sh b/scripts/long_term_forecast/ILI_script/MICN.sh new file mode 100644 index 0000000..6b79e46 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/MICN.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 36 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 36 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 36 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 36 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/ILI_script/Nonstationary_Transformer.sh b/scripts/long_term_forecast/ILI_script/Nonstationary_Transformer.sh new file mode 100644 index 0000000..a83b902 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/Nonstationary_Transformer.sh @@ -0,0 +1,95 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 32 32 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 32 32 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 16 16 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 8 8 \ + --p_hidden_layers 2 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/PatchTST.sh b/scripts/long_term_forecast/ILI_script/PatchTST.sh new file mode 100644 index 0000000..ff8fba2 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/PatchTST.sh @@ -0,0 +1,96 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --d_model 1024\ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --d_model 2048\ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 4 \ + --d_model 2048\ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --n_heads 16 \ + --d_model 2048\ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/TimesNet.sh b/scripts/long_term_forecast/ILI_script/TimesNet.sh new file mode 100644 index 0000000..cb378a1 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/TimesNet.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --d_model 768 \ + --d_ff 768 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/ILI_script/Transformer.sh b/scripts/long_term_forecast/ILI_script/Transformer.sh new file mode 100644 index 0000000..eee0209 --- /dev/null +++ b/scripts/long_term_forecast/ILI_script/Transformer.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_24 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 24 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_36 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 36 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/illness/ \ + --data_path national_illness.csv \ + --model_id ili_36_60 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 36 \ + --label_len 18 \ + --pred_len 60 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 7 \ + --dec_in 7 \ + --c_out 7 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Mamba_all.sh b/scripts/long_term_forecast/Mamba_all.sh new file mode 100644 index 0000000..9e34eab --- /dev/null +++ b/scripts/long_term_forecast/Mamba_all.sh @@ -0,0 +1,4 @@ +./scripts/long_term_forecast/ECL_script/Mamba.sh +./scripts/long_term_forecast/Traffic_script/Mamba.sh +./scripts/long_term_forecast/Exchange_script/Mamba.sh +./scripts/long_term_forecast/Weather_script/Mamba.sh diff --git a/scripts/long_term_forecast/Traffic_script/Autoformer.sh b/scripts/long_term_forecast/Traffic_script/Autoformer.sh new file mode 100644 index 0000000..9123d7e --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Autoformer.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/Crossformer.sh b/scripts/long_term_forecast/Traffic_script/Crossformer.sh new file mode 100644 index 0000000..d6bb5d5 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Crossformer.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --top_k 5 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --top_k 5 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --top_k 5 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --top_k 5 \ + --des 'Exp' \ + --n_heads 2 \ + --batch_size 4 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/FiLM.sh b/scripts/long_term_forecast/Traffic_script/FiLM.sh new file mode 100644 index 0000000..6f4a721 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/FiLM.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=FiLM + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --batch_size 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --batch_size 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --batch_size 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --batch_size 2 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/Koopa.sh b/scripts/long_term_forecast/Traffic_script/Koopa.sh new file mode 100644 index 0000000..2322080 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Koopa.sh @@ -0,0 +1,87 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=Koopa + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_48 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --pred_len 48 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_192_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 192 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_288_144 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 288 \ + --pred_len 144 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_384_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 384 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/MICN.sh b/scripts/long_term_forecast/Traffic_script/MICN.sh new file mode 100644 index 0000000..7f83d28 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/MICN.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/Mamba.sh b/scripts/long_term_forecast/Traffic_script/Mamba.sh new file mode 100644 index 0000000..f531e19 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Mamba.sh @@ -0,0 +1,29 @@ +model_name=Mamba + +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_$pred_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 862 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 862 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/MultiPatchFormer.sh b/scripts/long_term_forecast/Traffic_script/MultiPatchFormer.sh new file mode 100644 index 0000000..7e79479 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/MultiPatchFormer.sh @@ -0,0 +1,96 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MultiPatchFormer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/Nonstationary_Transformer.sh b/scripts/long_term_forecast/Traffic_script/Nonstationary_Transformer.sh new file mode 100644 index 0000000..c7d63d1 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Nonstationary_Transformer.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ + --p_hidden_dims 128 128 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ + --p_hidden_dims 128 128 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ + --p_hidden_dims 16 16 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ + --p_hidden_dims 128 128 \ + --p_hidden_layers 2 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/PatchTST.sh b/scripts/long_term_forecast/Traffic_script/PatchTST.sh new file mode 100644 index 0000000..69d9b6c --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/PatchTST.sh @@ -0,0 +1,103 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --batch_size 4 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/Pyraformer.sh b/scripts/long_term_forecast/Traffic_script/Pyraformer.sh new file mode 100644 index 0000000..a4e8f3b --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Pyraformer.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/SegRNN.sh b/scripts/long_term_forecast/Traffic_script/SegRNN.sh new file mode 100644 index 0000000..9fceb70 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/SegRNN.sh @@ -0,0 +1,27 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_$seq_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 24 \ + --enc_in 862 \ + --d_model 512 \ + --dropout 0 \ + --learning_rate 0.001 \ + --des 'Exp' \ + --itr 1 +done + diff --git a/scripts/long_term_forecast/Traffic_script/TSMixer.sh b/scripts/long_term_forecast/Traffic_script/TSMixer.sh new file mode 100755 index 0000000..4f8d94f --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/TSMixer.sh @@ -0,0 +1,101 @@ + +model_name=TSMixer +learning_rate=0.001 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ diff --git a/scripts/long_term_forecast/Traffic_script/TimeMixer.sh b/scripts/long_term_forecast/Traffic_script/TimeMixer.sh new file mode 100755 index 0000000..6ee3434 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/TimeMixer.sh @@ -0,0 +1,125 @@ +#export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=3 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=32 +d_ff=64 +batch_size=8 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id Traffic_$seq_len'_'96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id Traffic_$seq_len'_'192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id Traffic_$seq_len'_'336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id Traffic_$seq_len'_'720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size $batch_size \ + --learning_rate $learning_rate \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/TimeXer.sh b/scripts/long_term_forecast/Traffic_script/TimeXer.sh new file mode 100644 index 0000000..6d975b3 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/TimeXer.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 3 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --des 'Exp' \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --des 'Exp' \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --des 'Exp' \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --des 'Exp' \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 diff --git a/scripts/long_term_forecast/Traffic_script/TimesNet.sh b/scripts/long_term_forecast/Traffic_script/TimesNet.sh new file mode 100644 index 0000000..0baca10 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/TimesNet.sh @@ -0,0 +1,99 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --d_model 512 \ + --d_ff 512 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Traffic_script/Transformer.sh b/scripts/long_term_forecast/Traffic_script/Transformer.sh new file mode 100644 index 0000000..88b7e5c --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/Transformer.sh @@ -0,0 +1,91 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 diff --git a/scripts/long_term_forecast/Traffic_script/WPMixer.sh b/scripts/long_term_forecast/Traffic_script/WPMixer.sh new file mode 100644 index 0000000..16443c3 --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/WPMixer.sh @@ -0,0 +1,49 @@ + +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=traffic +seq_lens=(1200 1200 1200 1200) +pred_lens=(96 192 336 720) +learning_rates=(0.0010385 0.000567053 0.001026715 0.001496217) +batches=(16 16 16 16) +epochs=(60 60 50 60) +dropouts=(0.05 0.05 0.0 0.05) +patch_lens=(16 16 16 16) +lradjs=(type3 type3 type3 type3) +d_models=(16 32 32 32) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(db3 db3 bior3.1 db3) +levels=(1 1 1 1) +tfactors=(3 3 7 7) +dfactors=(5 5 7 3) +strides=(8 8 8 8) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/traffic/ \ + --data_path traffic.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/Traffic_script/iTransformer.sh b/scripts/long_term_forecast/Traffic_script/iTransformer.sh new file mode 100644 index 0000000..583f28d --- /dev/null +++ b/scripts/long_term_forecast/Traffic_script/iTransformer.sh @@ -0,0 +1,103 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/traffic/ \ + --data_path traffic.csv \ + --model_id traffic_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 4 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 862 \ + --dec_in 862 \ + --c_out 862 \ + --des 'Exp' \ + --d_model 512 \ + --d_ff 512 \ + --batch_size 16 \ + --learning_rate 0.001 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/Autoformer.sh b/scripts/long_term_forecast/Weather_script/Autoformer.sh new file mode 100644 index 0000000..e5dbb52 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/Autoformer.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Autoformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/Crossformer.sh b/scripts/long_term_forecast/Weather_script/Crossformer.sh new file mode 100644 index 0000000..d1698f0 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/Crossformer.sh @@ -0,0 +1,102 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Crossformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/FiLM.sh b/scripts/long_term_forecast/Weather_script/FiLM.sh new file mode 100644 index 0000000..7b15125 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/FiLM.sh @@ -0,0 +1,85 @@ +export CUDA_VISIBLE_DEVICES=6 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 720 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 192 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model FiLM \ + --data custom \ + --features M \ + --seq_len 336 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 diff --git a/scripts/long_term_forecast/Weather_script/MICN.sh b/scripts/long_term_forecast/Weather_script/MICN.sh new file mode 100644 index 0000000..bbe064f --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/MICN.sh @@ -0,0 +1,102 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=MICN + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 96 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/Mamba.sh b/scripts/long_term_forecast/Weather_script/Mamba.sh new file mode 100644 index 0000000..a9598bb --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/Mamba.sh @@ -0,0 +1,29 @@ +model_name=Mamba + +for pred_len in 96 192 336 720 +do + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_$pred_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $pred_len \ + --label_len 48 \ + --pred_len $pred_len \ + --e_layers 2 \ + --d_layers 1 \ + --enc_in 21 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 21 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + +done \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/MultiPatchFormer.sh b/scripts/long_term_forecast/Weather_script/MultiPatchFormer.sh new file mode 100644 index 0000000..6bec2d5 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/MultiPatchFormer.sh @@ -0,0 +1,98 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=MultiPatchFormer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 1 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 256 \ + --d_ff 512 \ + --des 'Exp' \ + --n_heads 8 \ + --batch_size 32 \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/Nonstationary_Transformer.sh b/scripts/long_term_forecast/Weather_script/Nonstationary_Transformer.sh new file mode 100644 index 0000000..27136d4 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/Nonstationary_Transformer.sh @@ -0,0 +1,96 @@ +export CUDA_VISIBLE_DEVICES=6 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 128 128 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 128 128 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --p_hidden_dims 128 128 \ + --p_hidden_layers 2 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/PatchTST.sh b/scripts/long_term_forecast/Weather_script/PatchTST.sh new file mode 100644 index 0000000..ca19683 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/PatchTST.sh @@ -0,0 +1,97 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=PatchTST + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --n_heads 4 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --n_heads 16 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --n_heads 4 \ + --batch_size 128 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --n_heads 4 \ + --batch_size 128 \ + --train_epochs 3 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/Pyraformer.sh b/scripts/long_term_forecast/Weather_script/Pyraformer.sh new file mode 100644 index 0000000..7af7d54 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/Pyraformer.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Pyraformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 2 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/SegRNN.sh b/scripts/long_term_forecast/Weather_script/SegRNN.sh new file mode 100644 index 0000000..5ec4613 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/SegRNN.sh @@ -0,0 +1,27 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=SegRNN + +seq_len=96 +for pred_len in 96 192 336 720 +do +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_$seq_len'_'$pred_len \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --pred_len $pred_len \ + --seg_len 48 \ + --enc_in 21 \ + --d_model 512 \ + --dropout 0.5 \ + --learning_rate 0.0001 \ + --des 'Exp' \ + --itr 1 +done + diff --git a/scripts/long_term_forecast/Weather_script/TSMixer.sh b/scripts/long_term_forecast/Weather_script/TSMixer.sh new file mode 100755 index 0000000..bea5bda --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/TSMixer.sh @@ -0,0 +1,99 @@ + +model_name=TSMixer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ diff --git a/scripts/long_term_forecast/Weather_script/TimeMixer.sh b/scripts/long_term_forecast/Weather_script/TimeMixer.sh new file mode 100755 index 0000000..2d50112 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/TimeMixer.sh @@ -0,0 +1,133 @@ +#export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +seq_len=96 +e_layers=3 +down_sampling_layers=3 +down_sampling_window=2 +learning_rate=0.01 +d_model=16 +d_ff=32 +batch_size=16 +train_epochs=20 +patience=10 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 96 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 192 \ + --e_layers $e_layers \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 336 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len $seq_len \ + --label_len 0 \ + --pred_len 720 \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --d_model $d_model \ + --d_ff $d_ff \ + --batch_size 128 \ + --learning_rate $learning_rate \ + --train_epochs $train_epochs \ + --patience $patience \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/TimeXer.sh b/scripts/long_term_forecast/Weather_script/TimeXer.sh new file mode 100644 index 0000000..e93bf90 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/TimeXer.sh @@ -0,0 +1,93 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeXer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 256 \ + --d_ff 512 \ + --batch_size 4 \ + --itr 1 \ + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 128 \ + --d_ff 1024 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 256 \ + --batch_size 4 \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 128 \ + --batch_size 4 \ + --itr 1 diff --git a/scripts/long_term_forecast/Weather_script/TimesNet.sh b/scripts/long_term_forecast/Weather_script/TimesNet.sh new file mode 100644 index 0000000..fe06193 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/TimesNet.sh @@ -0,0 +1,102 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=TimesNet + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/Transformer.sh b/scripts/long_term_forecast/Weather_script/Transformer.sh new file mode 100644 index 0000000..7c0466b --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/Transformer.sh @@ -0,0 +1,88 @@ +export CUDA_VISIBLE_DEVICES=7 + +model_name=Transformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ + --train_epochs 3 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --itr 1 \ No newline at end of file diff --git a/scripts/long_term_forecast/Weather_script/WPMixer.sh b/scripts/long_term_forecast/Weather_script/WPMixer.sh new file mode 100644 index 0000000..828abb2 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/WPMixer.sh @@ -0,0 +1,49 @@ + +export CUDA_VISIBLE_DEVICES=0 + +# Model name +model_name=WPMixer + +# Datasets and prediction lengths +dataset=weather +seq_lens=(512 512 512 512) +pred_lens=(96 192 336 720) +learning_rates=(0.000913333 0.001379042 0.000607991 0.001470479) +batches=(32 64 32 128) +epochs=(60 60 60 60) +dropouts=(0.4 0.4 0.4 0.4) +patch_lens=(16 16 16 16) +lradjs=(type3 type3 type3 type3) +d_models=(256 128 128 128) +patiences=(12 12 12 12) + +# Model params below need to be set in WPMixer.py Line 15, instead of this script +wavelets=(db3 db3 db3 db2) +levels=(2 1 2 1) +tfactors=(3 3 7 7) +dfactors=(7 7 7 5) +strides=(8 8 8 8) + +# Loop over datasets and prediction lengths +for i in "${!pred_lens[@]}"; do + python -u run.py \ + --is_training 1 \ + --root_path ./data/weather/ \ + --data_path weather.csv \ + --model_id wpmixer \ + --model $model_name \ + --task_name long_term_forecast \ + --data $dataset \ + --seq_len ${seq_lens[$i]} \ + --pred_len ${pred_lens[$i]} \ + --label_len 0 \ + --d_model ${d_models[$i]} \ + --patch_len ${patch_lens[$i]} \ + --batch_size ${batches[$i]} \ + --learning_rate ${learning_rates[$i]} \ + --lradj ${lradjs[$i]} \ + --dropout ${dropouts[$i]} \ + --patience ${patiences[$i]} \ + --train_epochs ${epochs[$i]} \ + --use_amp +done diff --git a/scripts/long_term_forecast/Weather_script/iTransformer.sh b/scripts/long_term_forecast/Weather_script/iTransformer.sh new file mode 100644 index 0000000..4b09121 --- /dev/null +++ b/scripts/long_term_forecast/Weather_script/iTransformer.sh @@ -0,0 +1,98 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_96 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 96 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 512\ + --d_ff 512\ + --itr 1 \ + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_192 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 192 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 512\ + --d_ff 512\ + --itr 1 \ + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_336 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 336 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 512\ + --d_ff 512\ + --itr 1 \ + + +python -u run.py \ + --task_name long_term_forecast \ + --is_training 1 \ + --root_path ./dataset/weather/ \ + --data_path weather.csv \ + --model_id weather_96_720 \ + --model $model_name \ + --data custom \ + --features M \ + --seq_len 96 \ + --label_len 48 \ + --pred_len 720 \ + --e_layers 3 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 21 \ + --dec_in 21 \ + --c_out 21 \ + --des 'Exp' \ + --d_model 512\ + --d_ff 512\ + --itr 1 \ No newline at end of file diff --git a/scripts/short_term_forecast/Autoformer_M4.sh b/scripts/short_term_forecast/Autoformer_M4.sh new file mode 100644 index 0000000..f6f88f8 --- /dev/null +++ b/scripts/short_term_forecast/Autoformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Autoformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/Crossformer_M4.sh b/scripts/short_term_forecast/Crossformer_M4.sh new file mode 100644 index 0000000..23786da --- /dev/null +++ b/scripts/short_term_forecast/Crossformer_M4.sh @@ -0,0 +1,147 @@ +export CUDA_VISIBLE_DEVICES=5 + +model_name=Crossformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 16 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ No newline at end of file diff --git a/scripts/short_term_forecast/DLinear_M4.sh b/scripts/short_term_forecast/DLinear_M4.sh new file mode 100644 index 0000000..4b10f02 --- /dev/null +++ b/scripts/short_term_forecast/DLinear_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=DLinear + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/ETSformer_M4.sh b/scripts/short_term_forecast/ETSformer_M4.sh new file mode 100644 index 0000000..177bf62 --- /dev/null +++ b/scripts/short_term_forecast/ETSformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=ETSformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ../dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 2 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/FEDformer_M4.sh b/scripts/short_term_forecast/FEDformer_M4.sh new file mode 100644 index 0000000..a49411e --- /dev/null +++ b/scripts/short_term_forecast/FEDformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=FEDformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/FiLM_M4.sh b/scripts/short_term_forecast/FiLM_M4.sh new file mode 100644 index 0000000..b4032b5 --- /dev/null +++ b/scripts/short_term_forecast/FiLM_M4.sh @@ -0,0 +1,147 @@ +export CUDA_VISIBLE_DEVICES=3 + +model_name=FiLM + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 16 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ No newline at end of file diff --git a/scripts/short_term_forecast/Informer_M4.sh b/scripts/short_term_forecast/Informer_M4.sh new file mode 100644 index 0000000..b83637a --- /dev/null +++ b/scripts/short_term_forecast/Informer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Informer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/LightTS_M4.sh b/scripts/short_term_forecast/LightTS_M4.sh new file mode 100644 index 0000000..5a35976 --- /dev/null +++ b/scripts/short_term_forecast/LightTS_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=LightTS + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/MICN_M4.sh b/scripts/short_term_forecast/MICN_M4.sh new file mode 100644 index 0000000..1d93496 --- /dev/null +++ b/scripts/short_term_forecast/MICN_M4.sh @@ -0,0 +1,147 @@ +export CUDA_VISIBLE_DEVICES=4 + +model_name=MICN + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 16 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ No newline at end of file diff --git a/scripts/short_term_forecast/Mamba_M4.sh b/scripts/short_term_forecast/Mamba_M4.sh new file mode 100644 index 0000000..417a6c3 --- /dev/null +++ b/scripts/short_term_forecast/Mamba_M4.sh @@ -0,0 +1,135 @@ +# export CUDA_VISIBLE_DEVICES=1 + +model_name=Mamba + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --enc_in 1 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --enc_in 1 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --enc_in 1 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --enc_in 1 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --enc_in 1 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --enc_in 1 \ + --expand 2 \ + --d_ff 16 \ + --d_conv 4 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 128 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ No newline at end of file diff --git a/scripts/short_term_forecast/Nonstationary_Transformer_M4.sh b/scripts/short_term_forecast/Nonstationary_Transformer_M4.sh new file mode 100644 index 0000000..29ea72d --- /dev/null +++ b/scripts/short_term_forecast/Nonstationary_Transformer_M4.sh @@ -0,0 +1,147 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Nonstationary_Transformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ + --p_hidden_dims 256 256 \ + --p_hidden_layers 2 \ No newline at end of file diff --git a/scripts/short_term_forecast/Pyraformer_M4.sh b/scripts/short_term_forecast/Pyraformer_M4.sh new file mode 100644 index 0000000..66f67b8 --- /dev/null +++ b/scripts/short_term_forecast/Pyraformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Pyraformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/Reformer_M4.sh b/scripts/short_term_forecast/Reformer_M4.sh new file mode 100644 index 0000000..d432fed --- /dev/null +++ b/scripts/short_term_forecast/Reformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Reformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/TSMixer_M4.sh b/scripts/short_term_forecast/TSMixer_M4.sh new file mode 100755 index 0000000..34aad15 --- /dev/null +++ b/scripts/short_term_forecast/TSMixer_M4.sh @@ -0,0 +1,135 @@ +#export CUDA_VISIBLE_DEVICES=1 + +model_name=MTSMixer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/TimeMixer_M4.sh b/scripts/short_term_forecast/TimeMixer_M4.sh new file mode 100755 index 0000000..15802a1 --- /dev/null +++ b/scripts/short_term_forecast/TimeMixer_M4.sh @@ -0,0 +1,180 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimeMixer + +e_layers=4 +down_sampling_layers=1 +down_sampling_window=2 +learning_rate=0.01 +d_model=32 +d_ff=32 +batch_size=16 + + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 128 \ + --d_model $d_model \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + --train_epochs 50 \ + --patience 20 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 128 \ + --d_model $d_model \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + --train_epochs 50 \ + --patience 20 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 128 \ + --d_model $d_model \ + --d_ff 64 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + --train_epochs 50 \ + --patience 20 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 128 \ + --d_model $d_model \ + --d_ff 16 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + --train_epochs 50 \ + --patience 20 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 128 \ + --d_model $d_model \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + --train_epochs 50 \ + --patience 20 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers $e_layers \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 128 \ + --d_model $d_model \ + --d_ff 32 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate $learning_rate \ + --train_epochs 50 \ + --patience 20 \ + --down_sampling_layers $down_sampling_layers \ + --down_sampling_method avg \ + --down_sampling_window $down_sampling_window \ + --loss 'SMAPE' \ No newline at end of file diff --git a/scripts/short_term_forecast/TimesNet_M4.sh b/scripts/short_term_forecast/TimesNet_M4.sh new file mode 100644 index 0000000..0040273 --- /dev/null +++ b/scripts/short_term_forecast/TimesNet_M4.sh @@ -0,0 +1,147 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=TimesNet + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 64 \ + --d_ff 64 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 16 \ + --d_ff 16 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 32 \ + --d_ff 32 \ + --top_k 5 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' diff --git a/scripts/short_term_forecast/Transformer_M4.sh b/scripts/short_term_forecast/Transformer_M4.sh new file mode 100644 index 0000000..ba0af09 --- /dev/null +++ b/scripts/short_term_forecast/Transformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=1 + +model_name=Transformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ No newline at end of file diff --git a/scripts/short_term_forecast/iTransformer_M4.sh b/scripts/short_term_forecast/iTransformer_M4.sh new file mode 100644 index 0000000..5e4702c --- /dev/null +++ b/scripts/short_term_forecast/iTransformer_M4.sh @@ -0,0 +1,135 @@ +export CUDA_VISIBLE_DEVICES=0 + +model_name=iTransformer + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Monthly' \ + --model_id m4_Monthly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Yearly' \ + --model_id m4_Yearly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Quarterly' \ + --model_id m4_Quarterly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Weekly' \ + --model_id m4_Weekly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Daily' \ + --model_id m4_Daily \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' + +python -u run.py \ + --task_name short_term_forecast \ + --is_training 1 \ + --root_path ./dataset/m4 \ + --seasonal_patterns 'Hourly' \ + --model_id m4_Hourly \ + --model $model_name \ + --data m4 \ + --features M \ + --e_layers 2 \ + --d_layers 1 \ + --factor 3 \ + --enc_in 1 \ + --dec_in 1 \ + --c_out 1 \ + --batch_size 16 \ + --d_model 512 \ + --des 'Exp' \ + --itr 1 \ + --learning_rate 0.001 \ + --loss 'SMAPE' \ No newline at end of file diff --git a/tutorial/TimesNet_tutorial.ipynb b/tutorial/TimesNet_tutorial.ipynb new file mode 100644 index 0000000..d589d2a --- /dev/null +++ b/tutorial/TimesNet_tutorial.ipynb @@ -0,0 +1,1552 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# TimesNet Tutorial\n", + "**Set-up instructions:** this notebook give a tutorial on the learning task supported by `TimesNet`.\n", + "\n", + "`TimesNet` can support basically 5 tasks, which are respectively long-term forecast, short-term forecast, imputation, anomaly detection, classification." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Install Python 3.8. For convenience, execute the following command." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "pip install -r requirements.txt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Package Import" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import torch \n", + "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", + " #convolution block used for convoluting the 2D time data, changeable" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. TimesBlock Construction\n", + " The core idea of `TimesNet` lies in the construction of `TimesBlock`, which generally gets the base frequencies by implementing FFT on the data, and then reshapes the times series to 2D variation respectively from the main base frequencies, followed by a 2D convolution whose outputs are reshaped back and added with weight to form the final output.\n", + "\n", + " In the following section, we will have a detailed view on `TimesBlock`.\n", + "\n", + " TimesBlock has 2 members. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class TimesBlock(nn.Module):\n", + " def __init__(self, configs):\n", + " ...\n", + " \n", + " def forward(self, x):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, let's focus on ```__init__(self, configs):```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def __init__(self, configs): ##configs is the configuration defined for TimesBlock\n", + " super(TimesBlock, self).__init__() \n", + " self.seq_len = configs.seq_len ##sequence length \n", + " self.pred_len = configs.pred_len ##prediction length\n", + " self.k = configs.top_k ##k denotes how many top frequencies are \n", + " #taken into consideration\n", + " # parameter-efficient design\n", + " self.conv = nn.Sequential(\n", + " Inception_Block_V1(configs.d_model, configs.d_ff,\n", + " num_kernels=configs.num_kernels),\n", + " nn.GELU(),\n", + " Inception_Block_V1(configs.d_ff, configs.d_model,\n", + " num_kernels=configs.num_kernels)\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, have a look at ```forward(self, x)```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def forward(self, x):\n", + " B, T, N = x.size()\n", + " #B: batch size T: length of time series N:number of features\n", + " period_list, period_weight = FFT_for_Period(x, self.k)\n", + " #FFT_for_Period() will be shown later. Here, period_list([top_k]) denotes \n", + " #the top_k-significant period and period_weight([B, top_k]) denotes its weight(amplitude)\n", + "\n", + " res = []\n", + " for i in range(self.k):\n", + " period = period_list[i]\n", + "\n", + " # padding : to form a 2D map, we need total length of the sequence, plus the part \n", + " # to be predicted, to be divisible by the period, so padding is needed\n", + " if (self.seq_len + self.pred_len) % period != 0:\n", + " length = (\n", + " ((self.seq_len + self.pred_len) // period) + 1) * period\n", + " padding = torch.zeros([x.shape[0], (length - (self.seq_len + self.pred_len)), x.shape[2]]).to(x.device)\n", + " out = torch.cat([x, padding], dim=1)\n", + " else:\n", + " length = (self.seq_len + self.pred_len)\n", + " out = x\n", + "\n", + " # reshape: we need each channel of a single piece of data to be a 2D variable,\n", + " # Also, in order to implement the 2D conv later on, we need to adjust the 2 dimensions \n", + " # to be convolutioned to the last 2 dimensions, by calling the permute() func.\n", + " # Whereafter, to make the tensor contiguous in memory, call contiguous()\n", + " out = out.reshape(B, length // period, period,\n", + " N).permute(0, 3, 1, 2).contiguous()\n", + " \n", + " #2D convolution to grap the intra- and inter- period information\n", + " out = self.conv(out)\n", + "\n", + " # reshape back, similar to reshape\n", + " out = out.permute(0, 2, 3, 1).reshape(B, -1, N)\n", + " \n", + " #truncating down the padded part of the output and put it to result\n", + " res.append(out[:, :(self.seq_len + self.pred_len), :])\n", + " res = torch.stack(res, dim=-1) #res: 4D [B, length , N, top_k]\n", + "\n", + " # adaptive aggregation\n", + " #First, use softmax to get the normalized weight from amplitudes --> 2D [B,top_k]\n", + " period_weight = F.softmax(period_weight, dim=1) \n", + "\n", + " #after two unsqueeze(1),shape -> [B,1,1,top_k],so repeat the weight to fit the shape of res\n", + " period_weight = period_weight.unsqueeze(\n", + " 1).unsqueeze(1).repeat(1, T, N, 1)\n", + " \n", + " #add by weight the top_k periods' result, getting the result of this TimesBlock\n", + " res = torch.sum(res * period_weight, -1)\n", + "\n", + " # residual connection\n", + " res = res + x\n", + " return res" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The ```FFT_for_Period``` above is given by:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def FFT_for_Period(x, k=2):\n", + " # xf shape [B, T, C], denoting the amplitude of frequency(T) given the datapiece at B,N\n", + " xf = torch.fft.rfft(x, dim=1) \n", + "\n", + " # find period by amplitudes: here we assume that the periodic features are basically constant\n", + " # in different batch and channel, so we mean out these two dimensions, getting a list frequency_list with shape[T] \n", + " # each element at pos t of frequency_list denotes the overall amplitude at frequency (t)\n", + " frequency_list = abs(xf).mean(0).mean(-1) \n", + " frequency_list[0] = 0\n", + "\n", + " #by torch.topk(),we can get the biggest k elements of frequency_list, and its positions(i.e. the k-main frequencies in top_list)\n", + " _, top_list = torch.topk(frequency_list, k)\n", + "\n", + " #Returns a new Tensor 'top_list', detached from the current graph.\n", + " #The result will never require gradient.Convert to a numpy instance\n", + " top_list = top_list.detach().cpu().numpy()\n", + " \n", + " #period:a list of shape [top_k], recording the periods of mean frequencies respectively\n", + " period = x.shape[1] // top_list\n", + "\n", + " #Here,the 2nd item returned has a shape of [B, top_k],representing the biggest top_k amplitudes \n", + " # for each piece of data, with N features being averaged.\n", + " return period, abs(xf).mean(-1)[:, top_list] " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To make it clearer, please see the figures below.\n", + "\n", + "![FFT demonstrator](./fft.png)\n", + "\n", + "![2D Conv demonstrator](./conv.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For more details, please read the our paper \n", + "(link: https://openreview.net/pdf?id=ju_Uqw384Oq)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4. TimesNet\n", + "\n", + "So far we've got `TimesBlock`, which is excel at retrieving intra- and inter- period temporal information. We become capable of building a `TimesNet`. `TimesNet` is proficient in multitasks including short- and long-term forecasting, imputation, classification, and anomaly detection.\n", + "\n", + "In this section, we'll have a detailed overview on how `TimesNet` gains its power in these tasks." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Model(nn.Module):\n", + " def __init__(self, configs):\n", + " ...\n", + " \n", + " def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):\n", + " ...\n", + "\n", + " def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask):\n", + " ...\n", + "\n", + " def anomaly_detection(self, x_enc):\n", + " ...\n", + " \n", + " def classification(self, x_enc, x_mark_enc):\n", + " ...\n", + "\n", + " def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First of all, let's focus on ```__init__(self, configs):```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def __init__(self, configs):\n", + " super(Model, self).__init__()\n", + " #params init\n", + " self.configs = configs\n", + " self.task_name = configs.task_name\n", + " self.seq_len = configs.seq_len\n", + " self.label_len = configs.label_len\n", + " self.pred_len = configs.pred_len\n", + "\n", + " #stack TimesBlock for e_layers times to form the main part of TimesNet, named model\n", + " self.model = nn.ModuleList([TimesBlock(configs)\n", + " for _ in range(configs.e_layers)])\n", + " \n", + " #embedding & normalization\n", + " # enc_in is the encoder input size, the number of features for a piece of data\n", + " # d_model is the dimension of embedding\n", + " self.enc_embedding = DataEmbedding(configs.enc_in, configs.d_model, configs.embed, configs.freq,\n", + " configs.dropout)\n", + " self.layer = configs.e_layers # num of encoder layers\n", + " self.layer_norm = nn.LayerNorm(configs.d_model)\n", + "\n", + " #define the some layers for different tasks\n", + " if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast':\n", + " self.predict_linear = nn.Linear(\n", + " self.seq_len, self.pred_len + self.seq_len)\n", + " self.projection = nn.Linear(\n", + " configs.d_model, configs.c_out, bias=True)\n", + " if self.task_name == 'imputation' or self.task_name == 'anomaly_detection':\n", + " self.projection = nn.Linear(\n", + " configs.d_model, configs.c_out, bias=True)\n", + " if self.task_name == 'classification':\n", + " self.act = F.gelu\n", + " self.dropout = nn.Dropout(configs.dropout)\n", + " self.projection = nn.Linear(\n", + " configs.d_model * configs.seq_len, configs.num_class)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4.1 Forecast\n", + "\n", + "The basic idea of forecasting is to lengthen the known sequence to (seq_len+pred_len), which is the total length after forecasting. Then by several TimesBlock layers together with layer normalization, some underlying intra- and inter- period information is represented. With these information, we can project it to the output space. Whereafter by denorm ( if Non-stationary Transformer) we get the final output." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):\n", + " # Normalization from Non-stationary Transformer at temporal dimension\n", + " means = x_enc.mean(1, keepdim=True).detach() #[B,T]\n", + " x_enc = x_enc - means\n", + " stdev = torch.sqrt(\n", + " torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5)\n", + " x_enc /= stdev\n", + "\n", + " # embedding: projecting a number to a C-channel vector\n", + " enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C] C is d_model\n", + " enc_out = self.predict_linear(enc_out.permute(0, 2, 1)).permute(\n", + " 0, 2, 1) # align temporal dimension [B,pred_len+seq_len,C]\n", + " \n", + " # TimesNet: pass through TimesBlock for self.layer times each with layer normalization\n", + " for i in range(self.layer):\n", + " enc_out = self.layer_norm(self.model[i](enc_out))\n", + "\n", + " # project back #[B,T,d_model]-->[B,T,c_out]\n", + " dec_out = self.projection(enc_out) \n", + "\n", + " # De-Normalization from Non-stationary Transformer\n", + " dec_out = dec_out * \\\n", + " (stdev[:, 0, :].unsqueeze(1).repeat(\n", + " 1, self.pred_len + self.seq_len, 1)) #lengthen the stdev to fit the dec_out\n", + " dec_out = dec_out + \\\n", + " (means[:, 0, :].unsqueeze(1).repeat(\n", + " 1, self.pred_len + self.seq_len, 1)) #lengthen the mean to fit the dec_out\n", + " return dec_out" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4.2 Imputation\n", + "\n", + "Imputation is a task aiming at completing some missing value in the time series, so in some degree it's similar to forecast. We can still use the similar step to cope with it." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def imputation(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask):\n", + " # Normalization from Non-stationary Transformer\n", + " means = torch.sum(x_enc, dim=1) / torch.sum(mask == 1, dim=1)\n", + " means = means.unsqueeze(1).detach()\n", + " x_enc = x_enc - means\n", + " x_enc = x_enc.masked_fill(mask == 0, 0)\n", + " stdev = torch.sqrt(torch.sum(x_enc * x_enc, dim=1) /\n", + " torch.sum(mask == 1, dim=1) + 1e-5)\n", + " stdev = stdev.unsqueeze(1).detach()\n", + " x_enc /= stdev\n", + "\n", + " # embedding\n", + " enc_out = self.enc_embedding(x_enc, x_mark_enc) # [B,T,C]\n", + " # TimesNet\n", + " for i in range(self.layer):\n", + " enc_out = self.layer_norm(self.model[i](enc_out))\n", + " # project back\n", + " dec_out = self.projection(enc_out)\n", + "\n", + " # De-Normalization from Non-stationary Transformer\n", + " dec_out = dec_out * \\\n", + " (stdev[:, 0, :].unsqueeze(1).repeat(\n", + " 1, self.pred_len + self.seq_len, 1))\n", + " dec_out = dec_out + \\\n", + " (means[:, 0, :].unsqueeze(1).repeat(\n", + " 1, self.pred_len + self.seq_len, 1))\n", + " return dec_out" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4.3 Anomaly Detection\n", + "\n", + "Similar to Imputation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def anomaly_detection(self, x_enc):\n", + " # Normalization from Non-stationary Transformer\n", + " means = x_enc.mean(1, keepdim=True).detach()\n", + " x_enc = x_enc - means\n", + " stdev = torch.sqrt(\n", + " torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5)\n", + " x_enc /= stdev\n", + " # embedding\n", + " enc_out = self.enc_embedding(x_enc, None) # [B,T,C]\n", + " # TimesNet\n", + " for i in range(self.layer):\n", + " enc_out = self.layer_norm(self.model[i](enc_out))\n", + " # project back\n", + " dec_out = self.projection(enc_out)\n", + " # De-Normalization from Non-stationary Transformer\n", + " dec_out = dec_out * \\\n", + " (stdev[:, 0, :].unsqueeze(1).repeat(\n", + " 1, self.pred_len + self.seq_len, 1))\n", + " dec_out = dec_out + \\\n", + " (means[:, 0, :].unsqueeze(1).repeat(\n", + " 1, self.pred_len + self.seq_len, 1))\n", + " return dec_out" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4.4 Classification" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def classification(self, x_enc, x_mark_enc):\n", + " # embedding\n", + " enc_out = self.enc_embedding(x_enc, None) # [B,T,C]\n", + " # TimesNet\n", + " for i in range(self.layer):\n", + " enc_out = self.layer_norm(self.model[i](enc_out))\n", + "\n", + " # Output\n", + " # the output transformer encoder/decoder embeddings don't include non-linearity\n", + " output = self.act(enc_out)\n", + " output = self.dropout(output)\n", + "\n", + " # zero-out padding embeddings:The primary role of x_mark_enc in the code is to \n", + " # zero out the embeddings for padding positions in the output tensor through \n", + " # element-wise multiplication, helping the model to focus on meaningful data \n", + " # while disregarding padding.\n", + " output = output * x_mark_enc.unsqueeze(-1)\n", + " \n", + " # (batch_size, seq_length * d_model)\n", + " output = output.reshape(output.shape[0], -1)\n", + " output = self.projection(output) # (batch_size, num_classes)\n", + " return output" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the end, with so many tasks above, we become able to complete `forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):\n", + " if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast':\n", + " dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec)\n", + " return dec_out[:, -self.pred_len:, :] # [B, L, D] return the predicted part of sequence\n", + " if self.task_name == 'imputation':\n", + " dec_out = self.imputation(\n", + " x_enc, x_mark_enc, x_dec, x_mark_dec, mask)\n", + " return dec_out # [B, L, D] return the whole sequence with missing value estimated\n", + " if self.task_name == 'anomaly_detection':\n", + " dec_out = self.anomaly_detection(x_enc)\n", + " return dec_out # [B, L, D] return the sequence that should be correct\n", + " if self.task_name == 'classification':\n", + " dec_out = self.classification(x_enc, x_mark_enc)\n", + " return dec_out # [B, N] return the classification result\n", + " return None" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5. Training and Settings\n", + "\n", + "By now we've successfully build up `TimesNet`. We are now facing the problem how to train and test this neural network. The action of training, validating as well as testing is implemented at __*exp*__ part, in which codes for different tasks are gathered. These experiments are not only for `TimesNet` training, but also feasible for any other time series representation model. But here, we simply use `TimesNet` to analyse.\n", + "\n", + "`TimesNet` is a state-of-art in multiple tasks, while here we would only introduce its training for long-term forecast task, since the backbone of the training process for other tasks is similar to this one. Again, test and validation code can be easily understood once you've aware how the training process works. So first of all, we are going to focus on the training of `TimesNet` on task long-term forecasting.\n", + "\n", + "We will discuss many aspects, including the training process, training loss etc." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 5.1 Training for Long-term Forecast Task\n", + "\n", + "The following codes represents the process of training model for long-term forecasting task. We'll have a detailed look at it. To make it brief, the training part can be briefly divided into several parts, including Data Preparation, Creating Save Path, Initialization, Optimizer and Loss Function Selection, Using Mixed Precision Training, Training Loop, Validation and Early Stopping, Learning Rate Adjustment, Loading the Best Model.\n", + "\n", + "For more details, please see the code below. 'train' process is defined in the experiment __class Exp_Long_Term_Forecast__." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def train(self, setting): #setting is the args for this model training\n", + " #get train dataloader\n", + " train_data, train_loader = self._get_data(flag='train')\n", + " vali_data, vali_loader = self._get_data(flag='val')\n", + " test_data, test_loader = self._get_data(flag='test')\n", + "\n", + " # set path of checkpoint for saving and loading model\n", + " path = os.path.join(self.args.checkpoints, setting)\n", + " if not os.path.exists(path):\n", + " os.makedirs(path)\n", + " time_now = time.time()\n", + "\n", + " train_steps = len(train_loader)\n", + "\n", + " # EarlyStopping is typically a custom class or function that monitors the performance \n", + " # of a model during training, usually by tracking a certain metric (commonly validation \n", + " # loss or accuracy).It's a common technique used in deep learning to prevent overfitting \n", + " # during the training\n", + " early_stopping = EarlyStopping(patience=self.args.patience, verbose=True)\n", + "\n", + " #Optimizer and Loss Function Selection\n", + " model_optim = self._select_optimizer()\n", + " criterion = self._select_criterion()\n", + "\n", + " # AMP training is a technique that uses lower-precision data types (e.g., float16) \n", + " # for certain computations to accelerate training and reduce memory usage.\n", + " if self.args.use_amp: \n", + " scaler = torch.cuda.amp.GradScaler()\n", + " for epoch in range(self.args.train_epochs):\n", + " iter_count = 0\n", + " train_loss = []\n", + " self.model.train()\n", + " epoch_time = time.time()\n", + "\n", + " #begin training in this epoch\n", + " for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(train_loader):\n", + " iter_count += 1\n", + " model_optim.zero_grad()\n", + " batch_x = batch_x.float().to(self.device) #input features\n", + " batch_y = batch_y.float().to(self.device) #target features\n", + "\n", + " # _mark holds information about time-related features. Specifically, it is a \n", + " # tensor that encodes temporal information and is associated with the \n", + " # input data batch_x.\n", + " batch_x_mark = batch_x_mark.float().to(self.device)\n", + " batch_y_mark = batch_y_mark.float().to(self.device)\n", + " # decoder input(didn't use in TimesNet case)\n", + " dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()\n", + " dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device)\n", + " # encoder - decoder\n", + " if self.args.use_amp: #in the case of TimesNet, use_amp should be False\n", + " with torch.cuda.amp.autocast():\n", + " # whether to output attention in ecoder,in TimesNet case is no\n", + " if self.args.output_attention: \n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)[0]\n", + " # model the input\n", + " else:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)\n", + "\n", + " # forecasting task, options:[M, S, MS]; M:multivariate predict multivariate, \n", + " # S:univariate predict univariate, MS:multivariate predict univariate'\n", + " #if multivariate predict univariate',then output should be the last column of the decoder\n", + " # output, so f_dim = -1 to only contain the last column, else is all columns\n", + " f_dim = -1 if self.args.features == 'MS' else 0 \n", + " outputs = outputs[:, -self.args.pred_len:, f_dim:]\n", + " batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)\n", + "\n", + " # calc loss\n", + " loss = criterion(outputs, batch_y)\n", + " train_loss.append(loss.item())\n", + " else: #similar to when use_amp is True\n", + " if self.args.output_attention:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)[0]\n", + " else:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)\n", + " f_dim = -1 if self.args.features == 'MS' else 0\n", + " outputs = outputs[:, -self.args.pred_len:, f_dim:]\n", + " batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)\n", + " loss = criterion(outputs, batch_y)\n", + " train_loss.append(loss.item())\n", + "\n", + " # When train rounds attain some 100-multiple, print speed, left time, loss. etc feedback\n", + " if (i + 1) % 100 == 0:\n", + " print(\"\\titers: {0}, epoch: {1} | loss: {2:.7f}\".format(i + 1, epoch + 1, loss.item()))\n", + " speed = (time.time() - time_now) / iter_count\n", + " left_time = speed * ((self.args.train_epochs - epoch) * train_steps - i)\n", + " print('\\tspeed: {:.4f}s/iter; left time: {:.4f}s'.format(speed, left_time))\n", + " iter_count = 0\n", + " time_now = time.time()\n", + "\n", + " #BP\n", + " if self.args.use_amp:\n", + " scaler.scale(loss).backward()\n", + " scaler.step(model_optim)\n", + " scaler.update()\n", + " else:\n", + " loss.backward()\n", + " model_optim.step()\n", + " \n", + " #This epoch comes to end, print information\n", + " print(\"Epoch: {} cost time: {}\".format(epoch + 1, time.time() - epoch_time))\n", + " train_loss = np.average(train_loss)\n", + "\n", + " #run test and validation on current model\n", + " vali_loss = self.vali(vali_data, vali_loader, criterion)\n", + " test_loss = self.vali(test_data, test_loader, criterion)\n", + "\n", + " #print train, test, vali loss information\n", + " print(\"Epoch: {0}, Steps: {1} | Train Loss: {2:.7f} Vali Loss: {3:.7f} Test Loss: {4:.7f}\".format(\n", + " epoch + 1, train_steps, train_loss, vali_loss, test_loss))\n", + " \n", + " #Decide whether to trigger Early Stopping. if early_stop is true, it means that \n", + " #this epoch's training is now at a flat slope, so stop further training for this epoch.\n", + " early_stopping(vali_loss, self.model, path)\n", + " if early_stopping.early_stop:\n", + " print(\"Early stopping\")\n", + " break\n", + "\n", + " #adjust learning keys\n", + " adjust_learning_rate(model_optim, epoch + 1, self.args)\n", + " best_model_path = path + '/' + 'checkpoint.pth'\n", + "\n", + " # loading the trained model's state dictionary from a saved checkpoint file \n", + " # located at best_model_path.\n", + " self.model.load_state_dict(torch.load(best_model_path))\n", + " return self.model" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you want to learn more, please see it at exp/exp_long_term_forecasting.py" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 5.2 Early Stopping Mechanism\n", + "\n", + "__EarlyStopping__ is typically a custom class or function that monitors the performance of a model during training, usually by tracking a certain metric (commonly validation loss or accuracy).It's a common technique used in deep learning to prevent overfitting during the training.\n", + "\n", + "Let's see the code below(original code is in `tools.py`)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class EarlyStopping:\n", + " def __init__(self, patience=7, verbose=False, delta=0):\n", + " self.patience = patience # how many times will you tolerate for loss not being on decrease\n", + " self.verbose = verbose # whether to print tip info\n", + " 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.delta = delta\n", + "\n", + " def __call__(self, val_loss, model, path):\n", + " score = -val_loss\n", + " if self.best_score is None:\n", + " self.best_score = score\n", + " self.save_checkpoint(val_loss, model, path)\n", + "\n", + " # meaning: current score is not 'delta' better than best_score, representing that \n", + " # further training may not bring remarkable improvement in loss. \n", + " elif score < self.best_score + self.delta: \n", + " self.counter += 1\n", + " print(f'EarlyStopping counter: {self.counter} out of {self.patience}')\n", + " # 'No Improvement' times become higher than patience --> Stop Further Training\n", + " if self.counter >= self.patience:\n", + " self.early_stop = True\n", + "\n", + " else: #model's loss is still on decrease, save the now best model and go on training\n", + " self.best_score = score\n", + " self.save_checkpoint(val_loss, model, path)\n", + " self.counter = 0\n", + "\n", + " def save_checkpoint(self, val_loss, model, path):\n", + " ### used for saving the current best model\n", + " if self.verbose:\n", + " print(f'Validation loss decreased ({self.val_loss_min:.6f} --> {val_loss:.6f}). Saving model ...')\n", + " torch.save(model.state_dict(), path + '/' + 'checkpoint.pth')\n", + " self.val_loss_min = val_loss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 5.3 Optimizer and Criterion\n", + "\n", + "The optimizer and criterion are defined in __class Exp_Long_Term_Forecast__ and called in the training process by function `self._select_optimizer()` and `self._select_criterion()`. Here, for long-term forecasting task, we simply adopt Adam optimizer and MSELoss to meature the loss between real data and predicted ones." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def _select_optimizer(self):\n", + " model_optim = optim.Adam(self.model.parameters(), lr=self.args.learning_rate)\n", + " return model_optim\n", + "\n", + "def _select_criterion(self):\n", + " criterion = nn.MSELoss()\n", + " return criterion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 5.4 Automatic Mixed Precision(AMP)\n", + "\n", + "AMP is a technique used in deep learning to improve training speed and reduce memory usage. AMP achieves this by mixing calculations in half-precision (16-bit floating-point) and single-precision (32-bit floating-point).\n", + "\n", + "Let's have a closer look on this snippet:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#in forward process:\n", + "with torch.cuda.amp.autocast():\n", + "\n", + "...\n", + "\n", + "#in BP process:\n", + "if self.args.use_amp:\n", + " scaler.scale(loss).backward()\n", + " scaler.step(model_optim)\n", + " scaler.update()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "` with torch.cuda.amp.autocast():` : The purpose of using torch.cuda.amp.autocast() is to take advantage of the speed and memory efficiency benefits of mixed-precision training while maintaining numerical stability. Some deep learning models can benefit significantly from this technique, especially on modern GPUs with hardware support for half-precision arithmetic. It allows you to perform certain calculations more quickly while still ensuring that critical calculations (e.g., gradient updates) are performed with sufficient precision to avoid loss of accuracy.\n", + "\n", + "`scaler.scale(loss).backward()`: If AMP is enabled, it uses a scaler object created with torch.cuda.amp.GradScaler() to automatically scale the loss and perform backward propagation. This is a crucial part of AMP, ensuring numerical stability. Before backpropagation, the loss is scaled to an appropriate range to prevent gradients from diverging too quickly or causing numerical instability.\n", + "\n", + "`scaler.step(model_optim)`: Next, the scaler calls the step method, which applies the scaled gradients to the model's optimizer (model_optim). This is used to update the model's weights to minimize the loss function.\n", + "\n", + "`scaler.update()`: Finally, the scaler calls the update method, which updates the scaling factor to ensure correct scaling of the loss for the next iteration. This step helps dynamically adjust the scaling of gradients to adapt to different training scenarios." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 5.5 Learning Rate Adjustment\n", + "\n", + "While the optimizer are responsible for adapting the learning rate with epochs, we would still like to do some adjustment on it manually, as indicated in the function `adjust_learning_rate(model_optim, epoch + 1, self.args)`, whose codes are shown below(original code is in `tools.py`): " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def adjust_learning_rate(optimizer, epoch, args):\n", + "\n", + " #first type: learning rate decrease with epoch by exponential\n", + " if args.lradj == 'type1':\n", + " lr_adjust = {epoch: args.learning_rate * (0.5 ** ((epoch - 1) // 1))}\n", + "\n", + " #second type: learning rate decrease manually\n", + " elif args.lradj == 'type2':\n", + " lr_adjust = {\n", + " 2: 5e-5, 4: 1e-5, 6: 5e-6, 8: 1e-6,\n", + " 10: 5e-7, 15: 1e-7, 20: 5e-8\n", + " }\n", + "\n", + " #1st type: update in each epoch\n", + " #2nd type: only update in epochs that are written in Dict lr_adjust\n", + " if epoch in lr_adjust.keys():\n", + " lr = lr_adjust[epoch]\n", + " \n", + " # change the learning rate for different parameter groups within the optimizer\n", + " for param_group in optimizer.param_groups:\n", + " param_group['lr'] = lr\n", + " print('Updating learning rate to {}'.format(lr))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 6. Validation and Testing\n", + "\n", + "During training, the model continuously adjusts its weights and parameters to minimize training error. However, this may not reflect the model's performance on unseen data. Validation allows us to periodically assess the model's performance on data that is different from the training data, providing insights into the model's generalization ability.\n", + "\n", + "By comparing performance on the validation set, we can identify whether the model is overfitting. Overfitting occurs when a model performs well on training data but poorly on unseen data. Monitoring performance on the validation set helps detect overfitting early and take measures to prevent it, such as early stopping or adjusting hyperparameters.\n", + "\n", + "Here, we still take long-term forecasting as an example, similar to train process:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def vali(self, vali_data, vali_loader, criterion):\n", + " total_loss = []\n", + "\n", + " #evaluation mode\n", + " self.model.eval()\n", + " with torch.no_grad():\n", + " for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(vali_loader):\n", + " batch_x = batch_x.float().to(self.device)\n", + " batch_y = batch_y.float()\n", + "\n", + " batch_x_mark = batch_x_mark.float().to(self.device)\n", + " batch_y_mark = batch_y_mark.float().to(self.device)\n", + "\n", + " # decoder input\n", + " dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()\n", + " dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device)\n", + " # encoder - decoder\n", + " if self.args.use_amp:\n", + " with torch.cuda.amp.autocast():\n", + " if self.args.output_attention:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)[0]\n", + " else:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)\n", + " else:\n", + " if self.args.output_attention:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)[0]\n", + " else:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)\n", + " f_dim = -1 if self.args.features == 'MS' else 0\n", + " outputs = outputs[:, -self.args.pred_len:, f_dim:]\n", + " batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)\n", + "\n", + " pred = outputs.detach().cpu()\n", + " true = batch_y.detach().cpu()\n", + "\n", + " loss = criterion(pred, true)\n", + "\n", + " total_loss.append(loss)\n", + " total_loss = np.average(total_loss)\n", + " self.model.train()\n", + " return total_loss" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Testing is similar to validation, but it's purpose is to examine how well the model behaves, so it's common to add some visualization with __matplotlib.pyplot__. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "def visual(true, preds=None, name='./pic/test.pdf'):\n", + " \"\"\"\n", + " Results visualization\n", + " \"\"\"\n", + " plt.figure()\n", + " plt.plot(true, label='GroundTruth', linewidth=2)\n", + " if preds is not None:\n", + " plt.plot(preds, label='Prediction', linewidth=2)\n", + " plt.legend()\n", + " plt.savefig(name, bbox_inches='tight')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def test(self, setting, test=0):\n", + " test_data, test_loader = self._get_data(flag='test')\n", + " if test:\n", + " print('loading model')\n", + " self.model.load_state_dict(torch.load(os.path.join('./checkpoints/' + setting, 'checkpoint.pth')))\n", + "\n", + " preds = []\n", + " trues = []\n", + " folder_path = './test_results/' + setting + '/'\n", + " if not os.path.exists(folder_path):\n", + " os.makedirs(folder_path)\n", + "\n", + " self.model.eval()\n", + " with torch.no_grad():\n", + " for i, (batch_x, batch_y, batch_x_mark, batch_y_mark) in enumerate(test_loader):\n", + " batch_x = batch_x.float().to(self.device)\n", + " batch_y = batch_y.float().to(self.device)\n", + "\n", + " batch_x_mark = batch_x_mark.float().to(self.device)\n", + " batch_y_mark = batch_y_mark.float().to(self.device)\n", + "\n", + " # decoder input\n", + " dec_inp = torch.zeros_like(batch_y[:, -self.args.pred_len:, :]).float()\n", + " dec_inp = torch.cat([batch_y[:, :self.args.label_len, :], dec_inp], dim=1).float().to(self.device)\n", + " # encoder - decoder\n", + " if self.args.use_amp:\n", + " with torch.cuda.amp.autocast():\n", + " if self.args.output_attention:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)[0]\n", + " else:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)\n", + " else:\n", + " if self.args.output_attention:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)[0]\n", + "\n", + " else:\n", + " outputs = self.model(batch_x, batch_x_mark, dec_inp, batch_y_mark)\n", + "\n", + " f_dim = -1 if self.args.features == 'MS' else 0\n", + " outputs = outputs[:, -self.args.pred_len:, f_dim:]\n", + " batch_y = batch_y[:, -self.args.pred_len:, f_dim:].to(self.device)\n", + " outputs = outputs.detach().cpu().numpy()\n", + " batch_y = batch_y.detach().cpu().numpy()\n", + "\n", + " #inverse the data if scaled\n", + " if test_data.scale and self.args.inverse:\n", + " outputs = test_data.inverse_transform(outputs)\n", + " batch_y = test_data.inverse_transform(batch_y)\n", + "\n", + " pred = outputs\n", + " true = batch_y\n", + "\n", + " preds.append(pred)\n", + " trues.append(true)\n", + "\n", + " #visualize one piece of data every 20\n", + " if i % 20 == 0:\n", + " input = batch_x.detach().cpu().numpy()\n", + " #the whole sequence\n", + " gt = np.concatenate((input[0, :, -1], true[0, :, -1]), axis=0)\n", + " pd = np.concatenate((input[0, :, -1], pred[0, :, -1]), axis=0)\n", + " visual(gt, pd, os.path.join(folder_path, str(i) + '.pdf'))\n", + "\n", + " preds = np.array(preds)\n", + " trues = np.array(trues) # shape[batch_num, batch_size, pred_len, features]\n", + " print('test shape:', preds.shape, trues.shape)\n", + " preds = preds.reshape(-1, preds.shape[-2], preds.shape[-1])\n", + " trues = trues.reshape(-1, trues.shape[-2], trues.shape[-1])\n", + " print('test shape:', preds.shape, trues.shape)\n", + "\n", + " # result save\n", + " folder_path = './results/' + setting + '/'\n", + " if not os.path.exists(folder_path):\n", + " os.makedirs(folder_path)\n", + "\n", + " mae, mse, rmse, mape, mspe = metric(preds, trues)\n", + " print('mse:{}, mae:{}'.format(mse, mae))\n", + " f = open(\"result_long_term_forecast.txt\", 'a')\n", + " f.write(setting + \" \\n\")\n", + " f.write('mse:{}, mae:{}'.format(mse, mae))\n", + " f.write('\\n')\n", + " f.write('\\n')\n", + " f.close()\n", + " \n", + " np.save(folder_path + 'metrics.npy', np.array([mae, mse, rmse, mape, mspe]))\n", + " np.save(folder_path + 'pred.npy', preds)\n", + " np.save(folder_path + 'true.npy', trues)\n", + "\n", + " return\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7. Dataloader and DataProvider\n", + "\n", + "In the process of training, we simply take the dataloader for granted, by the function `self._get_data(flag='train')`. So how does this line work? Have a look at the definition(in __class Exp_Long_Term_Forecast__):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def _get_data(self, flag):\n", + " data_set, data_loader = data_provider(self.args, flag)\n", + " return data_set, data_loader" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One step forward, see `data_provider(self.args, flag)`(in `data_factory.py`):" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Below are some dataloaders defined in data_loader.py. If you want to add your own data, \n", + "# go and check data_loader.py to rewrite a dataloader to fit your data.\n", + "data_dict = {\n", + " 'ETTh1': Dataset_ETT_hour,\n", + " 'ETTh2': Dataset_ETT_hour,\n", + " 'ETTm1': Dataset_ETT_minute,\n", + " 'ETTm2': Dataset_ETT_minute,\n", + " 'custom': Dataset_Custom,\n", + " 'm4': Dataset_M4,\n", + " 'PSM': PSMSegLoader,\n", + " 'MSL': MSLSegLoader,\n", + " 'SMAP': SMAPSegLoader,\n", + " 'SMD': SMDSegLoader,\n", + " 'SWAT': SWATSegLoader,\n", + " 'UEA': UEAloader\n", + "}\n", + "\n", + "\n", + "def data_provider(args, flag):\n", + " Data = data_dict[args.data] #data_provider\n", + "\n", + " # time features encoding, options:[timeF, fixed, learned]\n", + " timeenc = 0 if args.embed != 'timeF' else 1\n", + "\n", + " #test data provider\n", + " if flag == 'test':\n", + " shuffle_flag = False\n", + " drop_last = True\n", + " if args.task_name == 'anomaly_detection' or args.task_name == 'classification':\n", + " batch_size = args.batch_size\n", + "\n", + " #Some tasks during the testing phase may require evaluating samples one at a time. \n", + " # This could be due to variations in sample sizes in the test data or because the \n", + " # evaluation process demands finer-grained results or different processing. \n", + " else:\n", + " batch_size = 1 # bsz=1 for evaluation\n", + "\n", + " #freq for time features encoding, \n", + " # options:[s:secondly, t:minutely, h:hourly, d:daily, b:business days, w:weekly,\n", + " # m:monthly], you can also use more detailed freq like 15min or 3h')\n", + " freq = args.freq\n", + " else:\n", + " shuffle_flag = True\n", + " drop_last = True\n", + " batch_size = args.batch_size # bsz for train and valid\n", + " freq = args.freq\n", + "\n", + " if args.task_name == 'anomaly_detection':\n", + " drop_last = False\n", + " data_set = Data(\n", + " root_path=args.root_path, #root path of the data file\n", + " win_size=args.seq_len, #input sequence length\n", + " flag=flag,\n", + " )\n", + " print(flag, len(data_set))\n", + " data_loader = DataLoader(\n", + " data_set,\n", + " batch_size=batch_size,\n", + " shuffle=shuffle_flag,\n", + " num_workers=args.num_workers,#data loader num workers\n", + " drop_last=drop_last)\n", + " return data_set, data_loader\n", + "\n", + " elif args.task_name == 'classification':\n", + " drop_last = False\n", + " data_set = Data(\n", + " root_path=args.root_path,\n", + " flag=flag,\n", + " )\n", + "\n", + " data_loader = DataLoader(\n", + " data_set,\n", + " batch_size=batch_size,\n", + " shuffle=shuffle_flag,\n", + " num_workers=args.num_workers,\n", + " drop_last=drop_last,\n", + " collate_fn=lambda x: collate_fn(x, max_len=args.seq_len) \n", + " #define some limits to collate pieces of data into batches\n", + " )\n", + " return data_set, data_loader\n", + " else:\n", + " if args.data == 'm4':\n", + " drop_last = False\n", + " data_set = Data(\n", + " root_path=args.root_path, #eg. ./data/ETT/\n", + " data_path=args.data_path, #eg. ETTh1.csv\n", + " flag=flag,\n", + " size=[args.seq_len, args.label_len, args.pred_len],\n", + " features=args.features, #forecasting task, options:[M, S, MS]; \n", + " # M:multivariate predict multivariate, S:univariate predict univariate,\n", + " # MS:multivariate predict univariate\n", + " \n", + " target=args.target, #target feature in S or MS task\n", + " timeenc=timeenc,\n", + " freq=freq,\n", + " seasonal_patterns=args.seasonal_patterns\n", + " )\n", + " print(flag, len(data_set))\n", + " data_loader = DataLoader(\n", + " data_set,\n", + " batch_size=batch_size,\n", + " shuffle=shuffle_flag,\n", + " num_workers=args.num_workers,\n", + " drop_last=drop_last)\n", + " return data_set, data_loader\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "From above, it's easy to find that data_provider is responsible for collate the dataset into batches according to different tasks and running mode. It passes the parameters to dataloader(`Data`) to instruct it how to manage a data file into pieces of usable data. Then it also generates the final dara_loader by passing the built-up dataset and some other params to the standard class Dataloader. After that, a dataset that fits the need of the model and a enumerable dataloader are generated. \n", + "\n", + "So how to organize the data file into pieces of data that fits the model? Let's see `data_loader.py`! There are many dataloaders in it, and of course you can write your own dataloader, but here we'll only focus on __class Dataset_ETT_hour(Dataset)__ as an example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Dataset_ETT_hour(Dataset):\n", + " def __init__(self, root_path, flag='train', size=None,\n", + " features='S', data_path='ETTh1.csv',\n", + " target='OT', scale=True, timeenc=0, freq='h', seasonal_patterns=None):\n", + " ... \n", + " def __read_data__(self):\n", + " ... \n", + " def __getitem__(self, index):\n", + " ...\n", + " \n", + " def __len__(self):\n", + " ...\n", + " \n", + " def inverse_transform(self, data):\n", + " ..." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`__init__()` is the constructor used to initialize various parameters and attributes of the dataset. It takes a series of arguments, including the path to the data file, the dataset's flag (e.g., train, validate, test), dataset size, feature type, target variable, whether to scale the data, time encoding, time frequency, and more. These parameters are used to configure how the dataset is loaded and processed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def __init__(self, root_path, flag='train', size=None,\n", + " features='S', data_path='ETTh1.csv',\n", + " target='OT', scale=True, timeenc=0, freq='h', seasonal_patterns=None):\n", + " # size [seq_len, label_len, pred_len]\n", + " # info\n", + " if size == None:\n", + " self.seq_len = 24 * 4 * 4\n", + " self.label_len = 24 * 4\n", + " self.pred_len = 24 * 4\n", + " else:\n", + " self.seq_len = size[0]\n", + " self.label_len = size[1]\n", + " self.pred_len = size[2]\n", + " # init\n", + " assert flag in ['train', 'test', 'val']\n", + " type_map = {'train': 0, 'val': 1, 'test': 2}\n", + " self.set_type = type_map[flag]\n", + " self.features = features\n", + " self.target = target\n", + " self.scale = scale\n", + " self.timeenc = timeenc\n", + " self.freq = freq\n", + " self.root_path = root_path\n", + " self.data_path = data_path\n", + " \n", + " # After initialization, call __read_data__() to manage the data file.\n", + " self.__read_data__()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The actual process of managing data file into usable data pieces happens in `__read_data__()`, see below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def __read_data__(self):\n", + " self.scaler = StandardScaler()\n", + "\n", + " #get raw data from path\n", + " df_raw = pd.read_csv(os.path.join(self.root_path,\n", + " self.data_path))\n", + "\n", + " # split data set into train, vali, test. border1 is the left border and border2 is the right.\n", + " # Once flag(train, vali, test) is determined, __read_data__ will return certain part of the dataset.\n", + " border1s = [0, 12 * 30 * 24 - self.seq_len, 12 * 30 * 24 + 4 * 30 * 24 - self.seq_len]\n", + " border2s = [12 * 30 * 24, 12 * 30 * 24 + 4 * 30 * 24, 12 * 30 * 24 + 8 * 30 * 24]\n", + " border1 = border1s[self.set_type]\n", + " border2 = border2s[self.set_type]\n", + "\n", + " #decide which columns to select\n", + " if self.features == 'M' or self.features == 'MS':\n", + " cols_data = df_raw.columns[1:] # column name list (remove 'date')\n", + " df_data = df_raw[cols_data] #remove the first column, which is time stamp info\n", + " elif self.features == 'S':\n", + " df_data = df_raw[[self.target]] # target column\n", + "\n", + " #scale data by the scaler that fits training data\n", + " if self.scale:\n", + " train_data = df_data[border1s[0]:border2s[0]]\n", + " #train_data.values: turn pandas DataFrame into 2D numpy\n", + " self.scaler.fit(train_data.values) \n", + " data = self.scaler.transform(df_data.values)\n", + " else:\n", + " data = df_data.values \n", + " \n", + " #time stamp:df_stamp is a object of and\n", + " # has one column called 'date' like 2016-07-01 00:00:00\n", + " df_stamp = df_raw[['date']][border1:border2]\n", + " \n", + " # Since the date format is uncertain across different data file, we need to \n", + " # standardize it so we call func 'pd.to_datetime'\n", + " df_stamp['date'] = pd.to_datetime(df_stamp.date) \n", + "\n", + " if self.timeenc == 0: #time feature encoding is fixed or learned\n", + " df_stamp['month'] = df_stamp.date.apply(lambda row: row.month, 1)\n", + " df_stamp['day'] = df_stamp.date.apply(lambda row: row.day, 1)\n", + " df_stamp['weekday'] = df_stamp.date.apply(lambda row: row.weekday(), 1)\n", + " df_stamp['hour'] = df_stamp.date.apply(lambda row: row.hour, 1)\n", + " #now df_frame has multiple columns recording the month, day etc. time stamp\n", + " # next we delete the 'date' column and turn 'DataFrame' to a list\n", + " data_stamp = df_stamp.drop(['date'], 1).values\n", + "\n", + " elif self.timeenc == 1: #time feature encoding is timeF\n", + " '''\n", + " when entering this branch, we choose arg.embed as timeF meaning we want to \n", + " encode the temporal info. 'freq' should be the smallest time step, and has \n", + " options:[s:secondly, t:minutely, h:hourly, d:daily, b:business days, w:weekly, m:monthly], you can also use more detailed freq like 15min or 3h')\n", + " So you should check the timestep of your data and set 'freq' arg. \n", + " After the time_features encoding, each date info format will be encoded into \n", + " a list, with each element denoting the relative position of this time point\n", + " (e.g. Day of Week, Day of Month, Hour of Day) and each normalized within scope[-0.5, 0.5]\n", + " '''\n", + " data_stamp = time_features(pd.to_datetime(df_stamp['date'].values), freq=self.freq)\n", + " data_stamp = data_stamp.transpose(1, 0)\n", + " \n", + " \n", + " # data_x and data_y are same copy of a certain part of data\n", + " self.data_x = data[border1:border2]\n", + " self.data_y = data[border1:border2]\n", + " self.data_stamp = data_stamp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`__read_data__()` splits the dataset into 3 parts, selects the needed columns and manages time stamp info. It gives out the well-managed data array for later use. Next, we have to finish the overload of __class Dataset__, see `__getitem__(self, index)` and `__len__(self)`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def __getitem__(self, index):\n", + " #given an index, calculate the positions after this index to truncate the dataset\n", + " s_begin = index\n", + " s_end = s_begin + self.seq_len\n", + " r_begin = s_end - self.label_len\n", + " r_end = r_begin + self.label_len + self.pred_len\n", + "\n", + " #input and output sequence\n", + " seq_x = self.data_x[s_begin:s_end]\n", + " seq_y = self.data_y[r_begin:r_end]\n", + "\n", + " #time mark\n", + " seq_x_mark = self.data_stamp[s_begin:s_end]\n", + " seq_y_mark = self.data_stamp[r_begin:r_end]\n", + "\n", + " return seq_x, seq_y, seq_x_mark, seq_y_mark\n", + "\n", + "def __len__(self):\n", + " return len(self.data_x) - self.seq_len - self.pred_len + 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can also add an inverse_transform for scaler if needed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def inverse_transform(self, data):\n", + " return self.scaler.inverse_transform(data)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "By now, we have finished constructing the dataset and dataloader. If you want to construct your own data and run it on the net, you can find proper data and try to accomplish the functions listed above. Here are some widely used datasets in times series analysis.\n", + "\n", + "![common dataset](./dataset.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 8. Running the Experiment and Visualizing Result\n", + "\n", + "After managing the data, model well, we need to write a shell script for the experiment. In the script, we need to run `run.py` with several arguments, which is part of the configuration. Here, let's see `TimesNet` on task long-term forecast with dataset ETTh1 for example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "model_name=TimesNet\n", + "\n", + "\n", + "python -u run.py \\\n", + " --task_name long_term_forecast \\\n", + " --is_training 1 \\\n", + " --root_path ./dataset/ETT-small/ \\\n", + " --data_path ETTh1.csv \\\n", + " --model_id ETTh1_96_96 \\\n", + " --model $model_name \\\n", + " --data ETTh1 \\\n", + " --features M \\\n", + " --seq_len 96 \\\n", + " --label_len 48 \\\n", + " --pred_len 96 \\\n", + " --e_layers 2 \\\n", + " --d_layers 1 \\\n", + " --factor 3 \\\n", + " --enc_in 7 \\\n", + " --dec_in 7 \\\n", + " --c_out 7 \\\n", + " --d_model 16 \\\n", + " --d_ff 32 \\\n", + " --des 'Exp' \\\n", + " --itr 1 \\\n", + " --top_k 5\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After finishing the shell script, you can run it in shell using bash. For example, you can run the following command, for `TimesNet` ETTh1 long-term forecast:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "shellscript" + } + }, + "outputs": [], + "source": [ + "bash ./scripts/long_term_forecast/ETT_script/TimesNet_ETTh1.sh" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, the bash command may not be successfully implemented due to a lack of proper packages in the environment. If that's the case, simply follow the error information to install the missing package step by step until you achieve success. The sign of a successful experiment running is that information about the experiment is printed out, such as:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + "Namespace(task_name='long_term_forecast', is_training=1, model_id='ETTh1_96_96', model='TimesNet', data='ETTh1', root_path='./dataset/ETT-small/', data_path='ETTh1.csv', features='M', target='OT', freq='h', checkpoints='./checkpoints/', seq_len=96, label_len=48, pred_len=96, seasonal_patterns='Monthly', inverse=False, mask_rate=0.25, anomaly_ratio=0.25, top_k=5, num_kernels=6, enc_in=7, dec_in=7, c_out=7, d_model=16, n_heads=8, e_layers=2, d_layers=1, d_ff=32, moving_avg=25, factor=3, distil=True, dropout=0.1, embed='timeF', activation='gelu', output_attention=False, num_workers=10, itr=1, train_epochs=10, batch_size=32, patience=3, learning_rate=0.0001, des='Exp', loss='MSE', lradj='type1', use_amp=False, use_gpu=False, gpu=0, use_multi_gpu=False, devices='0,1,2,3', p_hidden_dims=[128, 128], p_hidden_layers=2)\n", + "Use GPU: cuda:0\n", + ">>>>>>>start training : long_term_forecast_ETTh1_96_96_TimesNet_ETTh1_ftM_sl96_ll48_pl96_dm16_nh8_el2_dl1_df32_fc3_ebtimeF_dtTrue_Exp_0>>>>>>>>>>>>>>>>>>>>>>>>>>\n", + "train 8449\n", + "val 2785\n", + "test 2785" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, the model starts training. Once one epoch finishes training, information like below will be printer out:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + " iters: 100, epoch: 1 | loss: 0.4701951\n", + " speed: 0.2108s/iter; left time: 535.7317s\n", + " iters: 200, epoch: 1 | loss: 0.4496171\n", + " speed: 0.0615s/iter; left time: 150.0223s\n", + "Epoch: 1 cost time: 30.09317970275879\n", + "Epoch: 1, Steps: 264 | Train Loss: 0.4964185 Vali Loss: 0.8412074 Test Loss: 0.4290483\n", + "Validation loss decreased (inf --> 0.841207). Saving model ...\n", + "Updating learning rate to 0.0001" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When all epochs are done, the model steps into testing. The following information about testing will be printed out, giving the MAE and MSE of test." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "vscode": { + "languageId": "plaintext" + } + }, + "outputs": [], + "source": [ + ">>>>>>>testing : long_term_forecast_ETTh1_96_96_TimesNet_ETTh1_ftM_sl96_ll48_pl96_dm16_nh8_el2_dl1_df32_fc3_ebtimeF_dtTrue_Exp_0<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n", + "test 2785\n", + "test shape: (2785, 1, 96, 7) (2785, 1, 96, 7)\n", + "test shape: (2785, 96, 7) (2785, 96, 7)\n", + "mse:0.3890332877635956, mae:0.41201362013816833" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After test finishes, some visible information are already stored in the test_results folder in PDF format. For example:\n", + "\n", + "![result ETTm1 2440](./result.png)" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorial/conv.png b/tutorial/conv.png new file mode 100644 index 0000000000000000000000000000000000000000..97c51728a7d560b2de5a60f82d7a26f1eec1acd1 GIT binary patch literal 683079 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

fFhz|w6!Ap zxFdFhH7MU&olM;}ZIjy;T5TblCEKdfQ*fGJH^`mALsz}*NZ)fXC(-R6m+H+^v$gOf!d@bjxVXc+0V}l1Qf((`2?c1cWUiAsI zn5V>AhwoKFDZ*x`lYeVqaX_FvuQaawfF+8p+{B{B4%Rrb7r0lhb6_x4rxwpQH;{K9i>pJM6`IKc%Q=^Ugb^3sJz~%Ie(A4{-g4S{u@GNKrSd-}Xr^aL=sC{Hg zTMV1Jp1}*+2~xI>p0}zIb8T;oyq>(iU?P&&r}Cl3r*jo=tQu>oTuWT8H1A>Up?Gv; z&t|=A8~@BbqgNbSZ*DrU^wmt=_&J$-@qx?6jR>$#;H6PH)zu6 ztVwracg*WbFlq(A&a-yP_@q$_GI!%7eY1VBu7g&VT2JM3KFB{@6E>4mUbmvq=(zXp zdMMHWZZKlMwdChpaIChnBz*bcQt8lU3FQ46o_XSavvTR`;r7Uz5?*osqCMwFlxLKQ zc(fR7vEdi%fz=#em4)_*QHG#fpqr5&&!Oy=a^FD9;TpIam_6=4oGOQ4Am--zY70(l z&Rl_%C-!(Nhwy>h^7!T1Wz3_KmGfp0?Df@~8Trkgs*IQ7VtXkkNoNi4u-k;s<c>guvHtQ$pr#f5GJ&vMqhEbTZFsc#4F)*avCmZOCy($R-3}&mMU!fkGdqN;4 z<`5vkmRooBxjcJ8>)q!I z@_Wbg=Xx*ZGYTg1FJk1^BNOdkwb8dT@BQl@?GQ;rk<^q{R774i&7925?VK&`UG}CD z@7lz2P|$NmK_P!~_eE8F`S=*w{*0BDu8Xd!iinxLE!Ug3_NL}s9<~m5?VyNyh#+rm z&0XHmd)U6Wa~AOsWBjXz2=e}}7{o~bR}~iz=%EvH-RomIzN!s2P*{6&6f1cOh%>PaNn^6>WH}(Hoia+c8S1EF##j!;}|9)uV*wy=E zy~yYI$Vx_C3wcFK+1&@#9r=sp&lP!p-}L&OFOxkAiUf+HjHH$a>b@^#Car7@u=q)W zUXoY?6-TKGhvj}AIw2uz+b7c;QC2p_>vZ%pXf8|UhcjatR90+VLc*O-#JeVWfwU4C z*h)c!q%k*Ob3cpW{X=(>!+^)1s=kOF2=d*ei8;S(fn5w=oKHlH;J>=?6l1+sM5RgC z9r$Q!gjFGRqX~|a68=VvvLZ25N0=LY(E$YK1h;NOq9Hy4t`A8{M|)d&5S>?HjvbeY zUfnO0x25u*$PR){5&lAvlD^_*@DGy9-(j&81spG zoObi*E@;`(vx_)FpW!1F*Cv<~B8Lb;QVaUoj4jV8?5mqhL!O=xc%vMm@XKzjyb_f~ zM8K(Gb^XQvCd+*zl*FTe75pCQ1v|?kcJ?wP-O<1Uzv=6)o+Qy#91VoD@0B2a3SH}H zPiQ=oVdZMX573dlSp|Z@9Bcg7iF=<~Mq-DxQ8=F`$;`YtF5ZTW0oi~ou&%OpD%Ho) zU-KSMRytNHdym^gdn2P491URv9NLdPC9Bkg>;9sB{NK>B-qQZoul=0Opu{ldO4-DA zqW*_d=*?AArd~m+!Cy4VKeUn5A@Ifh=4ES$jqbYn2zw*11zA5!@-X7)`-dIao=O!S z$Xk4#g21KzF}z%@(z(;bTN`|B5@jNvLeoEx9)(=4Akk4GVvXXE;k&_YUxuYV6S8CB z63K|P#)wT2%P85^kcAg%?mxN(U7MV>#&{=&A(;fbGaA){Cm(4v@52nMrODRIMY@K0 z5ZzbQ>-K3jrtk=;J9&?ZUgl+M%r;5~G}b%rt-f*{vE{bCtbxt0<>L^4pWP;w?;1bX zblNRVQe_d?fb--wqi)EvS5ss80@D^1-w_;Kd77OWm!Z%xfDw>Eoa+VtklQd(B#bfU z?@^-SOz&$|FI272%V~P9EGZ(3a8+Y{zp>KW8Vz9rtmQ1<>M52x#q9S}9u>8)ZLyWT zjUQBua|wknIN`A~0&+-E*sH?63{3>SQ#@;yL;Uvm@+MbCj@ENhaIM6e<7Gr@9(|fA z+!5JmIG6`Z>+Wo!T%8-Ffabzx|lI;RAx6dpoV;T%}Y2C zm;>=aO%`(SGKO<~1~|$RG_SyLI_S(Uy^&biw6-i;R(ItjZxv%V#7%00?i1P=uf%um z;}>08PpSuM28obj#|UW1hrrE>K1_U89bFL4Eh=(Sdh#rq2T`+VrWSR@r{gdy1Fw0m zPM}Jr88^x`%9}F5gcu~-uMKW>J3brL;?e$VkiueXBZh5uDL8B8QMH*{U@4~{L(}-B zZ-dtM=3n~7!VBXDZ=a!Z9y!T#e$ye*jnI#E^cf|)u#}n-3)k1}m-}mPoSiM26l%f> zM-S1cl?P9WZb2vNWEjL`KI4{sJnPaugxI0*J#VT+X>o~3R=gCIZt}R323BQSWcpjtQ@p9 z=#I$n9$tNZvIz^mQvulbLa@cHsy7m$S!NH=Wf4#@yvR`adUH0zy_JeiQMzczrWPWL zdD~*t$e}fLwAqpt5zlX1#i;XpNo?l3b(}Lg2mhr8#ZQ&`Vo@BQ*)6S-RQAmFt3_!e z6u#Bs6OLn|gAzJ8p{6ifO32xtdOlYs&1BGo9Jw6nVeQP=%-t-m4@nN%p5#{#fD*cF zK$%-1T+2UZNjf*E5#?RG_HVskOl#`5giz)-dY+f)N^S(vw7Y1DSUPbQ{!zi;bLq~E z`vIK_WGr)HGG2u^ub&!fr=yEAA|?rlAjG)DOxl@mF9~=4-AVA3CRhfp_|0#7Ze_d&6X(MO9j@GY^JOL_hW=Gq(%sD_=bPfoStaH({blE z@cc;Gk;|{2t!$OvjxOW`K$tTVA{%%CY#%a`J~G{|mIHF&;|C9UWe}1V2dlZgt!s&Q z8iF;%WivVvFz<2k`m49b8@wpdJN1P_;F2Ge2f8JU`OPY0!%lN_pK|h|kaO z?e<4Ku%uuMJj1BvR8@_RxOXqK`yc8*tMNazYz!U5i)|lBeR$oE2{2$nXTvbwO*Mi~ zKcL1A)Dl!-o5kFd>WPiA1jE%U385B7sA>3OvNu?dHKqhc-jQ`b#tevLrMvSoUU0|& zRb_;?>U{TjWjUwxYvQW(0(pv1_U$ibyZ^G3NO7VerR*|@u|W+B0)@;_tMnnZa7BC! z8qL3~tt{POxS0{dNz^-xx1svQHP-AF$nIaFcEW>vqMge;o}AcknCvn~LzL@&aY@Rj ziP8JB<$DU0a6c8MbWwo?BLtamOiTdW`TZ&aL0NmnnFeZ9PD`Wj86}$udoNhDL6-DF z*C}#(?w%$Ff@u00CLibT{LVkdsth78L@s?sYuz>+97}5ow_u+98uWS6>~r+MdBxv8 zW~MmtDR6}#Suc;^erDKtxgxsOKRPGocg;|b?5Pk$v;vsjGEHZg-f~XUnIX>S(;)pM zXH&=TKJuIw&M=@VuE_7;JR}HL!o&W+YMsxU@>&J&@XH68ADI~FKS}vDlT^9$G29g- zvW+wX&|Zfo7Y#n8)C_q3n0}0_P!g3}c1Y_TNqA8k4e=LCipflr#O!x$Rao7VzwogX zs&T9}P*h&<#m(I}vvvr&|9Bpqp9LkqFsc9jM;`uqX*A-4k5r^6nv*K#0&R&@iwvkC zZj%2D|pF=iyzj4}W*|HQBjo0XxQ`;!#ajkB@RVS!!yOuB$?|5`@I)O14wF-2X zgM(v?pWQ?ZwvVx{MXeXzXxNiw@Dz{B!e!xonpsQGiRpM<;z+f>q8GeOkEq!Wg1Hxh zVHBQg=EGoWoUL*=pbBC9^syqsIlZM!jJzG zu={_H5;<~q{}%Uq!`23#m5QWbJ(Yjp8E$d-hh3h za1d?bN2WEp)=1UV|$> z*44ry?25@E7>rC~AhPaL!)79Q7X^D6;?z@xtM1P59MJPnXis{Zi&^RS!~OR>h#0<3 zy1x~Q*tFA1FtqMMaS)tL8w}GKY&Au6O#~-Gy5W2fJy+-V=1X&PrU=zxLdamssr}`B zU$fcLj~{G}qcuZx^c)l34ce)cb@#n0YpbR=COS}NyX4}z3puF`K>@-X}0j{Qb^laFq!<(gqcPUb_8gg;C56(NGJltdromfH|9)%h;9zUSnC;FQa{`a48qn9tE0BZ9aUo}?f2RI6LZ#CyZ?wqRIBjMgxvm2hzPP9 z6x>S8{7YgrOKNKEpqu($wdR8o-VE5E;BuT0Dke4oSuwdiMN0<3{WzWmO2kFD4Btb| zV)C-0qu8v$>ZfJVmL|SR`2F@SAGZ1<9soMD+?Wh*!SO0dW;mHDHpEcO%b%5FKn_y6 zqL*JAbx^v*sH9x0J?ux)V3>#gHcZGoz+DzENc4448|CAWe^J+{B-8E(Uy)e+bp9>( z31BBk3?O_ivwkD*7=4AQ)?fW}4EROs!MTaF@yy`=drc2Q;hO20?t=F&gIEtA7S{QL zYTMf|*y7{oShIa`Fs{N`Mepz0{tEl%P~jh%XYLky47mcUV-WJG5HVyfW3c1-pzOyQ?q}_Q!Y0<1PdPogcQ}uK!s|VGPxsJOu*}J+BXq0ICUO1QL+1Z#xVJ~>2 zC!QpY5$RGRQ&eKkVSB7%NP+e8R^;HU()=^y0t-7wu{`FdC+hZ~kh{)%!D+Apj?tS6 zXFn2GO@a3dqtlf2-1m12=B$@l%eUM3*{%A2y875|W7Y6>%G_mMkO|!>CN(a}XI~XG z1uXxr9}1^{fxE##@S7dlZ*Q6{3aqK;sdPZIcgbHRhI+w1L^Lc0!har6ZMIIvDbWJTnid#j}m@$C1v|8v>uBHIwEB z`e;q9>)<8cQdl)tbpMtl?PqS}M(BSz=f1hVE`nNuy&uC@U?nk86!*irUovIWWB=Cd zL@wE#b|UXSJWppkg(0)dyLdx+5#iV`STalzWT)kK zmP;71#j1;kWHa_YRX57) z!HkZ|EYSb`xJTsbm+mC`u62>Nnp0^2L8PovW?B3{gnyRg|C})R7yEr&M&VA$hEuI- zwPR1NM)2n&7?=`3)9(T~+;yL8y?l8#Y+1_l%3#c;_7_(tQ&poh*}+%LPSCJ0($7RN z3qs4=yO{Vvj#_D=ywoCErbNwrR5sx?2G7P?E@gjTuTAPNm3-Jv8`Cvw2R8bGfyR-z z?ZOU~JbarVrHX8Kx&Ju28eTF(HW{ZDQG?g`ak?@`;oVeb2jr^NN4~3K4xIvLMPY1mkqyeytgCkD6P=@Qa=dGeD!OP9JQz3&e+ zLS+9lhcDEoYted3S;S#~jj6OYd*?laVCP>GdqO_;Jg2f-*H(67PRcGgME;#?kP^pV zW2~GH&94evBqWI%-2M09YRFVAa2gn%(k4yOuvG>xKaAk-wq{QrCU=rn5#=p;{;$QD zdi5-gbK`TO$JuRQR! zim*6jH+Gy&nWl8=BsAi`VwS$XkznZ{d}V1N)D6cM!sOQz%FkZ)Tv6XeF}mPq^a z+bXpJalj{84ydPEwpW=(Pn2(d>1!wLWVPuT_o0B%mv4J8w!eZkCE`13*vVkKc))-z zdv?@c)0vkqwNQZcrG3635YadTpP+AjxzoSG_=Oe@f^Ao5*Hn)na-6(ucxm>9-E}_r zx7?s14^}bgAW3l)g6S6?hH`eS!hH`f+5e`?P9EZ@y z?(8-im}Y-dU@I^Vz_zd8rckd}x_AwX15B@y6Oj>aI%p7L{U+%=W_(4(92dKV!#Xb{ z1VMp3Lg^aS4$Dy#t7Wnbz#aX8pbiuX? zRP$<_md0D{$cX0(QGpT!VX+Oyw|phmwR0T`JBdBIn2g8-DqXQp2xzVn`ETVLQ)Z)T zI>Z+D4$|(rGjv1XC3BLWNkoQ9)<+6oVsz8=V2TaBg0jc<9pNF$#K(jeGS^fwIEYNHhQaBMI+ z&?sWa(6eGc%l_)6xMWiFum=xm7C<5bgTaTye^4~YKEO>9BkH3%>%w@A6Ba7!QD9}9 zvskJppc4t!J2M#wh9zuZx`Zt9#a4VzwzLKqTnE8@{3pL~y+dzFPmit;L@TZD&TnRd zSDALOy!0~*fMRI!kFPWhCRq^4m6y_OVwEpeO3rRgh_m=@RFLajzAn5L^;s^>HRr}_ zez$yCp)!}xZS?)82iEo501~x@6z(DP+w!Qo%mm2^SBJgU+zIB8{+Ux_){cbeVk+$5 zllx-!jvcNOtxa6^>uzyu9*1h)(*z79T$2;ApKvz%XCX~rx&vRda>IVSpnGv>fjf$C z$@0qj;bffo^t{%S`Mc{dl4E|*6~Yw6*z`;(v9FhzfQC~-?$04qze74OHYGQ z?$vw=_WsziFceqvAX`wW(&b|F^Gj8i3kZcg64^+zUbndbRIfMk*O|k$*H<3PKcUoXnwy6Ie&u$kG%L}Q=QYG zm*?G0c+9FLs|mB&m>=VFLVl})!J;VHon45H7ZG7?N4^dT2lo9F0c7@PTzU{NzJ;wQ zczyI^m=7|J^s0YlMB6bXV=+9o2)-RV-5GrsXnf&QRw^AR{3&_+(LoTvgz!1a5tqDe z{{|*AtCIGdI~@Z$@6m9Dz;lqWvyGJ*7epMo7r-8fAru4|E_Nz7a8quTXyKgKXQGFg z(yKpWVHE>MTx4eStB-0v^n<5iC2foZ=HadC^7zN}gRWQ?jRrR3xvD<9L8=pRx-d_sUpyp@3US4ZfUW)HGTJInr?3)?9pityq z2NHq7BG?L2-ig7oQPKJqSq*0Wvv|hzUNH=5YH48~;bcMYSl_X)L##fz&J*vAN{vlZ zv2Llqe3Dj*XCMCe`Qd}V3jboR$ophMNO{=JdLn$ybE-FKDm)Utp89eYi9fVQj4^LN zDdVq?__ zF6F_eZY-3^i<|OBfcWi`XmaJ=VNd`WN?FLzS=7jwxOXHX5a5h|%*Kew4N_>0PA5hp zvZA=a&aaVaxJq+cDx|Leu8?d`36?B3X*XXGj`0Yi_Es!ic5S(J1gs9ZK}$$&ZzY$w z6~lw*xwEi0K+5p*5BTw>2tM~gh=+g647s3B`9}Qjg#t92y&Us*fwp@+b%SGmSKzg%=UE&2gRMD0jk7#RHBOT)%P8AC61g!gxQ4*K)k|R<775((mP6S% zze_J(VH7QP1S|Cog4$Nm9hU;qO^8cO?!P-m`%y}=6}V=YGaZgSD}DeGhK{lEMo@GjZ@eb^hc=FhB=cWw_0IU_Lqb$w*pn!xJ} zqMw<-X_r1ID1Hd(gxon35C7J3+|SdOR=^bc4sWT1MeQA>rN2i`dk%6*3+gROUQb_| zz_JG~qg&%{I&|7a>Ff~YF_y60ZNqK~{!bsXeUGe!*x*P1Mw}5r8gl##4Yo^{`^8Vo z_>eUKm_k5KHsJYhblVx&Mf8Z~BD`O3;Ti7-f^mXcV621jjQmj}>Pz=146ni(sGiWx z$%LhM%2s+tJjE1jo?phRRvjnkgqbp&WLZ$xdQl39<9B5TL=rDj z0iKfbuSGSg?5K_FRCgf5C-4qo#*?Ea5kxpGzX!2?^Z{EFffj+yRvgaJ+xxyr6?F~P`Xgv`u$#(KTHLeSpiFH~R``jUHq6o_jRG+u znLEa?#ipSYe*SOx+$Ug)pus&XicQ{}@4ql^cfk-i=zjoyn^A!8AjPR|s^E3t^D`dQ zw%0wB7BpWtr*>ZowLXr|$WCCQp40Jjq_M3?68IjCj^^8*;DJ_RpBMWhpMx)*$1u_J zIw~E;@L8bkp_Ga2cX8@GUe=`Yz}pW3x=5=VEOG?7%E&3{RPJ2K-78lXT=LM=cWW@8 z$WM7+3@#knL>`J!S~tZ-WdF(pk+*YUW8&Jrku8JLOq?wI<@wqo{O|j67VuItX6Mf*!mJxAu!ev z#_8&4bCsd<(JN5*&RtG#yGu-sJnCr(W3~}($fDKb_$c4!zBIBYQk_QpJE|d!= zhf_j)jC4ynsXe8pigu6dn8DWf&+wPOrn^rU@MYat@_@Iz*7TS`kyG;P zIkz(nK$P&scJ;{eij53m*jZkTk27#jbG#h~lzQ+4QP${XI&VF|`Mm#yB6i=Kj!pF= z;3wvIVw{dzN;q}GD-&D(B4^`>R_#}MPsHHI9cu&#xM*wZ*0T46X^#9zEh5N9;>L&P za*UrtYDOYKMjmOn@FO-ZHZ?aOjRPPvICaef(C7rondr2&JdwIuK|-ha#j_*HsGPee z(8qjd;OPv4qaTIKA$&byf-S&?By$U($8s#Ocz)}?x{6Z}=t1D+rf1evi=T+c9gy7o zQmE}8^y2>*!0GwlkhJW|gwD-}au6_Q)&L_9e`naHu4(}zd@1NMtl)`fl9L0c(AyaW zw6md1bPu+pX)+ftv_Mj+8yQb?|AnxNK1{gm+W7&%6e%QfP`7f)Un=zOv2m!-@3x@v zb|(4iwWHk-ojlIEc_qL7vF%A-x3V=*UYh%|u*p@!hC%W zjop`Ab-dP1?H?QM*aHcO%d-jff`@!pb4G{Fw^mt1OykFII=%srSrh3C!077^)pC7e z?3cY@1X#VBu8|ruvlEkaJi{dE>T7X5s>mkNh&Gd83UkoA-iqK+0Lr6@vfL7kDJ>BcpHG7U+Ut5DY!kUjL=_c_%74Ihm0f z6QlY?0R`DO^=$1kepvy0+(P?`HuhY>3R^4d(D#ohN99tCwG`}MFN{x;&Ixg6wzOfC ze_8%nn^(m8-SM>qwXN3+hGu_TWlhbu>pwqSV^BB!7ckJadPnxZfPuTz?~k!}@ZKBz z-SJrd|3e)oQ*(HaE|8(L#YTx5d=2Czep9B$ER156(xWxMwuye-qdq$?<(L1C zJXmB_{I&;-fVy<=SQJXD4z$o10zZHj%yH|IQxk^KXd}PgH$i!}b<5q?fIsFf3k^Jn zj`j1f6Q0E=f4y17f#4CiM{$D=@3yy<6n8Sq2nWt#QN-?`SLIAcI5``|EQW(FMaid+QK`XF5>XF=)}Hm7ArzxF@|iW&4{ zU42q~zFMBxHf+b;E}`Z3IUd7vu|7^3{}WWevqdy(yO^Ex!+Ix!2~kbzeGS$gMqdG| zjJ<5kgB>%chsLP|BH6dc;I5VEAiAWB1&B$AaA(Hj9MKm($8D_D65#Rth>uy6$wJWG z>fiAO^$&iJW?!w(W=l({>g|ktnK7`xb(z+)82Spm+&lIAYS#kou3mH+$g{0o5Wq{Z zpJks0o=!|$*+kK>w@hi8i0oHLj|(ikA6R}B^c8@drkL!6Stk_OWOm)4lj}-2DV{;F z8+sw6?9o8V`pUK}MOH#5zO%3LTtdEj0s1ww%rC9(9Ojb@B_2dEof4w0De#B>-3wk_ zrz>}vy62m8v8-kYh8#<0xUcXEM1GXyjA;2nP{%}Q(6r`1q&)_Egwod8Bp z_|dpq!q&(f91+zoMEX{o=)k#$zHWQJ-+ShC>4BxBFIHpC-FpJb5C`UhbX~^q_9xdS zcff>k{>@!DJ2DWlvvl8Vw{(R8wa?~jDuDzZHVUgtSjyHDy^3T4K8wJ~7uDz`4RQm7 zZV&2Yr~RmYd4#VA`g*cbyy#Q@xPhUY!Q;v8q8%5X?F*gV>jNh8Rh363z>z`cGbSdr zR?x~e^-)kN#kMkizRQ$0$wWcz{L3}<08k#D;35l+&#~lAy7!@K-J%m;^W$?C7>`nG zwsWp^DV^s=^p11JZD}XX^VE(=TaBi4cvO^F)yN3Wnb}M}`t_oG!{RCuyfIxZ@h2Vz z*`*421du=E5A{>YK?;&Xp8~~pMs<@mr5$@Wa%COrkuK$*mmMC$uhu_5dic>4G2l7X z^zyS&^5ZDopP{_fY8Yw86$RE#@hK#Kz{G2xxQI*KO7XAGT1i5Z!Eh959vqUY5(>YIE z4e;>uN*b7DaFYyG5)$d7D7G{aB}0Iqg72oZC#0+C%Y(Yd0ti$UndHJBYtuk<#>fQ? z#?YFhS~;JpDD-4Fm~v%|n*bLxXG!W1ktN?tv3#?4tAZSklK~ydmUERGFUfL_u>F-GIfNK}HjND+qcQOEYfic}w9p%A8@EbU@;vv%l*$%@s ze32Oz&=T@~y(dbYK>SQ2+2ed_CqHG|3TB?5ymHkoI6gIFn0EMMi*^r^V>xE842?1@ znjBfg`&y<>Ql6A(cRTUTU}sI4tLz%+5roU=hnAhs+c4*a z=om#u3c-W-?HV<%<(hcn3~att?r_?BD$jd-jhNtfQ9o?B6t@afZ*uL4H#jyC-foU% z&zh*x%uwD+cUDXG*-G0f`*EZeC3cZ0dJd#twj}Htgr!fKDEB`*9f{kBV%5yoaJ^35 zPqDPWfvz*>4siY8SULgh6g3Ya^qi6l6yNIGv8{3<1oOpCb`+T%jh7HZpTzbC`6gm9 zX%!&A4U^T5dAu5XS-q*gV;>km)h8J1y66bh9Oe!y#j^I2xZ)<>PV=QH?OtW@(IlqmuU(e{GY}C{C;K zWrBlC%+>=o6{6zW?~UWKH!i2`z!TGV-BxGZNYO=NErFw{fMUb1(k0_}p=v(rQ+qRi zW9b)bHOQ&%Z}8Si7yN0r+Im#5VN#^jI`jmFSaNbaM8Xq~v46d2+$7 zPUbl_c?!fgW5;(0O&_+m>Wwlt`zOcX9#!#IG*#G~;$Yktg?5fr4){(?b_8CZ9iLqk z4Asqw(m>!?j0^~b%ig!Mx3?H)PMX#apz?#}2_|e|-+x+hK0$yGw_R2#wsn2{Rs4B% z%?Gwf$+V9zFlvx3J1GF)DqdgIwMxfKkGvh?pHXQ=OqDk%H2T-3&UtQu@>>z-_S!d# zM9Z*Y_xv6@Z&9(E{i=_@MRYO)O^qEkz1(IUgIwBRTMJLPDm#g-TIu#PTFwGN<6B8w zw~#c~X+?_()62+(qc6j)$3CuvQysGl_CM0*W7+f2zd`bvFP7QUPQGTm^vzw5?3I7Y zKAL@TP`8BfLd9Yf0YyGcj2(lOdCoMi-JUZrL_hoJP{( z8&r0!0lDJ<#B;d8>d3bxf%dkCDYW0U;-^mk8V2?IFBi9n7OT16@k3O0;qc0dNG-r# zv4GCzY`bebKgBLa?fHR4s5JUx=naOSQif~8?*wMWg{>bqHAbz;eu%ItgNzJ`aRdT< zC3)RW(UM8ge%?oBb%XnB&x{}Fh_cCE*W3VyhV%lDsEJuroPn>w4AL`KJ>dKuG_h>u zf!1dMmzi6fc7?A6P@!Itt*+CQ%HWD+TbMk&1D~a%!n;(QM1VZzjk9Y+Pi_9FGg}_$iF^?ghT`6S!Fx zx_oYQhih0$n-3sYwwK>q_LhH|l65W5GNT)pO0$!BnTK-=-_pf0h;KUa80`7e8wpiJ zf)!0R==!k4dFsQ9_x}dv5~U`*lSf!_j0zId8xcdAcf`+L-lDs&YvG(dTfU3)DO(#e zZJF>L^nNd8d7zel^aa%SkvUkXl$4hnH1|3r-1GBst7Qh95HaEyGoGm3 zof|~!rw|Z%?-RZ+5?L`SxOP-rQm$lR+YtA9L&h(a`^~8fBj@N$T0S@e*tl|8%2oWJ zsESGFq;L(dUBKH0@U~@3AlU`W2OkR~)+2@EFIrYY`_Bt@K&tBSNdQ3n24SqqaW!sd zSNF4(aq(YfV_qC(keZWb%lxks8Iq!tzB>n6f#9A+#LMKF#0iNroyFoQYb5z z$IfgVw|o&_7xNPJDqOWbc2}e2$oDAc+n2K3Z}p!Q5WMJxmqG>m&3CrTnmkBo-aHuDa6jQG2V~%NGe-o^Z-}AJa`7k2yL4pY=;T}m z648##%$&U@gTU|K21nalcCAcRcMXuA#pq)3h43L$GN(fmSl_!;X&@`GVMxJObwo%f zU0N=#y`*z5Ly$R54=;#zJ1aVQJWj_rN&LJ>-7zFwd8hfv+rII-xa7&RQI-hU&>YJRpd6S?UlaV=7Fav72iaFucDf@_RGcDQ7ANYxRyA}3r zX~L=?UFyjWp&8O+@|yXv{Iv`j1cb?dJO$Ac8j0;B=pqv^HwSe}St)jn!nU<@^_>e0 zgVr}@-QkKz3&qoF+vil%m2aDGoaBsRlmNx0^_*%aornp>e6!-i_CdTcePy>+M$0q+ zZ@S1{s^&gzA*Xc2~{`A)<_I-!~@Io>KidoUL9sTq(W=K33oU#MJQs zFEKa1-~lohq&<}xmG4o^h3~NQ0A443%oF!6!3wVD1xqc6Z_hkWjF5ZSPULhy<1RmD ze0~*nL%1K2 z!xhlr)K@MJ$b*+AgG>A)pydqcUnb0Adnyj_#`u3@r)iZz}w) z$Mj#)a1cR=ka-Rx0-kBgl{f#*GmyFuIlJ$>?0s+Mt&TM=2d6$0_ZJIY^T+$XYwagr6#cJitUUDmCvK9(Tb$aQ{OUX)EXq{ zT7(q8>Z>D#^ziryi@K-TrM{J?%8FR!1fGLfd#3e_( zNB8_kz>aG&UNLDGneILJ^)taQ$hWcL{8ik5X~7BBf^@mzY$ZL(p2+8R8Qr$E4>`FO z)nD3$;|U|W%bH(#Z9R`yTknog7F=|=XRt4{S6Vghwf8MynySQrGtobhy}XId_t(9n z0`xtbiBCh!!B{nycn@RT=Ak&>-ET|~mm@ntm~igfTYJc5mlfcG3|VAk7TmOUTvXE^ zq$^;4fjs-wd<>|l9}?t=w4SCNZJ>J@Kbk?l?UG8qeN=BGe(0f3xg~afyJhk&$vuAw zDX3@pf-O90-iII(Nd9i7^{`M{T|LYr*=5Of2m88mEtn~?kbeJ&=PUs&Y}~KIVDv(2 z;i%rM@mHNEQvW0Ox^3MG7xc1W#P%y!!~V-tFyE2K*7I>=??c6#6;K>k{qaYaXU&s3 zwTx@8zE2E`-|SZ(Hts3?_>GA}^t-y7%BGhDVedH*vx8#-kJs{KSl6bhc z5bx!EO<{YUBj36&3`oz9zkA|E_mg}6hkj%)c=u-J4I)YNGJ|5f5>xDiyocMExWqrH zEkfV?}9MVFci1IjC(EXPiKrfK`8kr{<4vT(Tpvx$}<&nLX867Dnh_s|#rTnkPRy;7+X_AOOf z>dIt|2Z>#JEqRy7RF7jxeNN?-;NCVJ+}nD(cC}txzvKFYT99^ZEZX38u?-tf&o#w1 zdS#Qs|H9sTMm5#7YojP4Hb6u{Y6PU0D7^_&$4|^Xzecp7D)w#y7qn{8?FZGBf9$b+_xf7A!PnLo)vx=2=Y5 z`a*c-4~{?Y&m%>>A3tgtZM1bmqVk3gj|uj%PL%^Z_5%w~GgQBHYz+Z+E9VJO3#W5J zD%AlRRSncFPsMtvMLNPar*Lc4FWnMOzi>DfqZ?K!qARbmf%xONsHjgoo+}T~9PsCa z8Seq#oojycL9Se(|sh5^lW!U(yxQ zB?=9iDhCZO{g`{$oRREDo*EyX3ko$Wjgw`XLBPx%(|w0glvi5IH;GG!JXjLD-;9k= z;Au-peQ5iv-@L?5^YpG)b~A9mg6$)3x)-*2s(r9__#~5ZT-UJ8pu}JqcsxkHX~s_+)%Xakc|QsSe?0a17#-!M178AacIoM6 zm$VT#13)_re6B>bPrulMMM2(KD-{jSng;>v@;u_gNL3vx-E2Y zx~W>Fff@_++%6aE!GePIQUk2&-9mKn|CVd=ylC51N^_s2psq}d1-AjhD z&+;kTE@$+7^Z&F2`Z#K`-yhFYdCZF~UfaUM^3to#c(0rP|Zhnu7 zDjRbMjNydqijxlyFSuqV34*g7FNz!u;Esw{M1*gemOhlbti^fvz^CHsItzpss*@Y? zU`V8DaA zDJ%VestbG)^%EP|-^--aI;yV+leWjLg1DQKeH4wcL$-T}d}=AjDi%*`<%wUdB)42J zW?Di>!`}jgtumz44CU={;$tcbN@%!zA-1I9q?tJ4G?m#j3HaT35jfQxpJ9!Vb_IJY zt7ZfD%x&_oRVAVS+?=xj45nZ_^e2FBrH5)LNl1$hkanP@?h%+g>plLA5EEYI&0Nnx z@C&#uG3frIZ){Uew36zb+8DrDF#r+G!HRVCqu_CN=#ae-@Mo58gv3F^JlQBv`2bI&IMToY@H`F?BQEus5@F|b zEYl&$Jt|ZpF9m4}Ve@>l6$0+!FM*#Qmrf*-X5Rn9S~ zLAy<dZpWN}d&lbI6{WC~pnIX1FvVKj-}Cn=s?l1}99{O8Q{)_g*(Ho?9(* z?6HesT?>S=7>`~_GBWa?yZwn0VdDhfBhIHbH})XyIe$0+s31%_`lTIIk2HLcz^`3U zzV%h4ZcUuPoHRWPgn>Q8Js*pzS&x_+ct5Tc#xx@+QL&5{Aj=@f&5{ z6kGzxdx%22cr`gI2>La49Rf-IU=2sh`0Z4o%fkHOd3<%o9Fr(-+GS0S9w&$g-njL6`rm*52ZVzRTA-?Wuhh&H`#B zGyf2y-wPp64&=p`R-5e%5(HoN!fDp=jMh1Ynd?#IsF3^T1d`Ne%^V86% z4%q^Oqw%m^mS7n6y~itcpYLR7L^RYmyB&3w_24$p-!BOJt~|p`DYLqAphL-eCNH); zf2UPvSl^b-hjDuoaZawfYMIIO{t?9AjtA}iz5d3dvGjC9B~+(L>9F?>RUdA)DWb!L zgR+iWccLET|vPcys;3*t8WEoBSZ6kr?kmVmgdkQp;WKN8Z2^f znj9^}l?fR059yn`>u1hW4$)xJ6*IMp9%SCDWe5d5R=HK$@PQ6q(Z!<6UOV4B4~0$P zdu|>TTDa8-xKc}?wg*B*k~KixK!_x_rvkXqiL`e@-YevH?qNlA`blhkwP*vLV`V7h z#y%srOxTs6NqgkOAC>EbIQ)5nWfv#wlbh~cBfE$Sa*z8!hmL_h=2)s`HX|eRI2bPE zD$r_mx&3x!=V3!kDD;9UW(XO2v<1sgcaFLKr&B1m35!1ux6Xp1-ORHtU=fgT->QpN}2vb;%wV!fU;Kc$dnn&TmhU6=9kAxTUa`XvYk()Rjn zoRmuVa%9Npb)Z^W^O2KW4LGxZ| zpalc5t3NVu?+I+2|u1UK%Dn&m5>*l1F@6$=;!Cb+`hO6 zqm0OY`fIq$uIs*Qla6_h%qVXv2f)M4q)o9az|Ye4_Q|s{1GXZPPU9Z@zgR@6( ziQ(hfHr%s8bYrtmo3P$+-R-Z`1RNI}t+#QPB|C^LLBQvf`K z;tn!DR0z*myB~r=b+_Npu~iZW0vpt3R30cxev0k-nzYrT^<1Md=QpepW?5i~n{O_B z-1%QrIj7f5E3Ci8asV4r3@I|~R4hpvybAhDZ_6^GRYGBx8(xQNp10_(XzFFZz{mwr z1qTgE>p47r=YSk$+aig*SK)#_r(hIc8dXBoY@**95L6aZ64Q5FTvmG`LY>(ftw6d% z%}RwmpcB1tiWxiG+$JhfsFb4sg;`e4r( z;VHrK9wKu7-bEJoAmVgBbLkcmMR-KOAaUnO5fxAYD7&EyS$j-# zwYKOB3=)(){z95Y9M$w=7Doqj<4IQ53repLT-gO45`|QBP3FW?O*G&?YiKd^RkfNx ziUMg{%)Bs!e)obD7&oRERD~HqUe3UY+!*YtQl%pV7NkfR&Ik&T57{XJbc;g?E-yQV z*DOLrXLX_E+>myj(2d2>_Vq7t_?=9W=PB~J?74f#{AZ@t2Rbie6>2j;)QHDO`2{#M zU}X;hCGmH>dBv*dKf*I+29v(ctp~mknl`1KdU1$vJX7TCBtQaVKw91_h-gSG{o5F` z01~I_bLK!@@e|%1U5;OkIP&NSv@eAMLH`C7sscpB3Vb~i@wk3@S9yd}dkA(s7!Lhq z!nOsQJV1PFR7cTB6vXH43{U~mNl;QRr6ASybEr?JhVyBOL>TlUc6&fT#66BYQIFmO zh~wB8Sb7o#zX7452}-ps$g0S>yUlaBVVtxKsRNAmOUS?kx^1D`ja4f0~J^dqx%^YY)*FeM$aw$tjR;Z-TQJoFgM1mf`J2 z=tlZwvu@DMy(GsExTj|17OoBC6r$O(gM1F`*?N}9p~PJ=-QADN@zhD4>wf~cgBO0G z-_tTC9uMIAz#~&GvFWS0>6g{Di*)eG$c*aRz^Yw9Y!;XRyuP`S;z{6a=4BAwop*=> zGSfVS)%xjO^Ea#;iijRw+UmF|Ds9u^%|q3#pWzjyYNLOdnUPoii_SS^2Dw_s)*r~2 zWe~%(2x;Yrm{s-uBN~indqYZ&_ zCdge&#eHgJR>+j4HQUE`OQ5{*ZmYu$)zygSt86_y{xjvG($83z_r|8(^tVR%yvKi8 z3~}wZ(pH^+BDk6K4X$sfh_C1OeOI=ANVwf= zg@$G#PN94rF-?x7vuzZKmiB>2cP1}71+fQH1Xv4q>~UQN!=!Zt#Zl?7_s7c<`-ypX z_#vlrHem|O<%+z~?;9rVr2jGAy*Aq^AoXPxI=_~p@QxaA{L0w#d7!*Y1#_)SIDMHF z`0zNfda};&?RM4r9J+RSa_^{|&vj^jtfonIRvla(vJ~AR#_!&9E4mtZ;x}o(T8iO0 zvF8MZoR>JJVvGy|J@g2jI;QzbqvHllD*H534WabsKSSd{I*4!kVcRtW2!>lPnr)md z2p4I_vU|NMvkEL26N+^xI~YWrNCNO1IZXBdO(3}{698t%HU4f$%%G`Z>sl`ID!+X~ z11CGq3C3kWaL>ofm6*{yW7P(=?r2GKVgNH(TO1y!N((Ir?_wrR% z^y9{xV`(|J-4iJFUN9u%xSVO zW|?NbS66=a{Rb;I_HtnRYG?$7vjw6D9Xuq%{6ygL=g9Z=d8UfjsSk++B}LzZF%2dN z>3bv7@>`eEWT|E6p-hCwV;^h|x;kk0eE_wMB!yP(X-=i^d6^T|YMN90=9i~mrYE$2 ztrT@d9(uspT+!a>6lB3-Yn1+=%E5{qdJx3@`IxvEiW#RViGLzN-f>6dgSbBAxTGgj zWOrcBt0`(}8KDH{Nyc@vb@E%uB#1bIBl@vT?;qPPA>+8|k0)8E2h^&iqAQu-zV0Ts zu`mGzza5lx{s{PpKu#>-YWUmdXQCXw0Y!UWprp%5ck_4OQFNL~sP#sTGluZ@(q-RtZF`o;RpShv3Y+ZEh zTV=u-cl>93DQa>BxJ^2vs@m4)y0oCW!B!x|p8B^CS~KM(R(JA~wfms(;HDBIN3oBq zc{2H+3t~hv)>idEP8zAuKQ{fvCxf7H`^~6X1*k!WO0Ri|wX$(#xaF`7Vj^l;*FMWq zPVjRl!$UeCE3U4BPh4U{4~a}vfS&b>2-f;F& z;|atj{I)==oNWK#WAf=XJpU3H4m&Avtl5Wgd~IUP$TCY-(V+U=4TSQxIz;$A0(*E; z*oGDfeWEUe`+=qXNdQ?uS%(~}$g0N^k=B=qzD*L?Z2vqu^^gebX;@+?O>Jx_jXLpR zfeN*y1FAZnjH+m3AbWWHc|r>%psL@q_NEx1 zmoVSBi3rr)9?V{mi`(+r|8PGZa+uc!%wX_)d0J@SaZ8(@uykjRwdjBBfj!O z@iCP`Y8`-cA?YhTf-!l~ z_G>^C)V=2E*sMOb2S0nart$o%A|)qe_n;G%>Q<>+k8e+P4i8nOmUO5xv9epQ{Hn@M zVq9|USlj381StG~^Y%gd;R#Hj`BRx2zyw4A4VZ!LH;}m{hitknI`}T_=e7$SO+P`l z&Y#jx;|JLIc+L&Je)8K^%#uauAHjn9=sUix^sWh8u{3sR{=e5-fWJZjQ~?5# z4$m)@lJxXZD}k7+rRaPAkte_xN(0Gs@Vy7?@(<+gTmM7ef0aN-SkEYYg$acR=)gjR z&fYy0MLRDJujpvDN$9MLWE(%47OA;okG8Owzbto;;mW;_DlxAQCJWvK3tE{GJGep& z2;F8I7nix7!^%=1OjZkAI8xck@#=XvT=(l4!#M81hz#rI@pq``%BG(muxAA5xluB# zF=rm%O1#(OEB^iGY3Bje69X7&iLHpo`1lR#6CNlHa!N(YqM;PJFDZM3KURO6)vkSb z+nn7GqqItsCB1iIH!Sh1$F`n z)gzt8AB2f!Yi3lVBEO3ce^5plz-Et1&~0q6s|_cq!r0}@sqB1?gCCecg>>-J<=uuo zJr^n>>`T076c7BIYIyTEv`;E`XoNKrMPt#g<{JahMzePtz%66*RQ|*h1vj*bsYA_U zLg@jCyRim4hpx*Ki2gzeH*6=kWfgU$GxOk=$iv}cw-`=0P3tTA&65Gku_Jw0&9~g# zJ1G0Enmm1Q(>v>JT)_sA0Em|=G=Ijgr*Hw!!ZR|nI({7(9N>q2sC0=xZm`e!$CV&v z>7)bqvb|9GbdMQb^Pfk#E`nA`9||QN)ru;9H4>J}9~hUV3_K?i&XAj&VFid^0^=` zK|{UNI8LOI+G>YM{2F3zcbyWn3snyF?7-5(AMAu+$JJd1k5z-YJoZmj?0h^&NhS}B zH&N=hbmMrMHk=4Cu}G(q%=O`pF$?*0-`#<}vhDdN(SRpsY!7s>OoyteftrxYB(z5Z zkU0bnNXbB8e7m#;Zc=hX{7h7V&WsRWw!pDTE$Ust#Pe8qb?9yJsive&C&C?vOEa_d|NUm*2;8DA7N9uuj(bT>O#&so&f zQ##iAYR};XYmdTms7>#@a4e)2u4hy5f0K1DW6K z3Gri_$?F;EpK-73*+{!Bl`Zr~T~f`}lYb~_6w(moeWj?X#=vy)!ouJu%z|d+!2Y>M zb-0GzDVGu4c^0Xw8XuMufBTCc#bFnjLKH#*R+$PJ#^%*)IIiEIIQ#*W_bR*zt97Vk z97qGgMWP}Yv)WRJ6xXH?2B5!qy!Ls~UvlFO0Ky3>AGZGpGj=g(=Z8Px+Kw(D1hl@AF=fsG5_LQGg^4<8<2q8FKR8Uy->sF(~R{r!vPfu5FE zP3U~alyLn{^ca2p3Tx<>_O_zw^FNb)~FT{(qRs=GA3F)#KBaFC^V zcn(n-mk~j_FXEQDY@L-{Jr8j|px$|&og$xF4?6HK+D^W`=Rs`Ww!CKb@h-orXY)nX zz~=ZP$h*TS_ev`A0e~5i;;lly`GA`=Z4V`=Upgs{g$jWJJBixM_+^R{=C;s{L! zN*hvjT7Ro1M#k#+|}O+KFWq{hn4-6H@Rl|sZ{^voaP<}E#}&0T%1 zNNZ41;MChSe>UrTmauv%V3N&BX4ZE--Pvl25(POtFO>eV-Cct?#DXHaH3(Se!2%ZL z^N65ENYlL&zoHt+6o*C`Ro6zeAUb)(DBEQOKd$OOn{EWzaYS#;C<%$xmgW~C6yfAy7RUMGp|7P`>fPII}i+HWTo=-|CT*YOukl>zTEHmm!s%nyE6FhUgWi@Ke^v zln(F`&utZm1~~9h(yI!iU(es%!T%OT0{65_d$hZ{3YKSZ7ZB85Zz~{2p%U1Eq~A%< zWH%Bis^do|5h)vX(sqD+y3QsEZB z@>(q*qM6vpUTt!g#bsq&d$Vph@ZgPkIERq$XOrut`ba!`_BEMlV3NHs-#wVjiAg@B z5J%Vy??}ClpB(znPg`x)vl)&5IKB&9f-4>D2JNN@4b2;YlU705ubB#whPpagBQLfQ zR7kFZ#N50#5d?vPTda5`j*k6%$ByxuD0QOXy#G8IJxAO%gpTBpD|*05b5*2SE-^r__Yw}4ci-83< zQHgPd_8%;ixcz%Q(F?S`w?oVJ_L7<_wj|L7oNfloa_mBNHYxF?pF@L(b+Jf;m>yF{ z5|)I*>zFA8#H7koVMWy7!_xfq@rQN09V(nOiYL&CunwVo@*~CXjKI)zm0}@IT2mL^ zSj!n5A5=goc``no!RViwOa?3)^y^X1d$<92GN>|&lsUpl1!DUgX1eKKjC*{`)o6Nc zA9m&i6}&PCBvT<$c75^GOfe*y`b(uEprm(5ufX{*05kskC?CXwjjWUbSy$fd zv>UE6gBqYv2GboR_bsSH@x2bc}f!3)+*PnB>-5!dQG1@kQ+*xwX-hOaHl(EhgAOc8vglKWuUy%V4|H$LAHz*mkAK6KI1ClYh*Cbd+K9$7Rdycrv-YJn)MUThoPwO?#BMLW z9s1>}PLfpIkcP0Oz_c3a)#TIs+SVSsiCpR|Y=bW&wSl&1fcnfM};OTD+*E zliL6?JCR8~H(&vjS29?}+EWp6+RaLda+5wRPmkhoB;O50kWC~-;>F-e$60bK|7-9N z0h;e=N%;LXw;*7N^l+4dbOd4u@^TzIdph=rV0g2khbMpJwby!wjn{wDbgC>645W$$ zO(4w$Ieeph!d-j;nwOr^S_JPR$S*) z;d%*4$M#x$2XCjD8HUc}C2VJ9q1fa#y~NzpD1)pJS!oP=s+#!#)06&=reBA5&Q@67 zTR|MOnPFpGt3OCR84Nj@6I09OUdJHkCwAg7oa2-nN-l-dn-p_=vRsWiR?wLL`sq-k z><8aK!tNPz@2VOw_J>knm}-zCrwY7`N z;dCRge2d<@zd^8@i@^J|*=uf;qOz=H8#8z}u}McxC$s*AL9gdxO_m}voKsR#d?CA`1TkiFTZ1A7+3R~K_)22gK!g0K&YnUU6a zOUlYQxV(LENtt00HzWp4B3QC!K60XI1y%lC>@~aRR#i<%+%_}tgg88#bz?A=xi{>-(R8| zDs%Y=v{SZtJZ}qlmuyY|CbXWUCkY)O?}$0*%9U%MMrlQ9;8957(%7^q7aWbv2&%LRdFyv%6#i zDnE01s$7{TF^VDRhRw?954ogvH$?J);D&@IAJY%Au-Y7A-1~zj5Od7713pHzb0U-~ z_taN$g0Bn$97rXli!9g??ohhx!0S21WJ!g+;7|SdB}4~O#w=CSJ9rSAdjMiaUAufv zC2m{_kYB^Ka*kyFI=b#&?7utwYRuflb+iFTdiY2-zCDio5f|z@;j2klPXh9m<5jIc zE3W-GP|!eeaEQjH1hn_EV--oQH81`o%FR6Ge=%G$JZVrMYX#iGH0(9!f>ETmQ#I~T zs|MGVxf_;e59d`zKUu+L#oXhP4mfk+ZpwyK0xbPfC9rS9WX#SQk-MKB#~>FLlyPMT zS>1-G_rLzO6|k?OxEc^)%ws?~*^^ve@f9*v`TP|F9557rhtcOC^ehJMY9H9icB)RlwF)9+e)&PD<|J$sahodY6mvX& zYZ-BSYuWj*BM)ed;gnye17YtEV?HC0cL7i=r~X4B=!fnDOT=bZVW;j+B%|teHw(sd zhln!kCMVgnvCL$jl5)U{BClhgY2rx zT_3c&Tyl=D?gjCC=X zbZkX>*gKnC^-o+s+~Y!(Z>~Re@fajN_AuH zSNb<#F^Re`_t$($AEz_T!8dQJi>li}NAudl2WAiwLfz|HZ=dtC>5z4ZG2}86VDOao zvI6DJSrcxKjsv#mPs-O(QhpkHTh|4{J%BJz)QSs#rDC`&ja>W<>2rqN=iz>ykv9~e zPtRW}D0qJ30Yv5bVWiYkOWZH>9lZ>u)#PAx#h>miNZz%;43`~28SuLY=hBo`^ODe@ zcnU37oX)vgpS`(s?Pe9Px}K9QseArMi!LAG99iTCYFC+5|1K*jo9`H%7z?g_3J;qG?Lt^NY{T7eu-Mtq#vRI(w~s+yt=DI6}$nth09O4aoc1 zS5nWaeTVvXGKMmsJMhN=L-KR>th<0do>Z522%{qn6slbjnju5-^{mU2NuO*iQ z2VpiHuWs!J+|cQ{A*I_T@OO?2LL2E^`nK;3Ehan*J9+X0x#UYp&sb=9C_jEtFWv75dKY%?w<*|Ioxrq;Mpc)sX+#tCF|-ucE9sQz)08Y>aTh0vR9 z7nP#;ZA>J5{_ukdF5iK!eca^48$38*X|spe%VcE@ZJF3{LrJr<~~6mP7xOzyDv z)~0FQMa7?8_?0ojxD(CAn-$7^zO#R&T50U?g9_DM0*^WR*;8w2J$oA_%4q1z6 zM|6pgkE=*!W_#v!=CSsl7}g=|6WqORuMB`yqBwhx8l#I&RYwMWb}*rn58zgAi6Ysq z0TP}Op;s(tE*(p{O)dG@l(6E$c%~{nG{QqaYE?evHKhxq>NH*iCgZ#0R>FPjbA^O zr%ye6bXcyzw5T#w!7m%KW;wh*K=_K9s(hgt{5B(!bBFxV{nqKJi$8AF7+8K-Sa=;w z8PM11yA@Ti2D4exy`=GZeM-2Gru(5SQH#w;{;O!!Ir`KRVMb&C5Nmwp))duic#_I< zMNeWCDBb6HTT3|Y?5`WjjNCYkSJucZdfDh_znfspyeeq<0bN9VPPx2Nh`Te$px-E}8yzN`Dz~aU%$T zgW=v-3&!ON8b+FL&4f)XwZ-`0;R|bVCVcEHML3hHQ^nEspVT0i+(sFnScXO&@7(S< zI1jHuXB|SQ4@3%W@L*(x${OlqE)*%*@a$X@@mRSs3x3MV^G`}ZgPY{6_qvq~w#GjNZ{$i(lA}_>Iq6kN?g0Dt3tD z9unk-=i@vS4Yy-3pzUSGeGY>brD<8)v*j!gS*pdXJi^DBW`R+Jx7Cx+x9-Q8+_^v- z#mczfOx(>^Js}-Q{l7CdwjJnBnO!%1$VXYvhzzTl-k;*N+w1d4>)>cc<^92D#chqD zi&|`hvGQ~3-l1Res&_;;@Co4i>;38a-Fvex`h+!3KTmHtwJXYRM85|P)#oc);rird zeNI$kp3S+%HQ~L%PMe`$b)4(je{C_S3jQ=q?%t1l3u6w!4n-*p&7ZcSQ*N@Bs5^=p zHHuFBsU@@a_EdDt*I#FYSx~2nF7rufNWio^uiIF8f1GQ74TQzJJ4= z%la6Z1H?HAzP9vWALrze4V0q z$#*rI7ZrDfMLme2nTC2 zW#c}a+CVI_7%%lf+ar0SE^hhn8dy;cL_+_c-(hUt!8UmFKS|^^qW*4@h`ywhxBzlh z2ADi3w2O+veHV3qswoc5Qxi9T8UMRKqt0?|ULwdQ|Q8xZ#6UT==E=fM?JywZC`SEPj%zwm5B<+D`8$}ak=*l z5b(@X?vgChhgzLI#6FMjbghLhnLbwi(O2)Wj}MG)u(b)8gs;qr8o6I#6R!F7VD+;t zmOY2`1u>yj3E2TpB_vY9ZHmXrIC8RaapB2B~_SDj38$Z&I za?7JH>teh5`4eE#`pTl51sje!_g?e^3s*3?vZ5u)*5^gAM7Ys)R@!`wcZ6p09(JKh zOi53qJBc|(UFcFwxG`Sw7w_ggns*cSPUFQ*dtqzUH+oqtuiMm%NNEd~cLvbBQ<>Kz zC+>CMZ-ig|f5zAdltW$&5_S4b#4I^m9%Z~A_cnUSUfx;BAHr6)Wi@!!@_-l@5CZ^swx5Y z$G|;KPUBF!8c27P))(D!@^|jVvh4p@0W8+2W8!acCQE%0R=FmO@Jo1|-sI zMtm86QUXThxe{JPGD5K{($L|D@ep1AS;gd1Tx*I?OSI5n3KFJ^Xg(0!9Qr}ugu}!L zte))BvB`TyP`LafntffK&vJ2MuQxjO3lAE~KkB*O&v}E*a`0t$>aPb({>8SuK5{xU ze$%ebqg%O^`m9~q(k~MYro!SjnH7WI7SrV~U3u~|DgR^TsfSm*a93po%vb~}!qWb^ zpwir^tJnlkh@-hWOxNrLr_Wr=$~k8Haz4vT_UtQnF(LLPkn$!R5Qwp+md=>XUrPD9 z8UM+%{nOBXLz^0;Tci-?U*Iy!5*gs`E7{PS+OW*^f%;OwVp+%ONF#GINZ?8lB`RTX zHiobFyj{lQ@dI$C^epw=yO zPWM$Q;air$dS$LEDb|ZIT@LFEgzh>I&(<@Y@1q2Jdg#16JJ-#Hqiv2AGcDYNY1ff7 z{Zjs+zt))I8MG-s!@JIsseo(BU;Sb2&j zaks9lGN@%m*9ZNIZRGx37HZ0Ma6Yuh)d$^%G)6Kgjc~fhONyYNWpfUZp;@>rBn!3{ zNJ*iq-&LxuO*mimuAj%!=$m;%ory;ge!ON{#;eB4KOceGSJ|mJl$3eadAX=WUM!p% z`|b*Aetd#h;g}3NnRjVp5T5E>6-GTQ^mQg5DaUXab2e)OlSi2-P2Q#Fui^Ax=_?u1 z#M_fC5cuE+pe=#Hd-h>omZLRiK8k8+^ex{Y1yX zFYToPqg1KbdiM&Em1`T-4Q{#q^YC%kL28jihudFuKxK{+G!3xCQVn{TLe4OscpnCzJSxtFo*`GCTHC_Vl3P*{VLO4 zc(thfEkilK@RQ|BlR^xC!n#wn@yUF$rfZj#sfN@4K4kbl!(S0hs`KZ#APr!zSNE&FR?WNuIUUuG7V}CMtp5SL@ez zvnwapQb%|i_7ZYD@90C%JuygRe1Dol=#%$*JCVMRh0kv5Dyd&^N=y2DgG=AJT}2>9 zcleaC`tn^%Mz8;@OC(M z*jb+J(EG6B<4x`xbTa+AhL``x06s~2#Sg>p0`*vv@@VtI+7*k=xBPp6(eKq89mbz; zL%VDfeZsB|DhSDHDEu>EdALynV%PpvI}=dydjU24(-vDKN~FsCw)U<{0lST@{n!H? z(8DA_!{}9Ls$4AGbuOkEPvHElW>+svtcO_X=o%!F_R+XZNa7-<<*|Cw)$_vfDX7e`VKQ`go)hbk;8D`esf1ofEGe_QT=*Z-l zd+A}I2H`DX?7$^&MxQ_rGIJcl+XLQwrEtTS^u%-^)3(wSux^@Mhv6^7OU8_vQBjke zE4%S+4*wk2iyw|p|Ht0&j|g)A>-g-%ZqX|Ldvn=8$)O+XNw10g*ZEt7vrqhcv->+M zb^kr##D(6U|Kqf@3k;S1J)!B-v;Wxcf7yq$lcYp!QaE$a{c*Z(G)^YJyw#yB#lusY2@xzM z{vz3>j+M=Hu5DG?^cbVa1b%Tpt6s|Enmrfg*SGM)t_50^`vQ|8iQRQnkN>>_|^Rw zSHE^6?^5cL!rJB4o~9I#Ul!vdD2I$lE6oeJGsQH#_7hh-ZbwlIkcf#pm8ijMrYQ$y z@S!`O6}?S|CD8=mEkH$7yaZpS*}>=*Y2BWBSB+}BaSQ}ovb*zYJhyb*G3n24KrW;E z2%a~tO{~@q;6^W^RNtxI_%!2vJP>Swok|o8l}_ka172__IMEmlnk}4BHDZI))?wbh zGGPGAa~UaQi}-G?Kpz!~#=pF9tv@0-tJ;_Iqt4 zxXoU&rR`HopY-a5GKnZ=1A58s6ZmVr9EugvXKeAvc1QbbVyqBb4q3yB+Oaq&%vjz_ z6Ajj62;F!ncyoDZSQXLj{mRE^I=+rradUx0C^NiRTkG8Co%ZyVX!QQm96YyN5QE97 zJJeUO#Mv=A<25b`cZO=(v$_xgKX)aG7F>xS_B9FWE1B=}9$(D{YQ^PhjW`K`yT zSj|zyDC7mN8sc?nR-{|~iIbk)cu>W^PJuWdUk9XId;a|qw^6cklCa;SAG#w~OFUn9 zYxO*T%m$|RWXjH&w$Q8YdwKC(%&!p4TE5vdb8dpaq0lpaST`{G%&Q3x`;=8o7fs^I z^35qhOr3aOv;9qEZ^I!wp7!je0^%Mjp5XQ>{ec_$t~e6dG%@UBV5sFDVaxUn&li~H8FoJJ}ZW3=MEsa&8XGK-*Wo%DtW~ZP-sZ) z$aWXE=^Nso;XYK-LdIG#ui4O-2W5jN^M+d7p9jx!x~l7NdtV|S<~>(% z>ZA(?bxz837mt2W)}&1)9C?q(j6BqES+$dlkA!X#BAJVrlHr~Z`**AHpTc%QT9`ENBX70wUt5-#~LZPwLx_w89-J@+pa73sZ zwURpAhd2tPxQx0F<8S=-xN$f8Xv9mcGSo=Q97XZXpWWL{C6}o#A~XL zrz@^H;4MGAq^`kOuf4m-OO}y6nfJ!9`dh9mr|wC!>53F~|55lZs;QnAepT`2>Guwj ziN;1LC7w?oy$-uaE8=zU%#A+FoB3&?X3IZ|FP%y_YrOLQociawdwPnGO54L9v7hE+ z$m`@~4wLatNcJkWjHNA+I&+ufUVQJ`J(R94EJgo|7R6n zyDwjMzM;h!O_TR2CNKHn>T|BgDgPf9wn%fJ0r7T_8o3RM=;b{x_em@;abHE;?nxhF zN7?6nd``^&#n^ks!xi@JqN0~5At9m+L3E;bgMM)hDO-e@XRse#&`N z^+mj@jbL8PKh@KB44)K97YuRBFKg4(W+8guN$8nqMG)Sx{4o=g2WN?B? z5MP=;_@*p+I1uB#lnqHb<9AB;MOy@zN1PR8!4_(M(w#>^&iJox`oacH@}QoWTy*O} zC)4bg7jJQh{`cGW4<~Sc%wu75Fgp0ht^3GdaiOx6iIbW{$!gd zP`-cPC60h*Zj=CIq0v0>z}nB;?7tCq?Gan;wjp>q;_#99y{8b% zewC3#b9c(k7x2<_0Qt7EbNh!QXdAgCt@h;u1Kf-`t=-CX9p(tEJU=8{T(vhp;4Ex= zz3!AVS>D!YwBqQBy6DM*-LUL99+xFHg|anZI3``$z4g_J*&l6unGs>NA_`VjM&Wc zR8l!gbjhDXmQ8Um>#m+dt=N#mr}ls7q1{aU5uMoVmM3zOaoa+FjA#e6n;!Zc$ zGYcKtvdypf=EOv1SivKO{~m0YY@x_~3r(`pM4JXu2o}!I-v`ltEhF9dtzUZ6Fp?{{ ztqa*=j(GYeUH>_UZmDW$k@>$gUPStC?OKnX+X|&jB<7s)C--R(1Ao!14u$eO(C9;7 z>gPO+M<{AsXNRU|bZln=6XUV`a<3n2(%_oQjLDR+E#(W5nq_~r6HQOxh~vG8MV3Yu zCfIcQw`8~FY$UIC#xNbI0~o!P7JB+2`G-)%hl2eP-`)6JEt>w#Z<^kQSohE1TH z^;sWsi(A!+-(N@Pd@IIu8{(?Ob-d*n=nQ1WiZYbaFpIh* z(6KzI_+TzFl#=K$S{?Vq0$mLXtG#k#7TvM_y+(R@JA_ETnvH17Ja^=(=jCj_cYL`v z5z6TL_|K;^H2_iFouZT7iKjY$Bn~hn?~5$@I*a(BYSYg=m#goC0=5}G@hw*H)>JCV z<^i6r?{4aTQyV!bAGMvSk3+kPN~n0BPQ8weX%la2Ke!Egrq=lR)V30Dv$FEx0mZkd z)0~I8N?|c$x|87Zd^*&$$4iYdba&EwjF4z9j@phzDx+2J&-W(JyIRLD5h@K0-+`Xn z7SdXp1y;0vJHECBOI`0K@YBufsmWTYT8#7f6-*SPXdvFhO7yBMlf6H2GwD<8Z)&U6 zeAW>9S`Ws}DG# zg?OnphE~*2XRck)twGc%(z0-2f2d{KeM(%%L9!kG3AjGa*uY7drr$x6T3to!m!|!; z=8`!2Kc5+>=ICRQwRjg8ra<*8)2=?qNbuX-S{!|CqNpdII+Iy^mTC{R4BD7>Yrni!ho!&g7>pzq@<`s8Z#xY-qxVL0 zSQ5o}XO;>+uLdn;W>-`om*Jnd)Znsso37zCI?~oj9b!oG^Gh2Cf499AU;lLfg_ReT z%M&zk7^8Sa(-xN`I(S{R4yFn$gKICZv%y!!P*!U8os++ah3wEvCX4H!@SW-rFJ8Ht zJ-*HB*%J7X_xRSu=hq6sX4-d{EwS@is_2O&7ptp{c#VJ$hhVW6$qzGB2jZUoW(%4r zBncfa?XH1pQ?&oSrrP{RnmGexdsubrzi_U@Bcz1m_QW}K0kLLk|l8#=q6 z6;?M$gP9xnpM{!LP|jSTH(J2$v4t^5i1m+gVN>I%-$;vaLaRo>IQyo3TxX#o?{Us_ zmH~}2a4B&fI)`+ZaM}zjxvnrcX-m1t0Z_fyHW6Slq6bw`D2s?!&X4=jdg3CO~0j z-@oUG9;<>Yi1~cpG$2n0|H*a&9v=RZ^}68;33k>Kcg=yeP2X7l2#~9jOUrY*jXrhV z>r#8~SXi6FD&$q-MP4KUtTL!RG^k1Uha1y_KCpMv&-Ds7*LaDX!wc3vBidoy5?vDh zA!Hxj`QM6=N9q+=OtphiA8w!t4;LfmE9Amq*n#ljtD=AgIR=h zL%{>{Qqw=hG$|7=jT~DawO$MxeL4-h#zG#{lh{|PmZMViH{MYT6@7hu+}b_<@{iVQ zZ?=uWr@7s?ebX##*w`eR{*z!jywC(!fKiCzj{*dG zJPeVM?J2vHUT>p*Fn@~gr!~JV{%5AvNbmcXUo>1}Kst&7i<0zj4x-&8agQ=O)h#7U zZ%RJi7op8B+wxNE+bEbnjHP*0wx(4Him2p2i`nGk`Xy8>y*X2pSSr35cA#O;I_87T z*2I;wLutb+@fW=7{UiQmk?ot@3tSa1RgNZHL)EC;=-ZiCxMLugQp&BcsX>$5RcWKN z+sY1lCFC!ibqlR>`EL- z4X^shQ49AH<%&uk?`bwZ2T@wMP3y&Up7OGKE;k<{j;~>*<-E7v7Dkcq@abEvI2Iej zHOXJw#*%;Ez-1%1bceWqV7AoK$I|R8HiJ`22DB3j_gEly@5Rt`4Jht3r1#nOSVQId z4nX(HR^KaC{o{L?eR;4@@`Fv+k6UX(6SL#3YJ=gPN6nc3+=;vtGd}Wc!KmZ>h}P*q zZ{o@rFS-;TA^Xm3FK^-xGPc=B3$`$#DeLoIpz~CoG?CEhI1`5oW)iH;kK&oIe9X;U z-$#;+Vai_yHHH84Mgs>}7PFV8En;4#xKh)P`;ofLmS(~J7q(m@J>NXsPG&54DyiKz z5%2%;Mr@i~lF`biB)Q>Sk%RZXqy|_V$z5z(RKNbe-~ZAM+rTMs!T?($e7Yw5K*aK1 zwlP`qYc-}pUKdGKChPxnk}o`134^PY--#?6@zkw}Hh2st`08e2@B%(c7(W#WKMdzE|zf{RN_|2~3O%j`w`XST>5MdFbHtQ>ai3}bJZ7{5_= z)dxQVcv}REA2KlvPpPOg2RwV)@W$1wLXhIDa)$}XRiHX0q`mpv$;J&E&6c0dMv(J4 zRe{2$-jldko#CSJD-fzq2AQt5FVh`b1S09crnC%N25+v0#Fn!ExoFH^Z3b5qKT^k?zkyu` zb?uf;4Cj-I?kHfq?;_()eJz4ap`&nLQBrAN3fU|I8nGttz>bSl>mR#iW6!BuBxdS0 zXb&3MF@&+?9>`4^VxyHlZ-3vFC112kAH6Tn##w}O`Tg6VIQJ?Vw?KDozxA`>dHn-O><0LD z$Kw1>Tcam52tkFaes3u3tiBERl+E;A@}6ulaMMj7`d833qfi~g=&|0B=V6f(=BPQW zzb?u`)R2_=T!QI}wr^M}2X6ry11z_d@(i|@1W;5AQ(X(mZZ#s6eVpUO#n3{^hu_y- zf%}>ET;+*^mKWqT6fJNyuq)&nc{{Vp(u$sJoYc<}s!YgaX5RhB3&^o9=#{J^WzuSJ zIKm;BT{{!=%$vpRpH<99-sf*~Big4}iiwFiKc$8JCc2GSE#&GD4nGD&?g}1m={Pc2 z!u4@9;)(Bx%ij#A9LO)~JN!&;)X5%n98h!;V51;5BWjGDb|mZn{=Sx=iesyzi+8*J zbgpOUc|*f43*GsMma4RuPK^cV{0Z@=n@4)%Jv1h)U)`nLbB~^>#i1dlrs{56zjKm! z4L^VQ`~B3Qcv?#?etNCiHLB-n+@*b`@+AlOzL31tJ(v0nm~lThpCAT9N4-eEw&+uE*^@2?H=m`}3 zwwAwZvuj^P`hLytm^B6k54n@-xPbc7uRv=%cf-wxfSuueeoh2GJR80N%(`CL3)#+N z#K>VZ8dafqeha$}y~TE{GmtpAqH`Dxx0afDn#frRAv^wp(SThF^`BK>uAJu|xw~|1 z39N(pg@vDo|LqO*Pdo88=zYK8CQ2l$8qFwU^Ltj{n_7=dr95UeC7N>aV+@=xgRVVi zb^d5WBDFu`&++N9kG-(tS-AhZAlV%GH@zhr3Go^^3r?-1`G#8vpG8<=&!*^yyZ@q~ zRvX5P4cmGWd9@K);CTOG3jA-BBM2nRr*vKasOo35#Kl%fbH;vcVG9oV0Qzvnl#`ig znDQ0}WCqk9VI!54TDi4?tvm81fYR~t@O!IELg5c8lA^}!LBSg8~QxC ztGy85B+nI7{sj_ekYCfqg!{?1?c?jM{a_7dSs8xWom5p_@!vx)h=<8JXS9(( zhL9jPf@lO>6wc@lt7ml(+#PRx9frPpo-nvCCGdFoh>2U*cvpd1Tt}y>$wr7%jLN04O{_SP!CG{o%O2 zNJ4ki``vqF0Uzmt1NesY$hgB%5}@Y^tUi@sPy*c|Rl2+ly`v;b!~-n5#hYTcWl9pvB~! zy&-q6OBZ3rrnClX{E?P_)_CjH26tA1(hBFu_C$ej6lMA+ca<@XJcU6CBD8@v@i6Tz6Y`k&YbQ}=E$FHCmi#xx* zBz5%q9tOx?o>SyTdm-Zw+izp!$DNAm0c^+qTMz{gs`{GT5eAXR3}MX`D0 z#`ONkVfA>ZO74P{u<+l0`So)9{HMw+Brs@c66+d2Eq*)jA(qbPQ#+?0%VeQd;Z2LIJk^h33Z659{ z{qbQUjmqgKt5a7=E-n1WZ|)SS41+lh+j-h-3}a>0Uum}ec;!xa^dFkxc$aEjbZ{GX zJLwcz{APU3Q@@O;Cs5>f)32n*ATOLnJ(Cie`R-s#^w^1~!3gYN!87}VTKd*J#H2N* zaKuCQ^u-hw56KM%^%qeC%xdcd0klpaBPT{xSMz9@t8CxUKSuU<|CUbU#SBj}(%|r> zy0SR}8D~?bYz|o&%n_`aYJ|>lHaJQ=F1opz+Rt8mpcKsLx34L=(vBm?lqO>F46x4b z@r#PldA!f|+{(y7ILFCe-E2rUekRMS$a2yTGY^{Fy z-s$1qoNW!|T{1|He#SeqU2eT9=!1J18!0;@P@)%qe(;Z5ofqw4UIK39g?YBxiQ41e zj2q`i)JD_T14MuK1?JS%2=-hKig(-TzrjEr?8A?Wml|=8uMG0qR~{%%d^;C-#cgo6 zeThmK?<_u(oKf3D2jewV9>7 zu7;`aG4WAJx$jy4R_mA} zO_kUbcGpth1|Mnv9Z{*SHyWmPYYz!vO&x5k@xtUAKcgtq68J{j?*YYh^-*Vlj;8@W zyN?{L%dd0f?o1hC-{j_+AMLy$3E<8f%UjN;b8d+J0v0wtC6_}3&gNv#XShHwwVnnHC!ZHmsju-qczHL_nsi{CF_M}?s&4~`~E#MDPMvOBgr z)X0EhYkRVveFIiZ2R@hI-GSoy`9zBg)9u{Iz)pk3G0RIkFD+j7Tg1%>tZ)M0(jnJI z$}IKp)p>np$1{#+M6Qn#z>f3pn)b(;*IZAES)#hXAa%zL+kV5rAn;mE*A@!9 z>G(6r3jWErmZ*2IEstjG`?=ky=v(JS^nWA`FP_{Fw2+kn6Zr3Vx2%KfqODH;ff|su z>d)T8_?4RStT6>bJPGu3Om=iIVOZT;xVnmRHc!dhkCs7SPcs9p9u_?r7k`mtsi2z8 z1OLyfw~*a)NOkd-Hq_z5b98C-@ccW|C=sVviX*U7g@9+#)1a@Hi19f@n)gQJp005Hwn<)3d^-nX`P_h`f% zSJ#xVuloSuU;5?F;hvUK^~n>on%JM$G{#={B>ia*S_X&3%dVUs^u4zyHEp{}NVMLR zTu`XmjbYLFWr6L69T2tv+B9Ng|J(nkJ5FVY>h!U8`DgC$=%dynQ^}j|_}%SvbcU(_ z%_F-RGUt^1`%~`ql!jB&B-;NNRsQ?y8fxyOLn-~TI}aKrj#oP5a7JKN|3u~@*YXkI zgaO%|MpHnYl^H$JKa?h#_e|~hg*?N;a`VjAIqBkBh995$XcvLsg6^YhvNt8qpZXn} zlggk|q~w=vTLmRoF{4V;Lems@*8}U`Qn(cuw_%B7wAX=1jesmt)}LM$Ioz?w()fxj zlS65OsKgAK%IPI=8j`$ua}j-;y6^vQ@FDF+Qd2?k;PEL=7F zdkd_%W29n#M`4RH z)x2vT!>Xt)=w@rIiyX{@?4x(P?+ApOe7^(V4;563qUUsP-TG?}(0ry{B!^4EieRNz z<=A*W=aqdsfDQahHRAKNGyd@?lqaQbj*)+eM0pRI72b$p9=fTyFMo;`F)o1fSpZlF zyZ)-0M*$_ZC|GWj4a^)#dTZ9)0Rr~qQqjv;kh&4L^75A$!!59cJV(O1 z$;cSicX1W%hia{=$JEZ4<{i{6t4~+9pszo4;sU~PIO`c~AJZd3(FZ8|Dp>E}yQDq> z#?|fHA=qH71Y)K=n-#gB73s8u6n^nQfCZ*={g!7teqx^oM_#%Ir;dG5QzCyTJ}!wJ z>BPWt8klVDc$}QmMy8ZHz%Rg8b=mQA|3nv^9T>FRc6S8Kkh0wDI}?0PjNTg$BsXGS zqYW+R&HxmJ#uR7^j@F>NGIHDsbSHWP!^O006md4MjqSU8_sVv4?hX7l)|AAhMZm^u-GXYM@0K}4fw?75wuiZ z4iPBGe&LSd{(vUE4MoIsemAs#0b&t_AaPajo4#K!znpRg0Tz~bmUqifGmhb+3pc;6 z21t7QeJsur&_`zix#ed^sYUQr%NvDrb6egF?0IPTP#C}_cS0{yg2GTAp2Ao!jh{UC z!ultiXXL}GQMc%u99>37k@`$JM~aXD$KdpwZy%7aSS)#&BG>UBFt|>}3PZ1hCSgVB z^Ukx8AZ9D(9Ebkg15X3yX_l7~_c%AdF|E+BFaL#K%;C_TS*!%f;zC4Ug@QbAWsX;H zt}D;2=3R>zLKJ^x6|o~{s^RCphd11r04#Yr2Kk<=_tvf9#CNBIz!rnbR0S2v++JIJ z+IaBl?Nkfb$R^1IF_XmR9cNYS5Z!^)rFEl~us_mkzQIT@@aTyTO{UjV|2J|Rli6>P zn0p>IT~Sh_cSkTL>Cfkim?{YP$<6rS)qW^4OJx6+fwreaDeCYyWF*&ER2L{ zVmbJql2W{z(1`Ea&j!{Gl^EE&E zrk-@Mq1JX+W3&Xyc;g`AwrF z;&i7cd=tJx8*nA)g{sxRv%u>#7T6h3qQ04?<`Y{h;i@U2UPufsp-nrOB}}y& zO^vhvMIxL}z|rsC@h7v5!ZtHhBw7Rx<4?~2)Gw>R_vc!r93z~cCnldU8po~-V%Ea> z!T1#fPe}A6^cI< z)kx|iVkuzmshsy_AmB^uFjI5=Dp>TsK{{bTI20wq+50UPa##5=rUyqIkzdBu&!WiI zkL7CMln$3LzSmiz@b*|vdZig)uk6w~jGlGbH`k$YWtuJkufNYT$^6N&W=E}8h3s&s z7Jm1|NkEbL>DBT?ntfS8e@~yhtbU`yGmie8|NOFlc2YqlCtIW-C(e`0+d#vl-ogao zf&BY6vwH+~22awp#yR2zv&}0&#a6ZsD*vmw|8o)7sKWK26Df_x6bUu)%neP3hMuWw zL4W1OO7Vp$ucO!1PAK@WWjf*J|mlWp`a8Rq82q)@NW-k*c>KkB%_MOTajUR&+{!ed2KL z2D}+$syq*LU z&Q4g!!1VXKm?K!CrB$v&jYWfjFfYn>tMg8hk-=y|g?7aY{$0u|%yTHmrp(S*Ez8*?fTm;OZ2QO}qkZS5BN2s}T~{{`1Dy+5FV{ zGK6;`r%)%c+T%}5A51wTH6Bt^?3IGV~@`*MF4SWpN>1A z#}q_-&HAJ1o9n2nWjOjI8uoDASTLhb(IQ^z|9I*DJy=$_y|i6J89WFZuW?a6;_{H~ zfU4^a6y&Ip#yN+q&{n%>v&yMyxA0S6rst>!VsUsZ0;&YP-7TtWv(z67Hm4bIiOH=+ z9`}awMPU$BK#AkHD+(VNCOs_b|D7%VXZZaavmW>0zLy5KT~m64=8-_?oBV19_DQJm;zS!~w$7jkPE2IJe_g>G* zCoX3vUociPv1ZKo^Y)&IKNG`kDA|^mxAL;v4CUt>#QYr|cDt5NJjP~cziVG?!X~f!$qN%2v8GVI&Ew^!K6O9I494MCR#eYMPls zi5mPTN_L%d;%5-RwW{I){M#z&?S`z|feB_iq;;|`>+I;T`5-F|)@Zq;k9tVg`XgGk z;;{ld=FsxNQHncFGas~v)+oZijfY5RIi=kK_ek(_#90t`SclD?FbyZz&y#)dM z56>9b>l4}&d$E>Iv=|(;mvlCww&j&$Q@|tC^;xVNpfc64cQ6?d-IQMkYcCs0QWkB7 zuGT>L0su=RrExMZtTmS&ftgoml}HKp*i?hCH|$sYXDFajALaUI_Su+><1y5)`C>sa$& zn|lAW!e8s}ZH+wxRO0E!;J@RI;Te||X<+iAZK?3^?+l)cVWvJOiku@R8He{3rfAiv<2Y!1Fl;* z_#Nq#*pCC&ZeQur7M4a}v3uLUAX3vOg<&zYgJxw(-H4kd*S%SBsZCk?cL3JMsQZiw zNFR@Ivv7>t=dQ8N&^?luZ{i8OCZj;}f0=Gga$#~p89NDf$Z3p5=|!h+8y7aq3CxDk z%}%2v)mvDeSU41KiF$v24|wMwA(KO>!ttN(V3wG8B)a3--Rj2Di|a6ov6KNGnXqo*n#O|1bqxqQYWa{;w>9yJL!P6&^qXw}#R+z#Y*n6NQZ+37?C7 zc~H9!E5Xo@${wN@hwmk1DuK4OkH8@zpb!2}EU)%=molavm{!~UzTw$tODQI-B~%e4 zT%rJIa7^4CFK={dluj7m6#ugtYw1s4j7o}$bNDuq!bxnO;bP4^sM)@I!-a{}@3C+R zgu1gqa(3%{zfX72(m|FgcW3uuLr6E;L;ObCQUY{^KcexnMKCTV3H+G6vPFKG z0EFe6t}?JAIV5}s1i_5^W%~Ld9B=&q^}5cQ(kbYXE;$dn-o$Y**&}oKWQ<=8ME(7cE3%; z!TsYL3OQv#3zWQXYHqe>&u;=u7%4<`4OfE1mNoCl7!*J=Rl>==5qkO-n?rp`U7Z6r z>#aaxxe^6{3G0!X9ygUvMeaLayQ1^$D_V8mL3jbJL(bB#Gl(zp*W&$(B)6Y3-I>|& zIi|CUVT|^PMXx|80{~!Nh@wuD0rTOaEDk_J$=}d$gU{zQ45mpRwFYcmu=$+gsLuCY z5BWX$Ndp3izb)(PQm+FwFlV;&032QG;*bD;?YZ`{ zIhgVSxh^s@ZiZ~{D57!33^Ghsd6V2SI^)#Y&!|^bMwC>baWY}(o475&q)i^9;!>uq z1aI$AyTp|NMHhcJ2v)m1DyD*Ga52M49K&a}U@0<2P8u+Wl<019!sf#k5|k=pFQ|pi z;U}|S$PjWuLn_m$yG7&?*r(E7p6{C9bMe9A-`8wiJ+|Lw99}U5#h<-iI^9mUvOqu0 z__%gFUy|27{rJP#&s!RLJ`dCl5Ng?hz?hEL0TWKJQZ%FEQr!ll2?mqxwkO(~TonFLS$5Hu4(e z7Pa%5?OWO>LZ;@CiDDol;A^(m7Di0xO??0-!*WyBi;ep6`S(tfTb36EY|XO+H9tS{ znzjKy0T}aDCM8AlhK4X~zaS?CmX?J&G$I8OaQ;O z?{PPqztrx+WI9n9Q#yG_tpm}OLTBaqsiToWTir{G-bdvB29F8sZe&_n^-Z5{VMwBV zPm(jh)*Mi^qhz*3Gn?1hFpB(2XMo(`q7g%~$`!h)$KQ?rq`R_P>SzDQ@i2B}u+9*Y zuA=)i+UM@DR%6_tAeujHGFYr8!s;}J;&s+j%@ypawbZ$Bg)K=OX0ZScOkWPBtFrNS z)Wsu2v)w)m^Xi3n*TXBg-zbKO&q;jupATQStB;q&FpOc|(*?Afp!{emfnh-Kwf07|lz@~~m=?NKabyXieli${?E-x};c zKB~1sf}iSC`2wTe^wM@9x1hb0*oNN$;mK3FkVvZY*}Uj6f5e=|aSrOzKN#9+ip-UM z!d~zwk^f`<=eDF@GkLE(ud_j_uNZ%@?@*EA|U#SQ9EH0cS7n*28r#Q``bfdg zGq8W*K5O{fHAS|nv$u49=zBE&q@;|`iF%eFmF2sytg$Yq)JZtHfOuGn=Yo0Rz1|m{ z2XQzfS!-dCDphiBcgJbQ<9ZSS<-~u}CW&o%Fv1zJ>BTo(A<=@2nXXDLc=whuvV&$b zJPBZ669U{1k{svjEauqI)IyowD}=<^)~_oGFCP7*5x57Mdk(`~Ln;cHUs0>P#b2)K zM!%3(oaYw~w|>dNyupKa{Hh7wnXV`pRaMD+r1=UI3DVbKL9aG?4^k_++mqYVexl|?MLaL#uJBw~y#@F!+jyp2R zLTj&5Km8P6W_#OZ!Lfc~Sn8?>kdq=#KWqS0S9umj+Q1>Svz)tehOc%53)FqmUjK#r ziUZ*r9L1;P+s9utY*hV;*l_fxul`w8GkGlhid^a9D;;qtu0W3boIa@Qf2Jk6cT`p{ zfPdlP+*Ng-{Z2y8s)~&7S^CXiZgAq*B8<;XSs~%bSHt9hyl*=kUsexJET?ZAsVx3H z^qAI8>*n~0ulc}aKi(T+yp~JInzNnx=|-?9E!2yH=S`O6BX0)(Q_J=^*hl#t4xxlT z?^KNemvgywX~hi?;F{wg6;gJ4sVJdMQtf}uER6YcwY1*$yYHH0Hic)UR;EGM-SRph z5vsrQ$miUCLZ-op+BpnI`Uz8P@Pw!Rx0sC(+Z8!a{7w{ z~7vCkz_HW5adG8ey@|o28$<$@OAfI+wrq1-fQehYqPMSMHi#$iz$PaWqnofOQ7C-L8FQ30EiToGEA>Q22Ce=caM{MP|hAx z^kVG1MK>cu@!G`8{foO>ucR@Ov^p^4jwSpp6`J;A4QU{YcOnpPd4J6 zN-ym1q8Oy8f!asx8$7@9SKyV@yWc{?9QSEIdaESGB)@IjS~Xnok<#>zs8IOI(+A+D zlvx;Wv^OCB)b&E~tKE%ApOv~CO&eHeW($_YKl+1CDnw<>)aeXXH9X2exd=Qyq^iLD zl;_tWO-v@HsmFNh=!5{LAr^!$8Vn>X8k@qV>au`>-qRP;s%mKuKa8XvOs>-QM$oSB z#EjVgF3R%Z(#%SZe$g1hUEYw375%WY%kS%;6i}$q5_DA9B%r6Du7A1%+1vWtbM{7U zbs2;9T)oiL_xwnq;EIy^GOo9vyY+c*~{m#o`s-G{~*Esv_k z1GmXL1hiPOx2QDKye3z(?#Go7ow=-xVO3BFnrKD^%tYBAb0c52d|YG%`8X=+9GiUW z2^=I}!Ull`vy`y?+q3Uo2Rv3Ey}AIL;PV{3LV~-Vw=nvhYaVvJPhZh1bzScbgO(ov z9D%5rJQybwY1i-2Qh3njW72}sdQe_1%z>37&H0soP#MErf)oH4E+F3ppj^44WFuz^ zk$26N2DEPGFHOl!CDL9Z$5r{YFqtQM?r{RCM;i%7+D z(yc=EJ#kOa)D+2Tkblxo{*s#!ouJL4XOiroo%d&;yXqUk2blYZ#3 z5@ai^wSJ7MBwH@An%kCMedGCW41bq$dAx>9K|ZoA{i63fb3;Q1(QV-M>(c9N8XB=* z5!3H z*^tUz@_rE4$UCq-&ws1u;a|bHc@@B~DvjGAGX9|3$xvATW|#&UrSK7Cze)AS_-&w4 z6qJ^I+%s;H59OItQqlUQ$!Rtc{i*BXc-{Z|M&n`hO#iL*WbuqG;18NuidZZJnZF2` z4kWt{a(Ttz%{l~m4!O<@PoJ`im_9n+ZyGEYe%Q7>Co+7GU|)mk*fF3@yi)c_(VE2Z ztIko-cUTL?{{mtc8U3w4)aO-H{tGh6$Dm?{ z2cLd}c<4f@_Ghz0!_(<>Fy>A$Pf1RK3g{9hbG~ot;cI;fGF7}mY=5h zQ-$B?lV<};U>DH3h>YU$pWBo{RKZ;6gWZj~Q-ecL%^OkohrDku0RCHEO z_Ujhc{yF?1heFadx&->bj_(ppS3@vWE-bn;`7>seW(Hjv!2yRSyG9#?G-mru%?h~) z{zYtD8#y42#`b~TvlNY34;=g_bNG*qSSgl?1KNu2#~yOI&?>~!HQu12&>?0s`7un( zX467wIHCUG2(S=DEVue<+@22d=j(26Zk~gr*{=?obqWm!U$yNeeE;&So-L$29eT(7 zhL7-{0m3rfldaBgc)WTRBYA-J?Xim$k1C4a@owaa3-uo_oGra~z6b6z4``mu>2Cc^ ze?N+E*YdFzV%Ple5>azoQG%RV$^CE#$Zpd#)JIE}M27d^Gw)l5$J?DpkA|H`?T-(( zJGK?A{*kOk8iwcveG>Hh1%EGlM(5hwc4wy3 zzISeyHIzFD<~xk_^<#cm*PE`LdZqAsavG(Xc0L*cO@4RfI3@;0Ut@<$pZr~RIu0}SjNT|^3QYYaszCl6F5WJcIm zy1si$&_+wICLj|!t4Cz?cCNx94G_FaXBc1xN)6}(kexvNB@%Lh<}BJTdLvM@-zd$3 zNy&>guYGiTdBEa@7J=hnxIC5`w@?4zw3fQG-y_I3l(e7b$uM<8D7=5o6#)V-jn#H! zNyR@bUHL}A^KH}qHB%3(YgCfFWn7%5iy|R)ZSJq5(20anSlg>rnt}WqJSbs#0BHnv z8^OxYx(Dr+aoi?%jh#L7Or)GjgU_wwLZl9_!*}8?`e7*!#K+q_JqD(2m}6gEo4FrW zqu>RJ?Z)f1@ORKQr@EM@7ZZ@JGUylnmSb$ry{bXJGrwV!Qa!Ng-LS&lRs2-__$EU~ zUl4llXwX!1A8f=AX{Fdqi~ZL$jekvhv;fhbbqONvyarqTiph2((a&TX;C;AAr|Yx` z6q8DZwDjBAcij1m25vOA1T#mFEgWZg3E@;Xlr(Tm75h#tF9{8Ax3X-8$5qiy+k|$I ztW2uL1h<+-hui#m2%lF5VS>1XRRzk_f)Vy`s{zA@B3XWurC)-CqbD+)|%F-lsE6y40?0I|XlD?o zq70|2e)(Iyc8kBqtobV-cd|?13aj5MSWUEp$mh7TN3C70Cp}@$-B9D$;Ks$Y}xJvx>j0$)VojDR&?MPa;Sc6lHC&ft8PZxLCW3y@VZVl~&BT0lu@e zzhO`<)2)}hs#~vQ1&)?pyE&%?vI}8`Q}@(I-TWMmr_|okzI?{{U!UaLQcQX4p`jS# z-HGc;yS#aW3fIo0X~fT()A(Mtafj4zkBlFDR&>2PDJ%PlUav%#jd?ZmQ8_R&TT!H1 zc4`HiX@y=raDD!cxPN`2tPE}(L#%UND)%*XaDEAY!`7^!E*`$ zK#9p)mW*ucgL$Qm_|sAtkVXCQuz>;gm3y0Y{o9b_`|hukx6v903)$>DjgaG}*XpA} zLA>3pH#f>Ns`Mb=-<5UZfsWH&m`u@?XOupw({LnpG^wt&1RHj29(OrmM{X{f%8@l@ zswK$nKZek6{$mL3@|iI+9H;68?TYj`w!IBw#QWJ-C)#^nTLAmxwE zeSr+dL84nAO`W>vC>@}0;i>TFwO-Aoqi-g`iqi$j#wy9iK4I-Y%K1#1zK-ygUwuVH zW(Sc;|B637NRC*fmi3D#S^N-QZ%c9)q4@TP(5p_7JXn7tzJg@_>tg|OZ z#9yRysYzZ;YVXz=o$z8snCH3Lm6I<8$6Ty(jicXLpbqrzCi26(GAn9PK_jwK7tGH@ zn-NQHEeUWv(SiLV4X+sKiars;GeZ2c(1_CN_M87a;cJEPs-D2C-5tcx%P+q^}L)NFq z&ZSI}kc9X#3mfb0y(|hH-28+ws&!I4JAOt@(C~)>{!J+%pr6eV7RvbXvCL^XPjz9Ja@T`8_ex{oT^D$wWoz?k2JUD45Xr&-jj;-W_fhy{1sv zDfAp!Iv;uo`^#_T<8P)R(MVg?v;5EsRek3EVXb|W<$mM7 z;O~RvagCWfP9Pf_6A-JVbsD0{pH-?%Bb5)Rm4=qvR<*0?ANS`3LrpN^&&(g1M9_v( zor`m#+i}RBvA#-bI_Ybx>+5T~M#H{{#fUDtF z|JLLTA5V~>VqozMHk58-(QUW@ynNrZMZROz`j{3mvgA9#d;Gm$(8Wff*MYD2qZ3=E z|LyLlBgm2BII5(b0CMBYW(}9&m_m!8&z`Agf>hUKX^-4hYKG_cMnT8-<}IRSrg!l+ zk3L6twFN|ItF8IH)6LoqtjFAEAmsk<$b{*an9wUXEGwHw&s_8^ zB1Kk>Fpt;BSAP6oguQiGRA2b^tF)wml*EWgC>_$w5K1bbAl=<5A>jxJC=HSlLnBhs z&CuQ5-9rvJ%rJB2`+LuOo%5c5&i^xWt+n>r&+NUP`~KW$Xon%?N|Vc*PZxU|co=gL zRL4dq_l|J)4f_i`)&p}2Qnm(JE4)7+87O&)JS7e=>bX)UEyfM``POcj0$|(yL6h9O zx~7kG;Zg9MvOgGY42fbh-j)V73IRBUd37G7ht@3p+*Xi^IYgoigRl_S^TN7=LvnK6 zDGVY^46DI1@jqr>{b=Bm>2+Q>O?PXSQz1O}>$rkt3>phUyJX}byb9b zuN%kxE)QesORmops(*ptJ1K65Xy<`ea-ajb&-0x7`3D6R=Yr}wO4we=+4=IWP)bZ6 z6Jp5pn(b?sQ}c0s9-O1)hnd2Q1xH^z*W|!6bT~Ya&P4d?a3=CUbHt)~-*G5KLdWqo z(kWvmv}YguU{w?PaBQAweUkw21w$Lh{UOfpoaxXcV)wEnv1TEB1A{`2-_SSlawD zYmTx6Mvabr0XD`~_Z+pH~!#YR3dZ!PL%^&BnW@!?pzRL^oTEjCG@`VCVb zfKEqr+sieW5vDR|#aPQW##NtfW=O8wEvkCVc*^Ge>!6nUwJ(g#*3-dRbG`Qz%Y-C% z%=b3hHy6>dGgHoRe_hXBeDjzE4qB3B=k{DH|<02jYYY)$q1b;@*P(i`(2>!n=mLus`?J{2Y>UxuSo;xrie z3Ga{=K!@?lM4yL==ZIgPF3)zi8qT-e%}zKx)MpCQH}ATUQ~&(K8hzHlbjytwwY5tw zOU^i$apeasre|sQJ1M5ge$r>3dY^jnK~coTW1I&k;<%2Ve5rjO-88c{Xc)P5gnm@) zIF9un|Ls`HF7>6!yGMpdO77qkasw4DTWWG{Z(hE_;E&!mV3mc-um+vA@4Cb%S-W3; zGp_$$to8RH+{(`{eg$r`Tyd9zB$ec2!q)>{n%KsIuD?ft)+lBj>$8l0MJL;F`5I6| zP0;+UmsA08(@^F~*G8IeP_|W0v!kQKxeC)xej6^D_eKBuxPHA|7#>0Z_AD7}tgCh< zz<=RW6)*0}*e5nf{@9~A*je~S;>U0gVzsrUTgJaYo6lG&V7>;mkx4Cjw;j1zIwzN$ z8r-tC!E_`Fh359k+_IH;m+0L`8U(<)TrKT|k7|7JWmSW(;I&9>S8pWSZJ5^7C@}E^ zy7m>D>HGA!A8dLqXUa}{xsAD}aF82QuXC!U+Q-^KtQAh0xG&%NYiDkJBY4?W#?H2u z5O)d9CuO+MLX)szO#j;2)Hvj$5OaIqfRkjuK-5e=gOHthbk?a&G)iK?L#QJJGN|RH z|6GcRiin9)r~55Di10w;;~q3BsG@pz(eX=w!q^49_h~Bw%djw)dDRW(0-%u4kXG-v z{mNs2J;h3M6rbf-s+5jL$Ld|E>8I;;1&aG!q((U<@Pp@l!Iq9B+Ix;a5%m{|>Er;H zOWoz?T>zFy73j1b-Y$e%JWTFeu1C%?`?PELP)!rwyP9H-0%*!Z34~{j?Z1*G)zZRD z(ym5Sq!l447tqN~C-qnGGya|F2>$N=?o267{&;Y-DXo_2L%vB|ni3$O4q zc+^QXUW!8lK@5lVJS)QsszCI!1sZH%=H{%MNHM$rviI(TXfI2pXwX4jWSttbP>2+p z)Ru_e1mxQD`hat_be^LMAX%M|k1x{a&_yOT{=uSA`(ZlH$o4s*{oA;YkZVMK zyk0POIlrZqwPKfK$EEakZ0x&*5^;^a1>3BVw%dT*x=I{O@fjm=sGlhM*nNMNe_@CnXFE zzfywqot5|bBc9h*eZ9ZK|GG_LZ9Cb_1DkAA`$IA(vS8p?{<8)QiT5FKh9#)+C1G7% zD}PE7*yAJJu0P$OILAENM&p$L>GY_~NK&VncDazMuxNN&OTl}S)o`W&H$`SOzTpB??1{hjzNeNn^tbf)ck-zR z=>%k?Z9T{LOTFO-Ar!zjW!1lKG_EpPcA%Za+_yeAsrA}h1wu>>Xf>R1pwIpmTpbpk8eq@39Ntjnx3N{@+ z{*Gzw+FWLNMvqNyA zk*Ccd$0%We$#XGu*;37D-J(N@0A{h)G15=<7hV&5bz=vrz16GFdxDcxvkE@!sBX8) zh<@2%EJ?`HhV_~U2wwJ$h zYqFjx;k}%M%m0iU85rE_9%M;~P|d>@vFbw*@F^u5>dikPnc|PAcu_qYKJ&Dv7d!81 zjtk!@C!Xbg6AQ&j+P^D`@ZCn%a6R``=1C+w6O4FNBvyxX_xwijG40)Fci~47*LiOH zq@15&vtDm&Pc81BfyqG{j~^_5x2XzfR3i#I`@5+Km~)m;H`-j^9C!qKChnokV}=19N|gEdw2Qh${ss67!( z$~>!lu41SDz>_FUPlChmPl8(Fthr#@vy|mO<^z0wFIb=auwDR-N%8kX#Qn6&2WgF+ zCP-GY{fq_Oi96O<<+*7Usxgw7n#*m8KV=R;j5K||icFUg&&v?^h$AaEHQBNT zef^UA7X5*~_jRv?k&SSdE>ZS_VMujc9+uZU%m0$r1Wuiv`#*E?5c$=;KaqzuX=Y4?rELiD#CyOY zDs*B8O8cgj=t{H|>frb8+`IB-;+?AEj~LjQf%97;TmDgb$W z`F5RuB}e-i88_$4kSXzjv59xLF#MznNEf@zrdn4(b7|W-yocRc8SW`k)|O;=bg<*L z7l&E#St;{mxbPJMUOz!5aWvTW=O5@AMnK6 zzuEPBpiRBjyf<?SGY=FU%gjB-NG4p;`IWbHF(eJYzCfgJ%`ZGlJv!HIQ&9n)gW zd@aKw;1#FrplQ|HOE{aeu$bF64f)Uahm1r+-Ze$q=!4r|y;(BXHLs|&Dl=e&ZZ-T& zA-60VOo)q9aIz@YX$t^Td@j?t>*$&iNHcJ{40tCwpR;F8gBs5QLv)WzO4nbg_ zx3w0{P-**<3uA;^j+J}do2Di9cDV z+P3b1j|=`S`Tn!btmr6M&!or-?<=-b<~e60{z7LUXrM3FKgnR$v&f)xMQHvue~F8?*NBEm=A6X{g1y$ zorOItafQ}yq*}%doR@b)Pd2Zr=GJ3`$|?ZCn=S7U)fL4~W+RYaYqpTUWOG8lN3L67 zR^Yc+{LcSS@S^drFr@-2=oul z?0qWm;jw!7C-bNC7u@CJjO3gvnEN$MK@TzKJp}_!s`lh7ljODllOeGAc5IpWIZmIr znA7-!tz3`IQ>^}uaY&G0J|>G;`%P*}&44&0J%voG`=SA%{6WD!RK82zJ?mE=|Msh< zB*C}yMHlh8VUxt6VWFFe;MXGZE%t}evn;`v1W{!sIzw6&qw8Ov_4|MW?sXh}%5FH+ z-TCX{BPVRqU49$VFV#3w?*m_Ns$j;qgqVc5EG6~}(-W280@d)rva0_KdS|qd?w|;q z#fwH5*v?h`mE!zV!ix>*RzszBZIvZ$Axz|7buuM>5+M0lR; zNqj-cm**NXXw57rP{`2lLIx{|b(;7Ytk;_0D2&$(RDR|4tO46}C2%A|P^J`wvb%De z1sOw8zwI51F>xbT8g?J`0Z-rsFaR&2i%@;|m*Kt?lX>s(f#!4Hx52up8YqIAmdy;} zu%8K#J{1}mj+Vab=lqkDjXNk3?f>b+!zP2VCv;KAv8v!t^F=7b8Ues%pNerM)0XBu zpnZt1;0kqlbSeCGbd{N~ES5AWn$G5J@KW7-Lwh<<12@@|2vN%KEuCE2H&->l^XKY= zYjA5cLb8ogUTTNG0VOECaXbYUz?jL!Uik>^{;G91KLBGN2CZB3H14qigU2DE-+K9Z z;22W~_%&9qI5RX_E~7Hk`Wzffv?J7a&Q>oIs}LY(rY(%wyS~G)>}3o`Uc~~+iudQP zs2!J>%E2I1q8NGH2IwrK8=5C;ZNQ|5iFzwMcie1uhfauX`lqzT5$X@=4*b>i@eNko= z)`h}AUt@C2H0YUJ-S*Hz?i8UV$Bz?Vb@)dQ*BJgSlBnf^iO)GW(wN>WfG<^=GYq{x z0J+c3!DbpV;S?N$FH-;IO=V)0y%2-4vLh*_CU#6KDa3*n#mNSqVwb2r836JU7@N3 zbbbs*xYo5;_wZH&mW&yR3Xz@=|1|F3mIYewvwg$?qyg=P~(Z`21wtIW<<#|N@Ens7_GyZ-SuY4E=pNfeVpG_sO*Va zJ@5f6*cU+#_pTB8p7c6tD4sStVq20X>W&+lFjikDNDka53vv&_=J}kE!EH1D6CZS_OFW+ad`mAVL^OLlP)p_C5XatFdjNf%0bbofGzdCK(xVhL6E!A#|R3 zG@a^tC8yiQQ6qj48eJ*h7rx)(bDzv^o5nHH$4AUn=<+vjgfad@7Gy?&b^B?{p`w5e(Hr}}`0l3d!n+~TtbzoL7S zrl~1FME->CuU)%&rMZ8buC(ky`!Qd}lME5*BYEEaPjVDct*=t)Lv;%_j2ix|Bb(%wW0Eo>lb@eKU?hgNPZdZ9ygDxG_HX&{l=qY zGzrG|*Qg2{!Yuo6D)Rq6nOp} zW9-_1jFeD9QrJe|5iJwSaqi~nyup>Dd?luUdUMSG{`H1JD*)GJ2*qEolT5Tdwgetc zNjOQi(mnwJ%$(2*_qGps(so}Q)h)T0123#qalZJYvF8Rv5f`S-=mp7FfHLR%8hRN0 zMM!Sefe;MBwSO%6mK6Hk`gDHirtEYLar)W z?gpa_+2-2SW)4d#D0i)}iL>nB*NNw$k#pkb`>KCjF>Te`{KS6CzxFr70t)9@D>*E? zbulD^UnID^CF@M(wcft1*Y$?^KKO|_uYYH`!u)v^G&UtD&!X^?DjadmNu;s}|0OpWID7TKT zy%HYR?Fno`>r`dmOul4ve;Q`yDV&mHLFUPm_%g1 zVJDen%v4+NLUT~$3=!U}a4ZuN5J`MD-IVCNmxYY|{{6b#6oU?;u+IoL?xO9D28*>| z{vGwuX|WXs`~MW;bFmY2hVRd_5Z}GYev5DRS1)|c*&b(tzl~m}W&n9gqibY7^6S>} zD8`uS#4U=#7)M`uz6aJv9B7Hx$M!eagvR}BCsR~xx{3b8_Jn3Ivb zf4k+2RC;|FOH2o`NUv(*VZy(KgK-|;=AX~7o$@O`OZwHz8j&>FwX-E^}%?Fw+AQs@guUvju&t~XwlCB8@e4s=F0@Q!qCuFbbV5F9DwOISB>3XUMoFR-zX$IoD?D3gP zYq3i#Ea?4G54j`zg-jI2I~HhWt-1#>`M)%h>z2f^GJflaO1%4C=nskk74LEP@@Fg&)Ed&15f#vrrf1Y9 z6&0QMyGnq-1R3=07K;*Ms3JJ0{2@(MnQxtYIgpy20mz*K7|`jDA*v4gpUU!Q7^`uO zlPmuilqYTeYP58mxb_9Z`IXLJ+RKTmSQ4iXjb_C7y#}B+E!424(SvWpKzE zgwj)QG&NEso{R{7_2iiZBf5abLj6Va85~O8mj1quc8w5fLA&qDlZ07>m0P|Ys4?+H zf-3qTrls#=w0koHCRJEhzFdsTc@v0q>Vmt#4&6kx@@E(K!@_Vwz5hJfwvjvrQtOT~ zt)c{-5kWb+6(%_-v)gxx-+o4f1j(Zn8H+cwfFn^pWq%DA$WwJt5~zFOVT`F18vFm( zmXZk-+jw}2x)|f!HV zR*uUV<=_ZNz@_@EL~Vu=!*YVQ0cPK!@6P5NTk#_4r~_oPtJWPWeiV7Ia#6G-ux_)f z61oTGsgiz@4M@uL8r84jW4sqp2b@fzSY-T%6TmguMHF`xLQJc45KAs6lrdNaiwaZ+ zU4m@+p__owz%CW7vp5F5DIo%0DcM42;h&j8rm16*(%kev|FPDLh6gW9xxm^3L@+Nb76_*sS;_}*_ zE3qrNv7rF(4wt@`gSQRu%JgXl-{X1tf?jIXrq&KRl!Vn<*k(B9nV(?csY-WFZleo( zi949}kmVivHK-Qg(#iEu(dM{zZq$ZjP}>oyp#>g1`VtId@_`x9gItXEDTX2j1wRpU zW3&bP?zT0==&QUp5r(|`(HGBeWC--@DiQhWaF1c0w$CFoXrbR=q&79mGxY((UKF6YR7=hBx zc6Eiis=t8u{Y9t|v!PzYD154%0lnK;0w%|-ynNPcOc4Zb*-F^ANb>6bfvoYQ&lzJD zT6W%(#3HyF67gqHDpGvxKPJ1y*d{YokF zsM#Ew_}y&Tpb&O0bNfqBmc;Fkqum^p8qXuP#nYZ77w4nD{}8f^w7$FsOUYq;XNUyW~sr5T@TRI{R3MLCqA8F;g0xT!A3|F^QsKJ>2t-PM6~| zK>}wc3jEgEc=rjo^zxSGEcdybh6XDKqrqOvPPC{x=8NBdN1pgB#Z>5ncs2##7rJO6 zPVl|gc96%^g(jD{86AMu!9MV;0^jtqCFO%yJV`axkx@D5<%+WCD6~epol?*Wf1P66 zw6`bPHCg1ZM+tXIHjw0)|MFu{@$RN#B24qCKppf=r5RzrK^oVgOqKz@Ux5rhGdW`X-~Cih_23dCoD@4LilwK8fq5r8q{oVH?rnYkaU)G z^V&*xNQb*_;C8A=vdi@V{Dj=rHpAEGws_u!n*6a#+W{@Vtt(lOp#4G>`zXU1 zMVaS3xQXXCtKq5z+wOM^&-aq=yK&g?!W=};nn{!s+TFypv4^&?ycH{2(yw<}sRFhl zzvBw^wF&C%wyvi9tx{=lu^6A7xYff^Q1tx zbfvkVsPpJ1ydEeAxZU$0mPl%usTg_oi=D2(Vq_oj@6-O}Vs7k){V7`^zU`Gm8GB~) z*OT#Vin%~{X%^TMbg7A;>Et6!)z0vX*6+}K3Av~-oL&spQteK(fQR_CYbZ6;L!yV_ z43v0@Bz3ke^-#=PI0;ooo16H4!BmVuf1^2X2-HnM6cHYkUz~5C*dMaG|BZm8u)U$$ z{DJMp;H zvOQ$7Pp{`zIz2g~pG>aot2&R~g0AP!&NA9<6H-)-NM6<2PZj>$>|1?!5F;AJrg@8Y z9TUOAVCX#tFHReMG&YosUL}&n4hoiNu<*Cu=6;AH!0TZed?Tm?zb1_Px?T2lw1>=X zy2&&t{c|(5yc`-!uyt3bot;w^EIZg?c}!F&i$F6f{>`q~4*8mwFO#%rc1PDMO+T|d z8L=Z~Wqq~EqZi||%0$?8=g~x^+SNs&G=FD7j3HcCCF%jHG9R7mS(t#+I3F|!3`v`p{R*ydt3mtKG z{KdpXj2B~OA_vhMUs}HCVwxw&M%{vMC&DcboLlBAU}g`E`REVoLxN5Eg!e*Lj2VN4Tee?KHUU9U1s+AA97I$Xyg!^0|DnJ?tdzcyY-$@4YnS zuai;>q$lnaGr$SS^$oxXlKAn1(>0v5B$KV1lBJ>yO6O%Jv2{KRrsc*K1y3BUfm{J? z?se(J799-6wP-mYg8VT*R~}j&TYXt4+w1}aKJnT_LRS@J=5R2$6p{ktrp_~;p<6-hGalbQsdGoTT`zOm-^U%vK z(nsj; zU4!P)FBN;7r!K&uBAzJ=1@cN->}NwQAn#PE$KBGr4vUMzBG*cp-Y!JSzoLi)*f!Ao zAW4s}p0^9b8BqT3Gylgl_?{rGKK}j|mOci5IaD(rr%;No<5Wq5)!@17kzVEe>of7U z0auv!)laDrk??(Hq5~<$G>iXuaXzFp9MqZ!{MZ^G? zHQ5?Q%V&3cVAP8HQq(ZkQYswr^ko#@^GDxh_;|zL5uCOnvo-)V($%}q7IJX$zC0Fni+u-0&X(46JdW!H&*f)ZEvWrzX0V#XTex7&D z?`HN$FlnUz0j^mTJ6_5Beq3|+*6%ecg!Gg56NhLNrXQh1Cv2X1M+P%JlQ^AIMYc1~ zHN&y5>muTW^gOfL@Dl9CaF^}3e(@7eWH}&NL%*;m>}cx(n`Ek|hCq2fFiPE)FE_#N z*UdG2z(5^`Fbn8wMuMPpWc<>f4|(7G0RcwBdhVaywb)M+a-M}_^PB*m-LflD@b~ie z4y}WGP`W-}I}f)9Z-!;TkKak@OI_m@q%EP=2IRpQ8B2gQ?gSuBVWx!24xr%#D62G^~<2a64 zY|j8Ls9RIFoRfW8e3|XX)_=FgYF_RyoL|G z01h@g;#AZXX5a9}+>q-P-du-ICBx{?j)ConJ_@feQTlSf+UPs9%-4*j^$)aRp-jtIEoz;$+71cY7KG0by2%<&EI_= zrKZzr2259D^`4g4h~(C|H*65x|FP^@?(rZPbHmB4A$TCzDn};KZD7_zOBWF+^zyxISD6J1hv1u75Du+yg}i3s;Ew`!LEFRW zVwc0|m)WJmRi()>G#?x`DkPtq(QK7IW6Z;8?Cz9r(v80o;K5@UbL z@CwOA$oNYEbJrcofs50%3TQK8Hr=?0JaZWfPdZxXAJ~wM{qBHQD^{t&v+xyp%p5R5 zf<>-m!PZ4z=n$cJxo64Z9?~*8r0IQl#g?4>#M44jmO#%atit-Gs&)5df`$4!!u|)5 z(F~gkB&91pS_>Ik^Y;XR7ZF14oZHIaRe`qQsSVp8@tk- zPzEj`sYg0$je~qiVx@y5tJcOITTRz-d(Hk{mh<*5oTuW6g?vZnb*$^`2~tNHUnXEams*k&v8(p$`kP&!@8!1!w=^#WF&)?TJ# zvOorY(nK%{8s?md;ZkXE^BnnIANM+N=94b|ODd9&$#?dWiS*wZT%m0zSW{rq@1YF_ zpXXU#Q?k>U-bcGE0sE{QYaTl~c4K*qE>Au(=G}?y&9g9hM?C$cz8E4J`}C@2Dd1u> z%PI-^WQ)u)QWIQKR_}3U$&0#K^auEG&$^PF86Ug-Dd3o><>v_4_$}gS(Npd?S56P3 zlvnG$yOz@Ir7e;lStghI>`4I{t}OS!(q$_BuNk6VYx*56bgf9-s^`>G_8uZ8^6=Hc z%Ey`YYaX!DW|ugyBy^*m$udIp*?L|iwsiq}xPyRRFT%*fY=I!pSYU8t>#->N`+JW` z-SPwYkP3w|g^R|ry3{GDLmFeK&-rM&7eP0zME|*#^j=Mz_F&m}yI|JW)x%zE1yWcP zm6rB+aHJaHjU>741ES;0aIb9yHT1OQKE}{LvsOXy$)!uU%Zf+qYqZ!}ln>VUK++)o zWUlog^XOoiLDLurxyHYzWZM+T|gYMmLotF0y-=Vzc#&cY5R=l;I$|~<+hWMdJ zi}kJmzk0PB0uXSTE6nu2s@2thk)t-p zyFA5~MJ3I(BA6`Zdlw(J5!M(^+L(O*8uN6&EF75{s^os`Qaw_aK&t)V-EZjuUZ_z^ zYzJX$)N9HO-LbCs4waq3@g42f;To zK0ZEVjcRTiNu3?WmF;6uPj^JIS6p_h3%kND&ONdr_|qwyX8IkCr2(RL-8ZEi`x9zAn(ZYWe47;usB|Ssi z9gLz{{Z5jOL#fkl7P)(uJEtp5K@#>dwR|Ea@&$B=bo~3fOv#8^ET683&t;qwmfW+i zgJYw_Qasxg=U4{;y_H<^d><-_^IbdG;Y$>?_(QUVDtO{WW0<2m7dC*ml)iFDP<9Uw-4WbZSi0inOEG~J=LwJJK6r_wt zWq;6}WTl~;1Qz|vF<>&V{Z!U&F*Mefqx~&THI66N9fvcU)iAk`*SgYt$1=Ijo*J6C z79gzga7?I)GB?V7saG!A@mYB4OxoRz?!tutzy^%LB@ZUv3aY3&jTsx2zKD7T&bk+% z;iKfq=lgM{Nlh+gzu>{Hpkm<&h1+%%q!?4#xi)l!J)9GG-Sv@{u!iaJ{|vqlPXFH; zSN-obCNKDJ`d0sY`XbIRqoK&_=HLEDOokG(~{WKWfkgp-Wv{DbPfJLv-PT*{-}oEsE_#q z{lX-r_Cqj0yzXyuBj!w&sY@g9n!!saOVG0E0oa=fHaq%QZrPpWU2hxfT(+o5#(SCt~YhOnyPLCSP5eoF#Vo`!_$1|32b zM}?=6uLUF8ZjU05rnS`LSLhE=KW}ENT1jpUAmIqw^KMDjC`j~Hsf7uq5&nYtfYxnN zl*bC?+PX6`fM?SjmO4~VtuIBZvV#(M}Lo|UJ8{m91hkf#-` z=&$Wa?ztQZV~o{Eg4c&R{-sZaurwcYHdv9VTG!oxkm=}r1sKFJHj_%D@-MMRtR1)tjRk|&ork&Ll!1pQrv^n;J)D>uD6W}&#``_$r5;QAH{ zzmk=}xsxF9Qr(1cge}AwOK{8y(71>{M)K>_f4%=i;+Hol-r2`Oy%NEvV_SKId+S#B zaYu_cJf5#gxy%Vm3`e}malp|?nu zJK!znpJ%CD#wSoy>aY$QA?byvpV3~*=SXUi_ywZp4SDuI4E+jp634cz_b9l$Jp-CQ zA28X?_2_}SE7frZS`Zw)ew25-x-5iDzOwDN$h9#tM1cBcnnUOEMZGuEcOUbziZN47 zpx@J(MubgUe{@j%2GYIE;Lnigx7cB4IU&;CnS}xLnYttFpTD`>X^4Sn-ySGy;W3`I za_IaYN05luxY~;FZ1xO*ZGA@b^<%gwSbrsRNcjkQuX9ax6Vh8#{Tj!DXP7bD@neoz$##c*30Jj zvKVAvR7cn@g&_Y@sjFgdM2$XX#eqiTJb6PO16V`#d5qT)9R=QOrtBLQkV}9a8`AL5 zhI#3gr+we>4W`xdr&`vxed6sWr`AnNfrUbU&@s`-EL z|EZ%?FNQ3QGCx(4Wo%u)#g|>sWa;wY9o5Ar3{dHbvt;t6q0D8^)MI>Z+E&%sP)2M^ zG@fA68!3!8h36@t#N#3GV|rSMobv@YpM5YVuI=ymc>+@_!exfZ!~zdA;Ft8IsIqoHswD)cCf+I3z$tKTFqG75;_0Iek&jm z)7cM!fA2K@%>w?r%;?&(OF+T0IocD0|7hTL&Fe<9-top*Z5OhBPca11fwe7cov`PCeojH*t?Qw8kT0k1+LTof{=GhuEvH2Azhn69#Uu7Az0&4 zyMyc-I}g%ak_WuOVWbRHlLR#mwN?H{l}hF`)laJi=S=5!unmu?>BA+T-?J~NIo`!h zhtipB-`$+TVk8gu|1G_lP3*kux;o|7BNqu{uUJ0SXWZPp2b?r6*JJK?#VWu-&rZQY zw5kBd=4DK3c(hH!@O<#(m1}XYnpvMdvpqfetveF!Y})8uzv$qo7bdfDw!X^(K;#<+ zUVScAQJY)SKL=cNlDO<0`y`+zU+onxxlk^?PYx>}Qjs;W6Me37D;?^8xjba-*Ha)% zMQ-v{bndSap5vzU zAo3YM7@owpj>tQmxMv39Nj4mLxVE4P^ml{ZN35T+MXJQIZUC~t;-dXUJJalRrbj3A z((@y!k0PnpFiAQNJEE(;Y_;Elc|J3JB7da9S^=8%?J{?|lBFF$-ExCByY~Rv8%)Kw zDC-)96k17ifT;9gKihI{YFE|pKSJwXQ@q})dFw*?RNXCpJjdI}hACKuB09sD==Ft$ ztLUrfv*v6gY_AhSOybAf)Kwj=#4 zQ^luH7*|y+JcQiKM>=1~tX-DSIswTb#c+%mDvc_`7=Aw9%z7#@ImRt5_U-1e-sYr7 zN-#6#M9L+_7`@pW-Bn##Q$4r>#stRbz(@;bOZYqeYS~n^Px_dBN}I7RPFygMA48+l zwhaonb*sPkUOG4?+s8_!eoMiIg|EiS`!`S@_}-{`l*6XZa^zmi4# zP9TyX6FDDu6L+i6`F?x@Hn3eJ7u!f|ww$A^sEL{cxbYkSmJqbaAeh-qj zR+Uii0== z!1G~6c5)PG&EyFDKncVt_ND!VQt#Z8dHWXP)_H!C;VD?}xWPcfI(iIY9|4Ry2b{%y z{>q8NyU&S-pzhcOF@B5z?YI+q(_b$8^KbBzDek`3HHBf7dp|!~Xu|J?o&aSf8o&wC zyYN6N;=uQLY_^szp0@3M^EBsJU9lvWXQkA-`B7D$jF$4t5w;lVLF2CsS;uK&={I01 zI+2~{7aOj=O6Pd&K9?7HD_HyJzMx1h{%!C4!>G}L08{IoPu-pmMpNQMeB^HC^TPdi z7e3@*j%P#g@3|*}fwk}EDz%3`@0gWMHaO}Yg$32h;F3Fdo%QgYnmX-y)5DYiU-8%% zFcjcBHT@t~7M7?#ZaxAVRhB6V{Lreo&BA40BW`CoT8Ke{9HxYX}#eA~*1 zJ9^t4lQM$8OVO7om64bYuh1$gPX}6torMRpNDTwN<5jJpj_UUxxuQOeeyYUcx zoFf+KV?_LDvf(IFq}o6Q!^<7**~3ct?MW?F}#jLiGJj+4b8WixuP z9CnyiYhN#-r|aEC9Z4-MQfFNw%cRGiZ40Wf|n2&J}yx6J95lCoH@Q=mOe2)W5SG#r^Ym3+>^Hp zQW|Om>1-0+gRQ-Q@~L+&yjo`Mt(}Ne`e1<)`HpJitXWi zUI8x0jsz`VHg8TTPDvZ+cgBnw^e1WmdB&?jBA1-Dv%Y5<7;i3RJL|Bcvk;e~5d6uE z;>dT23fSm7 z`~EhVSo5R{VD{i424{$Q|68dubcGGY>$hJ7zZ~Fv>W;l+I#54FFK_J8g{`sJDb@D7 zG(H3W38&L6|E+KTQrJeuufOzx^wwyRTT>n@dirEw5bbMtJ%Z5!G^Vh)JLa^DJyDxN zDtvHBE^kCrA$ZnrAb>(Nm*XT>3{>S}Zk*`#ZuV_$ga$?QOs4H>FtD`5M#dG!Ggyh9 zAp9zLCS;X5HwIGmx`rm*Y6K+-@Ma^>&Zjg77of7k99d$=+$82L-u;0u%MI>Th6aNu zf0nYQ4aFCZGga(|xnDQ#DNdw3qfaIq9Uozu*0FvGm~E!p?sD!=j1@dcp82Xwm!Wi` z_3H25#b)FxVe6jIb(xs30b~&gvOIYj=Ap^cUxtb7bdX|td;rs_8;?en2^SXtmj-Na z$(bc>Mhrx5grcgtl}JmHz1er!HDjo$0%L)TQ=T4$roq2)eU3*naX+B14qtzxxVhG^ zwwYxKbhW}vUAM2lYSH=!a6lZZgkW?wLrh?Q@dK^WS;_}(x!N2JkP;XvPTET$+izM} zGmFqHOrhSgt?D?_TPmt{hK^6!$orrm2a{i^TxMYLX*9Dd!(TB)B-zNL_=p;c+g^^% zIB3RW;!@)tgm^NRv*Yp|h;}RxYM$9H8)v~O=`Z+Km~*8lb5S6KRj@bf9IF-0lu3qV zZ`ApPj4>d~K)scV4aaApQe#Koh>LV} zW?W)G^PARmLY8`nyF&!pbG3(Q>+u#-1rxq0Ozi)n?JdKijJm#W5NQOF5Tv9_KtO32 zLb^e^1Vlu-o1qbq?glB5?q=vNLAtv;2PWRr>$>mvJ>JjH@qB|hhQ0SWthJ8Wd;iz( zKMeGqK%SCHv^sJ?mYw_^={v_Z3ldaDKh6B+=Pv+w^)%-yA{V`x*Qw93HwP4_QmlJ> zRAvpW%WZ6J&H(dD*sXZqT|KE2G{)mw@G!2k%MfGo;LtjtHo>+?yhyXmI(doSe&P2p z#QZ#acw^ts*BKXMAn2+?hYK95kZYLbn4u-8Lo4N|roz4b`2;tuaZ|xDARt7cdhyMa z-?BgLb3Zc`tM?ou=G&K~@fUmD_PBuELJlVtd}Dy7mhlw_VgG$ME+-42cts^kq4$gC z)wc~&=MHYY8)4S3wv=_`YYEhopKLJiCeF^*h{$l-iw)EGDfYm^a-hd8)|EFkr7uF> z6L8dGat=TEQvP}b4C*B>4jU)vVlX-MV*St8WeE}>a zFG2*9FcZ3yeJXQPE`NQE6;cyd3%8HB`UY^&YBihtw*6O~!%P+&+H&~e=&OHo za@(pxy=g(BJS|PlTlg&dc_{I$iJPda9{Ew+vsz8yjg8se)Z)B*xwr7hm}!X{55d*J zN5VM@5OHP8@NdU#@n{!RHvlBuHTJB*vbF+FNSq2%x*xnGn?MJbCZDo|vyPBq3{rwhkX+x(jn>N(pHpYk9IeG@`dtT!787C`1&L>3CaW|3 z=bxa;qz)jAYJW?Yq_Xjyqz$d6aE#rgyj?q*asaG-zeN5uW@s~6ddv}Bi-=!?fUCrO z_?c&}?0~!S^`tGx@bA(u0CUt&gJ$@BQ>3YA4;R~hxKfHg(8E_h;bEpzjRi`wOZk|# zR2)N-LEO_{Dzx=DcUao>x;JrizxEFk*H$Z6V*Gs8!Q*o)?BJZ#grgz`UAOB$vaAH> zR#SEI9m+%ZTV?(>H@zO?000hNY!`CEji7HI!RyJ#CC2Stc!8tiyZ3AOcGdEX5;+h` zFmVGprmZGpk5go$8ByGv`CJBiJNqI5$psm`t}xP?_;d!EHBLbCjBqA&#rOi6U!%Og z?-BDPgu~^?7mv&A=RR_U)tg7KIc~-uqLrH%vR6ak`S#sghLLRQo4Q%^oXI(CvY4so z&4n<~<8f`7XYH5jj!BlCN^>$OLC4iNWu$|g4G%If6X((%!{X#M8A>1Nj-0&Y$R$~` z2nZla;h&jhBLHoj0yZ==oCq?w*kGG+R-A*DmnAm#7(@Mn0_uLSDBT}m-i-!!yB1!@o zz3++vOM+Ipo~T|!9xGbEOc%k4zY$eQnML`jOQ=%5`l1hg79N?ACw0d5NSG`V4tca| zt@XlMTx8)T-M)-}RQ>f%@%7XTED(2b-OuD5ZYR&HG_Zt3&bv4MsIjXBtk$L5h3Jg% z=n&0~9^eq*A>2t+t4b;_TeAwYuf37s+Nze1nC9AwdSgiKg?}{5aa#YH-bWrYx;mQ$ z4UdQ&A9BP);n>hi*I6W@RRdkPmBjl+rPl6Psu-Hd=GMy^9b-SnI7xl>Ax>1HHWUo; zs_DO#abWBbLm5d?f7E-adsU>T{%KK7*qudamhghi$KRi9Y*AM{Q?k(P5S0EtG)_jh z*fs-r{HZ`YC=*&%WkwOH3}8@dML1mD;@R4KA3reZjdvlQ88T0t*IYbOqM&0&Xg_OD$F zXXK}e0;w}COarsm(chxPrKsOXzu5WnBK@hQ9*Zz`MeC{1{S5`tQ65giY$!BFO0)J) zzAH1Be5fm@=hP zmai4LfL0on((h%9^MhNl5<(|7f)No&{X#0Cer86mk*Zn|+rlT#!|AUk%nf6GwG zI*o(l71sk_`Zq1H~J+7hv}Cruf0#>uHs_=qtGP@cEXbZb&ZT^`(Fl zjlybJb-hUb#5`k4uKfrLvi=FE>*6F{BowyiGv z#eplKiz<+9?p(xdg3UoM?PT5-Q{5xNN${=4db4HDh&Hdq+qL&TM*5wg$gBQiXlON5 zxFH%Hvi(bHhXmhd>=nl!7M6Qm%Q!%~X4laE)6}Tjq)aEk-1a@XZ#A-U&C#GiQUbgG z1`ORv8LiPF1 z(j6yat{aJ%p4TIvzLGww#$bifI5M~i=86t^XlU0hwm+fKiAcCwuzYLWdvkB%2QA#o zgKa!8Ufbrhd+*+3TI5vk9QR`(G)2zzewcbnXE77K{xtTZb#T~ zIk;i|e)=%WlG+ct!%)ImAOHIxmD+3HR6*(O2=ctGZRUJKI%jN4WNX>)RM2;gXO#f- zyQ59sYJ0HQcj=n^YDAuBgqOwHdEVw~ED#pu76-bD^mJz;y`}_fO+H#0f|&kNytA2q zF3g(VRVy8K3^2h4*O^!{qIny?P`#kVc#EPjqcL5Kd?WmRJ=CJ%4#buTtnVXTe*0Hz zs* ziI@HQXXeA)$D62}7k!xR_IUKr$-M)r^sO-r7P{pyi}u?!$T2)+j?GYlP%o%>tYzZC z-S2WIhjo7%(bN8QU-b{B=)|j7g1WCch(d&slL5BFk^d!BpPl7NQR1)xO9;*&2u zTWL9}*z&tagfT#dO;H`q``eyhW_u$9@4y+qVt9sva~oFNgfB{7#=cnZM@6Hgj<&d7 zNbWnDan|h2|3>%_ACsqnR0YBD+(~_s)LB;6Cr$z|X~YX%WTap1ygouMk3&KnVE|x} z@%=5jc;Pk?A>ElmBx{; zu(h&+-pSTh+^c1tRwUi*piH1;Dq~quvR1K92_ayQYg|o=TphhDz7s2UOchkPOP$4s zaRRO8!q>$SV$6gE*;*UZ?s8Z`fHudk`>}N2<4ZfjYRz@5ROaXALkgCa+YzM9aWklcMV($l zjMGd}pVygWs*HG?R$lU7d|MaJ``r3GX1Om5+js1|diQOA9Wh@2ZDDxhZBJ8n-Z#O; z>o5c$ivwqKuXItB_efl{AY`-|WAC5Ra7$i7@gkZKS@=e<|zH#;M70RjSrs6#X7K4vPof?4X z5$|coChykmE%y(jXxcmPfJV+Ujr`|L|5l8Tg*vIx6Hp!ABawW{QHL3!>d9v}$JxLf zbFyTfgr;m={3VfKONc6xkX{yx+Sjp1w_gjXakA>+T;>gMdK^zXhbx}-r=R6) zEK~%4%SP&$D7#fc5G@%ZQ1-_0MQdR){iempSqu%KpV)CcxedGx+PSHTuS|RpA>Pm# zopU?B9@pbZM?U9PxoW&=hSKjw(V#!mOoa}T!$Hy!g=AJLga%U~?Xavgv@* zI@7Z2YK%-Ho3%`2+JqzPy-KfY_4K3tmPN9g?c%v1Y9@AQ?3Ch$+)!@f&mFDk;w~C^ z;0je4~22j2z=E$sp^2KJZ*v^wQ{ig2% z=b`R(JmY8lTcRI;vzrMc|0t9$bM*9AfewkR$i8|ri``|%HgvAL{CSMP5X}*3=UsgtsA*gx>m0jc$fr%H?3vJwoBY~9QD{!r}(oIP*)N7oi)9Ne2Y-^`rGN)g<^ zEkB|&o{HH`=4QMj7+mwc%L;hmZh(Biq_@#+0pipXC~ zPNlkp%M8I|(ryXiMmnt!G{0Fl^NXL|xHw2>Q#$<2Z;N#$>*{tUs)$97`fH5}YT`T) zQskMSK;~f|H`$0vvzK~*h>d*uGKY4i4_o=&<8TgUJs_c->>7TeRQh%RGn9Z-Rx-3o zE*=Kx2~O4x2nd2pH^nXj1{L&o_mBw!N?LnjOUBLo)o*%&Jl>1Zf$6X7Q_4!W#BpBf zYWTsusqQ3oj|Smq zkE$&RXnTSjRmDy|ukSyMJXS8N>8gKYN4g!=Ih(9M=VBx)ITY=2NP^S{Rh!=KFG%5s zm;XiH3NR$oNJjU`CL#u|ou3`11ya8Y3GZ31aJyTM>}i{nX(15Zf8C}Vf*}_~^(N0S zp~y$PJdg(|0VV61waWc`T>Io)ukV8b_Btc%wDqhHb@65EA0%~@q^&5y>`LpNn1IM5 zOC!FR$CDXM>x>(N+AG!`3lVF?>_lDY+bejAk8Qkc$%Y9f7^g@EA><5akpBsA)=G~c zyAM5MAum-q=SBN15#gsG5aNfFndztG4zRX9a@P%Bm`dif8UF}2L>`$(l}^M=1{xkz zXtCz}Egv=8?K4y^goGS{!ZM2qt+j?#+4meTOXR|Vs0Xu#Po@xq!d|2Ma0azXc8Z9{ zVOFoQICu>_ib56XyJH+{ba5|B{PETs??8p5vO*KwISSTq3}LNqeWqz5zli2!&y0Py z{b%d=!M6x&6ZV)d%1C8C(g_ta+&Nf|k^Q&+wf>dO1^MF`DzNUPPJZF-SO5M{H%xJF zwO#%gQ>u&a&5{iFFJh3IMX;yn@Q-5CIB6-%s-+74YQIkap#_^lAu@3^Z5*`e@DdL%+8rF$?W`i z(wakoWkJxxkAyE~xl^kYR%$U0TV&I<&n{X=gjgJhD^$i`ly3w$^ijD-_Z+IyEBD zq<%^EwIoMp=OLz?jfb?(uj=i^2-ouE$VI`yu&LiQgy-(_Z>*`zA;_~tee;2ifLCd) z2SpjVWhzO<5!hMryKuWCD4;0E?_`W(3j)s;eYV_e(Cy7~g) zSHpXXob68!M&UbL;G`J6HzHdGy|0po?m z{q*oF%-8vu^|}FspO~yxrJ9~=)Ko$)LYJltCLsZSWwmxkHLx9L7jlGxP~rE?SUmAu z>^n2HzXZufIA976B&2Hn;J zebDd9@%M3itSj427aOeUFLN&QooRexo3%MgtE3cPaR|URFctJSjU1sn_#L`ZehE7n z5wxAOm^7Q~`G5EFxu?J%d=PInvO!MU5UfcdT~inuJxb_r&sc7(NG&p6rw|Ai@}GIq zDYJf3ply=x^##lkg=AJ;BnKY;h?E_HP$K`C<+zDBHXbfoR|I(9E>>ut=!1u$Iu*z( zXT;oj@l!<8<3#2#c+q9gp^exLMZ3B1RsL*c6A~ft4Cleh11vqbVzvOLC7%OLSyETD zz#ayML+(`jK6IEAvzH@pOexh(-t3QDRC*$IVin{tEF&xC36;@BX9tWQ@7(xTJ=$f> z5?}AehrkL#13dAf!BMc0A(PL?dpBorL~RJ`KDXQ#2@nX1`~$DtIIA3A?hEhrNe92b ztc-)meWD(N^!6!7)6uZPoQP<-9>{h|gJEV3h2*MRq!KI#TRM)VUv$&8D}3hvj9s)` zqlW3As1qJj-2$KxCxLl-;_6en`3lve3D-HjIoBZEAZay%Tfc{@;HE(cfGn{m#eGnz z3Ixx0nIyIFq7=zXHZwt>Os!xe&q86?clxKM3Cetq=PL~7tB=Q9c90wG$?&mC$wxjo zM0t5KPiliMkcO=6<8KDTy-djL8;uC7omhnavwmDAq=9{V-w9fz$?B()r$vv^H?sz+ zWr15Ce>u$=I@bfJ%31@oVJQr@7sbjMyACaN*T>IvH_z5uV+`C5`cH3#PhFxmyt?g* zK0Y)8M`wo%6Xr3X-G)Ucb_S&3rM)h|#Hb1i;Uz?zR9$^CU)zD*_kctilq!mo`=0*| zA`saI*!$i@F}=cPO$n`Qt?A7t4F=WTrd&f4ni0H5KX@lxEG7O7T^iW8uG}o+k~Y(B zTT7R)_bMoIHU|f-iPPTq0&Of}KSCt%T%&;9)RD6TO#BQ;Ywi%e3;!FLhNk`rCLo81Pj( zceJq{vYV|FEK5q-bz8D!KF$9QkKv)Qi}0;=0T@jMahC}bX(pF@vTT_;gy{hZC#C_s zPueGzLn&+u?6M~RP*gzF%PLib;qTmU^(=A49w)Rl<6?Roo<#YmDxH#Avx320+V(A` z)3KF>@SK|meo`8>7Q1k3lr0%_Q4lO%K_T3>fX$HA(*pHelaiQz+j)41#_#h=OZl9u zi68f$@|r`o(~>yV=9U{$S)-)jA^KU8Zpk!-2)%O14s@agNoCOJo@1s$?N0Y*KQGt5 z$-}o%pbU39d%ca{{i>X|5P3r(GzS6OT2;2Oe7o94n*rqI3?)PJ<4TPmj(d`HU{4yw zW-3hc+2-!P+NjH7t|8Zb-4_Z|ngalTXTe?BjXp$UPs2fngLy5pSTsk(`>>j-PbYD@ z@AhLsFIZKeh|&+v5$%Zh7N!ZYXT^k;Vk z;`h!sptY?{x&G@jMr0zW+}ryO0F&13wx}?!VH@lMg;K^R)z;`AkoB&(1zB*FQ?+vT zW^IZeKQ)}7Wu`(Uiw*D~*z-KY2raDNe1(C<@7HXbC--Lmf;&FI^Y7z+R;GRUu<)!! z+U{8CO{Lgu(}U|3OeD@`s2d_tF%rQ+R*8;HBj$ME*7=9tqoCBQYP_bH~t}oKQtLW08jRiDtN&l`kS97m{ZM;Lo&B$dY%ZD+m>; z(Z_YL`}%AYtuqm!Y$$k&S3gPtc28-M1&%^sPCT&yD^YiR|CT&w&d1mdh#{*1^AeiX z4E@A=F-@qZRi}=JNubh-%&+nn>`xQ1ai@qe8~V|>*Rs*TQ@Q$2@;Xgw&bON1vJ#XI zP&(rgU-O4o+Oq8fgjQPEmb{>!h~7cSr~B2v@i4_!=B$_J*0!|7x`sIVj*l=Xc+su#e<1WAB+-7XJ2I5hx{4I z=>kku_G3=l!2X1qN^BW!dj@GXu!l&aZ((nu$TrTVTZb=^cz*)ODlzNs9*pv*)dSRa zgR!)Mz8lgnn-TB_X!^M5&0o2Dr_BTx9|9ef?m(Xgmt``s~- zct`ctN5-Bv?>E5vU12TO6|MT)ev=ZIz)u}t@{*A1vQ#^qVI=P?M({c6|7xfWBXk~S zf1-;iOiJT+=g({P#k_Lg2x3#o#uR$m>nILfD$OCcxR=0#Bu5h5#NZIXCxj#*9M#C5B z%({wk_JOD?sz0^2n=?86uIF>nvRY0lm#bcDfD{&&009JQW=c!|yZ4L0OVil@DaG{x za~j24tcfSNn3cTq=mlc?h4V;5*O~XHRXqfK1BS;h(n7QJ_J=#*JDS;QWW3TlZJOXxLg<($EpI%L{ZZa^3oE zDE%Y@0Ue4SpO(gZPI)EYahM?TX|EMtDLFy22j66a6NP@~W%D8LJduTjJy;@VJgHN& z9=wQl=s>kXvrJPcvW)^+;Sn>@%o}K`90l7lWXGHtg?REKFP)$9H=wU0QtUMk@P3ga z(cNK0xDVZ(Nd`7Oa^6~g*!Wfq-w3xB&tzZX*$a(mt!%Idb~kR(gxsCc6I@g6o4iHbm?k}K7eLp_SS5abq#s923{*~ zIQ%`u?(_(3JM$)+6{&G_OR39JbOHgVBc$itSSl2^cCw7^4rm8!zCBq|6oM5TGw_bF zOqd)oIpJtM$u%l+VpZU%8bxJfvFe9yfuF!|bM^?{pETdCp3WNBIRXyH)WjUjas(fc z{y}dcNQ8Hjz%PQv4>yhoe?JtB!Yzz_?OkmXU*$XM?eVS!FvNGoKOjib-Rjvwse9#z zz5eppM?q?vS3NY-NCg-;Tdb!Xqwl^rM>Q6W((_Y6=j@~dtR%$0W^ z@vPj@S;tbrTQo~4rtZUWHHsmgty@7OpN@lBvig%AXVdm^o-3Q8VfxNNBj4FFi58aCohAa!Td zD(pvzh05~M#0mRN^o`W)tbzSbC;?b0f~#rW$LE89v4;&h?&C%bKEcc&d)pWE2Gnz9 z`6>A^O5MQtFCR~l%a?05yiHDC7&N}G-%dA!VHeC5(zRa%#D7&BkD9fvdThDMDsH&1 z`Rd>!%&0At8aZ;L!q+}SnUrWpJ&{@x_CVuz10wK}vJ7lL73jyVKbh}qEMejXXa4~z zPj!WB+1-vH)Q0isa1U~e>Ob&$-7Ky>>xL(kHT5G1o}6ONpH02qEJ zyHn-a=?~h8A^@&zyu3u^voBHgVGmWsrgZArmBMB2yJB?FQ}E$tKYsX*><45THVLy| z+J@9iqZEm(=$MD%>?i1=AKf?YS9G9bNCX!P z%#-ZCM&Q~SV|-@*>1m!__mz#W2!W9U0(xrJauNtbdU6`hYy@cwAq(NS7cc|0Z6rht zNxF?t&C=iDYF6Ro0O7l@ra+YNXYZX-xSZgyp@|XAyLuL>14>-d!_j= z{+2J!B4YOFWug-U4%S>D_6;!o zw_PMG9T^^IjQJXbhuEMWOC(g{dHVMqn0#~U;li!8vIQwa!Z!tvvnFJ`Ku;`ls)5 z^;B+vpr!J5gOja&J2)%oZ)1&V-qfIB{QjAV2{m@vkiPeqbZ1`)CU695%X`5;+2`M! z=8wQAg6?Oc?md>*6`Mtc#&8Ue-5K&40Cd@HmWugcB>lru*98mB;LEh;s-U@6mWK(gys!TBfnVmO5h`X z&t&Uqw-+W?TIoeRZ4j01mUXpR5kx;e8B+iyH0LuGU?9RX$_l=<4wq4E zq4`BABU-_K+zY>3*;{nqU)L|2e4?qSL#RJ9-I9IxoUPsO!7Bal0m>X9SI0YvZ*`=uy++MSHa>V^YwWw7F7uA5iPwj;hZyLmY3W9mDY@p;`Qj} zLFnQZMers;-QrAriqo^FJzMKRCy2+9uqtJ~6{Xp4$*agt+={)`6;pW-VYzuJm0M96 z%f$1xFwO-J)*(fb(}=>)QIG<0wTCF0@cJ+7mGX%WKghZ1ONiL2{h!|VSTbUe>wfwD zH_hTEgiQ0Ei|k%q$&B`S9Qg|rm;&Oc!FZq@X#c6e#Q$2XSPmTn?x9T{cD)~k@4ylp z$fx*LYeah=s*c=0mH)kB{k?pB0BZfhp}!t`HpFtaaoPlTqjHLi3*;*%?T0qz4z6)B zMrc)*Bg>(UukVnhl|1e<5EohE0n5EC>sGfT)EXJ0)S$;T;+C&{G>$u$akR-f;@?ze zL20iqpRj)vx1K$NO!4LNl?A=WKT8$rdY-fsV{PYJ4Q9^3p=tvlgRDwz8 zGyj?YNxL#XVBc0yL>IOu*K>%uj6&uVPn%l=9r<)aKZnKmo<}QfL=Wk?MYydRtwKiUR<# zDmoqjuDj=67QtOeHHRvoUc|DVuQKh9nFv0f^SxWi!3)ll{(|}dzO6tLkEGL^2*mEC zoaEj6PS!>FN7%W$jBJ8;fQYv%SdaMQXzI<6-0Th_hSXYr776Jt6s(^w7*5;HN>6{6 zq(R;F-mcm9AdHN(jAo3cc||p+HEqQ$;GrCs@_KRH6PA!t#2BA7t=m^XwvA)yypM4l zGscdtO3@|HY6~-C*d%SL{$~`byHrg_TKDM+AXH0le@d#_&?TrI&4o@Cm z?U!){9TVUBU$tzajVI0Ipj-g`FudqIyI_g=>URgno@SGsX-t?4=>!o;`3tsW67nk_ zZHdrJVU17?<=G0#pM%U6(xE={lcsoF)^Htf_v3l)e|VDeGmnFGR{||TSr#t7=qzhE zZ_&iBE7;ziT!{DGsjav!cK83X08YpR&ZVp{y_vxG+^GVrI)8v=NV=$9Wi2^n*pmH24V6sph_fYWhX&VNy^D-)s@gScTnAPvf6_d7YDtco&lO zgDNWJPP^PKH1qd$Y!H6+c#h+P#ccFWigiHq-bUhp;!e7$0!BptyZi^IzXp>NKL^=o z)De^05hCwrqj;QMl3rfTBXdf@?XI40N~d}VM3;|sY7(wb=Kh%c;bb(JqDHnp%;`qm z70P?vn~KOljxQ=3LH*i&7rWzK4;ML6t!t(*Uj+GHfR!nyIO33?Tv0Lw? z?(teD%U8_hq)F1g&r5zEbFcp0N`Uz8Mk)-iuNq-o@~1&x(B7kOmIgU$_+%yq#48tN z{z32uE#3bF2N+T6Ia);C{TeN?gwI=;x}-P>2v0=p?S%H^fR<-d_yptX%yfRGXEYfu zIY&^0k7O4C^-o58-&|q885(tkILc>D_dnf++=;qzyo{a=zQ;3MA)Q57v9k(R*iFj# z*Fkp;7-T8kn#!i=E#-crXAICXL49>;7oV8YWSiqXK*vu|$FQ3EI9w|6bhPxWL5$;Fu+s35D;olO!kl{lHZ@&ak>A*2tJT?akcFK9E!oB?KKA0R;G`u3n zSx?nb&}-!RHOQR!VuALHIe38er$M6~2d(@(xac3)eZexP9aYPYu^GSfOS0;E>60Q{ zLS6*V{Mh}T8U!mGq_@N~IE{^4_`&VF&>`sQz+IedbBcKSaqXShkfthVCps!Y=W8cd zA>_4oMA|GK+vSWjQu;oAD*|x%K-lDh<`sT^3}7pwi2kAGq zu-$CGL)Ky@{o{Ui#7lhbes+Q&2PyKS7BBMny z+xvj1v$As9(b5&fUh%PYCFKh@`bw){iqo#|zT%n?6Xuf%yE+Cl0hcjRY7Y<*?t{Mv z5BwmoAP~H?<|n$36*#DDRg8y9Z5GeH{(@320_RUe5CfaSMFAmxb&L{M#hC3 z=WBn$lT5&RCMIvDk&y$?~IB{bYnJF$;5uNxo?crC`kl9Ml~h?SSh+P zEgM$}9`Dojlg^Eg0BwqOS@z5|oNFlhWN&f`k>c?b)f3WlKjNic30Xx@ zmif6n!8pv1`JFI8Ev>5_ZCX&?@GZ9P+YE}@hk10F!CQLsNV=`b%|odCcc}?|7=1hE zM2-f{XeLsZiy@A>>(}d_iFAT&`>=uM{JI4{pD^gGPNplhSiZ>q!5vR2DZI~)s*OK} z`Nd;UymMt|-}%06V$%+?_O4 zIc1mbRL2`@{~>y*GaJTp&Jv?ZJ@pwKCZK1PHG?bC(xP^lu9QS|h4ZjPxe%Imd3Z(06Knpo5zN>7JGs3G5iLm1jZu77}-BN%oZ4uuq}RYTcV_P zFAm}*1>s0OXBRN~B~NsqIzq}pWgS46$kSiVt~&`C<69Ci&?@ve*BW=(Nzx&uxTL;G zv&`X!0os=rHn^=fr!!0E#W{|l3zUvK=wLo=ol@;tiU(a%DK42;_44CQVw_ja8_OFr%9yna)80+_VbZjEqxep6CG0%ecl@DrtN(?)2X z0`WifLweik-Esm^<9TdcqMMs zEB*)vt(HT!(jtD>=Ao}k_Km*U{E~oDTI&JOOC+8<{{-*;NCR0Tj#em2=eM8)VTE;t zO|c0ltZ-Cr_UM%tQ84k{^Eb~;?lXdCf=kP*TMWVL_ex>De9PJoLki+$_@m`mKiJW{ z#lpCxCr>f7o=tIeP?LN7xLdmJ=j6u$a!|Wo>&jd&MWlu&haDH9TpeC{K7`{n*&Jw0 z3jZqgXElv?6UVFK=fK*%~UEVDrWUg(S1Y*&3MXzWFe_^sKnJ9T7y5 zqQqw4gxGeJhWA(cjN(3o$Q}?61q~Lo=tlp>W3K!DQEVF$hPbgn_e~AE_L&mAu96~1 zXt+C>o*QQ_bX@(`;K%DzqMg+(pFKY9Kz$y3l(Q;423mt15XFeb9U&7`MdJAMU;D|E z41g>&vJdw}=@aHgv|QsqsS1=wtu5VF2%o9!S^2w(R}7nVpe&)be?xZoKA?L&d#E1r znIwrB^W4j3-dg$G@5QkR-=&KTK4Rs=RJ9!Yj)vk28DQ%KPz1!b%AYya;IzdK1;2ut zL5P#Z`jMNBAJY?9u;*t3kiU0MKfMx0oIY9z{2`Bff=OLzlE|vO!&^B=z}x-y8^x}Y zenlgAfm)g(yqr$sB($yQ;%(NzpC8J}I<1oXhs40ScjO3KhK1x|o z_CVooaThdhnonz9hU^~Q{=^8d$l1dLRretB9)9ETd~JM6GQ8j2;>TYx5fJy0j`SNb zC35#?qJH{4XA)T$QDC<4M(=-LX#{g5v&BbP)P7D=>nC%@@Gn_K)a(A1V@n>3w~!<^ zA0GzWv z-$P(|AObDR)aGZcG38zwuP>!!md{bv{bnYCi{ret;H>#qVxe7D9m<<%P8GOgQ~1w( z&}O?|nPGewxy=i9o(NjI2&0sm+ldzatW`YbR&di+5DCrjy=T_55#5-DjWFIe1&<~} zr*Os%hwB^*LG+(h=UaoQE?70+)SVE$({!6jHW~qg8{2mL$`gWnna2_Y1j*kAD1Qs= z0t*$a0~R{`VB&j2as&};qhoSNG>KB<_27PPd%sIzk0Ih0MnDnzoKm(J@1~phqgJsl z>zCWL8~awAlgd`u`@yQP)8BQ#w=In@Q>pXKdFojmV+)dL_XWljIruAZ9ase%t#c56 zRlJO(gJ=`_)PbWhL*lS5^0(OLi`d}I(Q*1+_gZ9^hlhFxfy(bhl(ZfIH~6NkchP8&kI^=+MelNj%HP&b~U zTQ@dyFSm9Qb?9?ll7wM?E&MJV{lrX=Cw$tHt~aX9Cc70H!^Lz1qd~#+P2~J0ZSZ$u zI`tib$Rr~%h(`B*UYp^vge%&EF41^22~c91^xY7(R(3}}ot_=zmCRnED|n$ z2<8r?c{n(qwEHm~K=bTHSeO8NuOl~~?OJvFBygR;@7SA>V6xLiC>hpwdBJG0bTvWL zoB&SmjSlSJYdnU1~ zeoIuWw`Si52={pVXLOghF7CG}ubVJ6AJ_brPG+g=_vTFeviPiOVh6j5Caf$47KH20 zzHTWk2E4W2KHD=E7>#j*!OsSY@1M{c*~CdppANH^+iYzGJW@YTvzcr0NORQOV!pXo%=%jVfEeIDH}L^5Mt!c7 zbI4on<%J%CvDhBFf$W}qe0a`x!O*KXfl*hnh^u6QV~LCv*h^y`%#QWrnDGY|*}c~4 z7n`AZ&Tqpm39jWqf|#O9l$t11fgb+?^KA~h@sN7(`JRJQ4OuR-DnTI7Isc94_4t4O zXEXN#F|1+F{)!AIQIZMl9rO3*#;|XW1w?CIZI(@BUimS?bOmN-E-J=d4U7oFgvAz; zAdo)85itlx^wRnRO9c00`Wwou?dquZ=ivL7@@h4J&idz? z!xNc>I#fQ#B-)|s?wTnXAF-dCx;M66GRa@SHofcx5ZDgat__iAtS6K9q9(T37(d)) zG|TI-L>mcoIsN!K^NK}i@+ga47nme?TfO4x^E{PNrbU|ITgUp5*WC)iepA`^Tlb9} z0vGzcF;0w_Y-fghY>LjzEWj`R^96q%Vw3|6%LSimmF-q|QST_=yBs@X{(iIF6G~9) zIIzWw!9|g_Pd0Y}xsO-;JW!S!w|CHXHEPZS_)}}H|56KHC8U=Lb|jpD(D-4Mb}!VS zlj^=6M2mV9kfTGj%JIGBHlh-8!5S2VN7dL+wmc}{u;@7Dn&+@Pg!iR<_x+{dEjG=& zgLvsBR^BwFfRW?OY2w#+jeD3vc756Hak>jxZJ&`KkaahdnAo)XfUI;udGBBjw~~HX)zlvF z5=ayLT_Waw*RkHG&<#Dz&11nG;kg&qAPb)}a&9-;0syt+*Fkq6Il$*waz5Dk`CLwM zj#s*sw?HaMA5+`A|eU>(u(C2;^A6L{>Ep21zQ_!rDrRZ_MdBO!iN9GiT z*G)@85U&idGnp!V6j%5h5s*9$FdUtCHDUO z9{xwYbYWJ{L?G{~C#ZhaymQyM{BOAZHwl6K*cKlUbI%=~T9zNmHyjFx_B|C(Dr`=O zmu-$mqk3Ep_?H@t|MKMj(nLRht>?N2qp&RyvgHP|dC0z-M9Dygt7H1=wo_AHu99;_ zJL_qs3Lf>5bB)8EzhE8+3d@9j+dQAt>ZS79&s+FX=MX`BL$kmX+_VwFRPik{)p;_1 zL(e@^oj8XO1mD*59K3vJUG=H`JJfW!IgZ!^l@ok#{VmD9Ka|gtr&1Gup*zj1WDM5( z)*nuGS^?TXeLO6!82*iA-ETk4)A@RUv55c#o0Nq8YEM04s_61erJ9gWSUx1Qm5_i` zuoY(hbEDFJJPK->KsFfY8XpAYZnVfL|^O#{S2aCI;v(7zZEMr1ScF`39>-hjJJaf{Yb5{jzuT|){1tE3*5CJB zl{FACI_^l!V4@0x0X1wtmjni)yGqs=RGv%{p6y_e_USGWdRwoONAI3O>hht7-TZ3SS<`xc@7Qk_a@SpDVHjH7!4lTIaWJg$wE&jT z*FGPOOa3hGmNI8+#T>`159b6*dqwE(K7Z_r)iGJXh#SrL_{}O|#>UKIQR}?(bwlU2 zp>aWmQAtKSg_R&e$L^&-qZlSN5Vuubv+F_%C(6H-63-x!eB@6?^X`iH<_wMTDJh zL}Q5@gl6V$A2+WK5H$CnU-+zE0f_{Szuoh}+lwvi3zf0RlJDrbOK$J>G4(&F&NcKX z60&(tWp*uAwbP!xHd6%r&X`ju-eoGTr4&Y|5GINC_q)5W%)=QaXe*b{wtWt|Wn}fB z#g~V5d84=N!Ff6$GGoEo?zJh)ja1^}uOshb)fU}bVc)~>OI2f-sBI-XQ1~ok6-j&n zSQF`5(qvNV>A~1Dizq&u3DqvZKY2CEt*~)Anrx-=Q%D9m1?T%ik*q5@dl-S$$2B2@ zO|1#rLi;c0M2~qO!pAe~pBu8$DtDvvQ8vb-u~{4Jxd#s<1c+1yh|u1-&KlR3BnC!M^qW_QU^ z{qyC7sB?f~Ifj_Vw-|GR#N-TLPZ0oH<^Qf%o@YOvkuV~Oc{Wd&4c|W7m68#hZgksTL0l)w!Q{fk=3 z4IYU{M5H)QJb>)yDm)AWDDse9!5lB_RZU7F8hbJiZPZc96`i=|vqj*XIr+xeVqAG7{2qC_mp zsyyBO89;Z}=o~iv@!GNN*y}^dMcn+p*$!&wxH?hh#MAmrTSMIL*v5dU80a~zR)LOa zs_~A{Ti?ZFl4mDODV~P6)2>`{}3O}ZYZU(j{S#|9}v<^E8Z(^d^aziX53lCFXn(BJ2afL z^gyfqpZ7~Jw4)Hm&TXzbV_pce>AkC>Rqi58oOR~%{l{O>gS3I)#~9U8oepfJN^f!k zDt^oooi!rrUeb%MlHfB?oeMfH5elur>Lo6)!mA;~&vR_i8G?hGNe0}b^(b-$H+g~@ zdW&I;!0;5kilmeRO$ypWfA|r+T11ESkiDWo)ua}A4IdXUZ>b9mB6wJXfN@=!{J(We zL1t49a&zj>Da|KsI97U9Y`^BYUefLsa}Kokw%v1YMKCes*?U|g_wWoAX*OTL)jaxY zTn}psv*>g1G*zrGVSf*xgjtn}qO`;(M|;;vc~K@TS!B##N(&Uoli zGxuu`MXQl^OFHyiC&xiKXXO@MrCn+nOtJ&k8DA-`euf53Jap}*+lNIw6`QG1llXc4 z=mp_dAShAqnTZ>o9-CphJ5sL^!&HO-Udi7>+G1HCE0MOrEuCG%? zv!2XOMyOi`ar?Rh(7t~7_a=tK!$U&+fmW|s0a^a8xcqerX>_;)hJfxgj`W;3pehI< z6x-wameOBX%k8nMF+dPmKOr)miRpMofdv|LT6ou|V~r%iZs(@9?$%nPcXb8Wkem)H zKi1M3Cc{2P&-p#VR*5l49McxdCh61GuA(pe*N}6h(Th!V$w7}_dH3MzA`ub?L3e)> zWWW7b@mf(MswR){jcw_tzn?MR`4Gda8+}$9Ku-sooeuc2fRl^b0g!?6o(dFjuft}T zLjeEOG-kqU;%&U3&p1=9?%h96?}uu%_jXk};%t95wmGj~L?Uq~8Kpp$a^)ONsr`Ah z%D6?#(-Y2a9(~x_eD;ct@W`mqUXR*Pv+kp&cp+t5}mbA&V zSL$7kW%!>+wv@f*(Zt6+*_dK5>>x>)+uUF@cjudw)Wll!aqT%<93^x)DDWX1B`10W zWXaenv?y#K>BwbfhCB)H6zGHcjv$*L^<)9=ul^W~_Wo`#|iI6qp!DX64zY;fJHuJ5`5yZudC%o&>jaSKj_9~H!k z@y?W-+1?s|Jm##UOoKcQix1Ie-5kEakUnzxOL*v3uwsrLCci6~z=wyI5F-UU)VtPI zadg-miQ(XChUa%l%U#Qr8*px(y^UO(A-=`9KLhgr2G;u6$Q@A$6lX3~FgMD9@t!%I zG@$5byEDRSSIT@7D6`-d3MHKYKWXoE#X4Fzsu%p>sOovIQe@)07pbqlAAPAfpp|54 zHR&==54q2`dd*j z>YCR8e>w3?p|C`DK@(f&DdvO572}WBqi-gp za^{n2WyMJ8Sp|Pn;l&rQzwr&|j%$CqiLLH!%)_8puV5oecXAN{w8~0JtX#JXILi+U zEP^V84!hKR6L!OTa0IHv^h-KKuDRPd16bNex!PnG;|--iS@p@}(ktIpE_wE3ZW}%w zDLW!zp=F(T0ob)MfgPq_d5h`j#flhgW$LdpQVw&!RqJL1StR58KFk+_*6Y{od`dsL z_EQ{(wDx)}M@amc_&zIPCLO6ePMv35<%vI+k4{d~h^;H{``Z(tIFOwh;Vd@B!#VlS zd(9F4X_EtwfnkqoPlU+<)jLzkeuE|Z>c*y7vpuq6 zFONM}Pr8F_-`$^$^bq^f_jV^oIoI+t(Fsun_3u_Bb^CF^Vnc)HAoePs(n82#WiRW= z_Hn=#k(TYap&Gn#pjsSdU4pJ`Uaht0lL)*Re&?7@Jd}p6yU}M(fkW?(|4>Q6lqn?U zE%ve&4`B;1d`scjy-|+p_RkUVaIW?y!4+jA-V|)tpF;F_LUqE-zMKiIp}%+o zn1<>K2vqzg^0-8&x5mX zCHyy;0(Rz850SlZQoUr(5Ci_wSd#U=1gQvYeaa79t}b`wp(t9Ry+P?>;k`vo7CRSD zKh{m6!;xX{)!2?mI??+=?Lv|a)1A5(k=K%K7{tDnz3mol`@h86b6B(wQN zeS=$7yr~>IJeQ8n|K>CFp|14XKT-qSyT2lZJV<$X>p5FBXg9YycP%2F>f89o%1T@J zoYb0N2eGw}$205zsp57D5KEBVoSNPpR(0x?4Y7kZDwUg;+{%;75!MqG>I{%0@IK-) z-2RQ#d8Ro!u(T>`L(%$0LG!8~A7G}YkiD_aXsT(dq4PtXzCQL5MDjF+`j|khwEgVd zcgJ3c-2p0$g*Cm&(Azdwm&C1g0Aq2kCDv1$l4vO9^n~1{xLmh|K;oB+6dGOxThMnoKpa5oxSc~e1hqjs*zdj3ojizUjIahD?Gprc zpl!eS`d`oLX#ixTIC}B3r`+l+paQhVNO{06RBV}#Mht5Y=rIlOe8~yErMUy7ocB|J z^#?^_1)(B7F(>VQnlJyLAe{&MCA8;>pxe@$B-n!1blDru7!Ew6(cUbb2S{w*q1(;r z=rJkq@9+1|TfVXxZ0d(>i?s8{$v*SlNS;00jEv*h*$=QOrSY8X4W7_Q?vEmgXy5o# zP`)(`oxO!hkn6ck*^Lo+yLiQOS2UfjwALH#>3#Cl?PD%-r-$q!pjQle9D7uu^l-@c z4CdY6JNS*)IgagnJ<(I5CoTVGAC>M-u8`V^?Da}{X%z!+ygzpizvH(z-fVuJ21{v` z7Wwge!=o=wT4D4*D;A%NG)8QxU4{@~M-Z~cro!8GY_qt_FvctYVoai9sQ*OKvoZz= zs3R5V0zJB=Sn2Nc0e87j-*7Xq;q=Gq$&qR4DJ!qS5H?HPYB3Eoxf7Lv9@tkn`7s1u zB{Tp?TfLLmyGzxF=GC=>O#jtZpKinqZE149 ch@b#m{wRDBD=lp^abMGuot2Pk- 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∾el~L@%X);YZm&Mr{aPno- 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 oFCEH1BifAdZ9(_x4mP93P` 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%0A&k?1i`K&6ZPlqv;P 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 z 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

xk(Cfj@+ibhnxZn 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�n z`ucx|v>UC&w{zrbu3khTAq6_J*doBy;PjE9dfM;wkG^scsb>kYp5pjIbw;oxK()oB zs*jZ8PL@)p(tzZB0_SOIcP(2s3K-WGjWrG{z0U-ESUWs^;sV?-Q2;0wl@3&r;HtXw z_2=>p#CUQ61bbk4qOmjI`vVzT8k7&J0;LUvL?~W6p(_Yl+qG*a7j=%m&>o-{^Yw&Y zLLV9C9=Nm2Kp5A&71;9O`=jx(zG57hM$zZ^AP$iCzF^a^8&eX>Ml2^BJGSgwtY9+= zkCpSM=dvOz1@3e*1K-ns1zxIcDtNeIc4PcO>ya7;Rbs>UK}6?DRXb5;`U+o%ZQMZX zi%yC;AvUMVFb1ILI1R}0gmy3;FhHXKRA7Du!y6$^xM4vQynh#B9mAJ~`_LPj`%hRm zxZP%D%zG%xfxY_08D&~$162ES`Neo2N#}eC!g*IJQnc=hmBK9)Ee%RgqB6E>D z=8JC3;nqjv>j9kTlh?7|lehtR!Ju(jNGw5haf@Ks9a+xAEx7&BAl*e(+(2=&R`dO? zAwDw|{K2_bFRyYL{H$jheJieP_fHq}jc6VIQQP|-dDu8voB<1*XB(Ci?(5RX#PB&2 z22|LoW}`oTz;(6mjmyHX7Y!?*qfbVUOBR`xc3idJK{spbSd~_lJ3tmAwCvqt?igZj z>O)fpDjVpCT+;l>4h`rz7qa4*)6R8npRL_6QOyu$lvtr}%K6qfXd-C%LUDC=wNzr#u!*lu8M zNRbsJWw}$*f58u`HxO`3%^Uya8wrf(Zo}S*OxOTMn#e9JfRvuFg+f$OiY`7oH3kj@;M42~R;yoXN!5_ZFp5N8|7VcP9)DT3&|nZ$9i zI+p;@<27v?cktZWHwPeQ9x=wr>ML-r&@p)Of%8ihcS&u$ZqP3FYI^y+Kc(bNS@iAj zc|-ZVU`EoBMlzp4vw@xr)WVkAZqMxzSnM7#RQqhScnRdPE}8nk@B>S%KLn6gTA*RLDyeS%^{Z}i|;n^8*99uM5pHi#2`pzR0Ul1}wLT(?pkcLMJG5?#Lc{cBz zKX?)gp8R`4LPlzE;0D+s6FHcU4Y&{VM!tj<#du*#-877J zQ{bR6*FlR#4F@FxkJwh6{C~vzG<#`K`(AKW?pmNC%D$m|NVM5l z_>tRprTygKxLa>0M49Tzi4p~7temwqmY>i~zZKbwQF0S!U$t^}&r*T_Xbkv6I-+&iqQ+ov6Z+)L8>NI=hz9DNL`d z5>7tV=vX{32Fu*ctG!hW<|J&H`b5rhZ8bo{KJX%7=(SWm+TIo_hV@WVZ^!3C_5g$H z&{F!vX3C}??Z5XtQ`!x7)YN-#4#jyTc~2`oTNrOL_9X+AWlNz~S=F!&a{cW4_EssO zVJ}t*(9D!8F@4298+UbX8RN|`beuM(j>ptC zv1xgB=~|^V!tH?aU%JUIGA`_@v#6(pv}Y`ltgg#4jk_x%09<@pZm>BK?a8ScPLPs* zGzKHk`BF_#NQfw~ZhZ#fq_EW+_X$i8A^eYXk55GSB`Mjjj|tRtX$T{nLzSB?5$=a{ zMVzw^+XcIFpOWU6bhR^sgW9yfTCUX+4IdUr^O2JriDF27g7qls&UO`dD@Z7!rUe$s z>N+QRIWYT4hGN0A1^T}dHls`X!4nB4|0lgOIy4Y8^M4eLJ_U+@%RK+m8A62&1IYd> zIT$dYKtZ$oUm4|JCH&Z${MTFs9i8a@{{G?L{}o314C(~#fBj!6WVON6Sp9#M@bBc( zVQxaJ3n&JRDTF0EEIcx2G2j738%IqD-9JcW^HEkj4dK>MX`lDEZifibTt#uh&#`@S zSwmeg0EIk*;C2I7jCtu7M z@NYo5OWx@4ix!5H1^5A5GDH7TrPFTWTz+CaDvN}q2%P2_#t~D

YE&ebyBHbT`O% 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 literal 0 HcmV?d00001 diff --git a/tutorial/fft.png b/tutorial/fft.png new file mode 100644 index 0000000000000000000000000000000000000000..1325ba300a30278b3b1bc1c20d9236876379713f GIT binary patch literal 637644 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

nYh~u6{(j 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°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 {val_loss:.6f}). Saving model ...') + torch.save(model.state_dict(), path + '/' + 'checkpoint.pth') + self.val_loss_min = val_loss + + +class dotdict(dict): + """dot.notation access to dictionary attributes""" + __getattr__ = dict.get + __setattr__ = dict.__setitem__ + __delattr__ = dict.__delitem__ + + +class StandardScaler(): + def __init__(self, mean, std): + self.mean = mean + self.std = std + + def transform(self, data): + return (data - self.mean) / self.std + + def inverse_transform(self, data): + return (data * self.std) + self.mean + + +def visual(true, preds=None, name='./pic/test.pdf'): + """ + Results visualization + """ + plt.figure() + if preds is not None: + plt.plot(preds, label='Prediction', linewidth=2) + plt.plot(true, label='GroundTruth', linewidth=2) + plt.legend() + plt.savefig(name, bbox_inches='tight') + + +def adjustment(gt, pred): + anomaly_state = False + for i in range(len(gt)): + if gt[i] == 1 and pred[i] == 1 and not anomaly_state: + anomaly_state = True + for j in range(i, 0, -1): + if gt[j] == 0: + break + else: + if pred[j] == 0: + pred[j] = 1 + for j in range(i, len(gt)): + if gt[j] == 0: + break + else: + if pred[j] == 0: + pred[j] = 1 + elif gt[i] == 0: + anomaly_state = False + if anomaly_state: + pred[i] = 1 + return gt, pred + + +def cal_accuracy(y_pred, y_true): + return np.mean(y_pred == y_true)