nemo_automodel.components.models.kimi_k3.attn_res_triton
nemo_automodel.components.models.kimi_k3.attn_res_triton
Hand-written Triton kernels for the Kimi-K3 attention-residual mix.
The mix (situ._attn_res_core) scores every entry of [tokens, k+1, hidden]
(the k block residuals plus the current prefix sum) with an RMS-normalised
dot product against norm_weight * proj_weight, softmaxes the k+1 scores
per token and returns the probability-weighted sum of the entries. The eager
chain materialises torch.cat((block_residual, prefix_sum)) and an fp32
upcast of it, and the torch.compile version (BackendConfig.compile_situ)
lowers the row-broadcast multiply and the entry-axis reduction into 1-D
pointwise / reduction kernels that run far below HBM bandwidth (on a 256-GPU
K3 profile the two named kernels cost 761 us and 390 us per call at stage 0,
where k is at most 1; k grows to 8 on the last pipeline stage).
These kernels handle one token per program and stream the hidden row in
C-wide chunks (autotuned 512-4096 columns x 4-8 warps), so the register
footprint stays small and many programs share an SM. The forward streams every
entry once for the two row reductions (sum of squares, dot with the score
weight) with elementwise accumulators reduced once per entry, softmaxes the
scores in registers and streams the entries a second time for the weighted sum;
no concatenation, no fp32 copy, bf16 in / bf16 out with fp32 math. The
per-token probabilities, inverse RMS and dot products (3 x (k+1) fp32
values) are saved for the backward, which runs as two kernels: a per-token
coefficient kernel (<grad, entry> reductions and the softmax backward) and
a [tokens / BWD_ROWS, chunks] gradient kernel that writes the analytic input
gradients and accumulates the score-weight gradient per (row block, chunk) into
a partial buffer that is summed in torch (deterministic, no atomics).
The fp32 math matches _attn_res_core up to fp32 accumulation order (the
reference multiplies each element by the inverse RMS before its dot-product
reduction; the kernel reduces first and scales the sum), which is below bf16
resolution for the shapes this is used at.
Module Contents
Functions
Data
API
One token per program: <g, x_j> per entry, then the softmax-backward coefficients.
With p = softmax(s), s_j = r_j * a_j, r_j = rsqrt(mean(x_j^2) + eps), a_j = <x_j, sw>: dp_j = <g, x_j>, ds_j = p_j * (dp_j - sum_i p_i dp_i). Writes c_sw_j = ds_j * r_j (the coefficient on the score weight) and c_x_j = -ds_j * a_j * r_j^3 / H (the coefficient on x_j), so that dx_j = p_j * g + c_sw_j * sw + c_x_j * x_j.
Program (row block, chunk): dx_j = p_j g + c_sw_j sw + c_x_j x_j for R tokens on one C-wide chunk.
Accumulates the score-weight gradient of its chunk over its R tokens and writes it to dsw[row block, chunk] (deterministic partials, summed by the caller).
One token per program: scores, softmax and weighted sum over NB block entries + the prefix row.
Autotune candidates: chunk width x warps (register footprint vs loads in flight).
Fused attention-residual mix backward.
Parameters:
the forward inputs.
[tokens, hidden] gradient of the mixed output (contiguous last dim).
the forward’s [3, tokens, k+1] fp32 statistics.
Returns: torch.Tensor
(d_prefix_sum, d_block_residual, d_score_weight): the first two in their inputs’ dtypes, the
Fused attention-residual mix forward.
Parameters:
[tokens, hidden] current residual stream (any float dtype; sets the output dtype).
[tokens, k, hidden] prior block starts, k <= MAX_ENTRIES (may be 0).
[hidden] RMSNorm weight of the score norm.
[hidden] squeezed [1, hidden] projection weight.
RMSNorm epsilon.
Returns: torch.Tensor
(mixed [tokens, hidden] in prefix_sum's dtype, stats [3, tokens, k+1] fp32) where the stats