A small, readable nanoWorld-style world model. The first milestone is an action-conditioned autoregressive Transformer that learns discrete environment dynamics:
BOS, obs_0, action_0, obs_1, reward_0, done_0, action_1, ...
Actions are conditioning tokens. The training loss is applied to predicted world tokens: next observation, reward, and done. This keeps the code close to nanoWorld while making the objective a world model rather than a plain language model.
Open-source world-model systems differ in scale and modeling family, but several useful patterns repeat:
- DreamerV3 learns a compact dynamics model and trains behavior from imagined rollouts.
- IRIS combines a discrete autoencoder with an autoregressive Transformer world model.
- DIAMOND shows that strong visual world models can drive agents through imagined environments.
- nanoWorld is the style target: small files, direct PyTorch, and minimal magic.
This repo starts with the IRIS-like discrete-token path because it is the simplest route to a ~100M parameter model that is easy to inspect, test, and extend. A visual tokenizer can later replace the toy grid observation IDs without changing the Transformer core.
src/nanowm/
config.py model presets, including nano_100m
model.py nanoWorld-style decoder-only Transformer
tokens.py world-model token grammar and type helpers
gridworld.py deterministic synthetic environment dataset
train.py training loop and checkpointing
sample.py action-conditioned rollout from checkpoints
modal_train.py Modal GPU smoke/train entrypoint
tests/ unit tests for tokens, data, model, and parameter budget
architecture.md architecture and implementation plan
handoff.md running work log and next actions
Use Python 3.10 or newer.
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e ".[dev]"
pytest -qOn this machine, Miniforge Python 3.12 had a native readline segfault during pytest startup. The project tests passed with a temporary stub:
mkdir -p /private/tmp/nanowm_readline_stub
touch /private/tmp/nanowm_readline_stub/readline.py
PYTHONPATH=/private/tmp/nanowm_readline_stub:src pytest -qTrain the tiny debug model locally:
nanowm-train --config-name debug --max-iters 100 --out-dir out/debugTrain on the open-source Hugging Face CartPole trajectory dataset:
python -m pip install -e ".[hf]"
nanowm-train \
--dataset hf_cartpole \
--config-name debug \
--block-size 128 \
--hf-max-rows 50000 \
--max-iters 100 \
--out-dir out/hf-cartpole-debugThe default HF dataset is NathanGavenski/CartPole-v1, which provides row-wise obs, actions, rewards, and episode_starts. The adapter quantizes the 4D CartPole observation into a discrete observation token and derives terminal transitions from episode boundaries.
Roll out a checkpoint with random actions:
nanowm-sample --ckpt out/debug/ckpt.pt --steps 16Run a small GPU smoke test:
modal run modal_train.py --config-name debug --max-iters 100Run the Hugging Face CartPole smoke test on Modal:
modal run modal_train.py --config-name debug --max-iters 10 --dataset hf_cartpole --hf-max-rows 5000Run the ~100M preset after the smoke test is healthy:
modal run modal_train.py --config-name nano_100m --max-iters 1000The Modal entrypoint mounts src/nanowm into /root/nanowm so local package code is sent into the remote container without requiring a package publish step.
Verified smoke command:
modal run modal_train.py --config-name debug --max-iters 10This completed on an A10G with CUDA/bfloat16 and best_val_loss near 3.68.
Verified HF smoke command:
modal run modal_train.py --config-name debug --max-iters 10 --dataset hf_cartpole --hf-max-rows 5000This completed on an A10G with CUDA/bfloat16 and best_val_loss near 7.29.
debug: 2 layers, 64 hidden size, for tests and fast iteration.small: 6 layers, 384 hidden size, for local experiments.nano_100m: 14 layers, 12 heads, 768 hidden size, roughly 100M parameters with the compact gridworld vocabulary.
Implemented now:
- Discrete token grammar for observations, actions, rewards, and done flags.
- Causal Transformer with tied token embeddings, nanoWorld-style residual scaling, Flash Attention when PyTorch provides it, and masked CE loss.
- Synthetic gridworld dataset for deterministic smoke tests.
- Hugging Face CartPole trajectory adapter for open-source RL data smoke tests.
- Training, checkpointing, sampling, tests, and Modal entrypoint.
Planned next:
- Add a visual tokenizer interface so image/video latents can replace gridworld observation IDs.
- Add richer evaluation metrics: one-step observation accuracy, reward accuracy, done accuracy, and multi-step rollout consistency.
- Add optional policy/imagination code once the world model loss is stable.