CosDir is a lightweight, scale-invariant directional loss that plugs on top of a standard
pointwise objective (MSE). It aligns the first-difference vectors of the prediction and the
target along the forecast horizon by cosine similarity, so it improves directional accuracy (DA)
without sacrificing magnitude accuracy. It is architecture-agnostic and adds only an O(HC)
difference-and-cosine computation per batch.
This repository contains the code needed to reproduce the main forecasting experiments: the MSE
baseline, CosDir (fixed mixing weight), and CosDir-UW (the weight is learned per run, so no
λ is tuned by hand), across 15 forecasting backbones.
Given a prediction ŷ, target y (both [B, H, C]), and the last observed value y_last
([B, 1, C]), let Δ denote the first difference along the horizon (including step 0 vs. y_last).
- MSE — plain mean-squared error (baseline / base loss).
- CosDir —
L = MSE + λ · mean(1 − cos(Δŷ, Δy)), cosine taken per (sample, channel). - CosDir-UW —
L = e^{−s₁}·MSE + e^{−s₂}·L_dir + ½(s₁ + s₂), wheres₁, s₂are learned log-variances (homoscedastic uncertainty weighting). The effective weight recovered after training isλ_eff = e^{s₁ − s₂}, logged with every run.
See losses/tslib_losses.py.
pip install -r requirements.txtPlace the forecasting CSVs under ./data/ (or pass --root_path). The standard benchmarks
(ETTh1/h2, ETTm1/m2, Weather, Electricity, Traffic, Solar) follow the usual Time-Series-Library
layout. The financial risk panels (svar, svol20log, svol60, sabsret, stock_vol) are the
per-asset realized-risk series described in the paper.
One run = one (backbone, loss, dataset, horizon, seed). Metrics are appended as a single JSON line
to --save_name.
# MSE baseline
python run_tslib.py --model DLinear --loss MSE --data_path ETTh1.csv \
--seq_len 96 --pred_len 96 --seed 2024 --save_name results.jsonl
# CosDir (fixed lambda)
python run_tslib.py --model DLinear --loss CosDir --data_path ETTh1.csv \
--seq_len 96 --pred_len 96 --dir_lam 0.5 --seed 2024 --save_name results.jsonl
# CosDir-UW (learned weight, hyperparameter-free)
python run_tslib.py --model DLinear --loss CosDirUW --data_path ETTh1.csv \
--seq_len 96 --pred_len 96 --seed 2024 --save_name results.jsonlSee example.sh for a small sweep over losses and backbones. Reported results in the paper average
over 5 seeds {2024, 2025, 2026, 2027, 2028} and the horizons {96, 192, 336, 720} (general benchmarks).
Each line of --save_name:
{"setting": "...", "model": "DLinear", "loss": "CosDir", "data": "ETTh1.csv",
"pred_len": 96, "dir_lam": 0.5, "lr": 0.0001, "MSE": 0.56, "MAE": 0.50, "DA": 0.54}CosDir-UW runs additionally record uw_s1, uw_s2, and lam_eff.
DLinear, PatchTST, iTransformer, TimesNet, TimeMixer, Autoformer, FEDformer,
TSMixer, LightTS, Pyraformer, Crossformer, FiLM, TiDE, FreTS, SegRNN
(select with --model).
run_tslib.py entry point (arguments, run one setting)
losses/ CosDir / CosDir-UW / MSE and the DA metric
exp/ training / evaluation loop (Exp_TSLib)
models/ the 15 forecasting backbones
layers/ building blocks used by the backbones
data_provider/ dataset + dataloader (windowing, standardization)
utils/ training utilities (early stopping, time features)
The backbone implementations and training scaffold are adapted from the
Time-Series-Library. CosDir and CosDir-UW
(losses/) and the direction-aware training/evaluation path are the contribution of this work.