nemo_automodel.components.speculative.dspark.draft_glm_5_2
nemo_automodel.components.speculative.dspark.draft_glm_5_2
DSpark speculative-decoding draft model with a GLM-5.2 attention backbone.
This mirrors the DeepSeek V4 DSpark draft (draft_deepseek_v4.py) structurally;
only the attention internals and rotary plumbing are swapped for GLM-5.2’s
Multi-head Latent Attention (MLA). The draft runs dense, non-causal attention over
a [context | noise-block] layout, with visibility supplied entirely by the
DFlash additive attention mask.
The GLM MLA is the classic DeepSeek-V3 layout (q_a_proj/q_a_layernorm/
q_b_proj, a compressed kv_a_proj_with_mqa/kv_a_layernorm/kv_b_proj
latent, a separate o_proj, and interleaved complex freqs_cis RoPE over the
qk_rope_head_dim slice), NOT V4’s single shared K=V latent + grouped O-LoRA +
per-head sink. There is no DSA indexer / sparse-attention path here: the draft is
always dense, and GLM’s sparse top-k machinery belongs to the target model, not
this draft.
Module Contents
Classes
Functions
Data
API
Bases: Module
Dense, non-causal GLM MLA over a [context | noise-block] layout.
Reuses GLM-5.2’s DeepSeek-V3-style MLA projections (Q-LoRA, a compressed KV latent,
a separate value up-projection, interleaved complex RoPE on the qk_rope_head_dim
slice) but drops the DSA indexer (the draft is always dense). Queries come from the
noise block only, while the compressed KV latent spans context plus noise. Visibility
is set entirely by the DFlash additive attention_mask (no causal flag, no indexer).
Bases: Module
Pre-norm residual block: GLM DSpark MLA followed by a dense SwiGLU MLP.
Bases: Module
Dense SwiGLU MLP for the DSpark draft.
This intentionally avoids GLM’s MoE and shared-expert paths; the draft keeps a
single dense feed-forward block sized to moe_intermediate_size (the per-expert
width), so the drafter stays lightweight relative to the 256-expert target.
Bases: Module
DSpark draft model with a GLM-5.2 attention backbone (dense, non-causal).
Keep the rotary freqs buffer in fp32 across dtype casts.
model.to(bfloat16) (the training build path) would otherwise round the RoPE
freqs table to bf16 and dephase RoPE with absolute position, eroding draft
acceptance (the mismatch grows with position, and a bf16 round-trip cannot be
undone by upcasting). Snapshot the fp32 frequencies before the cast and restore
them after (the Fp32Safe rotary idiom used elsewhere in the repo), so the buffer
never makes a bf16 round-trip.
Dense eager attention over an additive mask (no GQA repeat, no sink).
GLM MLA keeps one K/V per query head (num_key_value_heads == num_attention_heads),
so there is no group repeat. The additive attention_mask uses -inf for masked
positions (the DFlash SDPA mask); a plain matmul + fp32 softmax handles it correctly
(the DFlash mask guarantees no fully-masked query row, so no row softmaxes to NaN).
Parameters:
[B, H, q_len, qk_head_dim].
[B, H, kv_len, qk_head_dim].
[B, H, kv_len, v_head_dim].
[B, 1, q_len, kv_len] additive mask, or None.
softmax scale (qk_head_dim ** -0.5).
Returns: torch.Tensor
[B, q_len, H, v_head_dim] (heads folded back next to the feature dim).