twcch/DeReFusion

A simple-by-design Decomposition–Residual Fusion forecaster and fair benchmark for non-stationary financial time series. Built on thuml/Time-Series-Library.

Python

4

119 commits

updated Sep 5, 2026

See the code

README

DeReFusion

Official code for the paper DeReFusion: A Controlled Comparison of Soft Computing Fusion Strategies for Financial Time Series Forecasting via a Decomposition-Residual Architecture (Applied Soft Computing, 2026)

DOI Python 3.11 PyTorch License: MIT Built on Time-Series-Library

This repository contains everything needed to reproduce the experiments in the paper: the proposed DeReFusion model with its ablation and fusion-gate variants, the RevIN-wrapped baseline models and pretrained foundation models they are compared against, the daily OHLC stock/index/crypto/forex datasets, and the shared training and evaluation pipeline that makes the comparison fair.


Table of Contents


Overview

Daily financial prices — equities, indices, crypto, and forex alike — are strongly non-stationary: their mean and variance drift over time and the raw Close series carries a unit root (see utils/ADFtest.py). One way to attack this is to keep stacking capacity — deeper Transformers, recurrent–attention hybrids, learned fusion gates. This paper asks the opposite question:

On non-stationary financial series, how far does a deliberately simple recipe go — a linear decomposition base, a learned residual, and plain additive fusion — and does anything more elaborate actually buy accuracy?

To answer it, the repo provides two things:

  1. A fair benchmark — a single data pipeline, normalization scheme, training protocol, and metric set shared by every model, so differences in results reflect the backbone, not the harness.
  2. DeReFusion plus its probes — the proposed model splits the forecast into a DLinear base branch and a hybrid (LSTM → Transformer) residual branch, combined by direct additive fusion, all wrapped in RevIN. It ships with ablation variants that remove one branch or one residual component at a time, and fusion-gate variants that replace the plain base + residual with a learned gate. Sliding DeReFusion across these two axes isolates which branches matter and whether a smarter fusion is worth its parameters.

The repository is a focused fork of thuml/Time-Series-Library (TSLib): it keeps TSLib's experiment harness and reuses its layer library, but trims the model set down to exactly what the paper studies.


What makes the benchmark fair

Every model in this repository is evaluated under an identical protocol, so accuracy differences are attributable to the architecture and not to incidental advantages.

DimensionShared setting
Data loaderDataset_Custom (data_provider/data_loader.py) for all models
SplitsChronological 70% / 10% / 20% train / validation / test; validation and test windows are extended back by seq_len for lookback context
ScalingStandardScaler fit on the training split only, then applied to all splits
NormalizationRevIN (Reversible Instance Normalization) applied to every trained model — DeReFusion and all RevIN baselines — so the comparison isolates backbone complexity rather than the normalization scheme
Inputs / target--features MS: all four OHLC columns as input, single Close target (--target Close)
TrainingAdam optimizer, MSE loss, early stopping on validation loss (--patience), learning-rate schedule (--lradj)
SeedsControlled by --rand_seed (default 2021); the seed is embedded in each run's setting string so multi-seed runs are tracked separately
MetricsMAE, MSE, RMSE, MAPE, MSPE, R² (optionally DTW), plus parameter count, train time, inference ms/sample, and GPU peak memory

Reproducibility note. run.py seeds Python random, NumPy, and PyTorch (torch.manual_seed). It does not set torch.backends.cudnn.deterministic, so results on CUDA are reproducible up to cuDNN non-determinism. Run several seeds (e.g. 2020–2024) and report mean ± std, as the paper does.


DeReFusion — the architecture

File: models/derefusion/DeReFusion.py · --model DeReFusion

DeReFusion is a decomposition–residual dual-branch forecaster. A linear DLinear base branch captures the trend/seasonal structure of the lookback window; a hybrid residual branch (per-feature projection → LSTM → Transformer encoder → projection) models what the linear base leaves behind. The two are combined by direct additive fusion, and the whole forecast is produced in RevIN-normalized space and denormalized back to the original price scale.

Forward pass (B = batch, D = d_model, C = enc_in = 4):

x_enc [B, seq_len, 4]                              # OHLC input window
  │
  ├─ RevIN(norm) ──► x_norm [B, seq_len, 4]        # per-instance normalize (stats reused for denorm)
  │
  ├─ DLinear base branch ───────────────────────────────────────────
  │     seasonal, trend = x_norm − MA(x_norm),  MA(x_norm)   # moving-avg kernel = --moving_avg
  │     base = Linearₛ(seq_len→pred_len)·seasonalᵀ
  │              + Linearₜ(seq_len→pred_len)·trendᵀ          ──► base [B, pred_len, 4]
  │
  ├─ Hybrid residual branch ────────────────────────────────────────
  │     Linear(4→D) → LSTM(D→D) → TransformerEncoder(D)
  │       → Linear(seq_len→pred_len) over time
  │       → Linear(D→4) over channels                        ──► residual [B, pred_len, 4]
  │
  ├─ fused = base + residual                        # direct additive fusion
  └─ RevIN(denorm) ──────► forecast [B, pred_len, 4]   (target = Close column)

The two design choices that define the model — and that the variants probe — are:

  • Decomposition–residual split: the linear base and the learned residual are produced by separate branches over the same normalized window, rather than by one monolithic backbone.
  • Direct additive fusion: the branches are combined as plain base + residual — a parameter-free fusion. The gate variants below replace it with a learned gate to test whether that simplicity costs accuracy.

RevIN is the standalone Reversible Instance Normalization layer at layers/RevIN.py, shared with every RevIN baseline.

Ablation variants

Folder: models/derefusion/ablation_variant/. Each is a valid --model name (filename without .py).

--modelRemoves / changesResulting behavior
DeReFusion-woDyHybrid residual branch + fusionDLinear base only — tests whether the residual branch contributes at all
DeReFusion-woLSTMLSTM from the residual branchbase + Transformer-only residual — isolates the LSTM's contribution
DeReFusion-woTransformerTransformer from the residual branchbase + LSTM-only residual — isolates the Transformer's contribution

Fusion-gate variants

Folder: models/derefusion/gate_variant/. These keep both branches but replace the additive base + residual with a gated fusion (1 − gate) · base + gate · residual, asking whether a learned gate beats plain addition on small, non-stationary financial datasets.

--modelGateMechanism
DeReFusion-gatev1-volatilityawareVolatilityAwareGateGate driven by the raw input's per-channel std (computed before RevIN); a single volatility scalar must set per-timestep, per-channel weights
DeReFusion-gatev2-learnableLearnableGatePer-channel learnable scalar gate = sigmoid(α); static across samples and timesteps
DeReFusion-gatev3-inputconditionedInputConditionedGateSample-adaptive bottleneck net (seq_len → --gate_bottleneck → pred_len) producing per-sample / per-channel / per-timestep weights

Benchmark models

DeReFusion is compared against two families of baselines, all run through the same pipeline.

(a) RevIN-wrapped baselines — models/

Ten TSLib backbones, each wrapped with the shared layers/RevIN.py normalize/denormalize so they sit on a clean complexity ladder alongside DeReFusion. Names are case-sensitive and the hyphen is part of the model name (e.g. --model revin-DLinear).

Complexity tier--modelBackbone
Linear / MLPrevin-DLinearSeries decomposition + per-component linear maps
revin-LightTSLightweight MLP with interval/continuous sampling
CNNrevin-TimesNet2D temporal blocks over multi-period reshapes
Transformerrevin-InformerProbSparse attention + distilling
revin-ReformerLSH-attention efficient Transformer
revin-iTransformerInverted Transformer (attention across variates)
revin-PatchTSTPatching + channel-independent Transformer
revin-AutoformerDecomposition + AutoCorrelation attention
revin-FEDformerFrequency-enhanced decomposition Transformer
revin-ETSformerExponential-smoothing attention

(b) Pretrained foundation models — models/

Run zero-shot (no training) through the zero_shot_forecast task with --is_training 0.


Datasets

Ten daily OHLC series under dataset/, spanning 2016-01-01 → 2025-12-31. All files share the header date,Open,High,Low,Close (date is YYYY-MM-DD; values are split/adjusted floats). There is no Volume column. Row counts differ because each market follows its own trading calendar — crypto trades on weekends, equities/indices/forex do not.

TickerInstrumentTypeRows
BABAAlibabaStock2514
NVONovo NordiskStock2514
TMToyota MotorStock2514
GSPCS&P 500Index2514
DJIDow Jones Industrial AverageIndex2514
SOXPHLX SemiconductorIndex2514
EURUSDEuro / US DollarForex2602
USDJPYUS Dollar / Japanese YenForex2602
BTCUSDBitcoinCrypto3653
ETHUSDEthereumCrypto2975

Non-stationarity. utils/ADFtest.py runs the Augmented Dickey–Fuller test (via statsmodels and arch) to quantify the unit-root behavior of each series — the empirical motivation for applying RevIN to every trained model in the benchmark.

Loading convention. CSVs are read through the custom provider with multivariate-input / single-target settings:

FlagValueMeaning
--datacustomuse Dataset_Custom
--featuresMSall OHLC columns in, single target out
--targetClosepredict Close (moved to the last column internally)
--freqbbusiness-day frequency for the temporal embedding
--enc_in / --dec_in / --c_out4 / 4 / 14 OHLC inputs, 1 target output

run.py inherits TSLib's defaults (--data ETTh1, --features M, --target OT, --freq h), so the financial configuration must be passed explicitly, as shown below.


Repository structure

DeReFusion/
├── run.py                              # Single entry point — CLI, seeding, device & task dispatch
├── run_batch_long_term_forecast.py     # Parallel batch sweep runner (DeReFusion + RevIN baselines)
├── run_batch_zero_shot_forecast.py     # Batch sweep runner (foundation models, zero-shot)
├── models/
│   ├── revin-Autoformer.py             # 10 RevIN-wrapped baselines (revin-*.py)
│   ├── revin-DLinear.py
│   ├── revin-ETSformer.py
│   ├── revin-FEDformer.py
│   ├── revin-Informer.py
│   ├── revin-iTransformer.py
│   ├── revin-LightTS.py
│   ├── revin-PatchTST.py
│   ├── revin-Reformer.py
│   ├── revin-TimesNet.py
│   ├── Chronos.py · Moirai.py · TimesFM.py   # pretrained foundation models (zero-shot)
│   └── derefusion/
│       ├── DeReFusion.py                # proposed model
│       ├── ablation_variant/            # 3 ablation variants (woDy / woLSTM / woTransformer)
│       └── gate_variant/                # 3 fusion-gate variants (gatev1 / gatev2 / gatev3)
├── exp/                                # Task pipelines + Exp_Basic model registry
│   ├── exp_basic.py                    # auto-discovers models under models/ (lazy import)
│   ├── exp_long_term_forecasting.py    # the pipeline used by the paper
│   └── exp_zero_shot_forecasting.py    # foundation-model zero-shot pipeline
├── layers/                             # Reusable layers (RevIN, attention, embeddings, …)
├── data_provider/                      # data_factory.py, data_loader.py (Dataset_Custom)
├── dataset/                            # 10 OHLC CSVs (2016–2025)
├── utils/                              # metrics.py, visualization.py, ADFtest.py, tools.py
├── scripts/                            # Inherited TSLib reproduction scripts (standard benchmarks — see note)
├── requirements/                       # Ordered install files reqs_1..4.txt
├── Dockerfile                          # CUDA 12.1 / PyTorch 2.5.1 image
└── docker-compose.yml                  # dev service with GPU passthrough

Note on scripts/. These shell scripts are inherited from upstream TSLib and target the standard academic benchmarks (ETT, ECL, Weather, M4, anomaly/classification datasets). They are not the financial experiments of this paper — the benchmark is run through run.py and the batch runners as documented below.


Installation

Recommended Python: 3.11. Dependencies are split into four ordered files in requirements/.

Minimal install (DeReFusion + RevIN baselines)

The proposed model and the RevIN baselines depend only on PyTorch and the standard scientific/attention stack — not on the Mamba or foundation-model libraries.

# 1. PyTorch (CUDA 12.1 build — torch==2.5.1)
pip install -r requirements/reqs_1.txt

# 2. Core scientific + attention stack
#    (numpy, scipy, scikit-learn, pandas, matplotlib, einops, reformer-pytorch,
#     sktime, sympy, PyWavelets, tqdm, …)
pip install -r requirements/reqs_2.txt

CPU / Apple Silicon: requirements/reqs_1.txt pins the CUDA 12.1 wheel. If you do not have an NVIDIA GPU, install the matching CPU or MPS build of torch==2.5.1 from pytorch.org instead of step 1, then run step 2.

Foundation-model + Mamba extras (only for the zero-shot baselines)

requirements/reqs_2.txt also pulls the foundation-model stack (transformers, chronos-forecasting, timesfm, tirex-ts, gluonts, lightning, jax, …) needed to run Chronos / Moirai / TimesFM. The pinned Mamba state-space wheel and uni2ts live in the remaining files and are not imported by DeReFusion or the RevIN baselines, so you can skip them unless you need those backends.

pip install -r requirements/reqs_3.txt          # mamba_ssm — Linux x86_64 + CUDA 12 + Python 3.11 + torch 2.5 ONLY
pip install -r requirements/reqs_4.txt           # uni2ts and friends

reqs_3.txt pins a mamba_ssm wheel built for cu12 / torch2.5 / cp311 / linux_x86_64 only; it will not install on macOS, Windows, ARM, or other Python versions.

Docker (optional)

A CUDA environment is provided for full-stack reproduction:

# The Dockerfile installs from a single consolidated requirements.txt:
cat requirements/reqs_*.txt > requirements.txt
docker compose up -d --build
docker compose exec dev_tslib bash

The image builds on pytorch/pytorch:2.5.1-cuda12.1-cudnn9-devel, runs with GPU passthrough (NVIDIA_VISIBLE_DEVICES=all), shm_size: 8gb, and a /workspace volume. It targets the complete stack including the optional Mamba / foundation dependencies.


Reproducing the benchmark

All experiments run through run.py, which seeds the RNGs, selects the device, and dispatches to the appropriate task pipeline.

Train and evaluate the proposed model

python run.py \
  --task_name long_term_forecast \
  --is_training 1 \
  --model_id GSPC_96_24 \
  --model DeReFusion \
  --data custom \
  --root_path ./dataset/ \
  --data_path GSPC-2016-2025.csv \
  --features MS --target Close --freq b \
  --seq_len 96 --label_len 48 --pred_len 24 \
  --enc_in 4 --dec_in 4 --c_out 1 \
  --d_model 32 --moving_avg 25 \
  --train_epochs 30 --batch_size 32 --learning_rate 0.0001 \
  --patience 5 --lradj cosine \
  --rand_seed 2021

Run a baseline, ablation, or fusion-gate variant

Swap --model for any name from the benchmark set, the ablation table, or the gate table; every other flag stays the same:

python run.py --model revin-DLinear                     ... # a linear baseline
python run.py --model revin-PatchTST                    ... # a Transformer baseline
python run.py --model DeReFusion-woDy                   ... # an ablation (base branch only)
python run.py --model DeReFusion-gatev3-inputconditioned ... # a fusion-gate variant

Zero-shot foundation models

Run a pretrained foundation model with no training (--is_training 0, --task_name zero_shot_forecast):

python run.py \
  --task_name zero_shot_forecast \
  --is_training 0 \
  --model_id BTCUSD_zeroshot \
  --model TimesFM \
  --data custom \
  --root_path ./dataset/ \
  --data_path BTCUSD-2016-2025.csv \
  --features MS --target Close --freq b \
  --seq_len 96 --label_len 48 --pred_len 7

Swap --model TimesFM for Chronos or Moirai to try the other foundation models.

Device selection

  • CUDA is auto-detected and used by default.
  • Apple Silicon: add --gpu_type mps.
  • CPU: add --no_use_gpu.

Full sweep

The paper reports results over all 10 instruments × multiple forecast horizons × several seeds. The two batch runners automate this:

# DeReFusion + RevIN baselines (trained); parallel, MAX_PARALLEL=6, seeds 2020–2024
python run_batch_long_term_forecast.py

# Foundation models (zero-shot): TimesFM / Chronos / Moirai
python run_batch_zero_shot_forecast.py

Both runners shell out to run.py, key each completed experiment by an MD5 of its command, record progress in run_batch_progress.log and failures in run_batch_failed.log, write per-experiment stdout/stderr into run_batch_logs/, and resume where they left off. The dataset list, horizon grid (pred_len), seed list, and the active --model set are edited at the top of each script — comment blocks there hold the DeReFusion presets (the 2016–2025 instruments and horizons [1, 7, 12, 24, 36]).


Evaluation and outputs

The long-term-forecasting pipeline (exp/exp_long_term_forecasting.py) reports an extended set of metrics and diagnostics.

Metrics (utils/metrics.py): MAE, MSE, RMSE, MAPE, MSPE, R² — and optionally DTW with --use_dtw (off by default; time-consuming).

Diagnostics (printed and appended to the result log):

  • GPU peak memory — gpu_mem_peak_mb via torch.cuda.max_memory_allocated (CUDA only).
  • Training wall time and inference speed — inference_speed_ms (ms/sample, guarded by torch.cuda.synchronize()).
  • Parameter counts — total and trainable.

Output layout (relative to the working directory; all are git-ignored):

PathContents
results/<setting>/pred.npy, true.npy, metrics.npy (the 6 core metrics)
test_results/<setting>/auto-generated figures + per-window preview PDFs
checkpoints/<setting>/checkpoint.pthbest model by validation loss
result_long_term_forecast.txtappended one-line summary per run (all metrics + diagnostics)

Publication figures (utils/visualization.py, 300 DPI, serif/journal style, PNG):

FileContent
fig_prediction_curves.pngSample ground-truth vs. prediction windows with error band
fig_error_analysis.pngMSE-per-horizon-step bars + error-distribution histogram
fig_metrics_radar.pngRadar over MAE / MSE / RMSE / MAPE / MSPE / R²
fig_error_heatmap.pngAbsolute-error heatmap (sample × horizon)
fig_pred_true.pngContinuous ground-truth vs. prediction curve
fig_dashboard.png4-panel summary

Figures can be regenerated standalone from saved arrays:

python -m utils.visualization --input results/<setting>/ --output test_results/<setting>/

Adding a model

The registry (exp/exp_basic.py) auto-discovers models: drop a .py file anywhere under models/ that defines a class named Model, and its filename (without .py) becomes the --model string — no manual registration, and the module is lazily imported only when selected. This is exactly how the RevIN baselines (revin-*.py) and the DeReFusion family are wired in. An unknown --model name raises a ValueError listing the discovered models.


Citation

If you use this code or build on the benchmark, please cite the paper:

@article{hsieh2026derefusion,
  title   = {{DeReFusion}: A controlled comparison of soft computing fusion strategies for financial time series forecasting via a decomposition-residual architecture},
  author  = {Hsieh, Chih-Chien and Chen, Mu-Yen},
  journal = {Applied Soft Computing},
  volume  = {203},
  pages   = {116252},
  year    = {2026},
  issn    = {1568-4946},
  doi     = {10.1016/j.asoc.2026.116252},
  url     = {https://doi.org/10.1016/j.asoc.2026.116252}
}

Acknowledgements

This project is a focused fork of the Time-Series-Library (TSLib) by THUML @ Tsinghua University. It reuses TSLib's experiment harness and layer library, and adds the financial datasets, the RevIN-wrapped baselines, the foundation-model integrations, and the DeReFusion model family studied in the paper.


License

Released under the MIT License — see LICENSE.

  • Copyright © 2026 Chih-Chien Hsieh
  • Copyright © 2021 THUML @ Tsinghua University (Time-Series-Library)

Contributing

This is a personal research repository accompanying a publication, so external pull requests are not accepted (see CONTRIBUTING.md). It is open source under MIT and fork-friendly — you are welcome to fork it, adapt it, and build on the benchmark. Bug reports and questions can be raised as Issues.

twcch/DeReFusion

A simple-by-design Decomposition–Residual Fusion forecaster and fair benchmark for non-stationary financial time series. Built on thuml/Time-Series-Library.

Python

4

119 commits

updated Sep 5, 2026

See the code

README

DeReFusion

Official code for the paper DeReFusion: A Controlled Comparison of Soft Computing Fusion Strategies for Financial Time Series Forecasting via a Decomposition-Residual Architecture (Applied Soft Computing, 2026)

DOI Python 3.11 PyTorch License: MIT Built on Time-Series-Library

This repository contains everything needed to reproduce the experiments in the paper: the proposed DeReFusion model with its ablation and fusion-gate variants, the RevIN-wrapped baseline models and pretrained foundation models they are compared against, the daily OHLC stock/index/crypto/forex datasets, and the shared training and evaluation pipeline that makes the comparison fair.


Table of Contents


Overview

Daily financial prices — equities, indices, crypto, and forex alike — are strongly non-stationary: their mean and variance drift over time and the raw Close series carries a unit root (see utils/ADFtest.py). One way to attack this is to keep stacking capacity — deeper Transformers, recurrent–attention hybrids, learned fusion gates. This paper asks the opposite question:

On non-stationary financial series, how far does a deliberately simple recipe go — a linear decomposition base, a learned residual, and plain additive fusion — and does anything more elaborate actually buy accuracy?

To answer it, the repo provides two things:

  1. A fair benchmark — a single data pipeline, normalization scheme, training protocol, and metric set shared by every model, so differences in results reflect the backbone, not the harness.
  2. DeReFusion plus its probes — the proposed model splits the forecast into a DLinear base branch and a hybrid (LSTM → Transformer) residual branch, combined by direct additive fusion, all wrapped in RevIN. It ships with ablation variants that remove one branch or one residual component at a time, and fusion-gate variants that replace the plain base + residual with a learned gate. Sliding DeReFusion across these two axes isolates which branches matter and whether a smarter fusion is worth its parameters.

The repository is a focused fork of thuml/Time-Series-Library (TSLib): it keeps TSLib's experiment harness and reuses its layer library, but trims the model set down to exactly what the paper studies.


What makes the benchmark fair

Every model in this repository is evaluated under an identical protocol, so accuracy differences are attributable to the architecture and not to incidental advantages.

DimensionShared setting
Data loaderDataset_Custom (data_provider/data_loader.py) for all models
SplitsChronological 70% / 10% / 20% train / validation / test; validation and test windows are extended back by seq_len for lookback context
ScalingStandardScaler fit on the training split only, then applied to all splits
NormalizationRevIN (Reversible Instance Normalization) applied to every trained model — DeReFusion and all RevIN baselines — so the comparison isolates backbone complexity rather than the normalization scheme
Inputs / target--features MS: all four OHLC columns as input, single Close target (--target Close)
TrainingAdam optimizer, MSE loss, early stopping on validation loss (--patience), learning-rate schedule (--lradj)
SeedsControlled by --rand_seed (default 2021); the seed is embedded in each run's setting string so multi-seed runs are tracked separately
MetricsMAE, MSE, RMSE, MAPE, MSPE, R² (optionally DTW), plus parameter count, train time, inference ms/sample, and GPU peak memory

Reproducibility note. run.py seeds Python random, NumPy, and PyTorch (torch.manual_seed). It does not set torch.backends.cudnn.deterministic, so results on CUDA are reproducible up to cuDNN non-determinism. Run several seeds (e.g. 2020–2024) and report mean ± std, as the paper does.


DeReFusion — the architecture

File: models/derefusion/DeReFusion.py · --model DeReFusion

DeReFusion is a decomposition–residual dual-branch forecaster. A linear DLinear base branch captures the trend/seasonal structure of the lookback window; a hybrid residual branch (per-feature projection → LSTM → Transformer encoder → projection) models what the linear base leaves behind. The two are combined by direct additive fusion, and the whole forecast is produced in RevIN-normalized space and denormalized back to the original price scale.

Forward pass (B = batch, D = d_model, C = enc_in = 4):

x_enc [B, seq_len, 4]                              # OHLC input window
  │
  ├─ RevIN(norm) ──► x_norm [B, seq_len, 4]        # per-instance normalize (stats reused for denorm)
  │
  ├─ DLinear base branch ───────────────────────────────────────────
  │     seasonal, trend = x_norm − MA(x_norm),  MA(x_norm)   # moving-avg kernel = --moving_avg
  │     base = Linearₛ(seq_len→pred_len)·seasonalᵀ
  │              + Linearₜ(seq_len→pred_len)·trendᵀ          ──► base [B, pred_len, 4]
  │
  ├─ Hybrid residual branch ────────────────────────────────────────
  │     Linear(4→D) → LSTM(D→D) → TransformerEncoder(D)
  │       → Linear(seq_len→pred_len) over time
  │       → Linear(D→4) over channels                        ──► residual [B, pred_len, 4]
  │
  ├─ fused = base + residual                        # direct additive fusion
  └─ RevIN(denorm) ──────► forecast [B, pred_len, 4]   (target = Close column)

The two design choices that define the model — and that the variants probe — are:

  • Decomposition–residual split: the linear base and the learned residual are produced by separate branches over the same normalized window, rather than by one monolithic backbone.
  • Direct additive fusion: the branches are combined as plain base + residual — a parameter-free fusion. The gate variants below replace it with a learned gate to test whether that simplicity costs accuracy.

RevIN is the standalone Reversible Instance Normalization layer at layers/RevIN.py, shared with every RevIN baseline.

Ablation variants

Folder: models/derefusion/ablation_variant/. Each is a valid --model name (filename without .py).

--modelRemoves / changesResulting behavior
DeReFusion-woDyHybrid residual branch + fusionDLinear base only — tests whether the residual branch contributes at all
DeReFusion-woLSTMLSTM from the residual branchbase + Transformer-only residual — isolates the LSTM's contribution
DeReFusion-woTransformerTransformer from the residual branchbase + LSTM-only residual — isolates the Transformer's contribution

Fusion-gate variants

Folder: models/derefusion/gate_variant/. These keep both branches but replace the additive base + residual with a gated fusion (1 − gate) · base + gate · residual, asking whether a learned gate beats plain addition on small, non-stationary financial datasets.

--modelGateMechanism
DeReFusion-gatev1-volatilityawareVolatilityAwareGateGate driven by the raw input's per-channel std (computed before RevIN); a single volatility scalar must set per-timestep, per-channel weights
DeReFusion-gatev2-learnableLearnableGatePer-channel learnable scalar gate = sigmoid(α); static across samples and timesteps
DeReFusion-gatev3-inputconditionedInputConditionedGateSample-adaptive bottleneck net (seq_len → --gate_bottleneck → pred_len) producing per-sample / per-channel / per-timestep weights

Benchmark models

DeReFusion is compared against two families of baselines, all run through the same pipeline.

(a) RevIN-wrapped baselines — models/

Ten TSLib backbones, each wrapped with the shared layers/RevIN.py normalize/denormalize so they sit on a clean complexity ladder alongside DeReFusion. Names are case-sensitive and the hyphen is part of the model name (e.g. --model revin-DLinear).

Complexity tier--modelBackbone
Linear / MLPrevin-DLinearSeries decomposition + per-component linear maps
revin-LightTSLightweight MLP with interval/continuous sampling
CNNrevin-TimesNet2D temporal blocks over multi-period reshapes
Transformerrevin-InformerProbSparse attention + distilling
revin-ReformerLSH-attention efficient Transformer
revin-iTransformerInverted Transformer (attention across variates)
revin-PatchTSTPatching + channel-independent Transformer
revin-AutoformerDecomposition + AutoCorrelation attention
revin-FEDformerFrequency-enhanced decomposition Transformer
revin-ETSformerExponential-smoothing attention

(b) Pretrained foundation models — models/

Run zero-shot (no training) through the zero_shot_forecast task with --is_training 0.


Datasets

Ten daily OHLC series under dataset/, spanning 2016-01-01 → 2025-12-31. All files share the header date,Open,High,Low,Close (date is YYYY-MM-DD; values are split/adjusted floats). There is no Volume column. Row counts differ because each market follows its own trading calendar — crypto trades on weekends, equities/indices/forex do not.

TickerInstrumentTypeRows
BABAAlibabaStock2514
NVONovo NordiskStock2514
TMToyota MotorStock2514
GSPCS&P 500Index2514
DJIDow Jones Industrial AverageIndex2514
SOXPHLX SemiconductorIndex2514
EURUSDEuro / US DollarForex2602
USDJPYUS Dollar / Japanese YenForex2602
BTCUSDBitcoinCrypto3653
ETHUSDEthereumCrypto2975

Non-stationarity. utils/ADFtest.py runs the Augmented Dickey–Fuller test (via statsmodels and arch) to quantify the unit-root behavior of each series — the empirical motivation for applying RevIN to every trained model in the benchmark.

Loading convention. CSVs are read through the custom provider with multivariate-input / single-target settings:

FlagValueMeaning
--datacustomuse Dataset_Custom
--featuresMSall OHLC columns in, single target out
--targetClosepredict Close (moved to the last column internally)
--freqbbusiness-day frequency for the temporal embedding
--enc_in / --dec_in / --c_out4 / 4 / 14 OHLC inputs, 1 target output

run.py inherits TSLib's defaults (--data ETTh1, --features M, --target OT, --freq h), so the financial configuration must be passed explicitly, as shown below.


Repository structure

DeReFusion/
├── run.py                              # Single entry point — CLI, seeding, device & task dispatch
├── run_batch_long_term_forecast.py     # Parallel batch sweep runner (DeReFusion + RevIN baselines)
├── run_batch_zero_shot_forecast.py     # Batch sweep runner (foundation models, zero-shot)
├── models/
│   ├── revin-Autoformer.py             # 10 RevIN-wrapped baselines (revin-*.py)
│   ├── revin-DLinear.py
│   ├── revin-ETSformer.py
│   ├── revin-FEDformer.py
│   ├── revin-Informer.py
│   ├── revin-iTransformer.py
│   ├── revin-LightTS.py
│   ├── revin-PatchTST.py
│   ├── revin-Reformer.py
│   ├── revin-TimesNet.py
│   ├── Chronos.py · Moirai.py · TimesFM.py   # pretrained foundation models (zero-shot)
│   └── derefusion/
│       ├── DeReFusion.py                # proposed model
│       ├── ablation_variant/            # 3 ablation variants (woDy / woLSTM / woTransformer)
│       └── gate_variant/                # 3 fusion-gate variants (gatev1 / gatev2 / gatev3)
├── exp/                                # Task pipelines + Exp_Basic model registry
│   ├── exp_basic.py                    # auto-discovers models under models/ (lazy import)
│   ├── exp_long_term_forecasting.py    # the pipeline used by the paper
│   └── exp_zero_shot_forecasting.py    # foundation-model zero-shot pipeline
├── layers/                             # Reusable layers (RevIN, attention, embeddings, …)
├── data_provider/                      # data_factory.py, data_loader.py (Dataset_Custom)
├── dataset/                            # 10 OHLC CSVs (2016–2025)
├── utils/                              # metrics.py, visualization.py, ADFtest.py, tools.py
├── scripts/                            # Inherited TSLib reproduction scripts (standard benchmarks — see note)
├── requirements/                       # Ordered install files reqs_1..4.txt
├── Dockerfile                          # CUDA 12.1 / PyTorch 2.5.1 image
└── docker-compose.yml                  # dev service with GPU passthrough

Note on scripts/. These shell scripts are inherited from upstream TSLib and target the standard academic benchmarks (ETT, ECL, Weather, M4, anomaly/classification datasets). They are not the financial experiments of this paper — the benchmark is run through run.py and the batch runners as documented below.


Installation

Recommended Python: 3.11. Dependencies are split into four ordered files in requirements/.

Minimal install (DeReFusion + RevIN baselines)

The proposed model and the RevIN baselines depend only on PyTorch and the standard scientific/attention stack — not on the Mamba or foundation-model libraries.

# 1. PyTorch (CUDA 12.1 build — torch==2.5.1)
pip install -r requirements/reqs_1.txt

# 2. Core scientific + attention stack
#    (numpy, scipy, scikit-learn, pandas, matplotlib, einops, reformer-pytorch,
#     sktime, sympy, PyWavelets, tqdm, …)
pip install -r requirements/reqs_2.txt

CPU / Apple Silicon: requirements/reqs_1.txt pins the CUDA 12.1 wheel. If you do not have an NVIDIA GPU, install the matching CPU or MPS build of torch==2.5.1 from pytorch.org instead of step 1, then run step 2.

Foundation-model + Mamba extras (only for the zero-shot baselines)

requirements/reqs_2.txt also pulls the foundation-model stack (transformers, chronos-forecasting, timesfm, tirex-ts, gluonts, lightning, jax, …) needed to run Chronos / Moirai / TimesFM. The pinned Mamba state-space wheel and uni2ts live in the remaining files and are not imported by DeReFusion or the RevIN baselines, so you can skip them unless you need those backends.

pip install -r requirements/reqs_3.txt          # mamba_ssm — Linux x86_64 + CUDA 12 + Python 3.11 + torch 2.5 ONLY
pip install -r requirements/reqs_4.txt           # uni2ts and friends

reqs_3.txt pins a mamba_ssm wheel built for cu12 / torch2.5 / cp311 / linux_x86_64 only; it will not install on macOS, Windows, ARM, or other Python versions.

Docker (optional)

A CUDA environment is provided for full-stack reproduction:

# The Dockerfile installs from a single consolidated requirements.txt:
cat requirements/reqs_*.txt > requirements.txt
docker compose up -d --build
docker compose exec dev_tslib bash

The image builds on pytorch/pytorch:2.5.1-cuda12.1-cudnn9-devel, runs with GPU passthrough (NVIDIA_VISIBLE_DEVICES=all), shm_size: 8gb, and a /workspace volume. It targets the complete stack including the optional Mamba / foundation dependencies.


Reproducing the benchmark

All experiments run through run.py, which seeds the RNGs, selects the device, and dispatches to the appropriate task pipeline.

Train and evaluate the proposed model

python run.py \
  --task_name long_term_forecast \
  --is_training 1 \
  --model_id GSPC_96_24 \
  --model DeReFusion \
  --data custom \
  --root_path ./dataset/ \
  --data_path GSPC-2016-2025.csv \
  --features MS --target Close --freq b \
  --seq_len 96 --label_len 48 --pred_len 24 \
  --enc_in 4 --dec_in 4 --c_out 1 \
  --d_model 32 --moving_avg 25 \
  --train_epochs 30 --batch_size 32 --learning_rate 0.0001 \
  --patience 5 --lradj cosine \
  --rand_seed 2021

Run a baseline, ablation, or fusion-gate variant

Swap --model for any name from the benchmark set, the ablation table, or the gate table; every other flag stays the same:

python run.py --model revin-DLinear                     ... # a linear baseline
python run.py --model revin-PatchTST                    ... # a Transformer baseline
python run.py --model DeReFusion-woDy                   ... # an ablation (base branch only)
python run.py --model DeReFusion-gatev3-inputconditioned ... # a fusion-gate variant

Zero-shot foundation models

Run a pretrained foundation model with no training (--is_training 0, --task_name zero_shot_forecast):

python run.py \
  --task_name zero_shot_forecast \
  --is_training 0 \
  --model_id BTCUSD_zeroshot \
  --model TimesFM \
  --data custom \
  --root_path ./dataset/ \
  --data_path BTCUSD-2016-2025.csv \
  --features MS --target Close --freq b \
  --seq_len 96 --label_len 48 --pred_len 7

Swap --model TimesFM for Chronos or Moirai to try the other foundation models.

Device selection

  • CUDA is auto-detected and used by default.
  • Apple Silicon: add --gpu_type mps.
  • CPU: add --no_use_gpu.

Full sweep

The paper reports results over all 10 instruments × multiple forecast horizons × several seeds. The two batch runners automate this:

# DeReFusion + RevIN baselines (trained); parallel, MAX_PARALLEL=6, seeds 2020–2024
python run_batch_long_term_forecast.py

# Foundation models (zero-shot): TimesFM / Chronos / Moirai
python run_batch_zero_shot_forecast.py

Both runners shell out to run.py, key each completed experiment by an MD5 of its command, record progress in run_batch_progress.log and failures in run_batch_failed.log, write per-experiment stdout/stderr into run_batch_logs/, and resume where they left off. The dataset list, horizon grid (pred_len), seed list, and the active --model set are edited at the top of each script — comment blocks there hold the DeReFusion presets (the 2016–2025 instruments and horizons [1, 7, 12, 24, 36]).


Evaluation and outputs

The long-term-forecasting pipeline (exp/exp_long_term_forecasting.py) reports an extended set of metrics and diagnostics.

Metrics (utils/metrics.py): MAE, MSE, RMSE, MAPE, MSPE, R² — and optionally DTW with --use_dtw (off by default; time-consuming).

Diagnostics (printed and appended to the result log):

  • GPU peak memory — gpu_mem_peak_mb via torch.cuda.max_memory_allocated (CUDA only).
  • Training wall time and inference speed — inference_speed_ms (ms/sample, guarded by torch.cuda.synchronize()).
  • Parameter counts — total and trainable.

Output layout (relative to the working directory; all are git-ignored):

PathContents
results/<setting>/pred.npy, true.npy, metrics.npy (the 6 core metrics)
test_results/<setting>/auto-generated figures + per-window preview PDFs
checkpoints/<setting>/checkpoint.pthbest model by validation loss
result_long_term_forecast.txtappended one-line summary per run (all metrics + diagnostics)

Publication figures (utils/visualization.py, 300 DPI, serif/journal style, PNG):

FileContent
fig_prediction_curves.pngSample ground-truth vs. prediction windows with error band
fig_error_analysis.pngMSE-per-horizon-step bars + error-distribution histogram
fig_metrics_radar.pngRadar over MAE / MSE / RMSE / MAPE / MSPE / R²
fig_error_heatmap.pngAbsolute-error heatmap (sample × horizon)
fig_pred_true.pngContinuous ground-truth vs. prediction curve
fig_dashboard.png4-panel summary

Figures can be regenerated standalone from saved arrays:

python -m utils.visualization --input results/<setting>/ --output test_results/<setting>/

Adding a model

The registry (exp/exp_basic.py) auto-discovers models: drop a .py file anywhere under models/ that defines a class named Model, and its filename (without .py) becomes the --model string — no manual registration, and the module is lazily imported only when selected. This is exactly how the RevIN baselines (revin-*.py) and the DeReFusion family are wired in. An unknown --model name raises a ValueError listing the discovered models.


Citation

If you use this code or build on the benchmark, please cite the paper:

@article{hsieh2026derefusion,
  title   = {{DeReFusion}: A controlled comparison of soft computing fusion strategies for financial time series forecasting via a decomposition-residual architecture},
  author  = {Hsieh, Chih-Chien and Chen, Mu-Yen},
  journal = {Applied Soft Computing},
  volume  = {203},
  pages   = {116252},
  year    = {2026},
  issn    = {1568-4946},
  doi     = {10.1016/j.asoc.2026.116252},
  url     = {https://doi.org/10.1016/j.asoc.2026.116252}
}

Acknowledgements

This project is a focused fork of the Time-Series-Library (TSLib) by THUML @ Tsinghua University. It reuses TSLib's experiment harness and layer library, and adds the financial datasets, the RevIN-wrapped baselines, the foundation-model integrations, and the DeReFusion model family studied in the paper.


License

Released under the MIT License — see LICENSE.

  • Copyright © 2026 Chih-Chien Hsieh
  • Copyright © 2021 THUML @ Tsinghua University (Time-Series-Library)

Contributing

This is a personal research repository accompanying a publication, so external pull requests are not accepted (see CONTRIBUTING.md). It is open source under MIT and fork-friendly — you are welcome to fork it, adapt it, and build on the benchmark. Bug reports and questions can be raised as Issues.