A general-purpose Python library for training recurrent world models (simulators) on time-series data for model-based control, reinforcement learning, and model predictive control (MPC).
This library provides a clean, domain-agnostic framework for:
- Training world models that learn system dynamics from historical data
- Multi-step rollout training to reduce compounding prediction errors
- Flexible sampling strategies for diverse training scenarios
- Gymnasium-compatible environments for RL integration
- Easy deployment for MPC and control applications
Model behavior, schema expectations, training recipe, simulator usage, limitations, and benchmark references are documented in MODEL_CARD.md.
git clone https://github.com/esmaeelMhd/time-series-simulator.git
cd time-series-simulator
# Default install (CUDA 12.9 PyTorch)
pip install -r requirements.txt
pip install -e .CPU-only install:
pip install -r requirements.cpu.txt
pip install -e .Explicit CUDA alias (equivalent to requirements.txt):
pip install -r requirements.cuda.txt
pip install -e .Install all optional extras (tracking, Lightning, serving, validation, dev tools):
pip install -e ".[all]"- Python >= 3.10
- PyTorch 2.13.0 (CUDA 12.9 by default via
requirements.txt) - Use
requirements.cpu.txtfor CPU-only installs
├── configs/ # Hydra configuration
│ ├── config.yaml # Composition root
│ ├── dataset/ # Data schema & paths
│ ├── experiment/ # Per-run experiment profiles
│ ├── model/ # Model architecture defaults
│ ├── training/ # Training & eval defaults
│ └── serving/ # Serving defaults
├── scripts/ # CLI entry-point scripts
├── src/timesim/ # Core package (src layout)
│ ├── cli/ # Packaged CLI commands (optimize, retrain)
│ ├── config/ # Structured config dataclasses
│ ├── data/ # Schema, datasets, preprocessing, datamodule
│ ├── envs/ # Gymnasium environment adapter
│ ├── evaluation/ # Rollout, interventional eval, metrics
│ ├── models/ # RSSM, LSTM, Transformer, DLinear, TFT, XGBoost
│ ├── optimization/ # Optuna hyperparameter search
│ ├── serving/ # FastAPI + Streamlit dashboard
│ ├── simulator/ # Stateful simulator wrapper
│ ├── training/ # Losses, trainer, retrainer, rollout, Lightning module
│ └── utils/ # Helpers (config, logging, scaling, symlog, plotting)
├── tests/ # Pytest suite
├── Dockerfile # Container image
├── docker-compose.yaml # API + dashboard services
├── pyproject.toml # Package metadata & tool config
├── requirements.base.txt # Shared runtime dependencies
├── requirements.txt # Default CUDA 12.9 dependency set
├── requirements.cpu.txt # CPU-only dependency set
└── requirements.cuda.txt # Explicit CUDA alias
- Deep learning: PyTorch 2.x
- Training orchestration: native trainer + optional PyTorch Lightning module
- Configuration: Hydra defaults composition (
configs/experiment/*+ group profiles) - Experiment tracking: TensorBoard + optional W&B / MLflow (
tracking.backend) - Hyperparameter optimization: Optuna (
scripts/optimize.py) - Serving: FastAPI + Uvicorn (
scripts/serve.py) - Dashboard: Streamlit (
scripts/dashboard.py) - Containerization:
Dockerfile,docker-compose.yaml - Testing: pytest + property-based tests
- Data validation: optional Pandera (
data.validation.enabled)
The commands below walk through a complete optimize → train → evaluate → simulate → compare → serve cycle using the small config, which slices the dataset to 1 000 rows and trains for only a few epochs.
python scripts/optimize.py \
--config configs/wastewater.small.yaml \
--models latent_ssm \
--n-trials 10 \
--fast-modeRuns Optuna Bayesian search. Results are saved to runs/wastewater/small/optuna/latent_ssm/ (best params YAML, trials CSV, importance plots).
# Hydra entrypoint (recommended)
python scripts/train_hydra.py --config-name=wastewater.small
# Legacy entrypoint (equivalent)
python scripts/train.py --config configs/wastewater.small.yamlTo apply Optuna best params from step 1:
python scripts/train.py --config configs/wastewater.small.yaml --use-optuna-best-paramsOutputs per model go to runs/wastewater/small/<model>/ — checkpoints (.pth), scaler (.pkl), loss curves, forecast & simulation plots.
python scripts/eval.py \
--config configs/wastewater.small.yaml \
--model latent_ssmRuns multi-window rollout evaluation and recursive simulation on the held-out test split. Override horizon and window count:
python scripts/eval.py \
--config configs/wastewater.small.yaml \
--model latent_ssm \
--eval-horizon 12 \
--n-windows 4 \
--sim-horizon 100python scripts/simulate.py \
--config configs/wastewater.small.yaml \
--model latent_ssm \
--horizon 100 \
--start-idx 0Produces autoregressive rollout plots and CSV from a chosen starting point.
python scripts/compare.py \
--config configs/wastewater.small.yaml \
--models latent_ssm lstm transformerGenerates side-by-side comparison plots and summary CSV in runs/wastewater/small/figures/.
FastAPI:
python scripts/serve.py \
--config configs/wastewater.small.yaml \
--checkpoint runs/wastewater/small/latent_ssm/train_checkpoint.pth \
--port 8000Endpoints: GET /health, GET /schema, POST /reset, POST /step, POST /rollout.
Streamlit dashboard:
streamlit run scripts/dashboard.pyAny config value can be overridden from the command line:
python scripts/train_hydra.py --config-name=wastewater.small \
training_rounds.0.epochs=10 \
misc.device=cuda \
training.steps_per_epoch=50# Default API image (CPU PyTorch)
docker compose up api
# GPU API (requires nvidia-docker)
docker compose --profile gpu up api-gpu
# Streamlit dashboard
docker compose up dashboardOverride config and checkpoint via environment variables:
docker build -t timesim-api .
docker run --rm -p 8000:8000 \
-e TIMESIM_CONFIG=configs/wastewater.yaml \
-e TIMESIM_CHECKPOINT=runs/wastewater/full_with_time/latent_ssm/train_checkpoint.pth \
-v "$PWD:/app" \
timesim-api# Full suite
pytest tests/ -v
# Fast CI smoke test (synthetic data, no config needed)
python scripts/ci_fast_train.pyTest coverage spans data pipeline, encoders, RSSM cell, training loop, evaluation, API, simulator, and end-to-end integration.
.github/workflows/ci.yml runs on every push/PR:
- Lint (
ruff check src scripts tests) - Unit tests (full
pytest tests/suite) - Fast training smoke test (
scripts/ci_fast_train.py, 5 epochs on synthetic data)
The wastewater CSV used by configs/dataset/wastewater.yaml is not in this repository; see that config for provenance and the expected local path.
WorldModelBase — abstract interface for all world models:
class WorldModelBase(nn.Module):
def init_state(self, warmup_seq):
"""Initialize hidden state from warmup sequence."""
def step(self, state, control_t, exo_t, prev_output_t):
"""Single-step prediction."""
def rollout(self, warmup_seq, rollout_inputs, horizon, feedback="model"):
"""Multi-step autoregressive rollout."""SamplingStrategy — defines how to sample (start_index, horizon) pairs for training:
RandomStartRandomHorizon— maximum diversityRandomStartFixedHorizon— fixed horizon, random startsDailyFixedHorizon— domain-specific (start at midnight, 24 h horizon)GeometricHorizonSampling— curriculum learning (1, 2, 4, 8, …)StrideBasedSampling— regular stride intervals
WorldModelTrainer — training loop with multi-step rollout support, teacher forcing, scheduled sampling, and pure autoregressive modes.
# Multi-step (recommended) — trains with autoregressive rollouts
trainer = WorldModelTrainer(..., training_mode="multi_step", feedback="model")
# Combined — mixes one-step teacher forcing + multi-step rollouts
trainer = WorldModelTrainer(..., training_mode="combined", one_step_weight=0.3, multi_step_weight=0.7)
# One-step — teacher forcing only
trainer = WorldModelTrainer(..., training_mode="one_step")import pandas as pd
from timesim.data import load_csv_dataset, GroupedTimeSeriesDataset
from timesim.models import LSTMWorldModel
from timesim.training import WorldModelTrainer
from timesim.data.sampling import RandomStartFixedHorizon
# 1. Load data
df = load_csv_dataset("data/my_system.csv", index_col="timestamp")
groups = {
"control": ["valve_1", "pump_speed"],
"exogenous": ["temperature", "flow_in"],
"objective": ["quality_metric"],
}
dataset = GroupedTimeSeriesDataset(
df, groups,
input_groups=["control", "exogenous"],
output_groups=["objective"],
seq_len=24, pred_len=12,
)
# 2. Train
model = LSTMWorldModel(input_dim=4, output_dim=1, hidden_dim=64, num_layers=2)
trainer = WorldModelTrainer(
model=model,
dataset=dataset,
sampling_strategy=RandomStartFixedHorizon(horizon=24),
warmup_len=24, batch_size=32,
training_mode="multi_step",
device="cuda",
)
trainer.fit(epochs=50)
trainer.save("checkpoint.pth")
# 3. Simulate
predictions = model.rollout(
warmup_seq={"inputs": warmup_data},
rollout_inputs={"controls": controls, "exogenous": exogenous},
horizon=100, feedback="model",
)
# 4. RL integration
from timesim.envs import WorldModelEnv
env = WorldModelEnv(
world_model=model, dataset=dataset,
warmup_len=24, episode_len=100,
control_dim=2, exo_dim=2, output_dim=1,
target_output=target,
)
obs, info = env.reset()
for _ in range(100):
action = policy(obs)
obs, reward, terminated, truncated, info = env.step(action)- Domain-agnostic — no domain-specific assumptions in the core library
- Composable — mix and match models, sampling strategies, and loss functions
- Extensible — easy to add new models, strategies, and features
- Operationally careful — error handling, logging, and checkpointing throughout
- Research-friendly — clean abstractions for experimentation
MIT License — see LICENSE file for details.
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Submit a pull request