A multimodal foundation model for joint language and time series understanding
Chronicle is a compact 324M-parameter decoder-only transformer trained from scratch on natural language and time series within a single unified architecture. Text tokens and time series patches share the same transformer blocks, attention mechanism, and residual stream — cross-modal capability emerges from shared parameters rather than from bolting a time-series encoder onto a pretrained LLM.
From one backbone, Chronicle:
- matches Gemma-3-270M-PT across 19 NLU benchmarks,
- sets a new bar for frozen-embedding time series classification on 24 UCR/UEA datasets,
- beats every supervised fusion baseline on Time-MMD multimodal forecasting.
📄 Paper: Chronicle: A Multimodal Foundation Model for Joint Language and Time Series Understanding (Quinlan, Levasseur, Li, Zhu)
🤗 Checkpoints: huggingface.co/InertialAI/Chronicle —
both stages, the tokenizer, and the reference PyTorch implementation in one repo.
Stage 1 (stage-1/) is the unimodal-batch pretrained backbone; Stage 2 (stage-2/)
adds the short cross-modal alignment stage.
☁️ Hosted (coming soon): the same models will power InertialAI's API, including self-serve finetuning with automatic before/after evals and one-click GPU deployment.
| Parameters | 324M, 16-layer decoder-only transformer |
| Width / heads | d=1024, 8 GQA heads (4 KV) |
| Modalities | text tokens + standardized time-series patches, one shared stream |
| Pretraining | unimodal batches (≈92% text / 8% TS) + short interleaved alignment stage |
| Objective | causal next-token / next-patch prediction |
git clone https://github.com/InertialAI/Chronicle.git
cd Chronicle
uv sync # or: pip install -e .The checkpoints ship as safetensors with a minimal inference implementation
(model.py + tokenizer.py, just torch + tiktoken) bundled in the HF repo.
Verified example (text generation, CPU):
import json
import sys
import torch
from huggingface_hub import snapshot_download
from safetensors.torch import load_file
repo = snapshot_download("InertialAI/Chronicle")
sys.path.insert(0, repo)
from model import Chronicle, ChronicleConfig
from tokenizer import ChronicleTokenizer
config = ChronicleConfig(**json.load(open(f"{repo}/stage-2/config.json")))
model = Chronicle(config)
state = load_file(f"{repo}/stage-2/model.safetensors")
state = {k: v.float() if v.dtype is torch.bfloat16 else v for k, v in state.items()}
model.load_state_dict(state, strict=True)
model = model.float().eval()
model.cos, model.sin = model.cos.float(), model.sin.float()
tokenizer = ChronicleTokenizer.from_directory(f"{repo}/tokenizer")
ids = [tokenizer.get_bos_token_id()] + tokenizer.encode("Time series forecasting is")
with torch.no_grad():
for _ in range(16):
out = model(torch.tensor([ids]))
logits = out[0] if isinstance(out, tuple) else out
ids.append(int(logits[0, -1].argmax()))
print(tokenizer.decode(ids[1:]))
# -> "Time series forecasting is a technique used to forecast future values
# of a time series based on historical data."A transformers-native port (AutoModel.from_pretrained with forecast() /
embed() conveniences, as used in examples/quickstart.py)
is in progress; the examples target that interface, and the hosted API (coming soon)
will serve the time-series pathway.
Each script is self-contained, downloads public data, and runs on a single GPU (or CPU for the small datasets):
| Task | Script | Data |
|---|---|---|
| Forecasting | examples/finetune_forecasting.py |
AirPassengers (public) |
| Classification | examples/finetune_classification.py |
UCR GunPoint via aeon |
| Regression | examples/finetune_regression.py |
synthetic sensor windows |
| Text generation (text and series+text) | examples/finetune_text_generation.py |
AG News topics · EIA gasoline summaries |
| Text classification | examples/finetune_text_classification.py |
SST-2 sentiment (GLUE) |
| Joint text + TS | examples/finetune_joint.py |
captioned series |
data/prepare_datasets.py builds ready-to-train JSONL datasets
from public sources — ETTh1 change forecasting, EIA weekly gasoline-price change
forecasting (via Time-MMD), series-grounded
gasoline summary generation, and AG News topic naming. The records use the same shape as
InertialAI's finetuning API,
so the same files work locally and in the managed flow.
Two finetuning modes are shown, mirroring the paper's evaluation protocol:
- Linear probe (LP) — freeze the backbone, train a head on mean-pooled embeddings. This is the protocol behind the UCR/UEA and Time-MMD numbers.
- LoRA — low-rank adapters on the attention projections for the cases where a probe plateaus.
Prefer not to run GPUs yourself? The InertialAI API (coming soon) will offer the same finetuning as a managed flow — upload a JSONL, get a before/after eval, deploy.
reproduction/ contains scripts and the expected numbers for a subset of
the paper's benchmarks (UCR/UEA classification and Time-MMD forecasting), using only public
data. From the paper (mean over 5 seeds, aeon default splits, linear probes on frozen
embeddings):
| UCR dataset | Chronicle Stage 1 (acc) | Chronicle Stage 2 (acc) | Best frozen TSFM baseline |
|---|---|---|---|
| GunPoint | 0.919 | 0.851 | 0.931 (Moirai-2) |
| Coffee | 0.893 | 0.893 | 0.964 (Moirai-2) |
| ECG200 | 0.846 | 0.848 | 0.840 (TimesFM) |
| FaceFour | 0.864 | 0.759 | 0.609 (TimesFM) |
| Trace | 0.936 | 0.848 | 0.802 (Moirai-2) |
| Time-MMD (MAE ↓, linear probe) | Chronicle Stage 2 | Best fusion baseline |
|---|---|---|
| Energy | 0.370 | 0.396 (GPT2+TimesFM) |
| Public Health | 0.690 | 0.765 (BERT+TimesFM) |
| Social Good | 0.399 | 0.441 (BERT+TimesFM) |
| Average NMAE (9 domains) | 0.514 | 0.588 (GPT2+Moirai-2) |
See reproduction/README.md for the full protocol and the
per-dataset commands.
@article{quinlan2026chronicle,
title={Chronicle: A Multimodal Foundation Model for Joint Language and Time Series Understanding},
author={Quinlan, Paul and Levasseur, Jeremy and Li, Qingguo and Zhu, Xiaodan},
journal={arXiv preprint arXiv:2605.20268},
year={2026}
}Apache 2.0 — see LICENSE.