Skip to content

About

Repository for the paper "Reservoir Conformal Prediction for Time Series Forecasting"

Resources

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

8 Commits

Folders and files

Repository files navigation

Reservoir Conformal Prediction for Time Series Forecasting

arXiv License: MIT ICLR

{ResCP}

Code for reproducing the experiments in ResCP: Reservoir Conformal Prediction for Time Series Forecasting, published at ICLR 2026.

Authors: Roberto Neglia, Andrea Cini, Michael M. Bronstein, Filippo Maria Bianchi.

⚡ TL;DR

Reservoir Conformal Prediction (ResCP) is a novel, training-free, scalable, localized conformal prediction (CP) method for time series where local similarity is gauged by relying on reservoir states. By sampling more residuals associated with similar states, we condition the estimates on specific dynamics of interest in the time series. This allows us to generate prediction intervals (PIs) that are more informative and adaptive to local patterns in the data, and we empirically demonstrate its effectiveness across various real-world datasets. We also prove that, under reasonable assumptions, ResCP achieves asymptotic conditional coverage.

ResCP applies on top of any point forecaster — it only needs residuals on a disjoint calibration set. This repository contains two variants:

Variant Entry point Description
ResCP run_RExCP_sampling.py Training-free. Samples calibration residuals proportionally to reservoir-state similarity and takes empirical quantiles.
ResCQR run_RExCP_qr.py Quantile-regression readout trained on top of the (frozen, random) reservoir states.

🔧 Installation

conda env create -f environment.yaml
conda activate rescp_env

The environment pins CUDA 12.4 builds of PyTorch 2.4.1 and installs tsl from source. Experiments run on CPU as well, just slower.

All entry points import both src.* and reservoir_conformal_prediction.src.*, so the repository root must be on PYTHONPATH:

export PYTHONPATH="$(pwd):$PYTHONPATH"

The two run_*.sh scripts set this up themselves.

📊 Data

Everything needed is bundled under data/ — no downloads required.

Dataset Path Shape Target
Solar (NSRDB, 50 locations) data/solar/ 26,304 hourly steps × 50 nodes dhi
Beijing air quality (12 stations) data/air_quality/ 35,064 hourly steps × 12 nodes PM10
ACEA electricity load (Rome) data/elec_rome/ 137,376 steps @ 10 min × 1 node consumption
Exchange rate (8 countries) downloaded by tsl on first use 7,588 daily steps × 8 nodes rate

Solar is resampled from 30 min to hourly at load time. Beijing is the only dataset with missing values in the target (6,449 entries, 1.53%); those are forward/backward filled so the tensors stay finite, and the dataset mask marks them invalid so they are excluded from the training loss and from all reported metrics.

🚀 Reproducing the experiments

Pre-trained base models, their residuals (residuals.h5) and the calibration/test index splits (indices.npz) are bundled under reservoir_conformal_prediction/logs/base/, so both scripts run on a fresh clone with no setup:

cd reservoir_conformal_prediction
./run_rexcp_sampling.sh   # ResCP  — all 4 datasets × 3 base models
./run_rexcp_qr.sh         # ResCQR — all 4 datasets × 3 base models

To evaluate against your own base models, point LOGS at your own output directory:

LOGS=/my/logs/base ./run_rexcp_sampling.sh

Single runs are plain Hydra invocations:

python run_RExCP_sampling.py \
    src_dir=logs/base/beijing/rnn/2025-07-16/17-50-09 \
    dataset=beijing \
    conformal_predictor=rexcp_sampling_beijing_rnn \
    sampler=beijing_rnn \
    +clip_residuals=True

The ESN hyperparameters reported in Table 4 of the paper (spectral radius, leak rate, input scaling, temperature, sliding window) live in configs/conformal_predictor/ and configs/sampler/, one file per dataset/base-model pair.

🏋️ Training the base point forecasters

The three point predictors — a single-layer GRU, a decoder-only Transformer, and ARIMA(3,1,3) — are trained by run_base_model.py:

cd reservoir_conformal_prediction
python run_base_model.py dataset=beijing model=rnn
python run_base_model.py dataset=solar   model=transformer
python run_base_model.py dataset=elec    model=arima

Each run writes a new directory under logs/base/<dataset>/<model>/<date>/<time>/ containing residuals.h5 (calibration + test residuals and the target mask), indices.npz (the splits), config.yaml, and a checkpoint. Feed that directory to the conformal scripts as src_dir=.

The bundled checkpoints let you recompute residuals without retraining (ARIMA is fitted directly on the data, so it has none):

python run_base_model.py dataset=beijing model=rnn \
    +load_model_path=logs/base/beijing/rnn/2025-07-16/17-50-09/epoch=22-step=2300.ckpt

Splits follow the paper: 40% train, then a calibration split whose first 25% is held out for early stopping, and a 20% test tail.

📁 Repository layout

data/                                   raw datasets (see table above)
reservoir_conformal_prediction/
├── run_base_model.py                   trains the point forecasters, dumps residuals
├── run_RExCP_sampling.py               ResCP  (training-free)
├── run_RExCP_qr.py                     ResCQR (quantile-regression readout)
├── configs/                            Hydra configs
│   ├── training/                       base-model training
│   ├── dataset/  conformal_predictor/  sampler/
├── logs/base/                          bundled pre-trained runs
└── src/
    ├── reservoir_conformal_residual_sampler.py   core ResCP sampler
    ├── torch_reservoir_computing/               ESN implementation
    └── lib/
        ├── datasets/                   Solar, Beijing, ACEA loaders
        ├── nn/                         encoders (reservoir), decoders, base models
        ├── engines/                    Lightning predictors
        └── metrics/                    masked coverage, PI width, Winkler score

📏 Metrics

  • Coverage gap $\Delta C = 100 · (1(y_t \in \hat{C}(ŷ_t)) - (1-\alpha))$
  • PI width $q̂^{1−\alpha/2} − q̂^{\alpha/2}$
  • Winkler score — PI width plus a $2\alpha$-weighted penalty for observations outside the interval

All three are masked: invalid (missing) target entries never contribute.

📝 Citation

@inproceedings{neglia2026rescp,
  title     = {{ResCP}: Reservoir Conformal Prediction for Time Series Forecasting},
  author    = {Neglia, Roberto and Cini, Andrea and
               Bronstein, Michael M. and Bianchi, Filippo Maria},
  booktitle = {International Conference on Learning Representations (ICLR)},
  year      = {2026}
}

Poster

Poster

⚖️ License

Code released under the MIT License.

Dataset licences are those of the original sources: the Beijing air quality data comes from the UCI Machine Learning Repository (Zhang et al., 2017), the Solar data from the US National Solar Radiation Database (Sengupta et al., 2018) in the 50-series form used by Auer et al. (2023), and the ACEA load data from Bianchi et al. (2015).

About

Repository for the paper "Reservoir Conformal Prediction for Time Series Forecasting"

Resources

Stars

5 stars

Watchers

0 watching

Forks

Contributors

Languages