Skip to content

[model, peft] feat: GLM-5 DSA option: tilelang (2/2) - #17

Merged
yushengsu-thu merged 2 commits into
bridgefrom
glm5-dsa-2-glm-native
Jul 7, 2026
Merged

[model, peft] feat: GLM-5 DSA option: tilelang (2/2)#17
yushengsu-thu merged 2 commits into
bridgefrom
glm5-dsa-2-glm-native

Conversation

@yushengsu-thu

@yushengsu-thu yushengsu-thu commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Summary

Part 2/2 of splitting #15 (part 1/2 = #16: the megatron unfused backend + GLM-5.x enablement). Stacked on #16 — this branch contains part 1's commit, so the diff shows both until part 1 merges; review the [model, peft] feat: ... tilelang ... (2/2) commit only. The two parts together reproduce the bridge-dev-glm-merging model tree byte-for-byte (verified: git diff vs its head is empty for src/).

This part adds the second DSA sparse-MLA kernel backend: dsa_attention_backend="tilelang" — vendored fused TileLang kernels (SparseMLA + lighting_indexer fwd/bwd under models/glm5/tilelang/) driven by TileLangMLASelfAttention (tilelang/tilelang_mla.py), which replicates slime's absorbed-latent q/kv + apex fuse_rope numerics so the train-side attention output matches the sglang rollout, including R3 indexer replay. Requires the optional tilelang dependency (imported lazily — the default megatron path stays dependency-free) and the thd packed layout (--qkv-format thd). Training/forward-only: asserts inference_context is None (no KV cache); rollout is always served by sglang.

Bug fixes (fused-backend specific)

  • Crashes under TP + sequence-parallel"CuSeqLenKS shape[0] expected 512, got 128": _tilelang_index_qkw / _tilelang_topk omitted the SP/CP token-dim reconciliation native slime performs → added SP all-gather of index_q/index_k/head_weights, CP all-gather of index_k, and CP-scatter of the per-query starts/ends (CP ops are no-ops at CP=1).
  • Fused indexer crashes on short sequencestorch.topk(logits, index_topk=2048) raises "selected index k out of range" when the packed sequence is shorter than index_topk_original_topk (tilelang/indexer.py) caps k at logits.shape[-1] and pads the selection back to the fixed topk width with the -1 sentinel, preserving the shape SparseMLA and R3 replay expect.
  • LoRA-A frozen at TP>1TileLangMLASelfAttention._kv_up_proj_weight_and_norm folded the kv_b_proj LoRA delta using a non-differentiable torch.distributed.all_gather on linear_in (LoRA-A), detaching it from the autograd graph, so LoRA-B trained while LoRA-A never received gradients → use torch.distributed.nn.functional.all_gather (autograd-aware; reduce-scatter backward, correct because the gathered A participates in every TP rank's local delta).

New features

  • Fused backend dispatch: the fused path is dispatched in TileLangMLASelfAttention.forward, which intercepts at the MLA level (the fused kernel consumes the absorbed-latent q/kv, which only exist upstream of core attention); the block-spec builders (glm5_bridge._build_glm5_dsa_block_spec, cross_layer_dsa_dispatch.get_glm5_crosslayer_dsa_spec) point the MLA module at TileLangMLASelfAttention — on the default megatron backend its forward delegates to the base class → byte-identical. CrossLayerDSAttention also reads the flag so GLM-5.1/5.2 forwards share one dispatch point.
  • R3 indexer replay on the fused backend: lighting_indexer routes its top-k through miles' indexer_replay_manager.get_topk_fn when present + enabled, and TileLangMLASelfAttention.__init__ registers the per-layer replay stream (megatron-core's DSAIndexer only self-registers in DeepSeek-V4 mode). No-op unless --use-indexer-replay enabled the manager; import-guarded so the package works without miles.
  • LoRA-capable: the kv_b_proj adapter delta is folded into the absorb weight so its adapters genuinely train. LoRA on the DSA indexer is a genuine no-op here (the fused lighting_indexer returns only discrete top-k, no indexer loss → no gradient); the miles launcher excludes the indexer from LoRA targets by default.

Validation

  • Restructure + both backends verified e2e (colocate LoRA RL, gsm8k, rollout→train→save) on GLM-5.2_5layer fused+unfused and GLM-5.1-6layer fused+unfused.
  • Sequence-parallel fix: GLM-5.2_5layer LoRA e2e at TP=4 + sequence-parallel runs 10 steps clean (rollout → fused fwd → SparseMLA bwd → optimizer → save).
  • Differentiable all-gather: with plain dist.all_gather the kv_up lora_A stays frozen at TP>1 (5-angle verification + CPU micro-test: linear_in.grad None → nonzero with the fix).
  • R3 replay verified e2e (record → mangle stream → replay) on GLM-5.1-6layer and GLM-5.2-7layer, including skip-layer holder reuse: replay overrides the recompute and the kernel consumes exactly the replayed selection.
  • Full GLM-5.2 744B-A40B LoRA RL (fused backend, 64×H200) runs multi-step with healthy on-policy numbers (train↔rollout KL ~1e-4) on the integration branch this splits from.

Notes for reviewers

  • CP>1 is still blocked upstream (megatron-core asserts context_parallel_size==1 for the "dsa" variant); the CP branches here are no-op-at-CP=1 forward-compat mirroring native slime.
  • CrossLayerDSAttention._sparse_attention currently invokes the unfused kernel on both branches (leftover Step-4 TODO; the fused SparseMLA is never called from there — the real fused dispatch is at the MLA level).
  • Supersedes the model-tree half of GLM-5/5.1/5.2 DSA + LoRA enablement (DSA option: megatron-bridge-native and glm-native) #15 together with part 1/2; bridge-dev-glm-merging is kept (not deleted) as the integration branch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HFoyYjC55SRsNRXUzWMWKH

Copilot AI review requested due to automatic review settings July 2, 2026 23:05

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@yushengsu-thu
yushengsu-thu force-pushed the glm5-dsa-2-glm-native branch from 4c86b56 to a73fb7d Compare July 5, 2026 21:53
@yushengsu-thu yushengsu-thu changed the title [model, peft] feat: GLM-5 DSA option: glm-native (2/2) [model, peft] feat: GLM-5 DSA option: tilelang (2/2) Jul 5, 2026
@yushengsu-thu
yushengsu-thu force-pushed the glm5-dsa-2-glm-native branch from a73fb7d to d71fad8 Compare July 6, 2026 21:26
…ption: megatron (1/2)

Restructure models/glm_moe_dsa/ -> models/glm5/ (HF-facing identity
unchanged: model_type=glm_moe_dsa, GlmMoeDsaForCausalLM; deprecated import
shim kept) and enable GLM-5.x DSA training via the portable unfused
megatron-core kernels, selected by the GLM5ModelProvider dataclass field
dsa_attention_backend="megatron" (the default; the fused "tilelang"
backend lands in part 2/2 under models/glm5/tilelang/).

- old-core feature detection: back-fill the "dsa" spec + metainfo on
  megatron-core versions whose dispatcher does not know the variant
- fix DSA-indexer rope-half layout on HF<->Megatron conversion
  (_IndexerRopeHalfSwapMapping, self-inverse on export, with layout guard)
- fix GLM-5.2 MLA rope dims vs transformers>=5.12 mis-parse (re-read
  qk_rope_head_dim / rotary_base straight from config.json)
- GLM-5.2 cross-layer DSA index sharing (CrossLayerDSAttention): anchor
  layers publish top-k, skip layers drop their indexer and reuse it;
  build-time PP-stage assert + forward-time bshd+recompute rejection
- peft: default share_expert_adapters=False -- per-expert is the default
  grouped-expert LoRA layout; shared-outer is opted into solely via the
  experts_shared_outer_loras field

Signed-off-by: Yusheng Su <yushengsu.thu@gmail.com>
…e-MLA backend (2/2)

Add the second DSA kernel backend, dsa_attention_backend="tilelang":
vendored fused TileLang kernels (SparseMLA + lighting_indexer fwd/bwd under
models/glm5/tilelang/) driven by TileLangMLASelfAttention, which replicates
slime's absorbed-latent q/kv + apex fuse_rope numerics so the train-side
attention output matches the sglang rollout, including R3 indexer replay.
Requires the optional tilelang dependency (lazy import; the default
megatron path stays dependency-free) and the thd packed layout;
training/forward-only (asserts inference_context is None).

- SP/CP token-dim reconciliation in _tilelang_index_qkw/_tilelang_topk
  (SP all-gather of index_q/index_k/head_weights; CP ops no-op at CP=1)
- fused indexer: clamp top-k to seq_len for short sequences, pad selection
  back to the fixed topk width with the -1 sentinel
- LoRA: fold the kv_b_proj adapter delta into the absorb weight via
  torch.distributed.nn.functional.all_gather (autograd-aware) so LoRA-A
  receives gradients at TP>1
- dispatch: CrossLayerDSAttention reads the backend field; the block-spec
  builders point the MLA module at TileLangMLASelfAttention (delegates to
  the base class on the default backend -> byte-identical)

Stacked on top of "DSA option: megatron (1/2)"; the two commits together
reproduce the bridge-dev-glm-merging tree exactly.

Signed-off-by: Yusheng Su <yushengsu.thu@gmail.com>
@yushengsu-thu
yushengsu-thu force-pushed the glm5-dsa-2-glm-native branch from d71fad8 to dd9dad3 Compare July 6, 2026 23:20
@yushengsu-thu
yushengsu-thu merged commit b988c81 into bridge Jul 7, 2026
3 checks passed
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.

2 participants