跳转至

DeepSeek V4.1 QLI V2 与候选集成

DeepSeek V4.1 的索引器使用 QuantLightningIndexerV2,带有分页 INT8 索引 K。 导入的算子源码来自 ops-transformer-qli_candidate.zip, SHA256 771f0c16b9119c676c10cebef713b168f127ff194f3f2f98edcbcd0979c6f966。 其配套的 QuantLightningIndexerV2Metadata 也已构建并注册。

数据流

DeepseekV41Indexer.select 投影 Q 和头权重并应用 RoPE。 select_projected 将每个 Q 头量化为 INT8,并带有可表示的 FP16 scale。头权重和 K scale 为 FP16。现有的由源码管理的 K-cache 更新保持不变。

该算子直接消费 TND Q 和 PA_BBND 索引 K。DeepSeek V4.1 的 四槽位层级最外层分配器在共享页内将索引 K 和 FP16 scale 打包在 KV 之后。 C2 使用 64 行视图,块跨度为 131072 字节; C1 使用 128 行视图,块跨度为 147712 字节。Torch 适配器将 它们的实际前导步幅传递给 ACLNN。 两种布局都不需要将整个上下文收集到稠密张量中。

元数据接收原始查询边界、压缩后的 K 长度,以及 原始序列长度对压缩比的取模。当压缩比为 1 时,残差张量 必须不存在。在 A2/A3 上,本仓库仅编译模型的 TND/PA_BBND 布局;BSND 和非分页调用会被主机端校验拒绝。 A5 保留其通用的 QLI 数据类型、布局和量化支持。

三种候选模式共享同一个原生算子:

模式 含义 结果
1 候选源 未过滤的位置 TopK 和候选块 ID
2 候选消费者 使用本层的 Q 和权重在源块内重新排序
3 候选禁用 普通位置 TopK

候选是形状为 [tokens, 1, candidate_topk_blocks] 的 INT32 块 ID, 使用 -1 填充。它们既不是索引 K 向量,也不是位置 TopK。一个块 包含 8 个压缩位置。块分数使用最大位置分数; 最后一个可见块被固定。共享注意力状态在前向传播内保留该张量, 并在下一次前向传播时重置。

模型按时间顺序对返回的位置索引排序,并在注意力之前将 -1 填充移动到末尾。空的压缩上下文返回空索引,并且对于源而言, 返回全部无效的候选。没有源的消费者会引发错误。

当前 A3 契约

  • INT8 Q/K,FP16 头权重以及逐头 Q/逐 token K scale;量化模式 2。
  • 32 或 64 个复制的索引头,头维度 128,一个索引 K 头。
  • DeepSeek V4.1 压缩比 1 和 2,因果掩码模式 3。
  • 位置 TopK 在 [1, 2048] 范围内;候选块为 [64, 2048] 中 64 的倍数。
  • 在此内核实现中,候选块大小恰好为 8。
  • 编译包中仅包含 TND 查询和 PA_BBND 键布局。
  • A3 算子返回索引和候选 ID,不返回分数值。

数值参考遵循提供的 INT8 golden:INT32 QK 除以 1024,FP16 ReLU 和 weight * Q_scale,FP32 头归约,然后 K 缩放。 查询量化和 FP16 权重舍入与早期的浮点 Q 小算子路径不同。算子与此量化参考的一致性并不能 确立完整模型或数据集的精度。

构建与回归覆盖

在配套的 CANN/NPU 环境中使用 pip install -v -e . --no-deps --no-build-isolation 构建。两个新符号都已在 PrivateUse1 和 Meta 上注册。

针对候选生成/消费、混合请求、分页视图、Meta 形状以及槽位支撑的 SparseFlashMla 的独立算子级 E2E 覆盖 暂缓进行。下面的端到端结果描述的是原始布局。

导入的主机端分块需要一处语义修复:TND 候选大小为 T * N_k * blocks,因为 T 已经包含了每个请求。再次乘以 批大小会错误地拒绝混合请求消费者。内核偏移 已经使用 TND 查询前缀,不需要相应更改。

验证包括单芯片 eager 和 Meta 契约,以及在一台 A3 服务器上使用 TP4/DP4/EP16 的完整 40 层 W8A8 检查点(Engram 和 DSpark 已禁用)。四个端到端用例各在温度 0、 种子 7 下运行两次:算术、首都城市查询、多轮回忆,以及一个 20,032 token 的检索提示。两次运行都返回了预期答案和完全相同的输出 token。长提示超过了 16,384 位置的候选块预算。 它使用实际的候选过滤来执行分块预填充和解码。

检查点提供的 encoding.encode_messages(..., thinking_mode="chat") 与 /v1/completions 一起使用;该检查点不提供标准的 聊天模板。重复输出的一致性验证了这些固定的功能 用例,而非基线对比候选的数据集精度比较。图模式、 64K/128K 请求、多节点执行、Engram 和 DSpark 仍未验证。

编译范围

DeepSeek V4.1 的 A2/A3 路径使用 INT8 Q/K、FP16 权重/scale 和量化模式 2。其 编译后的 QLI V2 模板矩阵只有 1 个键,从 4 个缩减而来。A5 保留完整的 16 键矩阵,包括分页 BSND/TND 查询以及对应的非分页 BSND/TND 布局。A5 数据类型注册、主机端校验和内核分发保留 FP8、MXFP8、HiFloat8、MXFP4 和 INT8(分别对应量化模式 1/3/4/5/2)。 DeepSeek V4.1 的 INT8 调用点并不能证明其他 A5 路径未被使用。 两种架构都保留其原始的模板参数编码。

候选模式 1/2/3、压缩比、TopK 和序列长度仍然是 运行时参数。A2/A3 候选实现和 A5 实现 仍然在独立的架构分支中。此裁剪不会添加 A5 候选 支持,也不会改变默认 A5 包构建的算子:QLI V2 和 SparseFlashMla 目前包含在 A2/A3 包列表中。这些算子的显式 A5 构建使用 A5 模板选择。

SparseFlashMla 同样被限制为模型的 BF16 TND/PA_BBND SWA/CSA 调用。它在 A2/A3 上编译 6 个键,在 A5 上编译 12 个;共享键在两者上都保留, 而单头 CSA 特化仅限 A2/A3,拆分 G/向量化 寻址仅限 A5。HCA、独立的原始 KV 稀疏模板、其他布局 和 FP16 在两种架构上都被排除。主机端校验在内核查找之前拒绝 被裁剪的契约。完整编译矩阵见 csrc/attention/sparse_flash_mla/docs/ratio2_a2a3.md。 HcPre 已经将 A2/A3 键 0 与 A5 键 1000/1001 隔离;两个 A5 路径都可以 由运行时 token 计数选择,因此两者都不会被移除。

融合 Compressor 服务于 DeepSeek V4;V4.1 当前使用小型算子进行压缩。Compressor 已按架构选择四个键:TH/BF16、交错 RoPE、连续缓存以及 coff=1/2,并采用 FP32 RoPE。A2/A3 选择 EMPTY_X/PERF;A5 选择 NORMAL/EMPTY_X。两个 coff 值分别覆盖 V4 的 128 和 4 压缩比,并且仍支持空输入。A5 FULL_LOAD 需要 BSH,因此已被排除。主机端和内核端源码针对 arch32(A2/A3)和 arch35(A5)分别选择。

Compressor 的 dtype 注册现在与这些既有选择保持一致:每个架构一个签名,A2/A3 从四个减少为一个,A5 从两个减少为一个。Norm 权重在 A2/A3 上保持 BF16,在 A5 上保持 FP32。主机端校验同样会拒绝未编译的布局、dtype 和模式。空输入入口使用一个被丢弃的 else 分支,以便编译器不会在无条件返回之后实例化计算内核。这四个键本身及其编码保持不变。

仅 CPU 的模板回归测试可以在不导入 torch 或 CANN 的情况下运行:

python3 -m unittest discover -s tests/ut/ops -p test_aurora_tiling_keys.py -v

它会检查预处理器选择、架构隔离、模型布局调用、dtype 注册以及未改变的参数编码。它还会针对拒绝不需要的模板实例化的桩代码编译真实的 Compressor 入口,包括针对 EMPTY_X 的任何计算。它不会测量 CANN 构建时间,也不会执行 NPU 内核。在数值回归之前重新构建算子包;仅保留的键数量本身并不能证明实际耗时加速。

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 vl/vllm-ascend