Skip to content

chore: AUT-2547 nightly sync main into dev (2026-10-16) - #8305

Closed
svcnemo-autobot wants to merge 102 commits into
NVIDIA:devfrom
svcnemo-autobot:chore/nightly-sync-2026-10-16
Closed

svcnemo-autobot wants to merge 102 commits into
NVIDIA:devfrom
svcnemo-autobot:chore/nightly-sync-2026-10-16

Conversation

@svcnemo-autobot

@svcnemo-autobot svcnemo-autobot commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Background

Nightly main→dev sync (2026-10-16): the oldest exact 100-commit prefix of dev..main, tip 302ed2304135a75c295a86e84be9b526c81f803c, merged into dev base dee456ab738d400d113590592079e54ae68654fd. Commit 101 (efb6ed57) is excluded. Python: +28124 / -2883 lines, 294 files.

What changed

  • 102 commits over dee456ab: 100 unchanged main commits, 1 merge 6ca045f0 (parents dee456ab, 302ed230), 1 signed repair commit 898ccb7d.
  • Repair commit:
    • gigatoken added to training/mlm extras; uv.lock regenerated (uv 0.7.2; adds gigatoken 0.10.0, awkward 2.14.0, awkward-cpp 57). Dockerfile.ci.dev unchanged.
    • Main-API tests adapted to dev: MTP, get_batch, dynamic prefix caching, mimo, DSA, THD CUDA graph, max_seqlen_per_dp_cp_rank.
    • Dev H100 golden values refreshed for moe/gpt3_moe_mcore_te_ep8_resume_torch_dist_dist_muon (main Scope layerwise optimizer collectives to be per module for mulitmodal mimo training #6192).
    • Main's Megatron-FSDP v2 dbuffer.py/parameter_group.py taken (requester-approved); symmetric-memory tests skip on dev's PyTorch.
    • Review 5570704991: HybridStack raises ValueError for CP>1 + linear_cp_layout="contiguous" with GDN/KDA layers (they follow cp_partition_mode, zigzag by default; main CP layout integration #6776). New CP=2 test, 4 cases.
    • Review 5573599695: the MTP hybrid stub config sets cross_entropy_loss_fusion=False and cross_entropy_fusion_impl="native", read by dev [dev] misc fixes while bring-up chunk-wise cuda graph #8105's HybridModel.forward.

Details

  • Conflicts: 184 files (120 golden JSON), resolved by hand. CODEOWNERS, copy-pr-bot.yaml, Dockerfile.ci.dev equal dev; megatron/training/training.py from main (sync-guide override). No dev-deleted files restored.
  • Advisory (c5f94462, same as d743194c): 2218 flagged lines; 2088 merge-base lines changed by main; 98 dev-only + 32 repair lines each dispositioned (main commit cited, reformat, or requester-approved). 0 merge accidents, 0 restorations.
  • Remerge-diff: git show --remerge-diff 6ca045f0 (186 files).

Tested

  • Local H100 image agent-sandbox@sha256:12fb4544fa55dfa61f3038cbcfe7338ed1f241f40f5c8f7333bd60ffc91d3e83 (earlier 2cbc1243 passes carried by build-input equivalence).
  • Unit 29/30 passed. ssm on c5f94462: 321 passed, 8 skipped, 0 failed (incl. CP=2 cases). MTP: PR CI on c5f94462 failed only this bucket (run 39255571541); local 8×H100 rerun with cross_entropy_loss_fusion=False: 188 passed, 0 failed; the cross_entropy_fusion_impl line is never read with fusion off (all 9 reads checked). PR CI decides ssm/gated_delta_net/test_gdn_parallel.py.
  • Functional 80/82 passed; PR CI decides common/moe_perf and moe/gpt_dynamic_inference_tp4_pp1_ep4_16B_inference_optimized_swiglu_logitsmatch (dev base fails them locally too).
  • Skips: mimo_hetero_gtp_checkpoint_round_trip (HAVE_GTP=False); mfsdp_v2 symmetric-memory.
  • PR CI: d743194c 186 passed, 8 skipped; 898ccb7d pending.
100 imported main commits (ancestry order)
7e3780f3316b8b0a1c12b3c7585eedc05e908b84
93ebf8d72f1145f9666f739adf7bbc8c426e56dc
9691f47a911ae2b177bb790a9afdfd75c2dce6d2
a1912b3ad58015d0258064542cc36ffe5c33e0d7
e7b92efadb527c4ad01c2eb1a1d64692818f1b8d
e4331713379fe4224cbd0c0efb18e204e03496e9
82894c4d5c30c979b79d5484f26ffe975be82b11
fe1e8f8076da6e0de0fa84f48ba938e994f2a895
4e1df1b62ccb799269b131046362f1f948ad5308
3a560468e5b0a07792b4e24ef6f88a13e7495a81
a1580eb47b6ba1dddbdf17213f9e629ac610249b
93924d59c5e400fe60165fbe8f413cc4c73b167a
54b5e986630030c65d0daecffa18dff26c38002c
cf3b8ee60e7d1044ebfd7f0a7cf1dd57cde446a9
1d82259e1c56ba7ea1e8a2d6d08443827235f94a
893eb057577b637b2115536b107c5abf3ccaa6f0
db018b3b968db31751a51037678049a4b577478e
881f489fd442ccf0ff1972fe0bac297d5e3520f0
f30005143640bf5a00ea0a5ddb4f6ed2b0288158
28797d06ae3ddc2ab5110b9a60b159552edc0c15
a9381be5980c4a76bc5186ac7a80e14dd6baedba
fbbc142b80173aa141a5c877c385e306ee1a39de
606b9f4ea62139f3ce02a94b2d12546f54570f07
7afe031974dad95b4063977e92850f7bf2575851
57f56d43c8215617b4aafb29a402c4fec61926fc
41943e881fd71f0324b6304e2e8c2fbe995caf9a
723db5a72790aefc02f5a0228e6607eef70c0533
787649a6065be9a70e2b1c931283569b7ac9bc32
b3c9100f9f52a9dd6f74c20e41b24d909084c710
df197a816fbfcc0e22bb7072926218c549309f39
5b2a621f9644c6359365b488fa2fa76b756539cd
ab5e2c9de62182b3544f1cd2884a4b146d64803c
bb47df5416a951ae9743b4349aeaeafdf4860058
b4a4c0c4baccf4b506759290c30a0c4f242dcd72
6a7bc998cfd7c6e3d42a7efcd64e29a595d06ba3
faecf6b5033ff39c84c4ca64ba0018e4566784f2
60e03962622a42ceb985fe898718c8d3834d9e30
101966cc03eb1ddd050b66bc262f1db2dcf3a78f
0d970bfb19d4d09e566fd51879de2be8e27220b8
2e12e2cf71e60159f69460ba271ce54420578937
32a03b77c560f5f90115d49b59e4f1809a34726f
24f9a65b967051a1d7c05c2964e4369ef93b59c1
f101c470de586ae096bf4c4ea7b6e63d5ed630f4
3b0995dacf3773748c0b8cc253674cb9f0bc2edd
889c9099226409d689dc31e3975aa8571e276d0c
b7d476030afc8fb631d7358ccd1498591ebb30a2
74235697dd15ef596e36169a7991a7f22029cfce
e22e35a3b1418382cb868c3fe7ac8aaf21054b91
436bae00bba299f6f396704335803504732205fc
cdf3c05911b47883579494e82a05876d1fae8140
46a169647fe2827e776101331c9da39b97c32eb5
5ea9b42374bbfe41a247d357ccee14b7705740f3
3e75961a74dcd8fddc9053a0bf5640d486b5f951
2c8ac9b753e2a5e7b5f2504e9d89e5029c349b13
9fe752ef44a31c004f87e86fbe7e1f9dd3824f97
9cce740faa1bd65fe56f12a34045dc41e656b8cc
09fde85ea25fb67e9b32019089fae163a3233bd3
c50c6caf8dc0910906602d90afa68d04eb2c8330
6227fcd1b4371adbae5935fb89db9fc2bffe35cf
da5a81d491d6af1c18e52995a556e30ef84d4052
dafed1ae6acb2d2f2f65807263a00e9f0eeb2b9f
4dd85559d2d7e0a381fe3c5e260d2ddaf6945af2
d96d76c068191a6d3bb448ab561822120c9527ba
d98e8a64ddf34856e74b24714e3bedb2f5a39553
37485d9e3bc2bd0845358894ba05a057f5823e1c
ea12db0dc62f9ece1fc808abf4b3c39b47ba790f
51ffc290b37625663f6257cfe6bdf4e06c8e4e40
b964d1630ffe32736579677efc3b3327210987d0
aac9b2db7f0d203940f6c0a7f2852a094c18c12e
2dc1b2bb78de065020bd5bc055e045c7bf7773e3
dba084bf7a7d2b43c7317cfefb4be35e1a298941
d06416968b50d8e6607c91ca9c5194c59b2b2cdc
0560fbb6fd174868ca5eefb074af54c7c701bf9e
e358bf8ec9e8207187128ac2aadf7597274bba76
7a5028dce00602b124e23ff3552c6da3db6429b4
e655e0e5c95853ba1383b87eeba71269eff76a32
23cc208ac5c67c6b79bf9e54e2e4f2e58f3afd16
aeaf7c6e663e32c3c124636e3023e605da6dc2ce
377ad24cd05f41686fafe2e6747f47678b8581c8
7020985bf6082d39fa0771803333976f6d463d48
19abd1fc4d3e4334f9a82ee5cbccd4fa871dca6c
ff8c0f87dcb610269d9e645172819093e50139f7
cc99d8e89eb1cc64b27891bf3e276b1ff1eab391
dc931ad2f9ad1a05868718a9e438450c55898b8f
a97b0e20315e03d9a59fc1001311fb2c832febef
4ac689b8bfe55c00f61d7ff0d082cad558632445
5d3107a924ecdbcdae9de68cdfa06e7dfc638a92
92997bacf519da35e4bc68ecf06d9289cb229229
68b28af8c3bf31c9a2587eb2ff615cde4575f33a
35e42f006497b4b6c9c18e5f0b9a2ef03f88cebc
0d698bd2731e1bfba6ebfbafe07f20dba8ffdda4
8ac7abc4edb515334d8756fecf9ced07439c60b9
fac93f1c6c7a532d61f5eb6e37e687dc94442606
4c9d3852e694faf21dd62b75cd1afa6f81dda322
825c30a75884edd1f51685b63701a2cdbb4f882e
d0612089dc6c42bf8c88fa7395bd2bbe5d28a47f
4c4be575a34315e085aec00925a4bf62fb6dbbc0
388d2d181c42dc0845bf766ee42a7abb624f00ba
ad740d8239ca88f170b73e8c116ae95966a7219d
302ed2304135a75c295a86e84be9b526c81f803c

guihong-nv and others added 30 commits August 19, 2026 16:49
Signed-off-by: Ajay Balasa <abalasa@nvidia.com>
…IDIA#5908)

Signed-off-by: ilml <tolong@nvidia.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: wdykas <wdykas@nvidia.com>
Signed-off-by: dimapihtar <dpykhtar@nvidia.com>
Signed-off-by: Dmytro Pykhtar <dpykhtar@nvidia.com>
Signed-off-by: Charlie Truong <chtruong@nvidia.com>
Signed-off-by: Jingyue Wu <jingyuew@nvidia.com>
Signed-off-by: svcnemo-autobot <svcnemo-autobot@nvidia.com>
Signed-off-by: Keshav Santhanam <ksanthanam@nvidia.com>
Signed-off-by: ykarnati <ykarnati@nvidia.com>
Signed-off-by: Ritesh Patel <ripatel@nvidia.com>
Co-authored-by: gautham-kollu <gkollu@nvidia.com>
Signed-off-by: Jiangfei Duan <jiangfeid@nvidia.com>
Signed-off-by: Jingyue Wu <jingyuew@nvidia.com>
Signed-off-by: Kwangjun Ahn <kwangjuna@nvidia.com>
Signed-off-by: dimapihtar <dpykhtar@nvidia.com>
Signed-off-by: Dmytro Pykhtar <dpykhtar@nvidia.com>
Signed-off-by: Philip Petrakian <ppetrakian@nvidia.com>
Signed-off-by: rprenger <rprenger@nvidia.com>
Signed-off-by: Cory Ye <cye@nvidia.com>
Signed-off-by: Ryan Prenger <rprenger@nvidia.com>
Co-authored-by: Cory Ye <cye@nvidia.com>
Signed-off-by: svcnemo-autobot <svcnemo-autobot@nvidia.com>
Signed-off-by: ykarnati <ykarnati@nvidia.com>
…ry point (NVIDIA#6684)

Signed-off-by: ilml <tolong@nvidia.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: wdykas <wdykas@nvidia.com>
Signed-off-by: Anil Thomas <anthomas@nvidia.com>
Co-authored-by: OpenAI Codex <codex@openai.com>
Signed-off-by: YangFei1990 <feiw@nvidia.com>
Signed-off-by: Laura Dang <laurad@nvidia.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Jiangfei Duan <jiangfeid@nvidia.com>
…IDIA#6717)

Signed-off-by: Deepak Narayanan <dnarayanan@nvidia.com>
Signed-off-by: Shiqing Fan <shiqingf@nvidia.com>
Signed-off-by: Deepak Narayanan <dnarayanan@nvidia.com>
Co-authored-by: Shiqing Fan <shiqingf@nvidia.com>
Signed-off-by: Charlie Truong <chtruong@nvidia.com>
Signed-off-by: Charlie Truong <chtruong@nvidia.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 17, 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.

@ko3n1g

ko3n1g commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

/ok to test d743194

@ko3n1g

ko3n1g commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

/review mode=strict

@svcnvidia-nemo-ci svcnvidia-nemo-ci 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.

Strict review — changes required; review incomplete

Findings: CRITICAL: 7, IMPORTANT: 1, SUGGESTION: 0. Overall risk is high. The most impactful finding is an SSRF bypass in remote image fetching. The inspected multimodal paths also contain deterministic construction failures and an image-feature indexing error.

The remaining inspection task cannot be completed within this bounded run and its final continuation. The changeset contains 589 files and a 2.7-MB diff; substantial source, tests, and configuration changes remain uninspected. The required full-file, identifier-use, and cross-component checks are consequently unfinished. The task remains pending rather than being falsely marked complete. This is not clearance of the remaining changes, and no coverage-policy override is claimed. All currently validated findings are included below; review_progress records the outstanding work.

No tests were executed. Acceptance checks below are proposed; suggested code requires author verification.

Suggested structural corrections

Findings 2–3: construct the optional hybrid MoE spec conditionally

In get_hybrid_layer_spec_te, replace the configuration extraction/assertion with:

moe_layer = IdentityOp
if config is not None and config.num_moe_experts is not None:
    moe_layer = ModuleSpec(
        module=MoETransformerLayer,
        submodules=TransformerLayerSubmodules(
            pre_mlp_layernorm=TENorm,
            mlp=get_moe_module_spec(
                use_te=True,
                num_experts=config.num_moe_experts,
                moe_grouped_gemm=config.moe_grouped_gemm,
            ),
            mlp_bda=get_bias_dropout_add,
        ),
    )

Replace the current eager moe_layer=ModuleSpec(...) argument with moe_layer=moe_layer. Leave the Mamba, attention, and dense-MLP specs unchanged. Dense patterns never select the MoE slot; expert patterns receive the configured builder. This also removes the unsupported helper keyword.

Finding 4: validate individual layers within a block spec

In LLaVAModel.init, import TransformerBlockSubmodules from megatron.core.transformer.transformer_block. Replace the assertions inside the non-hybrid branch with:

layer_specs = (
    language_transformer_layer_spec.layer_specs
    if isinstance(language_transformer_layer_spec, TransformerBlockSubmodules)
    else [language_transformer_layer_spec]
)
for layer_spec in layer_specs:
    assert isinstance(layer_spec.submodules, TransformerLayerSubmodules)
    attention = layer_spec.submodules.self_attention
    assert isinstance(attention.submodules, SelfAttentionSubmodules)
    assert (
        attention.submodules.core_attention == TEDotProductAttention and HAVE_TE
    ), "Sequence/Context Parallelism is supported only with TE DotProductAttention."

Pass the original block spec unchanged to GPTModel. This retains the per-layer check and validates every local layer rather than bypassing the TE restriction for blocks.

Finding 5: preserve pipeline coordinates when creating the block spec

Add these arguments to the new get_gpt_decoder_block_spec call:

vp_stage=vp_stage,
pp_rank=pg_collection.pp.rank() if pg_collection is not None else None,

The absent-collection case retains the helper's existing fallback; supplied groups determine the PP rank.

Finding 7: count the features the encoder actually emits

In the dynamic-resolution loop of expand_image_tokens, replace the count calculation with the contract already used by LLaVA's dynamic preprocessing:

num_embeddings = (h // patch_dim) * (w // patch_dim)
if not module._drop_vision_class_token:
    num_embeddings += module._class_token_len
if do_pixel_shuffle:
    num_embeddings //= 4
if module._conv_merging:
    num_embeddings //= 4
per_image_embeddings.append(num_embeddings)

This uses the resolved class-token count, including constructor/configuration overrides. Native merger configuration must also be wired consistently as described in finding 6. Do not unconditionally add CLS tokens or divide every encoder's count by four. Retained-CLS plus pixel shuffle is not a newly supported combination: the current pixel-shuffle implementation expects patch-only inputs.

Finding 8: recognize only the deleted built-in metadata identities

Before the custom-class import in _get_tokenizer_model_class, add narrow compatibility handling:

legacy_text_models = {
    "default_tokenizer": "DefaultTokenizerText",
    "gpt_tokenizer": "GPTTokenizer",
    "bert_tokenizer": "BertTokenizer",
    "mamba_tokenizer": "MambaTokenizer",
    "t5_tokenizer": "T5Tokenizer",
}
legacy_text_identities = {
    (f"megatron.core.tokenizers.text.models.{module}", name)
    for module, name in legacy_text_models.items()
}
identity = (metadata.get("class_path"), metadata.get("class_name"))
if identity in legacy_text_identities:
    from megatron.core.tokenizers.text import MegatronTokenizerText

    return MegatronTokenizerText
if identity == (
    "megatron.core.tokenizers.vision.models.default_tokenizer",
    "DefaultTokenizerVision",
):
    from megatron.core.tokenizers.vision import MegatronTokenizerVision

    return MegatronTokenizerVision

Keep the current import behavior for other explicit class identities and the generic fallback for metadata without a class. The inspected deleted built-ins were thin wrappers around these generic classes.

Note: formal approval is not available for this request, so this review is posted as a comment only.

Review generated by codex

):
raise ValueError(f"Refusing to fetch image from non-public address: {parsed.hostname}")
req = urllib.request.Request(url, headers={"User-Agent": _IMAGE_FETCH_USER_AGENT})
with _no_redirect_opener.open(req, timeout=_IMAGE_FETCH_TIMEOUT_S) as response:

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.

[CRITICAL Correctness] Pin the validated destination through the actual HTTP connection

Failure: The public-address check resolves the hostname with gethostbyname, but urllib subsequently resolves the original URL again. In a proxy-free server, an attacker-controlled hostname can return a public A record for validation and 127.0.0.1 for connection establishment. Posting an image_url such as http://attacker.example:8080/private therefore makes the frontend issue a GET to a loopback service. The chat endpoint invokes this fetch before submitting inference; later image-decoding failure does not undo that request. Mixed A/AAAA answers also escape a check examining only one IPv4 result. Expected: the address actually contacted must satisfy the public-address policy.

Correction: Change _extract_image_url_bytes and its HTTP transport so resolution, validation, and connection use the same approved address. Validate every candidate the transport may select; prevent unchecked re-resolution and proxy routing. Preserve the original hostname for HTTP Host and HTTPS SNI/certificate verification. The exact transport implementation needs verification; rewriting an HTTPS URL to an IP alone is not a complete fix.

Preservation / proposed acceptance: With a mocked resolver returning public first and loopback on a subsequent lookup, assert that no connection or HTTP request reaches loopback. Repeat with a public A/private AAAA combination. Retain rejection of direct private/link-local destinations and 301/302/303/307/308 redirects, the five-second timeout, and the 20-MiB response cap. Public HTTP/HTTPS image URLs and base64 data URLs should still work; HTTPS must still verify the requested hostname. These are static attack-path reasoning and proposed tests, not executed results.

attn_mask_type = AttnMaskType.padding_causal

if config is not None:
assert config.num_moe_experts is not None, (

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.

[CRITICAL Correctness] Keep dense hybrid configs out of the MoE-only branch

Failure: The provider now passes language_config for every Nemotron5 hybrid. A normal dense nemotron5-hybrid-8b configuration has num_moe_experts=None, so this assertion aborts model construction. Previously the helper constructed the Mamba/attention/dense-MLP stack without requiring experts. Passing config=None is not a workaround: the new MoE expression is evaluated eagerly too.

Correction: In get_hybrid_layer_spec_te, construct the MoE spec only when a non-null expert count is supplied; otherwise leave its slot at IdentityOp, the dataclass default. Do not merely delete the assertion and call the MoE helper with None: its backend contract asserts a non-null expert count. The review body supplies a conditional replacement that also uses the current helper signature.

Preservation / proposed acceptance: Build the spec with config=None and with a dense config, for both padding=False and True; both must succeed without invoking the MoE helper. Retain Mamba/attention/dense-MLP specs and causal versus padding-causal masks. Construct a small dense M*- hybrid and verify its layer types and state-dict keys remain unchanged. With eight experts, the MoE slot must instead contain the configured builder and an E layer must construct rather than silently become an identity.

use_te=True,
num_experts=num_experts,
moe_grouped_gemm=moe_grouped_gemm,
moe_use_legacy_grouped_gemm=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.

[CRITICAL Correctness] Call the dev MoE helper with its supported signature

Failure: With a valid MoE config, for example num_moe_experts=8, spec construction reaches this call and raises TypeError: get_moe_module_spec() got an unexpected keyword argument 'moe_use_legacy_grouped_gemm'. The inspected helper accepts only use_te, num_experts, and moe_grouped_gemm. Consequently the new Nemotron6-MoE provider path cannot construct its spec.

Correction: Remove this unsupported keyword from this call, not from unrelated APIs. Keep the returned MlpBuilder in TransformerLayerSubmodules.mlp; that is the current contract. The conditional patch in the review body combines this change with the separate dense-config repair.

Preservation / proposed acceptance: With TE available, call the helper using an eight-expert configuration with grouped GEMM both enabled and disabled. Each call must succeed and select the corresponding experts implementation, then construct a small hybrid containing an E layer with eight configured experts. Dense/None configurations must continue to avoid this MoE-only call, and attention padding-mask selection must remain unchanged. These checks are proposed, not run.

config=language_config, padding=padding
)
elif getattr(args, 'num_experts', None):
language_transformer_layer_spec = get_gpt_decoder_block_spec(

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.

[CRITICAL Correctness] Adapt LLaVA's SP/CP validation to the new block-spec return type

Failure: Selecting num_experts now returns a TransformerBlockSubmodules object. With sequence parallelism or CP greater than one, LLaVAModel immediately reads .submodules from that object, raising AttributeError. The block dataclass has layer_specs and layer_norm, not submodules. GPTModel itself supports this block representation, so rejecting it before construction defeats the new branch.

Correction: Update the non-hybrid SP/CP validator in LLaVAModel.__init__ to inspect each local layer spec for a block input and the single layer for the existing ModuleSpec input. Keep the TE-attention restriction; do not simply skip validation for blocks. Pass the original spec unchanged to GPTModel. The review body contains the normalization/checking patch.

Preservation / proposed acceptance: Under initialized groups and TE, construct a small non-hybrid MoE LLaVA using the returned block spec at TP=2/SP=true and separately CP=2. Construction must not raise this AttributeError. A block whose second layer uses non-TE core attention must still fail the supported-backend check. Retain the per-layer ModuleSpec cases in test_process_embedding_token_parallel, including its padded THD and unpadded SBHD output-shape assertions.

use_transformer_engine=use_te,
normalization=args.normalization,
qk_l2_norm=getattr(args, 'qk_l2_norm', 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.

[CRITICAL Correctness] Forward the virtual pipeline stage when slicing MoE specs

Failure: For a non-hybrid MoE model with PP=2 and VPP=2, model_provider(vp_stage=0, ...) calls the new block builder without that stage. The builder slices local layers using get_transformer_layer_offset, which asserts that vp_stage is provided under VPP. This fails before LLaVA construction, even with SP/CP disabled. The training caller supplies the stage explicitly.

Correction: Add vp_stage=vp_stage and pp_rank=pg_collection.pp.rank() if pg_collection is not None else None to this call, as shown in the review body. The block must be sliced using the same pipeline coordinates as the language model, while absent explicit groups retain the existing fallback.

Preservation / proposed acceptance: Use a four-layer config with PP=2/VPP=2 and a mixed dense/MoE pattern. Build each physical/virtual stage and assert that each gets its intended one-layer spec, collectively covering all four layers exactly once without the assertion. Use a supplied PP collection to ensure selection follows that collection rather than a different global rank. Retain PP=1 and PP=2/no-VPP layer counts and vp_stage=None behavior when VPP is disabled. This is independent of the block-type validation failure above.

from nvlm.internvit import get_internvit300M_layer_spec

vision_transformer_layer_spec = get_internvit300M_layer_spec(use_te=use_te)
elif vision_model_type in ("pixtral-vit", "pixtral-vit-large", "qwen-vl", "kimi-vit"):

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.

[CRITICAL Correctness] Complete construction support for the newly selected native encoders

Failure: The added Pixtral/Qwen/Kimi branches are unreachable through this provider. With dynamic resolution and vision_model_type='qwen-vl', the earlier call to get_vision_model_config raises ValueError: unknown vision model type qwen-vl. Static resolution fails even earlier in get_num_image_embeddings. Even a direct LLaVAModel caller supplying its own native vision config eventually hits the unconditional geometry-helper call, whose implementation rejects all four new names.

Correction: Add native-only architecture resolution to get_vision_model_config, using the corresponding encoder registry entries, and extend the geometry contract used by both provider and LLaVA constructor. Native encoders have no CLS tokens; plain Pixtral emits one token per patch, whereas Pixtral-Large, Qwen, and Kimi emit one per 2×2 patch group. Wire the merger flag consistently for dynamic accounting. Fixing only the config rejection leaves the next constructor failure intact. A complete integration patch requires verification, so no speculative registry-wide rewrite is suggested.

Preservation / proposed acceptance: Parameterize provider construction over the four new names and assert expected architecture fields plus successful lightweight LLaVA construction. For a 4×4 patch grid, assert 16 tokens for plain Pixtral and four for each merged encoder, matching actual output. Preserve CLIP's retained/dropped CLS behavior, SigLIP's no-CLS behavior, existing RADIO configuration/overrides, and existing pixel-shuffle accounting; do not replace those established defaults wholesale with registry defaults.

per_image_embeddings = []
for row in imgs_sizes_cpu:
h, w = row[0], row[1]
num_embeddings = (h // patch_dim) * (w // patch_dim)

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.

[CRITICAL Implementation] Include retained class tokens in dynamic image expansion

Failure: For dynamic RADIO with patch size 16, eight retained CLS tokens, no pixel shuffle, and two images sized 32×32 and 32×64, this code allocates 4+8 image positions. The encoder actually emits 12+16 features: RADIO prepends CLS tokens per image, and LLaVA removes them only when requested. The second image's mask consequently starts at feature four instead of twelve, so it consumes features from the first image. The later maximum-index guard does not detect under-counting. Expected: expansion and per-image offsets must match the post-encoder/post-shuffle feature stream.

Correction: In expand_image_tokens, add the resolved module._class_token_len only when _drop_vision_class_token is false, then apply configured pixel-shuffle and native-merger reductions. The review body gives the replacement consistent with LLaVA's dynamic count contract. Do not blanket-add CLS tokens for no-CLS encoders or blanket-divide unmerged encoders by four.

Preservation / proposed acceptance: For the two-image example, assert counts [12,16], a second-image offset of 12, and that distinguishable per-image feature sentinels land only in their own positions. With CLS dropped, expect [4,8]. For dropped-CLS RADIO with 4×4 and 4×8 patch grids plus pixel shuffle, expect [4,8]; no-CLS native 2×2 mergers should also use [4,8] when configured, while unmerged Pixtral uses [16,32]. Retain the static num_tiles × img_seq_len path. Tests are proposed, not executed.

if metadata.get('tokenizer_class', None):
return getattr(metadata['tokenizer_class_path'], metadata['tokenizer_class_name'])
if metadata.get('class_name', None):
module = importlib.import_module(metadata['class_path'])

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.

[IMPORTANT Compatibility] Resolve metadata referring to the deleted built-in tokenizer classes

Failure: Previously valid metadata such as {'library':'null-text','model_type':'gpt','class_name':'GPTTokenizer','class_path':'megatron.core.tokenizers.text.models.gpt_tokenizer'} loaded successfully with vocab_size=16. The previous metadata writer could emit that class identity. This resolver now imports that identity, but the module was deleted, so loading raises ModuleNotFoundError. The same applies to the other deleted built-in text wrappers and DefaultTokenizerVision. Expected: existing tokenizer metadata remains loadable after this simplification.

Correction: Before importing explicit classes, map only the six deleted built-in identities to MegatronTokenizerText or MegatronTokenizerVision, or restore equivalent compatibility modules. The review body contains a narrow resolver patch. Do not ignore all class metadata: that would break the newly supported custom-class path.

Preservation / proposed acceptance: Load the literal null-text metadata above without tokenizer files and assert tokenize('1 2') == [1,2] and eod == 15. Parameterize the five old text identities, and exercise the old vision identity with the null-multimodal backend. Metadata without explicit class fields and newly written generic metadata must still load. Retain test_own_metadata_class's assertion that the result is an instance of CustomTokenizerClass. These are proposed checks, not run results.

Copy link
Copy Markdown
Collaborator Author

Sync author note on review 5556506430 (head d743194c)

I traced all 8 findings to source. Each flagged path is semantically identical to main at the slice tip 302ed230. Every one came in verbatim with a slice commit, and none was introduced by the merge resolution (6ca045f0) or the repair commit (d743194c):

# Finding Origin on main Evidence
1 SSRF re-resolution in _extract_image_url_bytes 881f489 (#6260) function body byte-identical to main
2 dense hybrid config hits the num_moe_experts assert 881f489 (#6260) examples/multimodal/layer_specs.py == main
3 unsupported moe_use_legacy_grouped_gemm kwarg 881f489 (#6260) main's get_moe_module_spec lacks it too
4 LLaVA SP/CP validator vs TransformerBlockSubmodules 881f489 (#6260) validator region == main
5 get_gpt_decoder_block_spec call missing vp_stage/pp_rank 881f489 (#6260) call site == main (formatting-only diff)
6 native encoders unreachable via get_vision_model_config 881f489 (#6260) config.py, encoder_registry.py == main
7 retained CLS tokens missing in expand_image_tokens 881f489 (#6260) vlm_inference_wrapper.py, radio.py == main
8 metadata naming deleted built-in tokenizer classes e433171 (#6622) megatron_tokenizer.py == main

The same defects therefore exist on main today. I confirmed findings 2, 3, 4, 5 and 8 from source; I did not reproduce 1, 6 or 7. The sync keeps main's content unchanged, so I'm not patching these on dev: a dev-only patch would make dev differ from main and conflict with the next sync. The fixes should land on main and reach dev through a later sync. The review itself says it is incomplete (589 files).

@FDecaYed FDecaYed 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.

One merge-specific issue to address before merging: with CP>1, hybrid KDA, linear_cp_layout=contiguous, and the default cp_partition_mode=zigzag, the new batch path supplies contiguous shards, but the retained chunkwise path converts them as zigzag again, scrambling token order.

For this sync, I suggest rejecting contiguous hybrid CP for the affected GDN/KDA layers until the layout contracts are integrated. Existing dev paths and the new Mamba support can stay unchanged.

Confirmed with a CPU-only source-prefix probe; no full GPU numerical test.

@nemo-autobot-origin
nemo-autobot-origin Bot force-pushed the chore/nightly-sync-2026-10-16 branch from d743194 to c5f9446 Compare October 19, 2026 12:37

Copy link
Copy Markdown
Collaborator Author

@FDecaYed thanks, you're right. When CP>1 and linear_cp_layout="contiguous" (added by main #6776), dev's GDN/KDA layers still take their CP input layout from cp_partition_mode, which defaults to zigzag. They re-partition shards that are already contiguous, which scrambles token order.

The fix is in the repair commit, now c5f94462:

  • HybridStack raises a ValueError when all three hold: CP>1, linear_cp_layout="contiguous", and the layer pattern contains GDN or KDA. The error tells the user to set linear_cp_layout="zigzag". Mamba with contiguous and GDN with zigzag still build.
  • A new test, tests/unit_tests/ssm/test_hybrid_block.py::TestHybridBlock::test_contiguous_linear_cp_layout_with_gdn_kda, covers this at CP=2 with 4 cases.

tests/unit_tests/ssm on 8×H100 at c5f94462: 321 passed, 8 skipped, 0 failed. CI on the new head is pending. Could you take another look?

@ko3n1g

ko3n1g commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

/ok to test c5f9446

@FDecaYed FDecaYed 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.

Thanks, the CP guard looks good, and all four new cases passed in CI. My original CP concern is resolved.

One small CI fix remains: the MTP test failure comes from the merge preview including dev #8105. The new cross-entropy branch reads configuration fields missing from _make_forward_stub() in test_multi_token_prediction.py.

Please add these defaults to the stub config and rerun the MTP tests:

cross_entropy_loss_fusion=False,
cross_entropy_fusion_impl="native",

This is separate from the CP guard; no production-code fallback is needed.

Single repair commit for the 2026-10-16 main->dev sync of the 100-commit
main slice ending at 302ed23 onto dev
dee456a.

Dependencies
- pyproject.toml: add gigatoken to the training and mlm extras, which
  code imported from main requires.
- uv.lock: regenerated with uv 0.7.2 (Dockerfile pin); adds gigatoken
  0.10.0, awkward 2.14.0 and awkward-cpp 57; no removals.

Tests adapted from main's API to dev's API
- transformer/test_multi_token_prediction.py: dev's MTPLossLoggingHelper
  exposes reduced values via reduce_loss_in_tracker()/tracker["values"].
- data/test_get_batch.py: dev's pretrain_hybrid.get_batch reads
  args.linear_cp_layout and args.context_parallel_size.
- inference/contexts/test_dynamic_prefix_caching.py: on dev the engine
  records the Mamba match count before admission; set it like the engine.
- models/mimo/test_mimo_1f1b_schedule.py: pass use_layer_wise_param_layout
  so DistributedDataParallelConfig agrees with the layer-wise optimizer.
- transformer/experimental_attention_variant/test_attention_variant_dsa.py:
  dynamic context parallel on dev requires max_seqlen_per_dp_cp_rank.
- transformer/test_multi_token_prediction.py (main NVIDIA#6119 speculative-decoding
  capture test): dev stores the MTP input on model._decoder_hidden_states_cache,
  not on inference_context.mtp_decoder_hidden_states.

Golden values
- moe/gpt3_moe_mcore_te_ep8_resume_torch_dist_dist_muon dev H100 golden
  refreshed from the exact merge-candidate run: main 0560fbb (NVIDIA#6192)
  makes the LayerWise Muon child grad statistics span the intra
  distributed-optimizer group; reverting only that line reproduces dev's
  previous golden values exactly.

- tests: set max_seqlen_per_dp_cp_rank in dev dynamic-CP/scheduler test configs
  (transformer_layer, transformer_config_dynamic_cp, dsv4_hybrid_attention_cp) to
  satisfy main NVIDIA#5902 validation; dev arguments.py already derives it when a
  sequence-packing scheduler is set.
- tests: transformer/test_thd_cuda_graph.py balanced DSA dynamic-pack case with
  max_seqlen_per_dp_cp_rank=None now expects main NVIDIA#5902's earlier
  ModelParallelConfig validation message.
- tests: extend main NVIDIA#6284 mimo overlap-lifecycle optimizer mock with the dev
  _optimizer_state_offloader/_layer_wise_non_distopt_child attributes (NVIDIA#6244).
- tests: extend main NVIDIA#6119 HybridModel MTP forward stub with dev
  moe_n_hash_layers and pg_collection.dp_cp used by the dev forward.

Megatron-FSDP v2 symmetric memory (requester-approved alignment with main)
- experimental/dbuffer.py, experimental/parameter_group.py: take main's
  version. Symmetric-memory MFSDP raises "requires PyTorch 2.12 or later"
  on PyTorch builds without torch.distributed._symmetric_memory
  .is_symm_mem_tensor, as on main. This drops dev's allocation-flag
  fallback (ef8d090, 4a534df); with it, the symmetric path's losses
  diverged across ranks on dev's PyTorch 2.12 pre-release image and
  test_fully_shard_symmetric_memory_matches_default_and_profiles_nccl[3]
  failed on the merge candidate.
- mfsdp_v2 tests: skip the symmetric-memory cases on such builds
  (test_symmetric_memory.py, the symmetric_memory params of test_overlap.py
  and test_cuda_graph.py, and test_mcore_adapter.py nccl_ub). They run again
  once the image provides is_symm_mem_tensor.

Hybrid context parallelism (review 5570704991)
- models/hybrid/hybrid_block.py: HybridStack rejects
  linear_cp_layout='contiguous' with context parallelism when the segment
  contains GDN ('G') or KDA ('K') layers. main NVIDIA#6776 feeds contiguous
  shards to linear layers, but dev's GDN/KDA chunkwise and headwise paths
  still read their input layout from cp_partition_mode (zigzag by default)
  and would scramble token order. Contiguous Mamba/GDP and the zigzag
  GDN/KDA paths are unchanged.
- ssm/test_hybrid_block.py: cover the GDN/KDA rejection and the zigzag GDN
  and contiguous Mamba builds under CP=2.
- tests: transformer/test_multi_token_prediction.py TestMultiTokenPredictionHybrid
  (main NVIDIA#6119) stub config sets cross_entropy_loss_fusion=False and
  cross_entropy_fusion_impl="native" (the TransformerConfig defaults);
  dev NVIDIA#8105 HybridModel.forward reads them when labels are given
  (review 5573599695).

Signed-off-by: svcnemo-autobot <svcnemo-autobot@nvidia.com>
@nemo-autobot-origin
nemo-autobot-origin Bot force-pushed the chore/nightly-sync-2026-10-16 branch from c5f9446 to 898ccb7 Compare October 19, 2026 15:13
@ko3n1g

ko3n1g commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

/ok to test 898ccb7

Copy link
Copy Markdown
Collaborator Author

@FDecaYed thanks. Both defaults are now in _make_forward_stub() in the single repair commit 898ccb7d: cross_entropy_loss_fusion=False and cross_entropy_fusion_impl="native". There is no production-code change.

I reran tests/unit_tests/transformer/test_multi_token_prediction.py locally on 8×H100 with cross_entropy_loss_fusion=False: 188 passed, 0 failed, including all 4 test_forward_compute_mtp_loss_contract cases. cross_entropy_fusion_impl is only read when fusion is on, so the second line doesn't change that result. CI on 898ccb7d will rerun the MTP bucket after a fresh /ok to test.

@ko3n1g

ko3n1g commented Oct 19, 2026

Copy link
Copy Markdown
Contributor

/ok to test 898ccb7

This branch was previously deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.