Yu-Fangxu/TS-Reasoner

[TMLR 2026] TS-Reasoner: Aligning Time Series Foundation Models with LLM Reasoning

3

stars

50

commits

Python

primary language

Jul 10, 2026

updated

README

TS-Reasoner: Aligning Time Series Foundation Models with LLM Reasoning

📄 Paper | 🤗 Model | 📚 Training Data

Fangxu Yu1, Hongyu Zhao1, Tianyi Zhou2

1University of Maryland, College Park   2Mohamed Bin Zayed University of Artificial Intelligence

🔥 Overview

TS-Reasoner couples a frozen Time Series Foundation Model (TimesFM) with a Qwen2.5-7B LLM so the language model can reason over raw numerical time series. Instead of post-training an LLM to read time series as text tokens, TS-Reasoner aligns the TSFM's latent representations with the LLM's textual input space through a two-stage recipe: (1) alignment pretraining on diverse, synthetically curated time series–caption pairs, followed by (2) instruction finetuning. Across time series understanding and reasoning benchmarks, TS-Reasoner outperforms a wide range of LLMs, VLMs, and Time Series LLMs with remarkable data efficiency (e.g., using less than half the training data).

🚀 Quick Start: Inference

conda create -n tsreasoner python=3.10 -y
conda activate tsreasoner
pip install -r requirements.txt

Run the built-in demo (a synthetic series with an injected anomaly) from the repository root:

python demo.py

Ask a question about your own data — one univariate series per CSV column, one <ts><ts/> placeholder per series in the question:

python demo.py --csv my_series.csv \
    --question "Sensor A: <ts><ts/>\nIs there an anomaly in this series?"

Or use the Python API directly:

from demo import load_ts_reasoner, ask

tokenizer, model = load_ts_reasoner()          # downloads TS-Reasoner-7B + TimesFM backbone
answer = ask(
    tokenizer, model,
    question="Time series 1: <ts><ts/>\nWhat is the overall trend?",
    timeseries=[[0.1, 0.3, 0.2, 0.5, 0.8, 1.2, 1.1, 1.6]],
)
print(answer)

from_pretrained is self-contained: the model code automatically builds its frozen TimesFM backbone (google/timesfm-1.0-200m-pytorch) on first use — no manual injection needed (load_ts_reasoner still injects the vendored copy for older cached versions of the model code). Raw series are value-scaled (Inference/encoding_utils.py) and passed to model.generate(..., timeseries=...) as tensors — no manual preprocessing needed.

📁 Repository Structure

├── demo.py                        # Minimal inference: load model + ask questions about raw series
├── change_config.py               # Flip a stage-1 checkpoint to stage-2 mode between training stages
├── Inference/                     # Batch inference (DeepSpeed)
│   ├── encoding_utils.py          #   Value-scaling encodings for raw series
│   ├── inference_tsmllm_deepspeed.py
│   └── inference.sh               #   Batch entry (edit MODELS/DATASETS inside)
├── captioning/                    # Synthetic time series → caption curation for alignment data
├── scripts/                       # Two-stage training entry + text-model baselines
├── Training/                      # DeepSpeed training pipeline (LLaMA-Factory-based)
└── timesfm/                       # Vendored TimesFM (PyTorch), Apache-2.0

🎯 Training

TS-Reasoner is trained in two stages (TimesFM stays frozen throughout). Both training sets are released at ParadiseYu/TS-Reasoner-trainingset — download them into Training/data/:

hf download ParadiseYu/TS-Reasoner-trainingset align_120K.jsonl --repo-type dataset --local-dir Training/data/alignment
hf download ParadiseYu/TS-Reasoner-trainingset sft-30K.jsonl   --repo-type dataset --local-dir Training/data/finetuning

Then launch the two-stage pipeline:

cd Training
# Stage 1: alignment pretraining on synthetic caption pairs, then
# Stage 2: instruction finetuning from the stage-1 checkpoint
bash ../scripts/train_tsreasoner.sh 120K 30K
  • Configure the base LLM and output location via BASE_MODEL (default Qwen/Qwen2.5-7B-Instruct) and MODEL_ROOT (default output/).
  • The datasets (120K alignment caption pairs, 30K SFT instructions) are registered in Training/data/dataset_info.json (LLaMA-Factory format); add new entries there to train on your own data.
  • Alignment caption data is curated with the pipeline in captioning/ (see captioning/readme.md).
  • Between the stages, change_config.py marks the stage-1 checkpoint with stage_2: true (handled automatically by scripts/train_tsreasoner.sh).

📖 Citation

If you find this work useful, please cite:

@article{yu2025tsreasoner,
  title={TS-Reasoner: Aligning Time Series Foundation Models with LLM Reasoning},
  author={Yu, Fangxu and Zhao, Hongyu and Zhou, Tianyi},
  journal={arXiv preprint arXiv:2510.03519},
  year={2025}
}

Contributors

Yu-Fangxu

50 commits

Yu-Fangxu/TS-Reasoner

[TMLR 2026] TS-Reasoner: Aligning Time Series Foundation Models with LLM Reasoning

3

stars

50

commits

Python

primary language

Jul 10, 2026

updated

README

TS-Reasoner: Aligning Time Series Foundation Models with LLM Reasoning

📄 Paper | 🤗 Model | 📚 Training Data

Fangxu Yu1, Hongyu Zhao1, Tianyi Zhou2

1University of Maryland, College Park   2Mohamed Bin Zayed University of Artificial Intelligence

🔥 Overview

TS-Reasoner couples a frozen Time Series Foundation Model (TimesFM) with a Qwen2.5-7B LLM so the language model can reason over raw numerical time series. Instead of post-training an LLM to read time series as text tokens, TS-Reasoner aligns the TSFM's latent representations with the LLM's textual input space through a two-stage recipe: (1) alignment pretraining on diverse, synthetically curated time series–caption pairs, followed by (2) instruction finetuning. Across time series understanding and reasoning benchmarks, TS-Reasoner outperforms a wide range of LLMs, VLMs, and Time Series LLMs with remarkable data efficiency (e.g., using less than half the training data).

🚀 Quick Start: Inference

conda create -n tsreasoner python=3.10 -y
conda activate tsreasoner
pip install -r requirements.txt

Run the built-in demo (a synthetic series with an injected anomaly) from the repository root:

python demo.py

Ask a question about your own data — one univariate series per CSV column, one <ts><ts/> placeholder per series in the question:

python demo.py --csv my_series.csv \
    --question "Sensor A: <ts><ts/>\nIs there an anomaly in this series?"

Or use the Python API directly:

from demo import load_ts_reasoner, ask

tokenizer, model = load_ts_reasoner()          # downloads TS-Reasoner-7B + TimesFM backbone
answer = ask(
    tokenizer, model,
    question="Time series 1: <ts><ts/>\nWhat is the overall trend?",
    timeseries=[[0.1, 0.3, 0.2, 0.5, 0.8, 1.2, 1.1, 1.6]],
)
print(answer)

from_pretrained is self-contained: the model code automatically builds its frozen TimesFM backbone (google/timesfm-1.0-200m-pytorch) on first use — no manual injection needed (load_ts_reasoner still injects the vendored copy for older cached versions of the model code). Raw series are value-scaled (Inference/encoding_utils.py) and passed to model.generate(..., timeseries=...) as tensors — no manual preprocessing needed.

📁 Repository Structure

├── demo.py                        # Minimal inference: load model + ask questions about raw series
├── change_config.py               # Flip a stage-1 checkpoint to stage-2 mode between training stages
├── Inference/                     # Batch inference (DeepSpeed)
│   ├── encoding_utils.py          #   Value-scaling encodings for raw series
│   ├── inference_tsmllm_deepspeed.py
│   └── inference.sh               #   Batch entry (edit MODELS/DATASETS inside)
├── captioning/                    # Synthetic time series → caption curation for alignment data
├── scripts/                       # Two-stage training entry + text-model baselines
├── Training/                      # DeepSpeed training pipeline (LLaMA-Factory-based)
└── timesfm/                       # Vendored TimesFM (PyTorch), Apache-2.0

🎯 Training

TS-Reasoner is trained in two stages (TimesFM stays frozen throughout). Both training sets are released at ParadiseYu/TS-Reasoner-trainingset — download them into Training/data/:

hf download ParadiseYu/TS-Reasoner-trainingset align_120K.jsonl --repo-type dataset --local-dir Training/data/alignment
hf download ParadiseYu/TS-Reasoner-trainingset sft-30K.jsonl   --repo-type dataset --local-dir Training/data/finetuning

Then launch the two-stage pipeline:

cd Training
# Stage 1: alignment pretraining on synthetic caption pairs, then
# Stage 2: instruction finetuning from the stage-1 checkpoint
bash ../scripts/train_tsreasoner.sh 120K 30K
  • Configure the base LLM and output location via BASE_MODEL (default Qwen/Qwen2.5-7B-Instruct) and MODEL_ROOT (default output/).
  • The datasets (120K alignment caption pairs, 30K SFT instructions) are registered in Training/data/dataset_info.json (LLaMA-Factory format); add new entries there to train on your own data.
  • Alignment caption data is curated with the pipeline in captioning/ (see captioning/readme.md).
  • Between the stages, change_config.py marks the stage-1 checkpoint with stage_2: true (handled automatically by scripts/train_tsreasoner.sh).

📖 Citation

If you find this work useful, please cite:

@article{yu2025tsreasoner,
  title={TS-Reasoner: Aligning Time Series Foundation Models with LLM Reasoning},
  author={Yu, Fangxu and Zhao, Hongyu and Zhou, Tianyi},
  journal={arXiv preprint arXiv:2510.03519},
  year={2025}
}

Contributors

Yu-Fangxu

50 commits

Languages

Python

99.7%