Skip to content

fix(modelopt): expand exclusions nested under model.language_model.* - #38781

Closed
divyvasal wants to merge 1 commit into
sgl-project:mainfrom
divyvasal:fix/modelopt-exclude-interior-language-model
Closed

divyvasal wants to merge 1 commit into
sgl-project:mainfrom
divyvasal:fix/modelopt-exclude-interior-language-model

Conversation

@divyvasal

@divyvasal divyvasal commented Sep 10, 2026

Copy link
Copy Markdown

Motivation

Follow-up to #36596. #36761 fixes the fused-module and model.-prefixed vision-tower halves; this fixes the third naming form, which neither the shipped matcher nor that PR handles: exclusions nested under model.language_model.*.

apply_weight_name_mapper strips language_model. only when it is the leading segment. ModelOpt writes some vision-language checkpoints with the decoder nested one level in — model.language_model.layers.N.* — while sglang builds it as model.layers.N.*. The strip never fires, every layer the checkpoint keeps in BF16 is built as an FP4 module, and the load dies on a packed-versus-unpacked shape mismatch.

Hit on nvidia/GLM-5.3-Flash-NVFP4 (the official NVIDIA checkpoint; #36596 was filed against LibertAIDAI's, which is spelled differently) at TP8 on 8xB200, FlashInfer 0.6.17:

AssertionError: target.shape=torch.Size([4096, 256]),
                loaded_weight.shape=torch.Size([4096, 512])

the FP4-packed parameter against the BF16 tensor the checkpoint actually ships.

Its exclusion list uses this form throughout — model.language_model.layers.N.self_attn*, ...mlp.gate, ...mlp.shared_experts* — so on this checkpoint the two PRs are both required and neither is sufficient. Measured against that exclusion list with the matcher's shipped behaviour, #36761's logic, and this change:

built prefix shipped #36761 this PR
visual.blocks.10.attn.proj miss fixed miss
model.layers.0.self_attn.kv_b_proj miss miss fixed
model.layers.10.mlp.gate miss miss fixed
model.layers.10.mlp.shared_experts.gate_up_proj miss miss fixed

Modifications

python/sglang/srt/layers/quantization/modelopt_quant.py: in apply_weight_name_mapper, expand model.language_model.<rest> to model.<rest> alongside the existing leading-segment strip. Same place, same shape, and the expansion is exact rather than a wildcard, so it cannot widen a match.

Accuracy

No numerical change. This only affects which modules are built quantized; it restores the checkpoint's own intent, which is that these layers stay BF16.

Checklist

  • Unit tests in test/registered/unit/layers/quantization/test_modelopt_nvfp4.py: the interior form matches, the checkpoint's own spelling still matches, a neighbouring layer index does not match, the leading strip is unchanged, and names without the segment are left untouched.
  • Verified against the unmodified hf_quant_config.json from nvidia/GLM-5.3-Flash-NVFP4, in the sglang image, on 8xB200.
  • With this and fix(modelopt): expand is_layer_excluded for fused and model.-prefixed names #36761 applied, the checkpoint loads and serves.

CI States

Latest PR Test (Base): ❌ Run #34433045876
Latest PR Test (Extra): ❌ Run #34433045790
Latest PR Test (AMD ROCm 10): ❌ Run #34433045968

ModelOpt writes some vision-language checkpoints with the decoder nested under
`model.language_model.*` while sglang builds it as `model.*`. The strip in
`apply_weight_name_mapper` only fires for a *leading* `language_model.`, so an
interior one never matches: every layer the checkpoint keeps in BF16 is built as
an FP4 module and the load dies on a shape mismatch.

Seen on nvidia/GLM-5.3-Flash-NVFP4, whose exclusion list is written as
`model.language_model.layers.N.self_attn*`, `...mlp.gate` and
`...mlp.shared_experts*`. With TP8 on 8xB200 the first mismatch is:

    AssertionError: target.shape=torch.Size([4096, 256]),
                    loaded_weight.shape=torch.Size([4096, 512])

the FP4-packed parameter against the BF16 tensor the checkpoint actually ships.

Expand the interior form alongside the existing leading-strip, at the same point
and in the same shape. Names without the segment are untouched, and the
expansion is exact rather than a wildcard, so it cannot widen a match: layer 10's
gate stays excluded while layer 11's is not.

This is the decoder half of sgl-project#36596. sgl-project#36761 covers the fused-module and
`model.`-prefixed vision-tower halves on the prefix side; the two are orthogonal
and touch different functions. On this checkpoint neither alone is sufficient:
sgl-project#36761 fixes `visual.*`, this fixes `model.layers.*`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@divyvasal
divyvasal force-pushed the fix/modelopt-exclude-interior-language-model branch from fc01082 to 9da1cd5 Compare September 10, 2026 03:21
@divyvasal

Copy link
Copy Markdown
Author

Closing as redundant — superseded by #38621, which merged on 2026-09-09 and which I missed when I opened this.

#38621 handles the same model.language_model.* case, and the vision-tower rename from #36596 as well, in a better place: a model-scoped WeightsMapper on Glm5NextForConditionalGeneration rather than a special case in the generic matcher.

hf_to_sglang_mapper = WeightsMapper(orig_to_new_substr={
    "model.language_model.": "model.", "model.visual": "visual"})

Confirmed on our side: with #38621 applied to the 2026-09-03 lmsysorg/sglang:glm-5.3-flash image, nvidia/GLM-5.3-Flash-NVFP4 loads and serves on 8×B300 with an unmodified hf_quant_config.json (132 exclusion entries, no hand-patching), and --moe-runner-backend flashinfer_cutlass works — both of which previously failed for us.

Thanks to the author of #38621. Sorry for the duplicate noise.

@divyvasal divyvasal closed this Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blackwell SM100/SM120 quant LLM Quantization

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant