📄 Paper | 🤗 Model | 📚 Training Data
Fangxu Yu1, Hongyu Zhao1, Tianyi Zhou2
1University of Maryland, College Park 2Mohamed Bin Zayed University of Artificial Intelligence
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).
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.
├── 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
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
BASE_MODEL (default Qwen/Qwen2.5-7B-Instruct) and MODEL_ROOT (default output/).Training/data/dataset_info.json (LLaMA-Factory format); add new entries there to train on your own data.captioning/ (see captioning/readme.md).change_config.py marks the stage-1 checkpoint with stage_2: true (handled automatically by scripts/train_tsreasoner.sh).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}
}
50 commits
Python
99.7%
📄 Paper | 🤗 Model | 📚 Training Data
Fangxu Yu1, Hongyu Zhao1, Tianyi Zhou2
1University of Maryland, College Park 2Mohamed Bin Zayed University of Artificial Intelligence
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).
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.
├── 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
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
BASE_MODEL (default Qwen/Qwen2.5-7B-Instruct) and MODEL_ROOT (default output/).Training/data/dataset_info.json (LLaMA-Factory format); add new entries there to train on your own data.captioning/ (see captioning/readme.md).change_config.py marks the stage-1 checkpoint with stage_2: true (handled automatically by scripts/train_tsreasoner.sh).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}
}
50 commits
Python
99.7%