⚡ KDA · Key-Dependent Attention

架构定位 → 数学原理 → 算法流程 → Triton Kernel → 与 Triton 协同 · 基于线性注意力的高效推理算子 · Triton 实现 · Ascend NPU 优化
KV Cache 恒定不变 · 复杂度从 O(N²) 降至 O(N) · 支持长序列高效推理
🧱 架构定位:KDA 在 Transformer 中的位置 整体视角
大语言模型(LLM)的本质是 N 层 Transformer Block 的堆叠。下面 3 张图由粗到细 展示 KDA 的位置。

图 A 特别说明:标准注意力 使用 softmax(QKT)V 计算,需要存储完整的 KV Cache。 KDA 替换了这个计算,通过维护固定大小的隐状态实现 O(1) 内存占用。
图 A Transformer 整体架构 · KDA 替换位置
flowchart TD Input["输入 Token"] --> Embed["Token 嵌入 + 位置编码"] Embed --> Block["循环 N 个 Block"] Block --> Output["输出层 (LM Head)"] Output --> Result["生成下一个 Token"] Block --> BlockDetail["每个 Block 内部见 图 B"]
图 B 单个 Block 展开 · KDA 替换标准注意力
flowchart TD In["输入 (d_model)"] --> LN1["LayerNorm"] LN1 --> Attn["注意力层"] Attn --> Add1["残差连接 +"] Add1 --> LN2["LayerNorm"] LN2 --> FFN["FFN (SwiGLU)"] FFN --> Add2["残差连接 +"] Add2 --> Out["输出 (d_model)"] Attn --> AttnDetail["标准注意力: O = softmax(QK^T) · V"] Attn -.->|"KDA 替换"| KDA["KDA: h = h·exp(g) + v·k^T"]
图 C KDA 计算流程概览
flowchart LR A["Q, K, V, gate"] --> B["状态更新
h = h·exp(g) + v·k^T"]
💡 核心变化:KDA 将标准注意力的 O(N²) KV Cache 替换为 O(D²) 固定隐状态, 实现了长序列场景下的恒定内存占用。
🔄 从架构到原理
了解了 KDA 在 Transformer 中的位置后,接下来深入数学原理。 KDA 的核心是将注意力计算转化为状态更新问题, 通过固定大小的隐状态压缩历史信息,实现 O(N) 复杂度。
1. 什么是 KDA 概述

KDA (Key-Dependent Attention) 是一种基于线性注意力和 Delta Rule 的高效推理算子。 它通过将标准注意力的复杂度从 O(N²) 降低到 O(N), 实现了对长序列的高效处理,同时保持了与标准注意力相当的表达能力。

KDA 的核心思想是:将注意力计算转化为状态更新问题,通过维护一个固定大小的隐状态 (h-state), 实现对序列信息的压缩存储,从而避免了标准注意力中需要存储完整 KV Cache 的问题。

图 1 KDA vs 标准注意力对比
flowchart LR A["标准注意力
O = softmax(QK^T) · V
内存: O(N²)"] --> B["❌ KV Cache 线性增长"] C["KDA
h = h·exp(g) + v·k^T
内存: O(D²)"] --> D["✅ KV Cache 恒定不变"]

📊 标准注意力 (Softmax Attention)

复杂度:O(N² · D) 时间 + O(N²) 空间
公式:O = softmax(QKT · scale) · V
特点:需要存储完整 N×N 注意力矩阵,KV Cache 线性增长

📊 KDA (Key-Dependent Attention)

复杂度:O(N · D²) 时间 + O(D²) 空间
公式:ht = ht-1 · exp(gt) + vt · ktT,Ot = ht · qt
特点:固定大小状态,KV Cache 恒定不变

图 2 KDA 核心优势
flowchart TD A["KDA 核心优势"] --> B["恒定内存占用
隐状态 [B, H, V, K]
与序列长度无关"] A --> C["高效推理
长序列无 KV Cache 爆炸
适合推理场景"] A --> D["硬件友好
计算模式规整
GPU/NPU 并行优化"] A --> E["门控机制
灵活门控衰减
控制信息保留时长"]
📐 数字实例化:显存占用对比

假设配置:d_model=4096, num_heads=32, head_dim=128, 序列长度=128K

标准注意力 KV Cache:
每层每token存储 K+V = 2 × 32 × 128 × 2bytes(FP16) = 16 KB/token
128K序列 × 32层 = 128K × 32 × 16KB = 64 GB

KDA 隐状态:
每层状态 S = 32 × 128 × 128 × 2bytes = 1 MB/层
32层总计 = 32 × 1MB = 32 MB(固定)

节省:从 64 GB → 32 MB,节省 99.95%
⚠️ 关键区分:训练学什么 vs 推理做什么

S矩阵永远不是模型权重,S是前向传播中间临时状态,不会存进checkpoint文件。
图 3 训练阶段:学习门控网络
flowchart TD A["输入 hidden_state"] --> B["Q/K/V 投影 + ShortConv"] A --> C["门控生成网络"] C --> D["α_t (逐通道遗忘门)"] C --> E["β_t (写入强度)"] D --> F["Delta Rule 更新 S"] E --> F B --> F F --> G["输出预测"] G --> H["交叉熵损失"] H --> I["反向传播更新门控网络权重"] I -.->|"梯度回传"| C

🟢 训练阶段

学习内容:Q/K/V投影 + ShortConv卷积 + 门控生成网络(α, β)
Checkpoint保存:所有网络权重;S矩阵不保存
训练算法:Chunk分块并行,块间传递S做反向传播
训练目标:学会"哪些维度要保留(α≈1)、哪些要遗忘(α≈0)、何时写入记忆(β)"

🟢 推理阶段

运行时:S从零初始化,实时迭代更新
Prefill:分块处理prompt,S逐步压缩上下文
Decode:每token更新S,输出 o = ST · q
对话结束:S直接丢弃,下轮重新置零

图 4 推理阶段:Delta Rule 三步迭代
flowchart LR A["S_{t-1}
旧状态"] --> B["Step1: k_t 读旧S
预测 v̂_t = S_{t-1}^T · k_t"] B --> C["Step2: 算误差
error = v_t - v̂_t"] C --> D["Step3: 门控更新
S_t = α ⊙ S_{t-1} + β · error ⊗ k_t"] D --> E["S_t
新状态"]
❌ 核心误区澄清

误区1:训练阶段就把文本预先压缩成S存进模型权重。
事实:训练不学具体文本内容,只学记忆策略;S无论训练还是推理都是临时中间变量。

误区2:KDA是推理时对普通Transformer KV做后处理压缩。
事实:不是后处理;整套门控网络必须预训练就嵌入模型架构。

误区3:α和β是固定超参数。
事实:αt和βt每个token都不一样,由输入特征经过可学习网络动态生成(由 fused_gdn_gating 计算)。
图 3.5 KDA + MLA 混合架构(基于 layer_type 切换)
flowchart TD A["模型配置
layer_type: linear_attention | full_attention"] --> B{"DecoderLayer 判断"} B -->|"linear_attention"| C["KDA 路径"] B -->|"full_attention"| D["MLA (标准注意力) 路径"] C --> C1["Q/K/V 投影"] C1 --> C2["conv1d 短卷积"] C2 --> C3["门控生成 g, β"] C3 --> C4["Delta Rule 更新 S"] C4 --> C5["输出 o = S^T · q"] D --> D1["Q/K/V + RoPE"] D1 --> D2["Standard Softmax Attention"] D2 --> D3["KV Cache 存储"] C5 --> E["残差 + LayerNorm + MLP"] D3 --> E
📐 架构选择来源(源码证据)

切换位置:patch_qwen3_5.py:130
if self.layer_type == "linear_attention": self.linear_attn(...)
elif self.layer_type == "full_attention": self.self_attn(...)

层类型配置:由模型 HuggingFace config 中 layer_type 字段决定(Kimi/Qwen3.5 模型)
3:1比例说明:每4层中3层为KDA(linear_attention),1层为MLA(full_attention)。此比例由模型预训练时配置决定,非 vllm-ascend 硬编码。

为什么要混合:纯KDA(线性注意力)对高频细粒度注意力表达较弱,混合MLA可保留精确检索能力,两者互补。
🔗 从原理到公式
理解了 KDA 的核心思想后,接下来用数学公式精确描述状态更新过程。 KDA 的数学本质是线性注意力的递推形式, 通过门控因子控制历史信息的衰减。
2. 数学公式推导 理论基础

KDA 基于线性注意力理论,通过将 softmax(QKT)V 分解为递推形式实现高效计算。

标准注意力: O = softmax(QKT / √dk) · V
KDA 状态更新: ht = ht-1 · exp(gt) + βt · vt · ktT
KDA 输出: ot = ht · qt / √dk
图 3 KDA 状态更新流程
flowchart LR A["h_{t-1}
历史状态"] --> B["× exp(g_t)
门控衰减"] C["v_t · k_t^T
新信息注入"] --> D["+ 融合"] B --> D D --> E["h_t
更新状态"] E --> F["× q_t
输出计算"] F --> G["o_t
当前输出"]
💡 关键变量说明

• gt:门控衰减因子,控制历史信息的保留程度。gt < 0 时衰减,gt = 0 时无衰减
• βt:Beta 系数,控制新信息的注入强度
• ht:隐状态矩阵,形状 [V, K],压缩存储历史信息
• qt, kt, vt:Query, Key, Value 向量
🚀 Chunk-KDA 的数学技巧
为了避免逐 token 递推的串行性,Chunk-KDA 将序列分成固定大小的块 (chunk_size=64), 块内使用矩阵运算并行计算,块间使用状态传递。 核心公式:A = I + K·KT,w = (I + A)-1 · K·β

3. KDA 完整算法流程 核心流程

KDA 的完整前向传播分为两个路径:Chunk-KDA(分块并行)和 Fused Recurrent KDA(循环融合)。

图 4 KDA 两条执行路径
flowchart TD A["输入: Q, K, V, gate, beta"] --> B{"选择执行路径"} B -->|"长序列 >64 tokens"| C["Chunk-KDA 路径"] B -->|"短序列 / Prefill"| D["Fused Recurrent 路径"] C --> E["输出: O, final_state"] D --> E

Chunk-KDA 详细步骤

图 5 Chunk-KDA 完整流程
flowchart TD A["Step 1: 累积门控和
g = chunk_local_cumsum(g) * RCP_LN2"] --> B["Step 2: 计算 K·K^T 和 Q·K^T
A, Aqk = chunk_kda_scaled_dot_kkt_fwd()"] B --> C["Step 3: 求解下三角逆
A_inv = solve_tril_kda(A)"] C --> D["Step 4: 重计算 w 和 u
w = A_inv · K · β
u = A_inv · V · β"] D --> E["Step 5: 计算 h-state
h = chunk_gated_delta_rule_fwd_h_kda()"] E --> F["Step 6: 计算输出
o = q · h + Aqk · V"]
1累积门控和 (Chunk Local Cumsum)
将逐 token 的门控值 gt 转换为块内累积和,用于后续的矩阵指数计算。
g = chunk_local_cumsum(g, chunk_size=64) * RCP_LN2
其中 RCP_LN2 = 1/ln(2),用于将自然对数底转换为以 2 为底的指数。
2计算 K·K^T 和 Q·K^T 矩阵
并行计算两个关键矩阵:
• A[i,j] = Σ_k β[k] · K[i,k] · K[j,k] · exp2(g[i] - g[j]) (块内 K·K^T)
• Aqk[i,j] = Σ_k Q[i,k] · K[j,k] · exp2(g[i] - g[j]) · scale (块内 Q·K^T)
3求解下三角矩阵逆 (Solve Tril)
计算 (I + A)-1,其中 A 是严格下三角矩阵。
使用分块求逆策略:16×16 → 32×32 → 64×64,通过 Triton 并行 kernel 实现。
4重计算 w 和 u
根据求逆结果计算权重矩阵:
• w = A_inv · K · β (用于后续 h-state 更新)
• u = A_inv · V · β (用于后续输出计算)
5计算 h-state (隐状态)
使用 Chunk Gated Delta Rule 更新隐状态:
h = chunk_gated_delta_rule_fwd_h_kda(k, w, u, gk)
支持初始状态 h0 和最终状态 ht 的保存/加载。
6计算最终输出
结合隐状态和块内注意力计算输出:
o = q · h + Aqk · V
第一项来自块间状态传递,第二项来自块内并行计算。

4. Triton Kernel 实现详解 代码解析

KDA 的所有核心计算都通过 Triton kernel 实现,充分利用了 Triton 的自动调优、内存管理和硬件抽象能力。

图 6 KDA Kernel 依赖关系
flowchart TD A["kda.py
主入口"] --> B["chunk_delta_h.py
h-state 计算"] A --> C["solve_tril.py
下三角逆矩阵"] A --> D["fused_recurrent_kda.py
循环递推"] A --> E["cumsum.py
累积和"] A --> F["l2norm.py
L2 归一化"] B --> G["utils.py
工具函数"] C --> G D --> G
Kernel 名称 功能 核心操作
chunk_kda_scaled_dot_kkt_fwd_kernel_intra_sub_inter 计算块间 K·K^T 矩阵 跨子块的 β·K·K^T 计算,支持门控衰减
chunk_kda_scaled_dot_kkt_fwd_kernel_intra_sub_intra 计算块内 K·K^T 和 Q·K^T 矩阵 子块内的并行 dot 运算
solve_tril_16x16_kernel_kda 16×16 基础分块求逆 下三角矩阵逆的原子操作
merge_16x16_to_32x32_inverse_kernel_kda 32×32 分块求逆 合并两个 16×16 块
merge_16x16_to_64x64_inverse_kernel_kda 64×64 分块求逆 合并四个 16×16 块
chunk_gated_delta_rule_fwd_kernel_h_blockdim64_kda 计算 h-state 隐状态 分块 delta rule 更新,支持向量门控
fused_recurrent_gated_delta_rule_fwd_kernel 循环递推 KDA 逐 token 递推,支持连续批处理
recompute_w_u_fwd_kernel 重计算 w 和 u 根据 A_inv 计算权重矩阵
chunk_gla_fwd_kernel_o 计算最终输出 结合 h-state 和 Aqk 计算输出
layer_norm_gated_fwd_kernel 融合 LayerNorm + 门控 单 kernel 完成归一化和门控激活
图 7 分块求逆策略 (Solve Tril)
flowchart TD A["16×16 基础分块
solve_tril_16x16_kernel_kda"] --> B["32×32 合并
merge_16x16_to_32x32_inverse_kernel_kda"] B --> C["64×64 合并
merge_16x16_to_64x64_inverse_kernel_kda"] C --> D["最终结果: (I + A)^{-1}"]

关键代码片段

# kda.py - Chunk-KDA 入口函数
def chunk_kda(q, k, v, g, beta, scale=None, initial_state=None, ...):
    if scale is None:
        scale = k.shape[-1] ** -0.5

    # 可选的 L2 归一化
    if use_qk_l2norm_in_kernel:
        q = l2norm_fwd(q.contiguous(), use_tiled_kernel=True)
        k = l2norm_fwd(k.contiguous(), use_tiled_kernel=True)

    o, final_state = chunk_kda_fwd(
        q=q, k=k, v=v.contiguous(), g=g.contiguous(),
        beta=beta.contiguous(), scale=scale, ...)
    return o, final_state
# kda.py - 分块前向传播核心逻辑
def chunk_kda_fwd(q, k, v, g, beta, scale, initial_state, ...):
    chunk_size = FLA_CHUNK_SIZE  # 默认 64
    # Step 1: 累积门控和
    g = chunk_local_cumsum(g, chunk_size=chunk_size, ...)
    g = g * RCP_LN2

    # Step 2: 计算 K·K^T 和 Q·K^T 矩阵
    A, Aqk = chunk_kda_scaled_dot_kkt_fwd(q=q, k=k, gk=g, beta=beta, ...)

    # Step 3: 求解下三角矩阵逆
    A = solve_tril_kda(A=A, ...)

    # Step 4: 重计算 w 和 u
    w, u, _, kg = recompute_w_u_fwd(k=k, v=v, beta=beta, A=A, gk=g, ...)

    # Step 5: 计算 h-state 隐状态
    h, v_new, final_state = chunk_gated_delta_rule_fwd_h_kda(
        k=kg, w=w, u=u, gk=g, initial_state=initial_state, ...)

    # Step 6: 计算最终输出
    o = chunk_gla_fwd_o_gk(q=q, v=v_new, g=g, A=Aqk, h=h, scale=scale, ...)
    return o, final_state
# fused_recurrent_kda.py - 逐 token 循环递推
@triton.jit(do_not_specialize=["N", "T"])
def fused_recurrent_gated_delta_rule_fwd_kernel(q, k, v, g, beta, o, ...):
    # 初始化隐状态
    b_h = tl.zeros([BV, BK], dtype=tl.float32)
    if USE_INITIAL_STATE:
        b_h += tl.load(p_h0, mask=mask_h, other=0).to(tl.float32)

    # 主循环:逐 token 递推
    for i_t in range(0, T):
        b_q = tl.load(p_q, ...).to(tl.float32)
        b_k = tl.load(p_k, ...).to(tl.float32)
        b_v = tl.load(p_v, ...).to(tl.float32)

        # KDA 特殊处理:向量门控
        if IS_KDA:
            b_gk = tl.load(p_gk).to(tl.float32)
            b_h *= tl.exp(b_gk[None, :])  # 门控衰减

        # Delta Rule 更新
        b_v -= tl.sum(b_h * b_k[None, :], 1)  # 残差计算
        b_v *= b_beta
        b_h += b_v[:, None] * b_k[None, :]     # 状态更新
        b_o = tl.sum(b_h * b_q[None, :], 1)    # 输出计算
        tl.store(p_o, b_o.to(p_o.dtype.element_ty), mask=mask_v)
# solve_tril.py - 下三角矩阵求逆
@triton.jit(do_not_specialize=["T"])
def solve_tril_16x16_kernel_kda(A, Ai, cu_seqlens, chunk_indices, T, H, BT):
    # 加载 16x16 子块
    b_A = tl.load(p_A, boundary_check=(0, 1)).to(tl.float32)
    b_A = -tl.where(m_A, b_A, 0)  # 取严格下三角部分

    # 迭代求解逆矩阵
    for i in range(2, min(16, T - i_t * 16)):
        b_a = -tl.load(A + (i_t * 16 + i) * H * BT + o_i + offset)
        b_a = b_a + tl.sum(b_a[:, None] * b_A, 0)
        b_A = tl.where((o_i == i)[:, None], b_a, b_A)

    b_A += m_I  # 加上单位矩阵
    tl.store(p_Ai, b_A.to(...))

5. KDA 与 Triton 的深度协同 技术融合

KDA 的设计充分体现了 Triton 的核心优势:将复杂的硬件优化细节封装在 Python 接口中, 让算法工程师专注于数学逻辑,同时自动获得接近手写 CUDA 的性能。

图 8 KDA 与 Triton 协同架构
flowchart TD A["Python 层
KDA API: chunk_kda()"] --> B["Triton 编译层
@triton.jit + @triton.autotune"] B --> C["硬件执行层
GPU/NPU Kernel 执行"]

Triton 核心特性在 KDA 中的应用

Triton 特性 在 KDA 中的应用 效果
@triton.jit 定义所有核心 kernel,支持 JIT 编译 运行时编译为目标平台代码,无需预编译
@triton.autotune 自动搜索最优 num_warps/num_stages 配置 不同硬件自动适配最优参数,性能提升 20-40%
@triton.heuristics 运行时判断 IS_VARLEN、USE_INITIAL_STATE 等 避免不必要的分支,减少 kernel 开销
tl.make_block_ptr 管理 Q/K/V 张量的分块访问 自动处理边界检查,避免数组越界
tl.dot 矩阵乘法运算 (K·K^T, Q·K^T, w·h) 映射到 Tensor Core / 矩阵运算单元
tl.exp / tl.exp2 门控衰减计算 硬件加速的指数运算
tl.load / tl.store 所有内存读写操作 自动向量化,合并内存访问
tl.constexpr 标记编译期常量 (K, V, BT, BV) 编译期展开循环,消除运行时开销
图 9 Triton 自动优化流程
flowchart LR A["定义 Kernel
@triton.jit"] --> B["自动调优
@triton.autotune"] B --> C["内存管理
Shared Memory 分配"]

✅ Triton 自动优化

内存管理:自动分配 Shared Memory,规避 Bank Conflict
线程调度:自动分配 Warp,优化线程束执行
向量化:自动合并内存访问,提升带宽利用率
流水线:自动插入预取指令,隐藏内存延迟

🎯 KDA 专注算法

数学逻辑:只需描述"做什么",无需关心"怎么做"
分块策略:通过参数控制粒度 (BT=32/64/128)
精度控制:支持 IEEE/TF32 精度选择
变量长度:通过 cu_seqlens 支持变长序列

🚀 协同效果

• 开发效率:相比手写 CUDA,代码量减少 60%以上
• 执行性能:自动调优后性能接近手写 CUDA 的 90%+
• 可移植性:同一份代码自动适配 GPU/NPU/多种硬件
• 可维护性:清晰的 Python 语法,易于理解和修改

6. 性能优化策略 工程实践
图 10 自动调优搜索空间
flowchart LR A["块大小 BT
32 / 64 / 128"] --> D["最优配置
@triton.autotune"] B["Warp 数量 NW
4 / 8 / 16 / 32"] --> D C["流水线 stages
2 / 3"] --> D
💡 KDA 中的 Triton 优化技巧

• 分块并行:将序列分成 64-token 块,块内完全并行计算
• 融合 Kernel:LayerNorm + 门控激活融合为单 kernel,减少内存访问
• 自动调优:通过 @triton.autotune 自动搜索最优配置
• 精度控制:关键计算使用 FP32,非关键路径使用 FP16/BF16
• 内存复用:inplace_final_state 参数支持原地更新状态
• L2 归一化融合:可选的 QK L2 归一化,避免额外 kernel
# kda.py 中的自动调优配置
BT_LIST_AUTOTUNE = [32, 64, 128]  # 块大小搜索空间
NUM_WARPS_AUTOTUNE = [4, 8, 16, 32]  # Warp 数量搜索空间

@triton.autotune(
    configs=[
        triton.Config({"BT": bt}, num_warps=nw, num_stages=ns)
        for bt in BT_LIST_AUTOTUNE
        for nw in NUM_WARPS_AUTOTUNE
        for ns in [2, 3]
    ],
    key=["H", "D"],
)
@triton.jit
def kda_gate_fwd_kernel(g, A, y, g_bias, beta, threshold, T, H, D, BT, BD):
    # Kernel 实现...
    pass

7. 代码模块结构 项目组织
文件 功能 核心函数
kda.py 主入口,包含 chunk_kda 和 fused_recurrent_kda chunk_kda(), fused_recurrent_kda(), layer_norm_gated_fwd()
chunk_delta_h.py 分块 h-state 计算,KDA 特有的 [V, K] 状态布局 chunk_gated_delta_rule_fwd_h_kda()
solve_tril.py 下三角矩阵逆求解,支持 16/32/64 分块 solve_tril_kda()
fused_recurrent_kda.py 逐 token 循环递推,支持连续批处理 fused_recurrent_gated_delta_rule_fwd_kernel()
cumsum.py 块内累积和计算 chunk_local_cumsum()
l2norm.py 可选的 QK L2 归一化 l2norm_fwd()
utils.py 工具函数:chunk 索引、偏移量、缓存装饰器 prepare_chunk_indices(), prepare_chunk_offsets()

8. 关键设计决策 深度解析
图 11 关键设计决策
flowchart TD A["关键设计决策"] --> B["选择 Triton
开发效率 + 自动调优 + 可移植性"] A --> C["[V, K] 状态布局
内存连续 + 向量化友好"] A --> D["chunk_size = 64
硬件对齐 + 内存效率 + 并行度"]
💡 为什么选择 Triton 而不是 CUDA?

• 开发效率:KDA 涉及多个复杂 kernel(矩阵求逆、门控计算等),Triton 显著降低开发难度
• 自动调优:KDA 的性能高度依赖块大小和 warp 配置,Triton 自动搜索最优参数
• 可移植性:vllm-ascend 需要支持 NPU,Triton 的多后端支持是关键优势
• 可维护性:相比 CUDA C++,Triton 代码更易理解和修改
💡 为什么使用 [V, K] 状态布局而不是 [K, V]?

• 内存访问模式:KDA 的核心操作是 h · q 和 k · v,[V, K] 布局使这些操作在内存中连续
• 向量化友好:K 维度通常较大(64-256),按 K 维度切分便于 SIMD 并行
• 与 FLA 对齐:保持与 flash-linear-attention 库的兼容性
💡 为什么 chunk_size 固定为 64?

• 硬件对齐:64 是 GPU warp size 的整数倍,便于线程分配
• 内存效率:64-token 块的 KV 数据刚好适合 Shared Memory 容量
• 并行度:64 提供足够的并行度,同时避免过度分块带来的开销
• 实验验证:64 是性能和精度的最佳平衡点
⚠️ 已知限制

• 当前仅支持 head dimension K ≤ 256
• NK > 1(K 维度分块)尚未支持
• 变长序列需要提前准备 chunk_indices
• 精度在某些边界情况下可能略有损失

总结
图 12 KDA 核心要点
flowchart TD A["KDA 核心要点"] --> B["1. KDA 是什么
基于线性注意力的高效推理算子"] A --> C["2. 核心算法
h = h·exp(g) + β·v·k^T
o = h · q"] A --> D["3. 两条执行路径
Chunk-KDA + Fused Recurrent"] A --> E["4. Triton 协同
自动调优 + 内存管理 + 硬件抽象"] A --> F["5. 工程价值
内存恒定 + 开发高效 + 可移植"]
核心要点回顾

1. KDA 是什么:基于线性注意力的高效推理算子,通过固定大小的隐状态替代标准注意力的 KV Cache

2. 核心算法:状态更新 ht = ht-1 · exp(gt) + β · vt · ktT,输出 ot = ht · qt

3. 两条执行路径:Chunk-KDA(分块并行,适合长序列)+ Fused Recurrent(循环递推,适合短序列)

4. Triton 协同:自动调优、内存管理、硬件抽象,让 KDA 专注于算法逻辑

5. 工程价值:内存恒定、开发高效、性能优异、可移植性强
基于 vllm-ascend 项目源码分析 · KDA 模块路径: vllm_ascend/ops/triton/kda/
华杉的技术博客 · 苏ICP备2026063680号-1
首页