Reproducible environment

September 8, 2026 ยท View on GitHub

The supported training runtime is Linux x86_64, Python 3.11.13, PyTorch 2.7.1 + CUDA 12.8, torchvision 0.22.1, and Lightning 1.9.5. The same CUDA wheels support RTX 3090/3090 Ti (Ampere) and RTX 5090 (Blackwell). Use a current NVIDIA driver; the validated baseline is Linux driver 580.173.02. A local CUDA toolkit, Conda CUDA packages, and LD_LIBRARY_PATH edits are not required. torch.compile additionally needs a host C/C++ compiler (for example gcc/g++). The RT-1 extra also builds LeRobot's evdev dependency and needs a compiler plus Linux input headers (Ubuntu's build-essential and linux-libc-dev packages). Use glibc 2.28 or newer; CI checks Ubuntu 22.04, and the GPU hosts use Ubuntu 24.04. macOS, Windows without WSL2, and Linux ARM are outside this locked runtime.

Video loading keeps the decord API through the pinned EVA Decord fork. The original 0.6.0 Linux wheel incorrectly declares a CPython 3.6 ABI inside its metadata, which makes dependency checkers reject Python 3.11 and triggers repeated reinstalls. EVA Decord 0.6.1 fixes those wheel tags. PyAV is pinned to 14.2.0 because later 14.x releases do not provide the required Linux Python 3.11 wheel.

Install and run

Install uv (CI uses 0.12.0), then run from a checkout:

./nanowm sync
./nanowm doctor --require-cuda
./nanowm python src/main.py experiment=dino_wm_pusht dataset=dino_wm/pusht model=nanowm_b2

nanowm downloads the pinned Python when necessary, creates an isolated .venv, and uses uv.lock without updating it. It also starts commands at the repository root, so SSH, a new terminal, or a batch job uses the same interpreter and paths. An activated Conda environment is unnecessary. Existing launchers work through ./nanowm bash src/scripts/train/main/dino_wm_pusht.sh (set GPUS=0 for one GPU).

For RT-1/LeRobot:

./nanowm sync --extra rt1
./nanowm doctor --require-cuda --rt1
./nanowm python src/main.py experiment=rt1 dataset=rt1/rt1 model=nanowm_b2

The RT-1 extra is locked together with core dependencies. Running commands preserves installed extras; ./nanowm sync intentionally resets to core, and ./nanowm sync --extra rt1 restores RT-1. The data source explicitly uses PyAV, whose wheel bundles FFmpeg libraries. LeRobot also installs TorchCodec, but the default data path does not load its system-dependent decoder. A custom +dataset.loader.video_backend=torchcodec requires compatible system FFmpeg shared libraries and is outside the default validation path.

Configure a machine once

cp src/configs/local/paths.yaml.example src/configs/local/paths.yaml
# Uncomment dataset_dir / rt1_data_root / results_dir etc. and set your paths.

The file is gitignored and automatically loaded by Hydra. Precedence is CLI overrides > local YAML > environment variables > repository defaults. If an environment variable should control a setting, leave its YAML line commented. Use ~local to ignore the machine file for a reproducibility check.

Relative input paths are resolved against the original invocation directory, before model/data loading, so Hydra's run-directory change cannot redirect them. With ./nanowm, that base is always the repository root. Hugging Face repo IDs remain repo IDs. .env is not implicitly loaded; use the local YAML or export variables in the job environment. Scheduler variables such as CUDA_VISIBLE_DEVICES are preserved. This path configuration applies to the Hydra entrypoint; standalone sampling scripts retain their documented CLI arguments.

Verify before changing dependencies

./nanowm doctor --require-cuda --output results/environment-report.json
./nanowm python -m pytest -q
./nanowm python scripts/smoke_train.py --output results/environment-smoke
# Also exercise the default compilation path (use a new output directory):
./nanowm python scripts/smoke_train.py --compile --output results/environment-smoke-compiled

The GPU test runs the actual PushT training entrypoint, writes a checkpoint, resumes optimizer state from step 1 to step 2, and performs standalone evaluation. It generates tiny videos and an untrained tiny VAE locally, with Hub access and W&B disabled. This checks runtime integration, not model quality or published checkpoint accuracy. doctor also runs bf16 CUDA forward/backward kernels and encodes/decodes video. Its JSON report records versions, GPU architecture, and the lock hash without dumping environment variables or credentials.

Every PR runs fresh core and RT-1 installations on GitHub-hosted Linux runners, checks dependency consistency, imports the real training stack, exercises video decoding and Lightning precision, and runs CPU model/config regression tests. GPU tests are run on the two hardware generations before accepting a dependency update. The workflow does not require exposing lab machines to public PR jobs.

To update dependencies, edit pyproject.toml, run uv lock, and commit both files. Keep .python-version in sync with the validated Python patch version. Normal users run sync --locked via nanowm, never uv lock --upgrade or an unbounded pip install -U. Dependency maintenance will still be needed as drivers/hardware evolve; the lock and checks prevent silent drift.

Migration and scope

environment.yml has been retired: two solvers must not own PyTorch. Existing Conda environments can be left intact; use ./nanowm sync to create the new project environment. Do not copy installed site-packages between machines.

This baseline covers training, sampling, evaluation, and optional RT-1 loading. MuJoCo/PyFlex planning simulators and Depth Anything 3 have separate native stacks; follow their application guides in separate environments rather than installing unbounded simulator/xformers packages into the validated training environment.

The original failures are tracked in PR #16 and PR #17. The dependency lock incorporates compatible diffusion/Hub/LeRobot versions; both Trainer call sites use Lightning 1.9's bf16 mixed-precision spelling. See PyTorch's Blackwell/CUDA 12.8 release notes and uv's PyTorch index guide.