[Triton][GDN] Support V-major (hvk) state layout in decode kernel#4057
[Triton][GDN] Support V-major (hvk) state layout in decode kernel#4057hsthe29 wants to merge 1 commit into
Conversation
fused_sigmoid_gating_delta_rule_update hardcoded the recurrent-state pointer
arithmetic to a K-major [N, HV, K, V] contiguous layout (o_k*V + o_v). Callers
whose state pool is V-major [N, HV, V, K] -- e.g. SGLang's MambaPool, allocated
[num_slots, HV, V, K] -- therefore could not use this kernel: reading the same
bytes with the opposite inner-axis order yields a transposed (wrong) state
(cos ~ 0.02), and the baked strides cannot be worked around with a .transpose()
view.
Add explicit (slot, head, K, V) strides to the kernel and a `state_layout`
selector on the wrapper:
- "hkv" (default): [N, HV, K, V], K-major -- byte-identical to the previous
hardcoded arithmetic (integer pointer offsets unchanged).
- "hvk": [N, HV, V, K], V-major -- lets V-major pools call the kernel in place
(h0_indices scatter) with no transpose-copy.
Validated (op_tests/test_gated_delta_rule.py::
test_fused_sigmoid_gating_delta_rule_update_state_layout): hvk == hkv for the
same logical state across K==V and K!=V, fp32/bf16, non-identity scatter --
output and final state match to FP-noise. The existing decode test (default
path) is unchanged (11/11 pass).
Signed-off-by: hsthe29 <thehosy2002@gmail.com>
🏷️ CI GuideRuns automatically on every PR:
Extended tests (opt-in via labels):
|
|
Hi @azaidy - this PR extends the GDN decode kernel ( It's fully backward-compatible: the default Could you please approve the CI workflows for this PR? |
Summary
fused_sigmoid_gating_delta_rule_update(the GDN / gated-delta-net decode kernel) hardcoded the recurrent-state pointer arithmetic to a K-major[N, HV, K, V]contiguous layout:A framework whose recurrent-state pool is V-major
[N, HV, V, K]cannot use this kernel: reading the same bytes with the opposite inner-axis order gives a transposed (wrong) state (cos ≈ 0.02), and because the strides are baked in, it can't be fixed with a.transpose()view.This is exactly SGLang's situation — its
MambaPoolrecurrent state is allocated[num_slots, HV, V, K](V-major), and its own sgl-fla decode kernel indexes it aso_v*K + o_k. So aiter's GDN decode kernel is currently unusable as a drop-in for SGLang.Change
Add explicit
(slot, head, K, V)strides to the kernel and astate_layoutselector on the wrapper:"hkv"(default) —[N, HV, K, V], K-major. Strides(HV*K*V, K*V, V, 1), i.e. byte-identical to the previous hardcoded arithmetic (integer pointer offsets unchanged → no behavior change for existing callers)."hvk"—[N, HV, V, K], V-major. Strides(HV*V*K, V*K, 1, K). Lets a V-major pool call the kernel in place (viah0_indicesscatter) with no transpose-copy.Both the initial-state read and the final-state write-back use the passed strides.
Correctness
New test
op_tests/test_gated_delta_rule.py::test_fused_sigmoid_gating_delta_rule_update_state_layoutasserts"hvk"=="hkv"for the same logical state (same recurrence, only storage differs), acrossK==VandK!=V, fp32/bf16, with a non-identityh0_indicesscatter. Output and final state match to FP-noise.hvkvs fp32 oracle (out)hvkvs aiterhkv(out+state)hvkvs SGLang sgl-fla decode on[V,K]pool (out)hkvpath) unchanged: 11/11 pass.black 26.x/ruff 0.15.xclean.Scope / follow-up
This covers the decode kernel. The prefill/extend path (
chunk_gated_delta_rule) has a separate gap for the same consumers: its public API takes noinitial_state_indices(no in-place scatter) and returns no per-chunkh(needed for SGLang's extra_buffer SSM-state tracking). That is a larger, separate change and is intentionally out of scope here.