This document is relevant for: Trn2, Trn3
GDN CTE Kernel API Reference#
Chunked gated delta-rule (GDN) prefill kernel.
Computes the gated delta-rule linear-attention recurrence in chunk-parallel form and returns the output hidden states plus the final recurrent state. algorithm selects the intra-chunk triangular-inverse method. Intended for prefill of a few hundred tokens and up; the default algorithm’s chunk grouping needs at least group_size chunks (1024 tokens at the default of 8) to amortize, and its measured advantage grows from 1.8x at S=128 to about 3.7x at S>=2048.
Background#
The gdn_cte kernel computes the gated delta-rule (GDN) linear-attention recurrence for prefill in chunk-parallel form and returns the output hidden states and the final recurrent state. The algorithm argument selects the intra-chunk triangular-inverse method.
API Reference#
Source code for this kernel API can be found at: gdn_cte.py
gdn_cte#
- nkilib.experimental.gdn.gdn_cte(query: nl.NkiTensor, key: nl.NkiTensor, value: nl.NkiTensor, g_log: nl.NkiTensor, beta: nl.NkiTensor, scale: float = 1.0, algorithm: str = DEFAULT_ALGORITHM, mask_pack: Optional[nl.NkiTensor] = None, group_size: int = DEFAULT_GROUP_SIZE, recurrent_state: Optional[nl.NkiTensor] = None) tuple[nl.NkiTensor, nl.NkiTensor]#
Chunked gated delta-rule (GDN) prefill kernel.
- Parameters:
query (
nl.NkiTensor) – [B, Hk, S, Dk], Query tensor in HBM, TOKEN-major; the permute the matmuls need rides on the load DMA. ITS DTYPE SETS THE COMPUTE DTYPE – matmul operands, q/k/v tiles and out. Must be L2-normalized, see Notes.key (
nl.NkiTensor) – [B, Hk, S, Dk], Key tensor in HBM, TOKEN-major, L2-normalized, same dtype as query.value (
nl.NkiTensor) – [B, Hv, S, Dv], Value tensor in HBM, same dtype as query.g_log (
nl.NkiTensor) – [B, Hv, S], Per-token log-decay (negative) in HBM, fp32.beta (
nl.NkiTensor) – [B, Hv, S], Per-token update strength in (0, 1) in HBM, fp32.scale (
float) – Query scaling, typically 1/sqrt(Dk). Applied ON DEVICE.algorithm (
str) – Intra-chunk inverse to use, “schur” (default) or “neumann”. Trace-time constant.mask_pack (
Optional[nl.NkiTensor]) – [N_MASKS, CHUNK, CHUNK] fp32 mask pack in HBM. REQUIRED by “schur”; build it with build_mask_pack().group_size (
int) – Chunks per grouped inverse for “schur”.recurrent_state (
Optional[nl.NkiTensor]) – [B, Hv, Dk, Dv] fp32, OPTIONAL MUTABLE IN/OUT. Supplied, it is aliased to the second output, updated IN PLACE, and its incoming contents are the initial state. Omitted, the kernel allocates the output and starts from a zero state with no load emitted. “neumann” supports ONLY the omitted form.
- Returns:
[B, Hv, S, Dv], Output hidden states in HBM in the compute dtype, HEAD-major and UN-normalized (no fused output epilogue).
- Return type:
nl.NkiTensor- Returns:
[B, Hv, Dk, Dv], Final recurrent state, always fp32 – the caller’s buffer when one was supplied.
- Return type:
nl.NkiTensor
Notes:
Dq must equal Dk (they contract), and Dk, Dv <= MAX_HEAD_DIM=128.
S must be divisible by 128 for “schur” and by 64 for “neumann”. This dispatcher enforces only the selected algorithm’s constraint.
Hv must be divisible by Hk; value head h reads key/query head h // (Hv//Hk). “neumann” additionally requires Hk == Hv (no head sharing).
q/k MUST arrive L2-normalized. That bounds q.k in [-1, 1], which is what makes bf16 matmul operands safe here; un-normalized inputs put the (I+A) inverse outside bf16’s usable range.
The recurrent state is fp32 whatever the compute dtype: it accumulates across the whole sequence, so it is the one place a narrow mantissa would compound.
Dimensions:
B: Batch size
Hk: Key/query head count
Hv: Value head count, a multiple of Hk (GQA ratio Hv // Hk)
Dk: Key/query/state head dimension (<= 128)
Dv: Value/state head dimension
This document is relevant for: Trn2, Trn3