From 5c2380ae2115dc34cdc4d927f56a40f677cd2e7f Mon Sep 17 00:00:00 2001 From: czzhangheng Date: Tue, 9 Dec 2025 17:49:18 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=82=E9=85=8DHI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/launch.json | 4 +-- config/HI/AirQuality.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/BJTaxi-Inflow.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/BJTaxi-Outflow.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/METR-LA.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/NYCBike-Inflow.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/NYCBike-Outflow.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/PEMS-BAY.yaml | 48 ++++++++++++++++++++++++++++++++++ config/HI/SolarEnergy.yaml | 48 ++++++++++++++++++++++++++++++++++ dataloader/loader_selector.py | 28 +++++++++++--------- model/HI/HI.py | 45 +++++++++++++++++++++++++++++++ model/model_selector.py | 4 +++ utils/initializer.py | 3 +++ 13 files changed, 453 insertions(+), 15 deletions(-) create mode 100644 config/HI/AirQuality.yaml create mode 100644 config/HI/BJTaxi-Inflow.yaml create mode 100644 config/HI/BJTaxi-Outflow.yaml create mode 100644 config/HI/METR-LA.yaml create mode 100644 config/HI/NYCBike-Inflow.yaml create mode 100644 config/HI/NYCBike-Outflow.yaml create mode 100644 config/HI/PEMS-BAY.yaml create mode 100644 config/HI/SolarEnergy.yaml create mode 100644 model/HI/HI.py diff --git a/.vscode/launch.json b/.vscode/launch.json index 21af481..cc2c023 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2107,12 +2107,12 @@ "args": "--config ./config/iTransformer/AirQuality.yaml" }, { - "name": "iTransformer: SolarEnergy", + "name": "HI: PEMS-BAY", "type": "debugpy", "request": "launch", "program": "run.py", "console": "integratedTerminal", - "args": "--config ./config/iTransformer/SolarEnergy.yaml" + "args": "--config ./config/HI/PEMS-BAY.yaml" }, ] } \ No newline at end of file diff --git a/config/HI/AirQuality.yaml b/config/HI/AirQuality.yaml new file mode 100644 index 0000000..07300c4 --- /dev/null +++ b/config/HI/AirQuality.yaml @@ -0,0 +1,48 @@ +basic: + dataset: AirQuality + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 16 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 6 + lag: 24 + normalizer: std + num_nodes: 35 + steps_per_day: 24 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 35 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/BJTaxi-Inflow.yaml b/config/HI/BJTaxi-Inflow.yaml new file mode 100644 index 0000000..d752667 --- /dev/null +++ b/config/HI/BJTaxi-Inflow.yaml @@ -0,0 +1,48 @@ +basic: + dataset: BJTaxi-InFlow + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 32 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 1 + lag: 24 + normalizer: std + num_nodes: 1024 + steps_per_day: 48 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 1024 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/BJTaxi-Outflow.yaml b/config/HI/BJTaxi-Outflow.yaml new file mode 100644 index 0000000..271fbc7 --- /dev/null +++ b/config/HI/BJTaxi-Outflow.yaml @@ -0,0 +1,48 @@ +basic: + dataset: BJTaxi-OutFlow + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 32 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 1 + lag: 24 + normalizer: std + num_nodes: 1024 + steps_per_day: 48 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 1024 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/METR-LA.yaml b/config/HI/METR-LA.yaml new file mode 100644 index 0000000..0826302 --- /dev/null +++ b/config/HI/METR-LA.yaml @@ -0,0 +1,48 @@ +basic: + dataset: METR-LA + device: cuda:1 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 16 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 1 + lag: 24 + normalizer: std + num_nodes: 207 + steps_per_day: 288 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 207 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/NYCBike-Inflow.yaml b/config/HI/NYCBike-Inflow.yaml new file mode 100644 index 0000000..be217a9 --- /dev/null +++ b/config/HI/NYCBike-Inflow.yaml @@ -0,0 +1,48 @@ +basic: + dataset: NYCBike-InFlow + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 32 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 1 + lag: 24 + normalizer: std + num_nodes: 128 + steps_per_day: 48 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 128 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/NYCBike-Outflow.yaml b/config/HI/NYCBike-Outflow.yaml new file mode 100644 index 0000000..0f93fe5 --- /dev/null +++ b/config/HI/NYCBike-Outflow.yaml @@ -0,0 +1,48 @@ +basic: + dataset: NYCBike-OutFlow + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 32 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 1 + lag: 24 + normalizer: std + num_nodes: 128 + steps_per_day: 48 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 128 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/PEMS-BAY.yaml b/config/HI/PEMS-BAY.yaml new file mode 100644 index 0000000..832f455 --- /dev/null +++ b/config/HI/PEMS-BAY.yaml @@ -0,0 +1,48 @@ +basic: + dataset: PEMS-BAY + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 16 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 1 + lag: 24 + normalizer: std + num_nodes: 325 + steps_per_day: 288 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: true + lr_decay_rate: 0.3 + lr_decay_step: 5,20,40,70 + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 325 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/config/HI/SolarEnergy.yaml b/config/HI/SolarEnergy.yaml new file mode 100644 index 0000000..8f55fac --- /dev/null +++ b/config/HI/SolarEnergy.yaml @@ -0,0 +1,48 @@ +basic: + dataset: SolarEnergy + device: cuda:0 + mode: train + model: HI + seed: 2023 + +data: + batch_size: 16 + column_wise: false + days_per_week: 7 + horizon: 24 + input_dim: 6 + lag: 24 + normalizer: std + num_nodes: 137 + steps_per_day: 24 + test_ratio: 0.2 + val_ratio: 0.2 + +model: + input_len: 24 + output_len: 24 + reverse: False + + +train: + batch_size: 16 + debug: false + early_stop: true + early_stop_patience: 15 + epochs: 1 + grad_norm: false + log_step: 1000 + loss_func: mae + lr_decay: + lr_decay_rate: + lr_decay_step: + lr_init: 0.0001 + mae_thresh: None + mape_thresh: 0.001 + max_grad_norm: 5 + output_dim: 137 + optimizer: null + plot: false + real_value: true + scheduler: null + weight_decay: 0 \ No newline at end of file diff --git a/dataloader/loader_selector.py b/dataloader/loader_selector.py index afd606d..f9bf823 100755 --- a/dataloader/loader_selector.py +++ b/dataloader/loader_selector.py @@ -7,17 +7,19 @@ from dataloader.TSloader import get_dataloader as TS_loader def get_dataloader(config, normalizer, single): + TS_model = ["iTransformer", "HI"] model_name = config["basic"]["model"] - match model_name: - case "STGNCDE": - return cde_loader(config, normalizer, single) - case "STGNRDE": - return nrde_loader(config, normalizer, single) - case "DCRNN": - return DCRNN_loader(config, normalizer, single) - case "EXP": - return EXP_loader(config, normalizer, single) - case "iTransformer": - return TS_loader(config, normalizer, single) - case _: - return normal_loader(config, normalizer, single) + if model_name in TS_model: + return TS_loader(config, normalizer, single) + else : + match model_name: + case "STGNCDE": + return cde_loader(config, normalizer, single) + case "STGNRDE": + return nrde_loader(config, normalizer, single) + case "DCRNN": + return DCRNN_loader(config, normalizer, single) + case "EXP": + return EXP_loader(config, normalizer, single) + case _: + return normal_loader(config, normalizer, single) diff --git a/model/HI/HI.py b/model/HI/HI.py new file mode 100644 index 0000000..aefbd12 --- /dev/null +++ b/model/HI/HI.py @@ -0,0 +1,45 @@ +from typing import List +import torch +from torch import nn + + +class HI(nn.Module): + """ + Paper: Historical Inertia: A Neglected but Powerful Baseline for Long Sequence Time-series Forecasting + Link: https://arxiv.org/abs/2103.16349 + Official code: None + Venue: CIKM 2021 + Task: Long-term Time Series Forecasting + """ + + def __init__(self, config): + """ + Init HI. + + Args: + config (HIConfig): model config. + """ + + super().__init__() + self.input_len = config['input_len'] + self.output_len = config['output_len'] + assert self.input_len >= self.output_len, "HI model requires input length > output length" + self.reverse = config['reverse'] + # self.fake_param = nn.Linear(1, 1, bias=False) + + def forward(self, inputs: torch.Tensor) -> torch.Tensor: + """Forward function of HI. + + Args: + inputs (torch.Tensor): shape = [B, L_in, N] + + Returns: + torch.Tensor: model prediction [B, L_out, N]. + """ + # historical inertia + prediction = inputs[:, -self.output_len:, :] + # last point + # prediction = inputs[:, [-1], :].expand(-1, self.output_len, -1) + if self.reverse: + prediction = prediction.flip(dims=[1]) + return prediction \ No newline at end of file diff --git a/model/model_selector.py b/model/model_selector.py index 0d9d120..7403893 100755 --- a/model/model_selector.py +++ b/model/model_selector.py @@ -1,4 +1,5 @@ from model.DDGCRN.DDGCRN import DDGCRN +from model.HI import HI from model.TWDGCN.TWDGCN import TWDGCN from model.AGCRN.AGCRN import AGCRN from model.NLT.HierAttnLstm import HierAttnLstm @@ -27,6 +28,7 @@ from model.ASTRA.astra import ASTRA as ASTRA from model.ASTRA.astrav2 import ASTRA as ASTRAv2 from model.ASTRA.astrav3 import ASTRA as ASTRAv3 from model.iTransformer.iTransformer import iTransformer +from model.HI.HI import HI @@ -92,3 +94,5 @@ def model_selector(config): return ASTRAv3(model_config) case "iTransformer": return iTransformer(model_config) + case "HI": + return HI(model_config) diff --git a/utils/initializer.py b/utils/initializer.py index b69c67f..7bee2be 100755 --- a/utils/initializer.py +++ b/utils/initializer.py @@ -23,6 +23,9 @@ def init_model(args): def init_optimizer(model, args): + optimizer = None + lr_scheduler = None + optim = args.get("optimizer", "Adam") match optim : case "Adam":