[megatron] GLM-5.3-Flash (glm5_next) support: KDA + NoPE-MLA/DSA + mHC hybrid MoE, 4-layer GPU CI entry - #2179
[megatron] GLM-5.3-Flash (glm5_next) support: KDA + NoPE-MLA/DSA + mHC hybrid MoE, 4-layer GPU CI entry#2179erictang000 wants to merge 4 commits into
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for the GLM-5.3-Flash (glm5_next) model in the Megatron backend, implementing custom Megatron-Core extensions such as Kimi Delta Attention (KDA), Manifold-Constrained Hyper-Connections (mHC), and a custom transformer layer that supports MoE. It also updates dependencies (including vLLM and FlashInfer) and includes compatibility fixes for vLLM >= 0.28.1. The review identified two critical runtime issues: an AttributeError in the DSA attention module due to an incorrect attribute name (self.index_topk instead of self.dsa_indexer_topk), and a TypeError in the mHC transformer layer caused by passing an unsupported padding_mask argument to the MLP forward call.
| if max_seqlen > self.index_topk: | ||
| raise NotImplementedError( | ||
| f"GLM-5.3-Flash sparse attention with sequences longer than dsa_indexer_topk=" | ||
| f"{self.index_topk} tokens (got {max_seqlen}) needs the k-pool indexer, which the " |
There was a problem hiding this comment.
The attribute self.index_topk does not exist on DSAttention or Glm5NextDSAttention. The correct attribute name in megatron-core is self.dsa_indexer_topk (or self.config.dsa_indexer_topk). Accessing self.index_topk will raise an AttributeError at runtime.
| if max_seqlen > self.index_topk: | |
| raise NotImplementedError( | |
| f"GLM-5.3-Flash sparse attention with sequences longer than dsa_indexer_topk=" | |
| f"{self.index_topk} tokens (got {max_seqlen}) needs the k-pool indexer, which the " | |
| if max_seqlen > self.dsa_indexer_topk: | |
| raise NotImplementedError( | |
| f"GLM-5.3-Flash sparse attention with sequences longer than dsa_indexer_topk=" | |
| f"{self.dsa_indexer_topk} tokens (got {max_seqlen}) needs the k-pool indexer, which the " |
| pre_mlp_layernorm_output, moe_padding_mask, moe_unflatten_mbs = self._maybe_unflatten_for_moe( | ||
| pre_mlp_layernorm_output, padding_mask, packed_seq_params | ||
| ) | ||
| mlp_output_with_bias = self.mlp(pre_mlp_layernorm_output, padding_mask=moe_padding_mask) |
There was a problem hiding this comment.
Standard Megatron-Core MLP and MoE layers (such as GroupedMLP or TEGroupedMLP) do not accept padding_mask in their forward method. Passing padding_mask=moe_padding_mask will raise a TypeError at runtime. You should remove this keyword argument.
| mlp_output_with_bias = self.mlp(pre_mlp_layernorm_output, padding_mask=moe_padding_mask) | |
| mlp_output_with_bias = self.mlp(pre_mlp_layernorm_output) |
The DeepGEMM platform coverage must be fixed or the unsupported environments explicitly rejected before merging because GLM-5.3-Flash cannot initialize there. Findings
|
| "vllm==0.28.0; sys_platform == 'linux'", | ||
| "vllm; sys_platform == 'linux'", | ||
| "vllm-router; sys_platform == 'linux'", | ||
| "deep-gemm; sys_platform == 'linux' and platform_machine == 'x86_64' and python_full_version >= '3.12' and python_full_version < '3.13'", |
There was a problem hiding this comment.
When the Megatron extra is installed on Linux aarch64 or x86_64 Python 3.13, the environment marker excludes the Torch 2.11-compatible deep-gemm package, so vLLM falls back to its Torch 2.13-linked extension and GLM-5.3-Flash inference fails to initialize its required DSA indexer.
Brings in the torch 2.13 upgrade (NovaSky-AI#2175), which replaces the `+cu.13.0.torch.2.11` local-version pins with plain versions from NovaSky-AI/skyrl-wheels and raises requires-python to 3.12. Conflicts were pyproject.toml (5 hunks) and uv.lock. Resolution takes main's torch 2.13 and CUDA-extension pins throughout, and keeps this branch's flashinfer 0.6.18 (required by the pinned vLLM) and the unpinned `vllm` driven by the per-commit dev-wheel source. Drops the `deep-gemm` dependency and its hosted wheel. It existed only because the wheel we could build topped out at torch 2.11 while vLLM's vendored `vllm.third_party.deep_gemm._C` is built against torch 2.13, so the vendored copy failed to import and vLLM prefers an installed `deep_gemm` when one exists. On torch 2.13 the vendored extension loads, so keeping a torch-2.11 build would have been actively harmful: vLLM would prefer it and then fail to import it, taking out the GLM-5.3-Flash DSA indexer that hard-requires DeepGEMM. Verified on the merged tree: `vllm.third_party.deep_gemm._C` imports, `vllm.utils.deep_gemm.has_deep_gemm()` is True, and no standalone `deep_gemm` is installed. `dsa_index_share_recompute.patch` is unchanged here: this branch still pins megatron-core 14346b65a, which the existing patch matches. (It needs refreshing only alongside the megatron-core bump to b3393bbb -- see NovaSky-AI#2180.) `patch_fa4_cute_import` is still required under torch 2.13: the cutlass DSL the pinned vLLM pulls in still breaks `flash_attn.cute`, and the guard still reports marking it unavailable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brings in the megatron bump (NovaSky-AI#2180): megatron-core 14346b65a -> b3393bbb and megatron-bridge 2b8cb21d -> 8e5f0e1, plus the refreshed DSA index-share patch and the removal of the expert-bias padding-mask shim. pyproject.toml conflict resolved to main's megatron-core rev, keeping this branch's flashinfer 0.6.18 and the per-commit vLLM dev-wheel source; uv.lock regenerated from main's so the only additions are flashinfer 0.6.18, the vLLM wheel and instanttensor. The new megatron-core ships mHC natively, which requires the adaptations this branch was carrying on top of the old rev: - `mcore_ext/hyper_connection.py`: the 688-line backport of Megatron-LM main's `HyperConnectionModule` is deleted in favour of `RMSNormInputHyperConnectionModule` (49 lines), which only overrides the input normalization to GLM's standard RMSNorm (`rsqrt(mean(x^2) + eps)`) instead of megatron-core's `1 / (rms(x) + 1e-6)`. - `mcore_ext/mhc_transformer_layer.py`: `TransformerBlock` now expands/contracts the mHC residual streams itself when `enable_mhc_connections` is set, so the layer no longer does it at the first/last layer -- otherwise the streams are expanded twice and the mHC mapping sees `[s, n*n*C]`. The layer keeps the per-sub-layer residual update and gains a guard rejecting `'mhc'` in `recompute_modules`, whose managers it does not thread. - `MegatronWorker.init_configs`: megatron-core rejects mHC under `recompute_granularity="full"`, which is what SkyRL's default `gradient_checkpointing=True` resolves to, and its suggested alternative needs the managers above. Downgrades to selective recompute of the remaining modules with a log line. Validated on the merged tree: `test_glm5_next_modules.py` 2 passed with per-module errors unchanged from before the bump (mHC exact to 4e-9, KDA 0.5% of the reference mean), and Megatron-vs-HF TP1 logit parity on GLM-5.3-Flash-4layer stays at the bf16 noise floor (KL(HF||Meg) 0.0086, argmax agree 92.7%, mean |dlogprob| 0.060). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ngle B300 node The existing GLM-5.3-Flash coverage runs the 4-layer slice, which exercises every code path but is not a coherent LM. This adds the real 45-layer `zai-org/GLM-5.3-Flash` checkpoint as a `test_megatron_models` row so the same logprob-parity and weight-sync check can be run against real weights, where generation should also read as sensible text. ~313B params in bf16 (~627 GiB, 97% of it routed experts) with ~17B activated, so it needs a whole 8xB300 node and cannot run in CI. It carries a new `b300` marker, gated exactly like `h100`: auto-skipped unless `-m b300` is passed, so `-m megatron_models` and `-m h100` both leave it alone. The gating loop in the GPU conftest now covers both markers instead of hard-coding h100. Mesh: Megatron TP2 EP8 ETP1 -> DP4 (EP x ETP == TP x DP), vLLM TP8 colocated on the same 8 GPUs. EP is the scaling dimension for a MoE this sparse -- 36 experts/GPU, ~76 GiB -- while TP only covers the ~9B of non-expert weights. PP stays at 1 because megatron-core rejects mHC with pipeline_model_parallel_size > 1, and CP at 1 because KDA has no context-parallel path. Everything else is picked up by the existing `glm-5.3-flash` branches: `language_model_only`, packed sequences, `inference_only_init`, `max_num_seqs=512` (the vLLM KDA triton grid limit) and the 4096-token / 0.5-utilization engine overrides. Also pins fla to its Triton kernels for GLM-5.3-Flash on Blackwell (`FLA_TILELANG=0`), the same workaround the Qwen3.5 rows use for GDN -- KDA runs fla kernels too. Scoped to Blackwell so the H100 rows keep fla's default backend. The real config needs nothing the bridge rejects: all 45 `indexer_types` are `"full"`, so the unsupported cross-layer DSA index sharing never comes up. Thresholds mirror the other large-MoE rows and have not been measured on this checkpoint; expect to tune them on the first run. Not run here -- this box has no B300s. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Signed-off-by: Eric Tang <erictang000@gmail.com>
What
Adds GLM-5.3-Flash (HF
glm5_next,Glm5NextForConditionalGeneration) to the Megatron backend and atest_megatron_modelsH100 CI entry on the 4-layer sliceeatang/GLM-5.3-Flash-4layer(mirror ofCharyZeng/GLM-5.3-Flash-4layer; real truncated weights, so the logprob distribution stays peaked and the vLLM/Megatron comparison is meaningful even though the slice is not a coherent LM).The architecture is unknown to both pinned upstreams: 45 layers of 3:1 KDA linear-attention / NoPE-MLA DeepSeek-sparse-attention (kpool indexer), 288-expert sigmoid MoE with one shared expert (dense MLP in the first layer), clamped SwiGLU, and Manifold-Constrained Hyper-Connections (mHC) on every block, shipped as a VL checkpoint.
Written from the HF modeling code against upstream Megatron-LM / Megatron-Bridge APIs, reusing what upstream already ships: megatron-core's
DSAttention+AbsorbedMLASelfAttention(the NoPE case,qk_pos_emb_head_dim=0, works as is),TEGroupedMLPwithactivation_func_clamp_valuefor the clamped SwiGLU, and — since #2180 bumped megatron-core tob3393bbb— megatron-core's ownHyperConnectionModuleandTransformerBlockmHC stream handling.Components
Model-specific code lives in two packages, split by where it should eventually land upstream.
workers/megatron/mcore_ext/→ Megatron-LM (megatron.core)hyper_connection.py(49)RMSNormInputHyperConnectionModule: megatron-core'sHyperConnectionModulewith the input normalization overridden to GLM's standard RMSNorm,x * rsqrt(mean(x^2) + rms_norm_eps), instead of upstream'sx / (rms(x) + 1e-6).TransformerConfigcarries the input-norm knobs (mhc_norm_eps/mhc_norm_eps_inside_sqrt).mhc_transformer_layer.py(199)HyperConnectionTransformerLayerwith MoE MLP support — megatron-core's own mHC layer raisesNotImplementedErrorfor MoE sub-layers (mHC + MoE is only reachable there by wrapping MoE as aHybridStacklayer), which GLM-5.3-Flash needs on all but the first layer.TransformerBlockowns the block-boundary stream expand/contract; this layer implements only the per-sub-layer residual update. Rejects'mhc'inrecompute_modules, whose managers it does not thread.kda.py(327)KimiDeltaAttention: KDA linear attention (Kimi Linear / GLM-5.3-Flash) from TE column/row/duplicated linears, three depthwise causal convs, fp32A_log/dt_bias, flachunk_kdawith the in-kernel safe gate (lower_bound * sigmoid(exp(A_log) * (f + dt_bias))) and flaFusedRMSNormGatedoutput gate. TP shards heads (conv/A_log/dt_biasalong heads; low-rankf_a/g_aduplicated; replicatedo_normgrads summed across TP); packed thd viacu_seqlens;sharded_state_dictlike GDN. Reuses the GDN config fields pluskda_gate_lower_bound. No CP, no inference cache.experimental_attention_variant="kda"candidate next togdn/gdn2.workers/megatron/glm5_next/→ Megatron-Bridge (models/glm/)provider.py(55)Glm5NextModelProvider(MLAModelProvider): mHC fields named after megatron-core'sTransformerConfig, pluskda_gate_lower_bound,mhc_norm_eps*anddsa_indexer_kpool*. The attention pattern uses the genericlinear_attention_freqlist (1 = KDA, 0 = DSA).layer_specs.py(113)build_glm5_next_layer_spec: per-layer KDA-or-DSA × dense-or-MoEHyperConnectionTransformerLayerspecs, built from the publicget_dsa_module_spec_for_backend/get_moe_module_spec_for_backend/get_mlp_module_spec_for_backendhelpers.dsa.py(49)Glm5NextDSAttention(DSAttention): the k-pool indexer selects every visible token whenever a sequence has at mostindex_topktokens, so megatron-core's token-level indexer withdsa_indexer_topk=index_topkis exact in that regime and is reused; longer sequences raise instead of silently attending to a different subset.bridge.py(318)Glm5NextBridgeregistered forGlm5NextForConditionalGeneration→GPTModel,model_type="glm5_next": config mapping offtext_config(skipping thehead_dim=0RoPE width) and 1:1 parameter mappings undermodel.language_model.*— KDA (separateq/k/v_conv1d,A_log,dt_bias), mHC (hc_*_fn/hc_*_basereplicated,hc_*_scale[3]↔ threealpha_*scalars via a small custom mapping, the shape Megatron-Bridge's DeepSeek-V4 bridge already uses). All 3050 language-model tensors map; no dropped conversion tasks. The vision tower is not bridged (language_model_only=Truerequired).SkyRL glue
patches/megatron/patch_fa4_cute_import.py+workers/megatron/__init__.py: flash-attn 2.8.x's FA4flash_attn.cuteraisesAttributeErroragainst the cutlass DSL the pinned vLLM pulls in, which megatron-core'sexcept (ImportError, PackageNotFoundError)probe does not catch, soimport megatron.coreaborts. The guard marksflash_attn.cuteunavailable only when it is actually broken. Still required on torch 2.13. Delete once megatron-core's probe catchesExceptionor the pins agree.MegatronWorker.init_configs: megatron-core rejects mHC underrecompute_granularity="full", which is what SkyRL's defaultgradient_checkpointing=Trueresolves to. Its suggested alternative (selective recompute with'mhc'inrecompute_modules) needs the mHC recompute managers the layer above does not thread, so this downgrades to selective recompute of the remaining modules with a log line.model_bridges.py: imports the bridge to register it.test_megatron_models.py:glm-5.3-flash-4layer_h100_tp2_ep4(Megatron TP2 EP4 ETP1 → DP2, vLLM TP4 colocated,language_model_only, packed sequences,inference_only_init,max_num_seqs=512).test_glm5_next_modules.py(new, single GPU):RMSNormInputHyperConnectionModulevs HFGlm5NextTextHyperConnectionat the model's activation scale, andKimiDeltaAttentionon packed sequences vs per-sequence HFGlm5NextTextLinearAttention.supported_models.mdx,.claude/docs/backends/megatron.md.Dependencies
0.28.1rc1.dev359+g98ed0856f([Model] add GLM-5.3-Flash support vllm-project/vllm#53906, the GLM-5.3-Flash model). Built for CUDA 13 / torch 2.13, matching the torch pinned on main after [chore] Upgrade to torch 2.13 #2175, so its vendoredvllm.third_party.deep_gemmextension loads and the DSA indexer (which hard-requires DeepGEMM) works with no separately installeddeep_gemm. Verified on this branch:vllm.third_party.deep_gemm._Cimports,vllm.utils.deep_gemm.has_deep_gemm()is True, no standalonedeep_gemmpresent.vLLM 0.28.1 fallout handled:
vllm.entrypoints.openai.cli_argsmoved tovllm.entrypoints.launchers.cli_args(imported with a fallback);/inference/v1/generate, which SkyRL's generation client calls, is now gated behindVLLM_ENABLE_SCALE_OUT_ENDPOINTS=1(set beforebuild_app); vLLM registers a nativesharded_rdtweight-transfer engine, so the SkyRL shim no-ops and its unit test accepts either engine.Validation
Megatron vs HF
transformers5.16.1 (sdpa, bf16) logits on the 4-layer slice, 82-token GSM8K prompt+answer, packed thd input (standalone torchrun parity script).On this branch (torch 2.13, megatron-core
b3393bbb), HF reference recomputed on the same toolchain:For scale, #2156 measured HF-bf16 vs HF-fp32 on this same slice at 0.0071 KL / 95.7% argmax, so this sits at the bf16 noise floor. The slice predicts near-randomly (HF logprob per target token ≈ −14.15), which makes argmax agreement the noisiest of the three statistics — most positions are near-ties that flip on tiny numeric differences while KL barely moves.
test_glm5_next_modules.pyon the same tree: 2 passed — mHC exact to 4e-9 against the HF module, KDA within 0.5% of the reference mean on packed sequences.test_logprobs_matching_roundtrip[glm-5.3-flash-4layer_h100_tp2_ep4]on Anyscale 4×H100:and again in the H100 CI suite alongside the other model entries (
logprob diff mean: 0.063314,vLLM logprob diff mean: 0.250699). Both of those runs predate the merge with main — they were on torch 2.11 with the megatron bump applied. The suites need re-running on this branch's tree; earlier TP2/EP2 parity (KL 0.0066, argmax 98.8%) is from that same pre-merge toolchain.Known issue
test_logprobs_matching_roundtrip[qwen3.5-0.8b-dense_tp2]OOMs on 22 GiB L4 in the megatron_models suite: vLLM reserves 19.83 GiB for KV cache at the defaultgpu_memory_utilization=0.9, then flashinfer 0.6.18'stop_k_top_p_sampling_from_logitsneeds a ~970 MiB vocab-wide softmax during sampler warm-up. Introduced by the flashinfer bump here — that entry has no gmu override and passes on main's 0.6.16.post3. Needs either a gmu override for small cards orVLLM_USE_FLASHINFER_SAMPLER=0; not reproducible on H100 (80 GiB hides it).Limitations / follow-ups
index_topk(2048) tokens; longer sequences raise (glm5_next/dsa.py). Needs aDSAttentionhook letting an indexer own the top-k selection (pool scoring → expand to tokens → append the query's tail pool).indexer_typescontaining"shared"; the 4-layer slice is all"full") raises: megatron-core'sdsa_indexer_topk_freq/skip_topk_offsetarithmetic runs over all layers and would pick KDA layers as sources in this hybrid.layernorm/mlp/mhcrecompute.A_log/dt_bias/mHC params) but this PR exercises forward + weight sync only.Upstreaming plan
Megatron-LM (megatron-core)
HyperConnectionModule: addmhc_norm_eps/mhc_norm_eps_inside_sqrtfor a standard-RMSNorm input norm, with the fused-kernel path extended or guarded. Retiresmcore_ext/hyper_connection.py.HyperConnectionTransformerLayer: allow MoE MLP sub-layers (currentlyNotImplementedError). Retiresmcore_ext/mhc_transformer_layer.py.KimiDeltaAttentionasexperimental_attention_variant="kda"(module + spec next togated_delta_net,kda_gate_lower_boundinTransformerConfig). Retiresmcore_ext/kda.py.Megatron-Bridge
models/glm/glm5_next_{provider,spec,bridge}.py= this PR'sglm5_next/package, once (1)–(3) exist upstream — the bridge only needs its layer/provider imports repointed._HCAlphaMappingpattern (hereHyperConnectionScaleMapping) intoparam_mapping.pyso both bridges share it.Once megatron-core carries (1)–(3),
mcore_ext/is deleted andglm5_next/imports frommegatron.core; once Megatron-Bridge carries the bridge,glm5_next/goes too andmodel_bridges.pyloses one import.🤖 Generated with Claude Code