feat(backend): add NeMo AutoModel (Wan 2.2 diffusion) as a first-class Primus backend#835
Open
mvstrauss wants to merge 2 commits into
Open
feat(backend): add NeMo AutoModel (Wan 2.2 diffusion) as a first-class Primus backend#835mvstrauss wants to merge 2 commits into
mvstrauss wants to merge 2 commits into
Conversation
Wraps NVIDIA-NeMo AutoModel's diffusion TrainDiffusionRecipe (Wan 2.2 T2V A14B) behind the Primus BackendAdapter/Trainer contract, following the same pattern as the torchtitan/megatron backends: a pinned third_party/ submodule installed editable on first run. - primus/backends/nemo_automodel/: adapter, pretrain trainer, argument builder, and registry wiring (mirrors torchtitan/megatron). - third_party/Automodel submodule pinned to 44f2acde; primus/_thirdparty.lock regenerated from the submodule pins. - examples/nemo_automodel/prepare.py: ROCm-safe editable install (pins the image's torch/torchvision/torchaudio/triton/aiter/flash-attn via a pip constraint so CUDA wheels can't be pulled) + optional aiter version shim so diffusers' aiter attention backend is selectable; idempotent. - configs: Wan 2.2-A14B model preset + optimized nemo_automodel pre_trainer module config, plus MI355X example EXPs (pretrain bs32 AC-on, bs8 AC-off, finetune, minimal default). - tests/unit_tests/backends/nemo_automodel: registration + config-strip guard + unsupported-stage tests. - docs: NeMo AutoModel row in examples/README.md. Co-authored-by: Cursor <cursoragent@cursor.com>
mvstrauss
requested review from
Xiaoming-AMD,
limou102 and
wenxie-amd
as code owners
July 1, 2026 14:25
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a new first-class Primus backend that routes Primus’ BackendAdapter/Trainer contract into NVIDIA NeMo AutoModel’s diffusion training recipe (Wan 2.2 T2V A14B), following the existing “third_party submodule + editable install on first run” integration pattern used by other backends.
Changes:
- Introduces the
primus/backends/nemo_automodeladapter, trainer, config builder, and registry wiring for backend discovery and trainer resolution. - Adds model/module presets for Wan 2.2 diffusion and MI355X example experiment configs (pretrain + tuned operating points + finetune).
- Pins the Automodel submodule in
.gitmodulesandprimus/_thirdparty.lock, plus adds a backend-specificexamples/nemo_automodel/prepare.pyfor ROCm-safe editable installation (and optional aiter version shim).
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/unit_tests/backends/nemo_automodel/test_nemo_automodel_registration.py | Unit tests validating backend/adapter/trainer registration and a config-strip guard. |
| primus/backends/nemo_automodel/init.py | Registers the adapter and trainer class in BackendRegistry. |
| primus/backends/nemo_automodel/nemo_automodel_adapter.py | BackendAdapter implementation: backend path resolution, config pass-through, trainer resolution, version detection. |
| primus/backends/nemo_automodel/nemo_automodel_pretrain_trainer.py | Trainer that converts params → temp YAML → AutoModel config loader → TrainDiffusionRecipe. |
| primus/backends/nemo_automodel/argument_builder.py | Config normalization helpers and Primus-only top-level key stripping before handing off to AutoModel. |
| primus/configs/modules/nemo_automodel/pre_trainer.yaml | AutoModel diffusion recipe-shaped module config defaults for Primus pre_trainer. |
| primus/configs/models/nemo_automodel/wan2_2_t2v_a14b.yaml | Wan 2.2 T2V A14B preset merged into the module config under model:. |
| examples/nemo_automodel/prepare.py | Backend prepare step: editable install with ROCm constraints + optional amd-aiter metadata shim. |
| examples/nemo_automodel/configs/MI355X/diffusion/wan2_2_t2v_a14b-pretrain.yaml | Baseline MI355X pretrain experiment wiring for the new backend. |
| examples/nemo_automodel/configs/MI355X/diffusion/wan2_2_t2v_a14b-pretrain-bs32-acon.yaml | MI355X tuned “AC-on bs32” benchmark config overrides. |
| examples/nemo_automodel/configs/MI355X/diffusion/wan2_2_t2v_a14b-pretrain-bs8-acoff.yaml | MI355X tuned “AC-off bs8” benchmark config overrides. |
| examples/nemo_automodel/configs/MI355X/diffusion/wan2_2_t2v_a14b-finetune.yaml | MI355X finetune experiment config (uses model.mode: finetune). |
| examples/README.md | Documents NeMo AutoModel in the supported backends table. |
| .gitmodules | Adds third_party/Automodel submodule entry. |
| primus/_thirdparty.lock | Records the Automodel submodule pin for dependency locking. |
…p failures - pre_trainer.yaml: stop hard-coding fsdp.dp_size=8. AutoModel derives dp = world_size / (tp*cp*pp) when dp_size is unset, so single- and multi-node runs work without manual edits and stay correct under any parallel topology. - prepare.py: replace the empty `except OSError: pass` in the constraints cleanup with a non-fatal log_info so the intentional best-effort cleanup is auditable instead of silently suppressed. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
Author
|
This PR adds NeMo AutoModel as first-class Primus backend. Initially added explicit configs for BF16 pretrain of Wan2.2, per request from DCGPU team on behalf of customer. We will later extend this with FP8 and MXFP4 support. |
zirui
self-requested a review
July 7, 2026 02:53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds NVIDIA-NeMo AutoModel as a first-class Primus training backend, wrapping
AutoModel's diffusion
TrainDiffusionRecipe(Wan 2.2 T2V A14B) behind the PrimusBackendAdapter/Trainercontract. It follows the exact same integration pattern asthe existing
torchtitan/megatronbackends — a pinnedthird_party/submodule thatis installed editable on first run — so a stock
rocm/primususer runs it via thestandard
git submodule update --init+run_pretrain.shflow.What's included
primus/backends/nemo_automodel/):adapter,pretrain_trainer,argument_builder, and registry wiring (__init__.py), mirroringtorchtitan.The trainer converts Primus
module_config.params→ AutoModelConfigNodeanddelegates to
TrainDiffusionRecipe(AutoModel owns FSDP2 / dataloader / optimizer /checkpointing), keeping us version-agnostic.
third_party/Automodelpinned to44f2acde(.gitmodules,branch = main), andprimus/_thirdparty.lockregenerated from the submodule pinsvia
tools/pip_index/gen_thirdparty_lock.py(thethirdparty-lockpre-commit hook).examples/nemo_automodel/prepare.py: resolves the submodule and does aROCm-safe editable install — pins the image's
torch/torchvision/torchaudio/triton/aiter/flash-attn via a pip constraint so CUDA
wheels can't be pulled — with the
diffusion,diffusion-mediaextras. Idempotent(skips if
nemo_automodelis already importable). Also applies an optional, opt-outAITER version shim so diffusers'
aiterattention backend is selectable onimages that ship a dev-versioned
amd-aiter(disable withAITER_VERSION_SHIM=0).primus/configs/models/nemo_automodel/wan2_2_t2v_a14b.yamlprimus/configs/modules/nemo_automodel/pre_trainer.yaml(optimized: AITER attention +
torch.compile+ fused AdamW + bf16 grad-reduceexamples/nemo_automodel/configs/MI355X/diffusion/):-pretrain-bs32-acon(headline AC-on),-pretrain-bs8-acoff(fastest AC-off),-finetune(mode: finetune, bf16 master), and a minimal-pretrainstub.tests/unit_tests/backends/nemo_automodel/): registration, aconfig-strip guard (fails if
module_base.yamlgrows a key that would leak into theAutoModel config), and unsupported-stage handling.
examples/README.md.Measured results (8× MI355X, 512×512, real PusaV1, fp32 master / bf16 compute)
Reproduced end-to-end through the full Primus runtime (
run_pretrain.sh→prepare_experiment.py→torchrun … train pretrain→PrimusRuntime→ backend →AutoModel recipe):
wan2_2_t2v_a14b-pretrain-bs32-aconwan2_2_t2v_a14b-pretrain-bs8-acofftorch.compileruns cleanly with the AITER custom-op backend (no graph break).Fresh-environment reproduction (this branch)
The headline point was re-verified from scratch: a fresh
rocm/primus:v26.3container + a fresh clone of this branch (only
git submodule update --initandthe base image), no pre-existing state. Steady-state (
bs32AC-on, 8× MI355X):(step 0 is a ~116 s warmup:
torch.compile+ first-time AITER gfx950 kernel JIT.)Matches the documented ~3.10–3.12 s/s/GPU @ ~84.9 GB; run exited 0 with a final
checkpoint written.
How to reproduce on a fresh node
Everything below needs only this branch + the
rocm/primusbase image + publicHugging Face artifacts. Adjust host paths to your machine.
1. Container
/data/primusis an empty host directory (the branch is cloned into it in step 2);/data/models,/data/wan22_cache,/data/hfare roomy host paths for weights, thedataset cache, and the HF cache.
docker run -d --name automodel_test \ --network host --ipc host --privileged \ --security-opt seccomp=unconfined --security-opt label=disable \ --device /dev/kfd --device /dev/dri --shm-size 64g \ -v /data/primus:/workspace/primus:rw \ -v /data/models:/models:rw \ -v /data/wan22_cache:/dataset:rw \ -v /data/hf:/hf:rw \ -e HF_HOME=/hf -w /workspace/primus \ rocm/primus:v26.3 sleep infinity docker exec -it automodel_test bash2. Branch + submodule (inside the container)
prepare.pydoes the editable, ROCm-pinned install automatically on the firstrun_pretrain.sh; nothing else to install by hand.3. Model weights (public)
pip install -U "huggingface_hub[cli]" huggingface-cli download Wan-AI/Wan2.2-T2V-A14B-Diffusers \ --local-dir /models/Wan2.2-T2V-A14B-Diffusers(The configs point
model.pretrained_model_name_or_pathat/models/Wan2.2-T2V-A14B-Diffusers.)4. Dataset — build the preprocessed cache
The recipe trains on a preprocessed latent/embedding cache produced by AutoModel's
own preprocessor (
tools.diffusion.preprocessing_multiprocess, shipped in thesubmodule). Two options:
(a) Real data —
RaphaelLiu/PusaV1_training(public, ~79 GB / ~3,860 clips):(b) Throughput-only smoke: point the preprocessor at any small folder of 512p
.mp4clips with sidecar.txtcaptions (--caption_format sidecar); a dozen clipsare enough for a steady-state throughput number.
Either way, set the EXP's
data.dataloader.cache_dirto the produced cache(
/dataset/pusa_v1_512sqin the examples).5. Launch
For a quick smoke, override
step_scheduler.max_stepsto a few steps. On non-8-GPUtopologies set
GPUS_PER_NODEandfsdp.dp_sizeto your world size.Test plan
reproduction" above): submodule init → ROCm-safe editable install (ROCm torch
preserved, no CUDA wheels) → AITER shim → config parse → backend routing → 8×
MI355X training to steady state, exit 0 + final checkpoint written.
pre-commitclean on all changed files (trailing-whitespace / eof / check-yaml /isort / autoflake / black / shellcheck / thirdparty-lock).
tests/unit_tests/backends/nemo_automodel/— 10 passed (adapter +trainer registration,
train→pretrainalias, config-strip guard,unsupported-stage error).
PrimusParser; overrides land (mode/precision/AC/batch/optimizer).
run-unittest-torchjob checks out submodules recursivelyand runs the change-selected
pytesttargets, so it will exercise the newtests/unit_tests/backends/nemo_automodel/suite. Left unchecked because it canonly run once the PR triggers CI (these tests already pass locally, above).
Notes for reviewers
prepare.pyeditableinstall is the supported path. The adapter keeps a "prefer already-installed" fast
path for images that do ship it.
model.stage(
high_noise→transformer,low_noise→transformer_2).pipeline_specis onlyconsumed in
mode: pretrain; it is ignored inmode: finetune(which loads viafrom_pretrainedwith the matchingactive_transformer).or relocate if you'd prefer the examples stay hardware-agnostic.