- 人工智能
- 大模型
- 模型推理服务
- Ascend
- CANN
【免费下载链接】vllm-ascend
Community maintained hardware plugin for vLLM on Huawei Ascend
本篇技术指南围绕 vllm-ascend 仓库中全新发布的kv_quant_sparse_flash_attention(QSFA)自定义算子展开,它在既有sparse_flash_attention基础上引入 Per-Token-Head-Tile-128(简称 per_tile)的 Key/Value 量化能力,专门服务于 Sparse Attention 场景下的长上下文大模型推理。读完本文,你将掌握该算子在 Ascend 950PR/950DT、Atlas A3、Atlas A2 系列产品上的支持范围、全部输入输出与属性参数语义、C8 量化下 packed KV 缓存布局(含 rope_head_dim=0 的紧凑 NoPE 路径),以及从算子注册定义、shape 推导、模板化内核到 Python SFA 接入的完整调用链,并可直接复用仓库中的精度测试用例进行验证。
背景:Sparse Attention 的性能矛盾与量化动机
随着大模型上下文长度不断增长,Sparse Attention(稀疏注意力)的重要性与日俱增:这一技术通过"只计算关键部分"大幅减少计算量。但代价是引入了大量离散访存——被选中的 KV block 在物理缓存中的位置并不连续,导致数据搬运时间增加,进而影响整体性能。
kv_quant_sparse_flash_attention正是面向这一矛盾的全新算子:它在sparse_flash_attention的基础上支持Per-Token-Head-Tile-128 量化输入(即每个 head 的 128 维数据块共享一个量化 scale),并针对离散访存做了指令缩减与搬运聚合的细致优化,以缓解稀疏索引带来的访存开销。
其计算公式如下:
$$ Attention=\text{softmax}\left(\frac{Q @ \text{Dequant}(\tilde{K}^{INT8}, {Scale_K})^T}{\sqrt{d_k}}\right)@\text{Dequant}(\tilde{V}^{INT8}, {Scale_V}) $$
其中 $\tilde{K},\tilde{V}$ 为基于某种选择算法(如LightningIndexer)得到的重要性较高的 Key 和 Value,一般具有稀疏或分块稀疏的特征;$d_k$ 为 $Q,\tilde{K}$ 每一个头的维度;$\text{Dequant}(\cdot,\cdot)$ 为反量化函数。可以看到,量化后的 INT8/FP8 Key、Value 需先按各自的 scale 反量化回浮点,再参与 QK 矩阵乘与 PV 矩阵乘,数学语义与标准 FlashAttention 完全一致。
产品支持情况
该算子的硬件支持矩阵(来自 README)如下:
| 产品 | 是否支持 |
|---|---|
| Ascend 950PR&950DT 系列产品 | √ |
| Atlas A3 系列产品 | √ |
| Atlas A2 系列产品 | √ |
| Atlas 200I/500 A2 推理产品 | × |
| Atlas 推理系列加速卡产品 | × |
| Atlas 训练系列产品 | × |
注意:不同硬件代际对数据类型、sparse_block_size 和 rope_head_dim 的支持存在差异(详见下文"约束说明"与"NoPE 路径"章节),落地时需按目标设备逐一核对。
参数说明
维度含义约定:B 表示 Batch Size;Q_S 和 KV_S 分别表示 query 和 key/value 的 Sequence Length;Q_N 和 KV_N 分别表示 query 和 key/value 的 Head Num;Q_D 和 KV_D 分别表示 query 和 key/value 的 Head Dim;Q_T 和 KV_T 分别表示 query 和 key/value 的 Total Tokens;sparse_size 表示一次离散选取的 block 数;block_num 和 block_size 分别表示 PageAttention 场景下的 block 总数和每个 block 的 token 数。
输入张量
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| query | 输入 | attention 结构的 Q 输入,不支持非连续。query 由相同数据类型的 q_nope 和 q_rope 按 D 维度拼接得到。layout_query 为 "BSND" 时 shape 为 [B, Q_S, Q_N, Q_D];为 "TND" 时 shape 为 [Q_T, Q_N, Q_D]。其中 Q_D = 512 + rope_head_dim。A2/A3 支持 Q_D 为 512(rope_head_dim=0)或 576(rope_head_dim=64);A5 的 INT8 和 FLOAT8_E4M3FN 场景同样支持这两种 Q_D,HiFloat8 场景仍仅支持 576。rope_head_dim=0 时 query 仅包含 q_nope。Q_N 值支持 1/2/4/8/16/32/48/64/128 | FLOAT16、BFLOAT16 | ND |
| key | 输入 | attention 结构的 K 输入,不支持非连续。由 k_nope、与 query 相同数据类型的 k_rope 和 float32 的量化参数按 D 维度拼接得到。layout_kv 为 "BSND" 时 shape 为 [B, KV_S, KV_N, KV_D];为 "TND" 时 shape 为 [KV_T, KV_N, KV_D];为 "PA_BSND" 时 shape 为 [block_num, block_size, KV_N, KV_D](block_size 取值为 16 的整数倍,最大支持到 1024)。KV_N 仅支持 1。KV_D = 512 + rope_head_dim*2 + 4*4,表示每行拼接数据的字节数。A2/A3 INT8 C8 支持 528(rope_head_dim=0)或 656(rope_head_dim=64);A5 INT8 和 FLOAT8_E4M3FN 场景同样支持 528 或 656,HiFloat8 场景仍仅支持 656。4 个 FLOAT32 scale 组成的区域起始偏移分别为 512 或 640 字节,偏移从 0 开始 | FLOAT8_E4M3FN、INT8、HIFLOAT8 | ND |
| value | 输入 | attention 结构的 V 输入,不支持非连续。A2/A3 C8 MLA 场景下,有效 V 为 key 反量化后的 512 维 NoPE 部分。算子调用时 key 和 value 可复用同一份 packed KV 缓存,物理最后一维为 528(rope_head_dim=0)或 656(rope_head_dim=64);原独立算子测试也支持传入最后一维为 512 的 NoPE value 张量。输出最后一维始终为 512 | FLOAT8_E4M3FN、INT8、HIFLOAT8 | ND |
| sparse_indices | 输入 | 代表离散取 kvCache 的索引,不支持非连续。layout_query 为 "BSND" 时 shape 为 [B, Q_S, KV_N, sparse_size];为 "TND" 时 shape 为 [Q_T, KV_N, sparse_size]。sparse_size 为一次离散选取的 block 数,需要保证每行有效值均在前半部分、无效值均在后半部分,且 sparse_size 大于 0。当 key 和 value 的数据类型为 hifloat8 时,sparse_size 仅支持 2048 | INT32 | ND |
| key_dequant_scale | 输入 | 预留参数 | - | - |
| value_dequant_scale | 输入 | 预留参数 | - | - |
| block_table | 输入 | 表示 PageAttention 中 kvCache 存储使用的 block 映射表。shape 为 [B, KV_S_max/block_size],第一维长度为 B,第二维长度不小于所有 batch 中最大的 KV_S 对应的 block 数量(即 KV_S_max / block_size 向上取整) | INT32 | ND |
| actual_seq_lengths_query | 输入 | 表示不同 Batch 中 query 的有效 token 数。不指定时可传 None,表示与 query shape 的 Q_S 长度相同。shape 为 [B,]。每个 Batch 的有效 token 数不超过 query 中的 Q_S 大小且不小于 0。当 layout_query 为 "TND" 时,该入参必须传入,且以该入参元素的数量作为 B 值,每个元素表示当前 batch 与之前所有 batch 的 token 数总和(前缀和),因此后一个元素的值必须大于等于前一个元素的值 | INT32 | ND |
| actual_seq_lengths_kv | 输入 | 表示不同 Batch 中 key 和 value 的有效 token 数。不指定时传 None,表示与 key 的 shape 的 KV_S 长度相同。shape 为 [B,]。每个 Batch 的有效 token 数不超过 key/value 中的 KV_S 大小且不小于 0。当 layout_kv 为 "TND" 或 "PA_BSND" 时,该入参必须传入;layout_kv 为 "TND" 时,每个元素表示当前 batch 与之前所有 batch 的 token 数总和(前缀和),后一个元素的值必须大于等于前一个元素的值 | INT32 | ND |
从算子的 C++ 注册定义(kv_quant_sparse_flash_attention_def.cpp)可以看到,这些输入在 CANN 算子原语中被声明为 REQUIRED(query/key/value/sparse_indices)或 OPTIONAL(key_dequant_scale/value_dequant_scale/block_table/actual_seq_lengths_query/actual_seq_lengths_kv),且全部标记AutoContiguous()并对齐 ND 格式。其中 value 输入通过Follow("key")声明其数据类型跟随 key,这从侧面印证了"key 与 value 可复用同一份 packed 缓存"的调用约定。
属性参数
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| scale_value | 属性 | 公式中 $d_k$ 开根号的倒数,代表缩放系数,作为 query 和 key 矩阵乘后 Muls 的 scalar 值。rope_head_dim 变化时继续使用调用方传入的 scale_value | FLOAT | - |
| key_quant_mode | 属性 | 代表 key 的量化模式,仅支持传入 2,代表 per_tile 量化模式 | INT64 | - |
| value_quant_mode | 属性 | 代表 value 的量化模式,仅支持传入 2,代表 per_tile 量化模式 | INT64 | - |
| sparse_block_size | 属性 | 代表 sparse 阶段的 block 大小。为 1 时是 Token-wise 稀疏化场景;大于 1 且小于等于 128 时是 Block-wise 稀疏化场景,块内 token 共享相同的稀疏化决策 | INT64 | - |
| layout_query | 属性 | 标识输入 query 的数据排布格式,默认值 "BSND",支持 BSND 和 TND | STRING | - |
| layout_kv | 属性 | 标识输入 key 的数据排布格式,默认值 "BSND",支持 BSND、TND 和 PA_BSND(PA_BSND 在开启 PageAttention 时使用) | STRING | - |
| sparse_mode | 属性 | 表示 sparse 的模式。为 0 时代表全部计算;为 3 时代表 rightDownCausal 模式的 mask,对应以右下顶点往左上为划分线的下三角场景 | INT64 | - |
| pre_tokens | 属性 | 用于稀疏计算,表示 attention 需要和前几个 Token 计算关联,仅支持 2^63-1 | INT64 | - |
| next_tokens | 属性 | 用于稀疏计算,表示 attention 需要和后几个 Token 计算关联,仅支持 2^63-1 | INT64 | - |
| attention_mode | 属性 | 表示 attention 的模式,仅支持传入 2,表示 MLA-absorb 模式,即 QK 的 D 由 512 维 NoPE 和可选的 RoPE 部分组成,且 KV 是同一份 | INT64 | - |
| quant_scale_repo_mode | 属性 | 表示量化参数的存放模式,仅支持传入 1,表示 combine 模式,即量化参数和数据混合存放 | INT64 | - |
| tile_size | 属性 | 表示 per_tile 时每个参数对应的数据块大小,仅在 per_tile 时有效,仅支持 128 | INT64 | - |
| rope_head_dim | 属性 | 表示 MLA 架构下的 RoPE 维度,仅在 attention_mode 为 2 时有效。A2/A3 INT8 C8 支持 0 或 64(0 表示省略输入中的 RoPE 分支);A5 INT8 和 FLOAT8_E4M3FN 场景同样支持 0 或 64,HiFloat8 场景仍仅支持 64。默认值保持 64 | INT64 | - |
| return_softmax_lse | 属性 | 默认 False。A2/A3 为 True 时返回 softmax_max 和 softmax_sum;有效 query 行的 LSE 可由 softmax_max + log(softmax_sum) 计算。rope_head_dim 为 0 或 64 时均保留此行为。A5 当前仅写 attention 输出,应使用 False | BOOL | - |
属性默认值可在 算子定义文件 中与文档交叉核对:scale_value默认 1.0,sparse_block_size默认 1,layout_query/layout_kv默认 "BSND",sparse_mode默认 3(注释明确"只计算下三角"),pre_tokens/next_tokens默认INT64_MAX,quant_scale_repo_mode默认 1,tile_size默认 128,rope_head_dim默认 64,return_softmax_lse默认 false。需要强调的是,尽管定义文件中key_quant_mode/value_quant_mode的初始值写为 1、attention_mode初始值为 0,但接口使用约束要求必须显式传入 2(per_tile)和 2(MLA-absorb),文档与 Python 侧调用均按此执行,切勿照抄定义文件的初始值。
输出张量
| 参数名 | 输入/输出/属性 | 描述 | 数据类型 | 数据格式 |
|---|---|---|---|---|
| output | 输出 | 代表公式中的输出 Attention。输出的 token/head 维度与 query 一致,最后一维为 512。layout_query 为 "BSND" 时 shape 为 [B, Q_S, Q_N, Q_out_D];为 "TND" 时 shape 为 [Q_T, Q_N, Q_out_D],其中 Q_out_D = Q_D - rope_head_dim | FLOAT16、BFLOAT16 | ND |
| softmax_max / softmax_sum | 输出 | return_softmax_lse 为 False 时均为空张量;A2/A3 为 True 时,layout_query 为 "BSND" 的 shape 为 [B, KV_N, Q_S, Q_N/KV_N],为 "TND" 的 shape 为 [KV_N, Q_T, Q_N/KV_N] | FLOAT32 | ND |
输出张量的 shape 推导逻辑与文档完全一致,可在 infershape 实现 中验证:attention 输出在 BSND 下为 4 维、TND 下为 3 维,最后一维均为query 对应维 - rope_head_dim;return_softmax_lse=False时 softmax_max/softmax_sum 被置为 1 维且长度为 0 的空张量。对应地,Torch 适配头文件 中construct_kv_quant_sparse_flash_attention_output_tensor会按上述规则分配attention_output、softmax_max、softmax_sum三块内存,并最终通过EXEC_NPU_CMD(aclnnKvQuantSparseFlashAttention, ...)下发执行——这正是 PyTorch 侧npu_kv_quant_sparse_flash_attention自定义入口的底层实现。
约束说明
- 该接口支持图模式。
- query shape 约束:Atlas A3 系列、Atlas A2 系列产品中 Q_N 不支持 48(A5 的 Q_N 支持列表见上文 query 参数说明)。
- key、value 数据类型要求:
- Ascend 950PR&950DT 系列:仅支持 float8_e4m3、int8、hifloat8;
- Atlas A3 系列、Atlas A2 系列:仅支持 int8。
- sparse_block_size 约束:
- Ascend 950PR&950DT 系列:只支持 sparse_block_size 为 1;
- Atlas A3 系列、Atlas A2 系列:支持 [1,16],且要求是 2 的幂次方;PageAttention 场景下要求 sparse_block_size 能整除 block_size。
- 非 PageAttention 场景下,layout_query 和 layout_kv 的取值需要保持一致。
内核实现结构:模板化调度与 AIC/AIV 分工
从源码结构看,该算子的执行内核(kv_quant_sparse_flash_attention.cpp)采用高度模板化的 C++ 调度框架,编译期通过FLASH_DECODE、PAGE_ATTENTION、LAYOUT_T、KV_LAYOUT_T、TEMPLATE_MODE、IS_SPLIT_G等模板参数组合出不同变体,并在运行时依据 query/key 的数据类型组合(BF16+FP8、BF16+HIFLOAT8、BF16+INT8、FP16+FP8、FP16+HIFLOAT8、FP16+INT8)分派到BaseApi::KvQuantSparseFlashAttentionMla模板类。
在 arch35(对应 Ascend 950 系)专用路径中,公共头文件 定义了QSFA_LAYOUT(BSND/TND/PA_BSND)、QSFATemplateMode(SWA/CFA/SCFA 三种模板模式)等枚举,并将算子任务拆分为MatmulService(Cube/AIC 核)与VectorService(AIV 核)两类服务:AIC 核负责 QK 矩阵乘、PV 矩阵乘等矩阵运算,AIV 核负责 softmax、反量化、scale 乘法等向量运算,二者通过 TPipe 流水配合。这种"AIC 算矩阵、AIV 算向量"的异步并行设计,正是该算子支撑大 KV_S 长序列场景的关键结构。此外,内核的 tiling 数据通过 tiling 头文件 中的KvQuantSparseFlashAttentionTilingDataMla结构在 host 侧计算并下传。
A2/A3 C8 NoPE(rope_head_dim=0)路径
本节描述 A2/A3 的 INT8 C8 路径;A5 的 INT8/FLOAT8_E4M3FN 扩展见下一节。两种输入合同如下:
| rope_head_dim | Q 最后一维(元素) | packed Key 每行(字节) | scale 起始偏移(字节,从 0 开始) | 有效 V / output 最后一维 |
|---|---|---|---|---|
| 0 | 512 | 528 = 512 INT8 NoPE + 4 FLOAT32 scale | 512 | 512 |
| 64 | 576 | 656 = 512 INT8 NoPE + 64 FP16/BF16 RoPE + 4 FLOAT32 scale | 640 | 512 |
表中的 V 维度指有效计算数据。算子调用时 Key/Value 可复用同一份 528 或 656 字节的 packed 缓存。
rope_head_dim=0 表示输入中没有 RoPE 分支,不需要调用方补齐 64 维 RoPE。内核会跳过 RoPE 输入读取,在内部原有计算区域补零,保留原计算分块和缓冲区大小——这使紧凑输入与相同 NoPE、scale、稀疏索引及页表下的"显式补零 RoPE"输入保持功能一致;调用方传入的 scale_value 保持不变。输出仍为 512 维,return_softmax_lse与图捕获/重放接口保持不变。
packed 每行字节数的计算同样可以在 Python 侧印证:get_sfa_qsfa_packed_head_dim 的实现为kv_lora_rank + qk_rope_head_dim * bfloat16字节数 + (kv_lora_rank / tile_size) * float32字节数,以 kv_lora_rank=512、rope=0、tile=128 代入即得512 + 0 + 4*4 = 528字节;rope=64 时代入得512 + 64*2 + 16 = 656字节,与文档表中的 528/656 完全对应。
测试入口
在仓库根目录、已编译并安装自定义算子的 A2/A3 环境中运行:
python -m pytest -sv tests/e2e/nightly/single_node/ops/singlecard_ops/test_kv_quant_sparse_flash_attention.py python -m pytest -sv tests/e2e/nightly/single_node/ops/singlecard_ops/test_kv_quant_sparse_flash_attention_rope0.py原测试继续使用原有随机 golden 和精度阈值。新增的 rope0 测试 共 53 项,仅在 A2/A3 硬件配置上运行,覆盖以下维度:
- 布局与分页:BSND + PA_BSND、TND + PA_BSND(块尾)、TND + TND(packed),以及 batch、尾块等边界;
- 数据与精度:FP16/BF16 双 dtype、rope0/64 双 RoPE 配置、LSE 开关(False/True);
- 图模式:NPUGraph 捕获后修改 KV 缓存并重放的场景(
test_rope_graph_capture_replay); - 合法性与错误路径:
test_rope_invalid_shape_or_dimension覆盖非法 RoPE 维度(-1/32/128 等)与非法输入 shape(Q 最后一维与 key 每行字节数不匹配),验证算子会按预期抛错; - 对照策略:随机紧凑输入与显式补零输入做逐位对照(
torch.equal);均匀 attention 用例以独立计算的"选中 V 均值"验证精度,并校验有效 query 行的 softmax_max、softmax_sum 及 LSE(LSE = softmax_max + log(softmax_sum) = log(有效 token 数)); - 端到端接入:
test_rope0_python_quant_cache_attention_pipeline调用真实 RMSNorm/INT8 量化(custom_kv_rmsnorm_rope)、cache 写入(_store_parallel_kv)与 attention 路径(_execute_sparse_flash_attention_process),验证空 RoPE(输出 shape 的 RoPE 维为 0)、FLOAT32 scale 字节布局、slot=-1 不写 cache 的哨兵行为,以及独立均值精度。
Python SFA 接入
A2/A3 的 C8 NoPE 接入复用现有 SFA 接口:量化并打包 INT8 NoPE 和 FLOAT32 scale,跳过空 RoPE 旋转,再调用自定义 QSFA 算子。缓存规格继续读取原有模型全局配置;本次不修改 V1/V2 的缓存分配逻辑。模型配置与当前层的 RoPE 维度均为 0 时,packed 缓存为 528 字节。全局 RoPE 维度为 64 而当前层为 0 的混合配置,不在本次模型接入范围内。浮点 NoPE 继续使用原有计算路径,本次不扩展 C8 NoPE 的上下文并行模型接入。
模型只有在选择 SFA 且enable_sparse_sfa_c8=True时才会进入 C8 量化路径,因此不需要额外的设备类型拦截。在 Python 侧,sfa_v1.py 中enable_sparse_sfa_c8的派生逻辑位于 ascend_config.py:vllm_config.cache_config.cache_dtype in ["fp8", "int8"]且模型使用 SFA 稀疏(或 kpool-indexer 模型)时自动置为 True,用户可通过--enable-sparse-sfa-c8显式控制(默认 False,见 ascend_config.py)。同时注意,稀疏 KV offload 与 SFA C8 主缓存不兼容,ascend_config.py 会在二者同时启用时直接抛出 NotImplementedError。
Ascend 950 INT8/FP8 C8 NoPE(rope_head_dim=0)
A5 复用现有 C8 接口和 NoPE512 布局,key/value 数据类型支持 INT8 和 FLOAT8_E4M3FN。每 128 个 NoPE 元素共享一个 FLOAT32 scale,每行包含 4 个 scale:
| rope_head_dim | Q 最后一维(元素) | packed Key 每行(字节) | scale 起始偏移(字节,从 0 开始) | output 最后一维 |
|---|---|---|---|---|
| 0 | 512 | 528 = 512 INT8/FP8 NoPE + 4 FLOAT32 scale | 512 | 512 |
| 64 | 576 | 656 = 512 INT8/FP8 NoPE + 64 FP16/BF16 RoPE + 4 FLOAT32 scale | 640 | 512 |
A5 场景使用attention_mode=2、key_quant_mode=2、value_quant_mode=2、quant_scale_repo_mode=1、tile_size=128和sparse_block_size=1。RoPE0 场景下调用方无需提供补零的 RoPE 数据,scale_value保持模型原值。A5 当前只写 attention 输出,应使用return_softmax_lse=False。HiFloat8 继续仅支持原有 RoPE64 路径。
从内核实现看(arch35 公共头文件中针对 672 字节 UB 行跨距的处理),内核按实际输入维度读取 GM 数据和 scale,保留原有 672 字节 UB 行跨距,并在缓冲区复用时清零缺失的 RoPE 区域;Q 输入准备会先初始化内部 NZ 缓冲区,再拷贝 512 个有效列;576 维 QK 计算、512 维 value/output 计算和原有 softmax 路径保持不变。这一"保留内部计算布局、仅按输入裁剪读取"的设计,使 528/656 两种紧凑缓存能与既有浮点 SFA 计算路径无缝共存。
端到端调用链:从模型层到自定义算子
将以上源码证据串起来,QSFA 在 vLLM Ascend 中的完整调用链如下:
- 模型层:AscendSFAImpl 在初始化时依据
enable_sparse_sfa_c8决定使用 C8 packed KV 缓存,并通过get_sfa_qsfa_packed_head_dim计算每行字节数;KV 写入时用custom_kv_rmsnorm_rope完成 RMSNorm + 动态块量化(npu_dynamic_block_quant,tile_size=128),将 k_nope(INT8/FP8)与量化 scale 打包进缓存。 - 调度层:DeviceOperator.execute_sparse_flash_attention_process 根据
kv_cache[0]的 dtype 路由:dtype 为 int8 / float8_e4m3fn / float8_e5m2 时走_execute_kv_quant_sparse_flash_attention,否则走原有浮点npu_sparse_flash_attention。 - 算子层:RoPE0 场景固定路由到本仓库自定义算子
torch.ops._C_ascend.npu_kv_quant_sparse_flash_attention(其 C++ 入口见 torch_adpt.h);RoPE64 场景可复用 torch_npu 内置 aclnn 算子,但内置算子没有 RoPE0 合同(会按 rope_head_dim=64 计算输出尺寸并在注册时出错),因此 RoPE0 必须走自定义算子——这一点在 device_op.py 中有明确注释。 - CANN 算子执行层:
aclnnKvQuantSparseFlashAttention依据 算子定义 完成参数校验,infershape 推导输出 shape,tiling 计算分块参数后,由模板化内核在 AIC/AIV 双核流水上执行。
值得注意的是,实测调用中 Python 侧传入的参数(来自 device_op.py)为layout_query="TND"、layout_kv="PA_BSND"、sparse_block_size=1、attention_mode=2、quant_scale_repo_mode=1、key_quant_mode=2、value_quant_mode=2、sparse_mode=3,与文档要求逐一对应;而原 e2e 测试(test_kv_quant_sparse_flash_attention.py)则以BSND + PA_BSND布局构造 batch=1、query_seq=1、kv_seq=4096、Q_N=64、KV_N=1、block_size=256、sparse_block_count=2048 的典型 decode 场景,两种布局路径均被覆盖。
使用建议与注意事项
- 按设备选择参数:A2/A3 仅支持 INT8 key/value 与
sparse_block_size ∈ [1,16](2 的幂次方),A5 支持 INT8/FP8/HiFloat8 但sparse_block_size仅支持 1;A5 还需使用return_softmax_lse=False。 - 布局一致性:非 PageAttention 场景下 layout_query 与 layout_kv 必须一致;TND 布局下 actual_seq_lengths_query / actual_seq_lengths_kv 必须显式传入前缀和形式。
- sparse_indices 排列:每行有效索引必须集中在前半部分、无效值(-1)在后半部分,sparse_size 必须大于 0。
- 量化参数打包:采用 quant_scale_repo_mode=1(combine 模式),4 个 FLOAT32 scale 紧随 NoPE/RoPE 数据之后,起始偏移 512(rope0)或 640(rope64)字节——在自研量化与打包逻辑时,务必与 528/656 字节的逐行布局对齐。
- C8 与稀疏 KV offload 互斥:
enable_sparse_sfa_c8与稀疏 KV offload 不可同时开启,否则会抛出 NotImplementedError;如需 offload,应关闭该开关并改用enable_sparse_li_c8(索引器缓存仍驻留设备)。 - 图模式与重放:算子支持图捕获与"修改 KV 后重放"(NPUGraph replay),但重放时 packed K 与 raw V 需同步更新;A2/A3 下 LSE 输出可用于 DCP 场景的 softmax max/sum 合并。
以上内容均基于当前仓库的 算子 README、算子注册定义、infershape、模板化内核实现以及 e2e 测试与 Python 接入代码交叉印证,可作为接入与排查 Sparse Attention C8 量化路径的直接参考。
- 人工智能
- 大模型
- 模型推理服务
- Ascend
- CANN
【免费下载链接】vllm-ascend
Community maintained hardware plugin for vLLM on Huawei Ascend
相关推荐
CANN ops-transformer 算子深度解析:kv_quant_sparse_flash_attention 量化稀疏注意力实战指南
CANN ops transformer 算子深度解析:kv_quant_sparse_flash_attention 量化稀疏注意力实战指南 本指南聚焦 CA
算子库人工智能大模型深度学习CANNAscendDagger TypeScript SDK `FieldTypeDef` 类完全指南:理解模块自定义对象的静态字段类型定义
Dagger TypeScript SDK FieldTypeDef 类完全指南:理解模块自定义对象的静态字段类型定义 本篇技术指南聚焦 Dagger v0.2
人工智能大模型模型推理服务AscendCANNvllm-ascend 稀疏注意力索引算子 QuantLightningIndexerV2 深度解析:量化存8算8与 Top-k 前处理实战
vllm ascend 稀疏注意力索引算子 QuantLightningIndexerV2 深度解析:量化存8算8与 Top k 前处理实战 QuantLigh
人工智能大模型模型推理服务AscendCANN
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考