Skip to content

[Examples]: MiniMax-M3 DSpark#1965

Open
h-guo18 wants to merge 1 commit into
mainfrom
haoguo/m3-dspark-recipe
Open

[Examples]: MiniMax-M3 DSpark#1965
h-guo18 wants to merge 1 commit into
mainfrom
haoguo/m3-dspark-recipe

Conversation

@h-guo18

@h-guo18 h-guo18 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Type of change: new example + bug fixes

Adds a MiniMax-M3 DSpark streaming training recipe under tools/launcher/examples/MiniMaxAI/MiniMax-M3/, plus the four fixes it needs to actually run. Each fix addresses a failure mode that is silent or misleading without it:

  1. Gemma-style final norm for the fake base (modeling_final_norm.py, modeling_fakebase.py): M3 uses a gemma-style final RMSNorm ((1 + weight) scale, fp32 multiply-then-cast). Selecting the norm by model_type alone picks plain rmsnorm — MiniMax's VL remote code coerces its model_type-less text_config to mixtral — which silently drops the +1 and corrupts the distillation target. New _FinalGemmaRMSNorm + selection by the explicit use_gemma_norm config flag (only MiniMax sets it).
  2. Loud failure for un-maskable answer_only_loss (hf_streaming_dataset.py): with a fast tokenizer whose chat template has no {% generation %} tags, apply_chat_template(return_assistant_tokens_mask=True) only warns and returns an all-zero mask — training runs at zero loss on every sample with no other symptom. Now raises at tokenization with an actionable message.
  3. SERVE_BLOCK_SIZE knob (train_eagle_streaming.sh): nemo_run exports env values unquoted, so a multi-token SERVE_EXTRA_ARGS="--trust-remote-code --block-size 128" loses everything after the first token. M3's MSA sparse attention requires KV block 128 (ValueError: No common block size for 16 at engine init otherwise), so --block-size gets a dedicated single-token knob.
  4. Relax the speculative_decoding transformers pin to <5.13 (match pyproject.toml): the old <5.4 pin downgrades recent vLLM containers (e.g. transformers 5.12.1, which also provides in-tree minimax_m3_vl) and breaks vllm serve (ALLOWED_LAYER_TYPES needs >=5.5.3).

The example itself encodes the validated M3 specifics: generation-tagged chat template copy (required for answer_only_loss — see fix 2), draft dims + base rope_theta=5e6 set explicitly (not inherited), mask token 200063 (reserved slot; added tokens end at 200060), EAGLE_CAPTURE_IDS = draft default target_layer_ids+1 + final layer, trust_remote_code at serve/export, and AWS-EFA NIXL notes (UCX segfaults at agent init on EFA nodes; LIBFABRIC required there).

Usage

cd tools/launcher
export SLURM_HOST=localhost SLURM_ACCOUNT=<account> SLURM_PARTITION=<partition> \
       SLURM_HF_LOCAL=<hf_models_dir> SLURM_JOB_DIR=<experiments_dir> NEMORUN_HOME=$PWD
uv run launch.py --yaml examples/MiniMaxAI/MiniMax-M3/hf_streaming_dspark_multi_node.yaml \
       identity=$HOME/.ssh/id_ecdsa detach=True --yes

Testing

  • tests/unit/torch/speculative/plugins/: 129 passed inside a current vLLM x86_64 nightly container (transformers 5.12.1), including 3 new tests for the assistant-mask guard.
  • Generation-tagged template verified against real corpus samples: input_ids identical to the original template, mask covers exactly the assistant turns (think prefix + content + eos), contiguous, no user-prompt leak.
  • The recipe is exercised end-to-end by a live M3 DSpark training run (this yaml modulo cluster paths): streaming serve + NIXL transport + resume all healthy; drafter MT-Bench AL exceeds our Kimi-K2.6 DSpark reference by ~8k steps.
  • ruff check / ruff format (0.15.20) clean.

Before your PR is "Ready for review"

  • Is this change backward compatible?: ✅ (norm selection only changes models with use_gemma_norm=True, previously mis-normed; the guard turns a silent zero-loss run into an error; SERVE_BLOCK_SIZE is opt-in; the pin relax widens the allowed range)
  • Did you write any new necessary tests?: ✅
  • Did you update Changelog?: ❌ (can add if desired)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added Gemma-style RMS normalization support for speculative decoding.
    • Added MiniMax-M3 multi-node training configuration, plus a full Jinja chat template supporting tool calls, multimodal content, and thinking modes.
    • Added optional SERVE_BLOCK_SIZE support for vLLM serve launches.
  • Bug Fixes
    • Improved training safety for answer-only loss masking by failing fast with a clear error when the required generation template markers are missing.
  • Compatibility
    • Expanded the supported Transformers version range for speculative decoding examples.

@h-guo18 h-guo18 requested review from a team as code owners July 12, 2026 00:51
@h-guo18 h-guo18 requested a review from kevalmorabia97 July 12, 2026 00:51
@copy-pr-bot

copy-pr-bot Bot commented Jul 12, 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.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The changes add Gemma final-norm support, validate generation tags for answer-only loss masking, add a MiniMax-M3 chat template, and provide a multi-node DSpark streaming training configuration with configurable vLLM block size.

Changes

Speculative streaming support

Layer / File(s) Summary
Gemma final-norm support
modelopt/torch/speculative/plugins/modeling_final_norm.py, modelopt/torch/speculative/plugins/modeling_fakebase.py
Adds Gemma RMSNorm behavior and selects it when use_gemma_norm is enabled in the base configuration.
Chat-template loss-mask validation
modelopt/torch/speculative/plugins/hf_streaming_dataset.py, tests/unit/torch/speculative/plugins/test_hf_streaming_dataset.py
Rejects answer-only loss masking when the tokenizer template lacks generation tags and tests tagged, untagged, and full-loss cases.
MiniMax-M3 chat rendering
tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja
Adds MiniMax-M3 tokens, system/developer instructions, multimodal content handling, tool calls, reasoning content, role rendering, and generation prompts.
MiniMax-M3 streaming launch
tools/launcher/common/eagle3/train_eagle_streaming.sh, tools/launcher/examples/MiniMaxAI/MiniMax-M3/hf_streaming_dspark_multi_node.yaml, examples/speculative_decoding/requirements.txt
Adds SERVE_BLOCK_SIZE support, widens the Transformers version range, and defines dataset preparation plus six-node DSpark training and serving settings for MiniMax-M3.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DSparkPipeline
  participant MakeDataset
  participant TrainEagleStreaming
  participant VLLMServe
  DSparkPipeline->>MakeDataset: create train.jsonl
  DSparkPipeline->>TrainEagleStreaming: launch multi-node training
  TrainEagleStreaming->>VLLMServe: start vLLM with block size 128
  VLLMServe-->>TrainEagleStreaming: serve speculative decoding
Loading

Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
Security Anti-Patterns ❌ Error The new MiniMax-M3 example hardcodes trust_remote_code=true / --trust-remote-code in launcher config, violating SECURITY.md’s default-false rule. Make remote-code loading a caller-configurable option defaulting to false, and enable it only via explicit user override for trusted checkpoints.
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and directly references the main change: adding a MiniMax-M3 DSpark example.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch haoguo/m3-dspark-recipe

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://NVIDIA.github.io/Model-Optimizer/pr-preview/pr-1965/

Built to branch gh-pages at 2026-07-12 02:10 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modelopt/torch/speculative/plugins/hf_streaming_dataset.py`:
- Around line 116-124: Update the error message in the assistant-mask validation
guard to reference the actual template location,
tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja,
while leaving the surrounding guidance unchanged.
- Around line 106-124: The guard around answer_only_loss must also raise when
the tokenizer is non-fast and no loss-mask recovery is available, regardless of
whether the chat template contains {% generation %} tags. Update the condition
using recovery, tokenizer.is_fast, and the existing template check, and adjust
the RuntimeError message to identify the unsupported slow-tokenizer path while
preserving the current guidance.

In
`@tools/launcher/examples/MiniMaxAI/MiniMax-M3/hf_streaming_dspark_multi_node.yaml`:
- Around line 99-100: Add the required MLM_MODEL_CFG environment variable
alongside HF_MODEL_CKPT in the MiniMax-M3 configuration, setting it to the
model’s Hugging Face repository ID and preserving the existing HF_MODEL_CKPT
reference.

In
`@tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja`:
- Line 1: Add the required provenance and licensing notices at the top of the
template before the special token variables: include the MiniMax source
reference, the upstream copyright and license notice, and the NVIDIA Apache 2.0
header. Also update the repository LICENSE to include the MiniMax Community
License.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 18176f48-ae3d-49dc-b512-26580fa2bc17

📥 Commits

Reviewing files that changed from the base of the PR and between 7ed19b2 and 468013d.

📒 Files selected for processing (8)
  • examples/speculative_decoding/requirements.txt
  • modelopt/torch/speculative/plugins/hf_streaming_dataset.py
  • modelopt/torch/speculative/plugins/modeling_fakebase.py
  • modelopt/torch/speculative/plugins/modeling_final_norm.py
  • tests/unit/torch/speculative/plugins/test_hf_streaming_dataset.py
  • tools/launcher/common/eagle3/train_eagle_streaming.sh
  • tools/launcher/examples/MiniMaxAI/MiniMax-M3/hf_streaming_dspark_multi_node.yaml
  • tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja

Comment on lines 106 to +124
recovery = None
if answer_only_loss and not getattr(tokenizer, "is_fast", False):
recovery = get_loss_mask_recovery(tokenizer)
if answer_only_loss and recovery is None:
# Fail loudly on a template without {% generation %} tags: transformers only
# warns and returns an ALL-ZERO assistant mask, which trains every sample at
# zero loss with no other symptom. (The regex matches the tag itself, not the
# unrelated `add_generation_prompt` identifier most templates contain.)
template = getattr(tokenizer, "chat_template", None) or ""
if not re.search(r"\{%-?\s*generation\b", template):
raise RuntimeError(
"answer_only_loss=True needs assistant masks, but the tokenizer's chat "
"template has no {% generation %} tags, so apply_chat_template would "
"return an all-zero mask and training would silently run at zero loss. "
"Pass a tagged template copy via data.chat_template (see "
"examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja for a "
"worked example), register a loss-mask recovery "
"(modelopt.torch.utils.loss_mask), or set answer_only_loss=false."
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

python3 - <<'PY'
from pathlib import Path

path = Path("modelopt/torch/speculative/plugins/hf_streaming_dataset.py")
text = path.read_text().splitlines()
for start, end in [(1, 220)]:
    for i, line in enumerate(text[start-1:end], start):
        print(f"{i:4d}: {line}")
PY

Repository: NVIDIA/Model-Optimizer

Length of output: 11809


🌐 Web query:

Transformers apply_chat_template return_assistant_tokens_mask slow tokenizer char_to_token fast tokenizer

💡 Result:

The return_assistant_tokens_mask parameter in transformers.apply_chat_template is used to generate a binary mask identifying tokens produced by the assistant (1 for assistant tokens, 0 for others), which is essential for excluding non-assistant text during supervised fine-tuning [1][2][3]. Key Technical Details: 1. Mechanism: This feature requires chat templates to use the {% generation %} keyword to explicitly define the assistant's response segments [1][4][3]. During tokenization, the method calculates the character-level offsets of these generation blocks and aligns them with the tokenized sequence [2]. 2. Dependency on Fast Tokenizers: The implementation relies heavily on the fast tokenizer's ability to map between character space and token space (e.g., using char_to_token mapping methods) [2][5]. Historically, issues with inaccurate masks (e.g., all zeros) were often linked to underlying defects in the fast tokenizer's alignment logic [5]. 3. Constraints: The parameter functions only when tokenize=True and return_dict=True [6]. Some classes inheriting from ProcessorMixin have encountered issues where these arguments were inadvertently constrained, blocking the use of the assistant mask [6]. While fast tokenizers are preferred due to their robust alignment capabilities, slow (Python-based) tokenizers lack the optimized alignment infrastructure required for this feature and generally do not support or correctly implement the advanced character-to-token mappings needed for this specific mask generation [3][7][8]. If you encounter problems with the mask being all zeros, ensure you are using a recent version of the library, as several fixes have been merged into the rust-based tokenizers backend to resolve alignment inaccuracies [5].

Citations:


Handle non-fast tokenizers in this guard. If tokenizer.is_fast is false and no recovery is registered, a template with {% generation %} tags still passes this check and falls through to apply_chat_template(..., return_assistant_tokens_mask=True), which depends on fast-tokenizer alignment. Fold the slow-tokenizer case into the same RuntimeError path so the failure is explicit.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modelopt/torch/speculative/plugins/hf_streaming_dataset.py` around lines 106
- 124, The guard around answer_only_loss must also raise when the tokenizer is
non-fast and no loss-mask recovery is available, regardless of whether the chat
template contains {% generation %} tags. Update the condition using recovery,
tokenizer.is_fast, and the existing template check, and adjust the RuntimeError
message to identify the unsupported slow-tokenizer path while preserving the
current guidance.

Comment on lines +116 to +124
raise RuntimeError(
"answer_only_loss=True needs assistant masks, but the tokenizer's chat "
"template has no {% generation %} tags, so apply_chat_template would "
"return an all-zero mask and training would silently run at zero loss. "
"Pass a tagged template copy via data.chat_template (see "
"examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja for a "
"worked example), register a loss-mask recovery "
"(modelopt.torch.utils.loss_mask), or set answer_only_loss=false."
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stale path in the error message.

The pointer examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja doesn't match the actual recipe location; per the PR's file list the template lives at tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja. The repo also has a distinct top-level examples/ directory (e.g. examples/speculative_decoding/requirements.txt), so this path silently points to a directory that doesn't contain the file, defeating the "actionable error" goal of this guard.

📝 Proposed fix
-                "Pass a tagged template copy via data.chat_template (see "
-                "examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja for a "
-                "worked example), register a loss-mask recovery "
+                "Pass a tagged template copy via data.chat_template (see "
+                "tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja "
+                "for a worked example), register a loss-mask recovery "
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
raise RuntimeError(
"answer_only_loss=True needs assistant masks, but the tokenizer's chat "
"template has no {% generation %} tags, so apply_chat_template would "
"return an all-zero mask and training would silently run at zero loss. "
"Pass a tagged template copy via data.chat_template (see "
"examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja for a "
"worked example), register a loss-mask recovery "
"(modelopt.torch.utils.loss_mask), or set answer_only_loss=false."
)
raise RuntimeError(
"answer_only_loss=True needs assistant masks, but the tokenizer's chat "
"template has no {% generation %} tags, so apply_chat_template would "
"return an all-zero mask and training would silently run at zero loss. "
"Pass a tagged template copy via data.chat_template (see "
"tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja "
"for a worked example), register a loss-mask recovery "
"(modelopt.torch.utils.loss_mask), or set answer_only_loss=false."
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@modelopt/torch/speculative/plugins/hf_streaming_dataset.py` around lines 116
- 124, Update the error message in the assistant-mask validation guard to
reference the actual template location,
tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja,
while leaving the surrounding guidance unchanged.

Comment on lines +99 to +100
environment:
- HF_MODEL_CKPT: <<global_vars.hf_model>>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Add the required MLM_MODEL_CFG repository ID.

The new model configuration omits the launcher’s model-staging variable.

Proposed fix
     environment:
       - HF_MODEL_CKPT: <<global_vars.hf_model>>
+      - MLM_MODEL_CFG: "MiniMaxAI/MiniMax-M3"

As per path instructions, new model configs must set MLM_MODEL_CFG to the Hugging Face repository ID.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
environment:
- HF_MODEL_CKPT: <<global_vars.hf_model>>
environment:
- HF_MODEL_CKPT: <<global_vars.hf_model>>
- MLM_MODEL_CFG: "MiniMaxAI/MiniMax-M3"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tools/launcher/examples/MiniMaxAI/MiniMax-M3/hf_streaming_dspark_multi_node.yaml`
around lines 99 - 100, Add the required MLM_MODEL_CFG environment variable
alongside HF_MODEL_CKPT in the MiniMax-M3 configuration, setting it to the
model’s Hugging Face repository ID and preserving the existing HF_MODEL_CKPT
reference.

Source: Path instructions

@@ -0,0 +1,250 @@
{# ---------- special token variables ---------- #}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the target file and related example templates for provenance/licensing patterns.
git ls-files 'tools/launcher/examples/MiniMaxAI/MiniMax-M3/*' | sed 's#^`#FILE`: #'
echo
wc -l tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja
echo
cat -n tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja | sed -n '1,80p'
echo
rg -n --hidden --no-messages 'SPDX-License-Identifier|copyright|license|provenance|source' tools/launcher/examples/MiniMaxAI/MiniMax-M3 tools/launcher/examples/MiniMaxAI -g '!**/*.pyc'

Repository: NVIDIA/Model-Optimizer

Length of output: 5262


🌐 Web query:

MiniMaxAI MiniMax-M3 chat_template.jinja license source commit minimax-community

💡 Result:

The MiniMax-M3 model is released under the MiniMax Community License [1][2][3], which is not an unrestricted permissive open-source license [1]. The chat_template.jinja file for MiniMax-M3 is hosted in the official MiniMaxAI/MiniMax-M3 repository on Hugging Face [4][5]. As of July 12, 2026, the model repository indicates that the license governing its use is the "minimax-community" license [2][3]. This license typically includes specific terms such as attribution requirements and restrictions on certain commercial uses [1]. You can view the specific content of the chat template and track its history directly via the Hugging Face repository [4][6]. The repository for MiniMax-M3 is maintained under the MiniMaxAI organization on Hugging Face [4][3], and related code can also be found in the MiniMax-AI GitHub organization [7]. Always refer to the official LICENSE file [8] located in the repository for the most accurate and legally binding terms regarding the model's usage.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether the repo already has license notices or hook exclusions for this file/path.
rg -n --no-messages 'MiniMax|minimax-community|third-party|Third-Party Software Notices|insert-license|m3_chat_template_generation\.jinja' LICENSE .pre-commit-config.yaml tools/launcher/examples/MiniMaxAI -g '!**/*.pyc'

echo
echo "LICENSE lines:"
wc -l LICENSE
echo
sed -n '1,260p' LICENSE | cat -n | sed -n '1,260p'

echo
echo ".pre-commit-config.yaml lines:"
wc -l .pre-commit-config.yaml
echo
sed -n '1,260p' .pre-commit-config.yaml | cat -n | sed -n '1,260p'

Repository: NVIDIA/Model-Optimizer

Length of output: 26892


Add the MiniMax provenance and license notices here.
This template needs a source reference, the upstream copyright/license notice, and the NVIDIA Apache 2.0 header, plus an update to LICENSE for the MiniMax Community License.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@tools/launcher/examples/MiniMaxAI/MiniMax-M3/m3_chat_template_generation.jinja`
at line 1, Add the required provenance and licensing notices at the top of the
template before the special token variables: include the MiniMax source
reference, the upstream copyright and license notice, and the NVIDIA Apache 2.0
header. Also update the repository LICENSE to include the MiniMax Community
License.

Source: Coding guidelines

@h-guo18 h-guo18 changed the title [Examples]: MiniMax-M3 DSpark streaming recipe + the fixes it needs (gemma final norm, assistant-mask guard, SERVE_BLOCK_SIZE, transformers pin) [Examples]: MiniMax-M3 DSpark Jul 12, 2026
Signed-off-by: h-guo18 <67671475+h-guo18@users.noreply.github.com>
@h-guo18 h-guo18 force-pushed the haoguo/m3-dspark-recipe branch from 468013d to b31352a Compare July 12, 2026 02:06
@h-guo18

h-guo18 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor Author

/claude review

"deepseek_v3": "rmsnorm",
"kimi_k2": "rmsnorm", # Kimi-K2 / K2-Thinking (DeepSeek-V3 arch) report model_type "kimi_k2"
"kimi_k25": "rmsnorm", # Kimi-K2.5 / K2.6 / K2.7 all report model_type "kimi_k25"
"minimax_m3_vl_text": "rmsnorm", # overridden to gemma_rmsnorm via use_gemma_norm below

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[IMPORTANT ModeState] This new minimax_m3_vl_text → "rmsnorm" table entry is a silent-corruption fallback that undermines the fail-safe this file is built around.

The selection order in _select_final_norm_type is: use_gemma_norm first, then this table. So the entry is only ever consulted when use_gemma_norm is absent/falsy but model_type == "minimax_m3_vl_text". In that case it returns plain "rmsnorm", which drops the (1 + weight) scale — exactly the silent bias into the reconstructed logits / distillation target that the rest of this module (and the gpt_oss-disabled comment above) deliberately avoids.

The file's stated contract is "unlisted → no norm → hard error" precisely because a wrong norm is worse than no norm. Mapping M3 to rmsnorm as a fallback trades a loud RuntimeError (from _maybe_apply_base_final_norm) for a silent +1 drop.

Since every M3 config that reaches here is gemma-normed, either:

  • Remove this entry so a use_gemma_norm-less M3 falls through to None → hard error, or
  • Map it to "gemma_rmsnorm" so the correct flavor is applied even if the flag is missing.

Both are safer than the current "rmsnorm".

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Review Summary

Findings — CRITICAL: 0, IMPORTANT: 1, SUGGESTION: 0

Reviewed all 8 changed files (5 source/example, 1 test, 1 shell, 1 requirements). The four fixes are well-motivated and the per-fix rationale in the PR body / inline comments is unusually thorough. The Gemma-norm math (fp32 normalize -> *(1+weight) -> type_as) is correct and matches MiniMaxM3VLRMSNorm; the constructor signature matches _FinalRMSNorm so the registry dispatch is consistent; the transformers pin (<5.13) is consistent with pyproject.toml; and the SERVE_BLOCK_SIZE knob is a clean, opt-in addition.

Most impactful finding

[IMPORTANT ModeState] modeling_final_norm.py:93 — the new minimax_m3_vl_text -> "rmsnorm" table entry is a silent-corruption fallback. Because use_gemma_norm is checked first, this entry only fires when the gemma flag is absent — and then it applies plain RMSNorm, dropping the (1 + weight) scale and silently biasing the reconstructed distillation target. That is the exact failure mode this file's "unlisted -> hard error" design (and the disabled gpt_oss entry) exists to prevent. Map it to gemma_rmsnorm or remove the entry entirely so a flag-less M3 hard-errors rather than mis-norms.

Assessment

Low-to-moderate risk. The change is backward compatible (norm selection only affects use_gemma_norm=True models, the mask guard converts a silent zero-loss run into a loud error, and the block-size/pin changes are additive). The one IMPORTANT item is a latent fail-safe regression rather than a live bug, since M3 configs set use_gemma_norm in practice — but it is worth closing since defeating the safety net is precisely what the surrounding code warns against.

Note: CodeRabbit's pre-merge gate flags the hardcoded trust_remote_code=true in the YAML (SECURITY.md exception needed) and a slow-tokenizer edge in the mask guard — deferring those to CodeRabbit rather than duplicating.

@codecov

codecov Bot commented Jul 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 57.14286% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 77.29%. Comparing base (7ed19b2) to head (b31352a).

Files with missing lines Patch % Lines
...t/torch/speculative/plugins/modeling_final_norm.py 47.05% 9 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1965      +/-   ##
==========================================
- Coverage   77.92%   77.29%   -0.63%     
==========================================
  Files         519      519              
  Lines       58217    58236      +19     
==========================================
- Hits        45366    45015     -351     
- Misses      12851    13221     +370     
Flag Coverage Δ
examples 43.29% <38.09%> (-0.17%) ⬇️
gpu 57.92% <33.33%> (-0.65%) ⬇️
regression 15.01% <33.33%> (+0.07%) ⬆️
unit 55.47% <57.14%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant