GLM5.3 Flash (KDA + mHC + KPool DSA) support + FP8 - #7054
HollowMan6 wants to merge 6 commits into
Conversation
|
This PR has been automatically converted to draft because all PRs must start as drafts. When you are ready for review, click Ready for Review to begin the review process. This will:
See the contribution guide for more details. |
There was a problem hiding this comment.
🟢 Approval recommended
The logic change is small, follows existing get_fp8_disabled_context usage patterns in related indexer code, and the only feedback is minor comment wording accuracy.
Pull request overview
Adjusts DSA indexer precision behavior under hybrid FP8 training to reduce quantization noise in the top‑k index score path, improving train/inference alignment for sparse-attention selection.
Changes:
- Disable FP8 quantization for
linear_wkandlinear_weights_projduring module construction so their parameters stay in higher precision when FP8 params are enabled. - Disable FP8 quantization for the K-path (
linear_wk,k_norm, RoPE, optional activation rotation) andlinear_weights_projduring forward, while keeping the Q-path (linear_wq_b) quantized.
File summaries
| File | Description |
|---|---|
| megatron/core/transformer/experimental_attention_variant/dsa.py | Split DSA indexer Q vs K/weights-projection execution so index-score-critical ops run with FP8 disabled. |
Review details
Suppressed comments (1)
megatron/core/transformer/experimental_attention_variant/dsa.py:1401
- The updated comments call out “(FP8)” and “run in BF16”, but
get_fp8_disabled_contextonly disables TE quantization and doesn’t force a specific dtype. Rewording to “quantized” vs “FP8/FP4 disabled” avoids implying these paths are always FP8/BF16 regardless of the model’s base precision configuration.
# q linear and apply rope to q (FP8)
# =========================================
# [seqlen, batch, q_lora_rank] -> [seqlen, batch, index_n_heads * index_head_dim]
q, _ = self.linear_wq_b(qr)
# [seqlen, batch, index_n_heads * index_head_dim]
# -> [seqlen, batch, index_n_heads, index_head_dim]
q = q.reshape(seqlen, bsz, self.index_n_heads, self.index_head_dim)
q = self._apply_rope(q, rotary_pos_emb, mscale, cu_seqlens=cu_seqlens_q)
if self.config.dsa_indexer_rotate_activation:
q = rotate_activation(q)
# =========================================
# k linear, k_norm, rotate, and weights_proj run in BF16 (FP8 disabled).
# =========================================
- Files reviewed: 1/1 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Fix DSA indexer FP8 precision split: run `linear_wk` and `linear_weights_proj` in BF16 while keeping `linear_wq_b` in FP8 under hybrid FP8 training. The DSA indexer has three projection linears: `linear_wq_b` (q-projection), `linear_wk` (k-projection), and `linear_weights_proj` (index score projection). Under FP8 hybrid training, all three were quantized to FP8 by default. However, `linear_wk` and `linear_weights_proj` feed the sparse-attention index scores directly — FP8 quantization noise in these projections perturbs the top-k selection and cascades into train/inference divergence. `linear_wq_b` (the q-projection) is a standard GEMM and can safely remain FP8. Signed-off-by: Hollow Man <hollowman@opensuse.org>
Signed-off-by: Hollow Man <hollowman@opensuse.org>
5bef51d to
be805e5
Compare
be805e5 to
095d51c
Compare
Signed-off-by: Hollow Man <hollowman@opensuse.org>
095d51c to
3fceb07
Compare
What does this PR do?
Add the model-side pieces needed to train GLM-5.3-Flash on Megatron Core's
HybridModel, plus the precision controls needed to keep an FP8-trained actor numerically aligned with a vLLM rollout of the released checkpoint:GLM-5.3-Flash at a glance (from its HF
config.json): 45 layers = 34 × KDA (linear_attention) + 11 × DSA (deepseek_sparse_attention) over NoPE MLA (qk_rope_head_dim = 0); mHC with 4 residual streams and 20 Sinkhorn iterations; indexer withindex_kpool = 4,index_kpool_always_select_tail = true,index_topk = 2048; KDAgate_lower_bound = -5.0; 1 MTP depth; 288 routed experts. KDA layers use the newKsymbol in the hybrid layer pattern.Changes
1. KDA in
HybridModel(commitKDA)dev:megatron/core/context_parallel_layout/(zigzag ↔ contiguous CP layout conversion for SBHD and THD; byte-identical todev),resolve_cp_groupinpacked_seq_params.py,nvtx_rangeinutils.py, andKimiDeltaAttentioninssm/gated_delta_net/kda.py(channel-wise gated DeltaNet on FLAchunk_kda, separatebeta_proj, headwise/chunkwise CP, packed THD).dev's KDA:kda_two_stage_gates: GLM-style low-rank gatesf_b(f_a(x))(decay) andg_b(g_a(x))(output) with a QKV-onlyin_proj. The decay gate is precomputed in FP32 with FLAfused_kda_gate(honouringkda_safe_gate/kda_lower_bound), and the output RMSNorm + sigmoid gate run in FLArms_norm_gated, so there is a single BF16 rounding after norm and gating.f_a/g_aare replicated (TELinear,parallel_mode="duplicated");f_b/g_bare column-parallel.A_log/dt_biasare FP32 and marked keep-in-FP32, so they surviveFloat16Module, optimizer construction and checkpointing.kda_disable_fp8: run every KDA projection GEMM with FP8 disabled (see §4).recompute_modules=["gdn"](gdn_norm_outkeeps working).KDALayerConfig, layer symbolK,kda_layerslot inHybridStackSubmodules, layer specs inhybrid_stack_specandhybrid_inference_stack_spec._GDNBase(common.py):in_projsizing for two-stage gates, per-variant gate-parameter dtype, headwise CP size override in_prepare_input_for_gated_delta_rule, chunkwise CP-context cache,is_mtp_layer.HybridModel.forward: the sameoutput_processor/output_processor_contexthook asGPTModel(caller-owned output projection and loss).TransformerConfigfields:kda_two_stage_gates,kda_safe_gate,kda_lower_bound,kda_disable_fp8,gdn_conv_pad_alignment,gdn_pre_gated_delta_rule_fusion(reserved; raisesNotImplementedErrorfor KDA).2. mHC (commit
mHC)mhc_norm_eps_inside_sqrt: compute the mapping norm asrsqrt(mean(x²) + layernorm_epsilon)instead of‖x‖ / √K + 1e-6.mhc_keep_mappings_in_fp32: keeph_pre/h_post/h_resand the residual-stream mixing in FP32 until the final cast to the activation dtype.mhc_learned_output_contract(defaultTrue, the current behaviour): withFalse, the residual streams are contracted by their mean instead of the learnedhc_head_*weights, in both theHybridStackpost-process and the MTP layer (GLM-5.3-Flash has no learned head).HyperConnectionHybridLayersetssupports_hybrid_recompute_kwargs,recompute.pyforwards the matching kwargs (includingpacked_sequence_cp_metadata), and theNotImplementedErrorinTransformerConfig.__post_init__is removed.use_fused_mhcraisesValueErrortogether with either new precision flag (the fused kernels do not implement them).3. KPool DSA indexer + NoPE (commit
KPool DSA)dsa_indexer_kpool > 1: keys are compressedkpooltokens at a time with a per-token compression gate (index_kpool_compress_gate, BF16, same parameter name as the checkpoint) plus a per-slot additive position bias (index_kpool_compress_ape, FP32): per-dimension softmax over the slots, FP32 accumulation, BF16 pooled key. Top-k runs over pools (index_topk // kpool) and is expanded back to token indices (fused_qk_topk_kpool);dsa_indexer_kpool_always_select_tailappends each query's incomplete causal pool so short prefixes stay fully visible. Packed THD restarts pools at document boundaries. The fused cuDNN DSA path is bypassed for KPool, and the head-weight projection stays in FP32.dsa_indexer_kpool_fp8: emulate the serving indexer's FP8 input path (FP32 Hadamard → BF16 → E4M3 with a power-of-two row scale) onqand on the pooled keys, so training top-k matches inference.qk_pos_emb_head_dim == 0is supported byDSAIndexerandAbsorbedMLA(no rotary embedding is built; the absorbed-q path has no positional slice).mla_disable_attention_fp8: runlinear_q_down_proj,linear_q_up_proj,linear_kv_down_projandlinear_projofAbsorbedMLAwith FP8 disabled.4. DSA indexer FP8 precision split (commits
fix: DSA indexer FP8 precision split …andlinear_wq_b also in bf16)linear_wkandlinear_weights_projare built underget_fp8_disabled_context(config, is_init=True)(BF16 parameters, no FP8 scales), and inforward_before_topkthe k path (linear_wk,k_norm, RoPE, activation rotation),linear_weights_projand thelinear_wq_bGEMM all run underget_fp8_disabled_context. Net effect: the whole indexer runs unquantized while the rest of the model keeps FP8.Motivation
With an FP8 actor and a vLLM rollout, every module the rollout computes in BF16 has to be computed in BF16 on the actor as well, otherwise the two diverge. The released FP8 checkpoint keeps the whole DSA indexer (
wq_b,wk,weights_proj,k_norm,index_kpool_compress_*) and every KDA projection (q/k/v_proj,b_proj,f_*/g_*_proj,o_proj) in BF16 (quantization_config.modules_to_not_convert), and vLLM runs the main MLA attention path in BF16. The indexer matters most: it feeds a discrete top-k, so FP8 noise there changes which tokens are attended, and actor/rollout agreement (Pearson) degrades. These options let the actor reproduce the serving precision split while the MoE experts (the bulk of the FLOPs) stay in FP8.Relationship to
devand other PRsdev:megatron/core/context_parallel_layout/*.devwith additions:kda.py, thekda_layerslot inhybrid_block.py, the wrapper handling inrecompute.py,resolve_cp_group,nvtx_range.dev): two-stage KDA gates,kda_disable_fp8, the KPool indexer, NoPE for the indexer / absorbed MLA,mla_disable_attention_fp8, the mHC precision flags, the mean output contract, full recompute with mHC,KDALayerConfig/Ksymbol,HybridModel.output_processor.weights_projprecision controls), Add Kimi Delta Attention (KDA) linear attention variant #5769 (community KDA as an attention variant), Feature Request: Kimi Delta Attention (KDA) #2446 (KDA feature request), GLM-5.2 training support tracking #6392 (GLM-5.2 training support tracking).Known gaps
cp_partition_modeplumbing onTransformerConfig/PackedSeqParamsthat it depends on is not onmainyet, so KDA is validated with CP = 1 here. CP > 1 lands together with thedevsync.NotImplementedError), andgdn_pre_gated_delta_rule_fusionis not implemented for KDA.Run functional testsis the right CI label.Testing
Unit tests added or updated (GPU):
tests/unit_tests/ssm/test_kda_gate_precision.py(new): FP32 gate parameters survive BF16 wrapping, gated-norm numerics, packed-THD output equals per-sequence output, forkda,kda_directandgdn.tests/unit_tests/transformer/test_mhc_precision.py(new): mappings, aggregation and mixing against a pure-torch reference in both precision modes; fused mHC rejects the new flags.tests/unit_tests/models/test_hybrid_mhc.py: full recompute (uniform / block × fp32 / bf16 + FP32 mixing / bf16 fused) matches forward and backward without recompute; a wrapped residual layer does not double-count its input.tests/unit_tests/transformer/experimental_attention_variant/test_kpool_causal_tail.py(new): every query keeps its full causal prefix under the pool budget (packed / unpacked, strided queries, FP8 on / off); the FP8 input emulation matches a Hadamard-matrix reference.tests/unit_tests/transformer/experimental_attention_variant/test_attention_variant_dsa.py: KPool projection dtypes and backward.tests/unit_tests/transformer/test_hyper_connection_recompute.py: drop the obsolete "mHC + full recompute is rejected" case.pytest tests/unit_tests/ssm/test_kda_gate_precision.py \ tests/unit_tests/transformer/test_mhc_precision.py \ tests/unit_tests/models/test_hybrid_mhc.py \ tests/unit_tests/transformer/experimental_attention_variant/test_kpool_causal_tail.py \ tests/unit_tests/transformer/experimental_attention_variant/test_attention_variant_dsa.pyIssue tracking
For PRs from open-source community contributors:
Linked issue: Related to #2446, #6392
Contribution process
Pre-checks
Code review
Feel free to message or comment @NVIDIA/mcore-oncall to help accelerate your merge into main. The less complex your PR is, the faster it will be approved and merged!
All PRs start as draft. If you open a non-draft PR, it will be automatically converted to draft.
Step 1: Mark PR as "Ready for Review"
.github/CODEOWNERS.Final Review might get declined if these requirements are not fulfilled.
Step 2: Final Review
For PRs that change
megatron/core, once all expert reviewers have approved, theFinal Reviewlabel is applied automatically and final reviewers are assigned.For PRs outside
megatron/core, this step is skipped.Step 3: Approved
Once all required reviewers have approved, the
Approvedlabel is applied automatically.Merge
Any member of mcore-engineers will be able to merge your PR.