Skip to content

feat(Automodel): add MiniMax-M3 GRPO training support - #4143

Open
jQizhang wants to merge 7 commits into
NVIDIA-NeMo:mainfrom
jQizhang:m3-rebase-907
Open

jQizhang wants to merge 7 commits into
NVIDIA-NeMo:mainfrom
jQizhang:m3-rebase-907

Conversation

@jQizhang

Copy link
Copy Markdown
Contributor

What does this PR do?

Add MiniMax-M3 GRPO training support with the AutoModel backend and BF16 vLLM generation.

  • Select the model load dtype based on optimizer FP32 master-weight support, allowing TE FusedAdam to load BF16 parameters while retaining FP32 master weights.
  • Backport the vLLM 0.25.1 MiniMax-M3 top-k buffer layout fix, updating the indexer and sparse-attention paths together with regression coverage.
  • Add a 32-node, 8-GPU-per-node non-colocated recipe using CP8/EP128 for training and TP16/EP16 for generation.
  • Document setup, supported configurations, limitations, and reference training curves in the model-family guide.

Issues

No linked NeMo-RL issue. The vLLM compatibility patch references upstream issue vllm-project/vllm#48603.

Usage

From a 32-node allocation with 8 GPUs per node:

uv run examples/run_grpo.py \
  --config examples/configs/recipes/llm/grpo-minimax-m3-32n8g-automodel-cp8ep128-noncolocated.yaml

Before your PR is "Ready for review"

  • Read the contributor guidelines.
  • Add regression tests for optimizer-dependent load dtype and the vLLM patch.
  • Run unit and functional tests locally for this submission.
  • Add model documentation and a reference recipe.

Additional Information

  • git diff --check passed against the locally recorded main merge base.
  • The committed guide reports a short CP8/EP128 GRPO validation run and includes curves through step 100. Training was not rerun when opening this PR.
  • Long-run convergence, additional training parallelism configurations, and longer sequences remain unvalidated.
  • The branch includes the recipe but does not yet register a corresponding nightly driver.

Signed-off-by: larkzhang-nv <larkz@nvidia.com>
Signed-off-by: larkzhang-nv <larkz@nvidia.com>
Signed-off-by: larkzhang-nv <larkz@nvidia.com>
Signed-off-by: larkzhang-nv <larkz@nvidia.com>
@jQizhang
jQizhang requested a review from a team as a code owner September 16, 2026 02:49
@jQizhang jQizhang added the CI:L1 Run doctests, unit tests, and functional tests label Sep 16, 2026
@jQizhang
jQizhang requested review from a team as code owners September 16, 2026 02:49
@copy-pr-bot

copy-pr-bot Bot commented Sep 16, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added the Documentation Improvements or additions to documentation label Sep 16, 2026
@jQizhang

Copy link
Copy Markdown
Contributor Author

/ok to test 3535f01

Signed-off-by: larkzhang-nv <larkz@nvidia.com>
@jQizhang

Copy link
Copy Markdown
Contributor Author

/ok to test 440d4b7

@jQizhang jQizhang changed the title feat: add MiniMax-M3 GRPO training support feat(Automodel): add MiniMax-M3 GRPO training support Sep 16, 2026
Signed-off-by: larkzhang-nv <larkz@nvidia.com>
@jQizhang

Copy link
Copy Markdown
Contributor Author

/ok to test 115ed78

@sharonyu-115
sharonyu-115 self-requested a review September 16, 2026 03:10
Signed-off-by: larkzhang-nv <larkz@nvidia.com>
@jQizhang jQizhang added CI:Lfast Runs a fast test suite and re-use nightly `main` container (but sync dependencies to PRs version) and removed CI:L1 Run doctests, unit tests, and functional tests labels Sep 16, 2026
@jQizhang

Copy link
Copy Markdown
Contributor Author

/ok to test 4637622

@jQizhang jQizhang left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Team review: PR #4143 — MiniMax-M3 GRPO training support

Reviewed by 6 agents (rl-expert, test-agent, bug-finder, design-reviewer, comment-reviewer, devil's-advocate). 2 non-blocking suggestions, 2 informational/minor items below.

No existing PR comments needed a response. Linters (pre-commit run --all-files) pass clean.

Generated by Claude Code

if isinstance(value, str) and value.startswith("torch."):
optimizer_kwargs[key] = getattr(torch, value.removeprefix("torch."))
if not _has_optimizer_fp32_master(optimizer_cls, optimizer_kwargs):
load_dtype = torch.float32

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nemo_rl/models/automodel/setup.py:755-767

1 action item.

TL;DR — this silently changes stored param dtype (fp32→bf16) for 5+ pre-existing production recipes, not just the new MiniMax recipe, with no nightly evidence it's safe.

PR-introduced, not a numerics-correctness bug. Model weight storage dtype used to be unconditionally torch.float32; now it's runtime_config.dtype (e.g. bf16) whenever _has_optimizer_fp32_master is true — true for grpo-qwen3.5-35ba3b-2n8g-automodel-ep16.yaml, grpo-nemotron3-super-120BA12B-16n8g-automodel-ep8.v2.yaml, grpo-glm47-flash-4n8g-automodel.yaml, vlm_grpo-gemma4-e4b-geo3k-1n8g-automodel.yaml, and dapo-nanov3.5-30BA3B-4n8g-automodel.yaml.

Compute precision itself is unaffected: FSDP2's MixedPrecisionPolicy(param_dtype=dtype, ...) in setup_distributed already casts the all-gathered shard to bf16 for forward/backward regardless of resident storage dtype, so this only changes stored-param dtype / memory footprint (previously fp32 storage made TE FusedAdam's separate fp32 master copy redundant; now it isn't). Undisclosed in the PR description; no nightly evidence for the affected pre-existing recipes.

AI-1

Action: confirm via nightly (a) at least one affected pre-existing recipe (e.g. grpo-qwen3.5-35ba3b-2n8g-automodel-ep16) still converges post-change, and (b) DCP checkpoint save/resume compatibility across the storage-dtype change (resuming an old fp32-saved checkpoint under the new bf16-storage code, or vice versa).

backend and BF16 vLLM generation.

> [!IMPORTANT]
> **Status: Functionally Ready.** The reference recipe has been validated with

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/guides/models/minimax/minimax-m3.md:7

1 action item.

PR-introduced. The "Status: Functionally Ready" label rests on a single 100-step run (~0.72 val accuracy), while this same doc's Known Limitations section says long-run convergence is unvalidated — and there's no nightly driver to re-validate it going forward (see the test-suite registration comment on the recipe YAML).

AI-1

Action: either downgrade the status label (e.g. "Experimental"/"Preview") until a nightly driver exists, or add the nightly registration — don't ship "Functionally Ready" without an automated re-validation path.

_patch_vllm_tool_parser_namespace_tool(patch_logger)
_patch_vllm_radio_layerscale_loader(patch_logger)
_patch_vllm_glm_decoder_sequence_parallel_moe(patch_logger)
_patch_vllm_minimax_m3_topk_buffer_layout(patch_logger)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nemo_rl/models/generation/vllm/patches.py:829

No action needed — suggestion only, not blocking.

Pre-existing pattern, this PR continues it. _patch_vllm_* is now 8 functions, hand-registered across two call sites (ensure_vllm_source_compat calls 4, _apply_vllm_patches calls 7 — an intentional subset/superset, not full duplication). A 9th patch author could add their function's body but forget one of the two registration sites — e.g. a diagnostics-only path that calls only ensure_vllm_source_compat would silently run unpatched.

Follow-up

A small registry (list[VllmPatch(name, apply, early_import_safe)] + a single loop per call site) would remove the risk of a call-site desync. Worth tracking given the file's growth rate — no tracking issue filed yet.

return tokenizer

@pytest.mark.parametrize(
"use_te, optimizer_kwargs, expected_dtype",

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests/unit/models/automodel/test_automodel_setup.py:919

No action needed — minor suggestion.

PR-introduced, minor. The new parametrized cases for _has_optimizer_fp32_master never exercise the except ImportError: return False branch or the optimizer_cls is not FusedAdam branch — both short-circuit before those paths are reached.

A small direct unit test calling _has_optimizer_fp32_master in isolation (no sys.modules monkeypatching needed) for these two branches would close the gap more cheaply than routing through the full setup_model_and_optimizer integration test.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI:Lfast Runs a fast test suite and re-use nightly `main` container (but sync dependencies to PRs version) Documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant