[Vulkan] FA f16-scratch fast path never enabled for hybrid-model (non-unified) KV caches

该报错通常出现在混合架构模型(如 Qwen3.8,包含 DeltaNet/SSM 层)在 Vulkan 后端运行量化 KV 缓存时,Flash Attention 的 f16-scratch 快速路径未被触发,导致 prefill 性能显著下降。优先检查 `ggml_vk_flash_attn()`

快速结论:该报错通常出现在混合架构模型(如 Qwen3.8,包含 DeltaNet/SSM 层)在 Vulkan 后端运行量化 KV 缓存时,Flash Attention 的 f16-scratch 快速路径未被触发,导致 prefill 性能显著下降。优先检查 `ggml_vk_flash_attn()` 中 `is_dense_kv_cache` 的判定条件是否过严。

适用环境:llama.cpp master(2026-08-30 版本)、Vulkan 后端、AMD Radeon RX 9070(RDNA4)、Windows;模型为 Qwen3.8-27B(qwen35 架构,混合:16 个 attention 层 + SSM 层,非统一 KV 缓存)。

最快修复方案:暂无官方合并的 PR;Issue 作者已确认问题并计划提交修复 PR,将 `is_dense_kv_cache` 中的维度 3 检查改为 `(t->ne[3] == 1 || t->nb[3] == t->nb[1]*t->ne[1])`。

注意事项:该修复方案已在本地测试通过,但尚未作为 PR 合并;`t->nb[3] >= t->nb[1] * t->ne[1]` 的宽松写法可能导致正确性错误,不建议采用。修复仅验证于 Qwen3.8 模型,其他混合架构模型效果未确认。

问题场景

用户在 llama.cpp 的 Vulkan 后端运行混合架构模型(如 Qwen3.8,包含 DeltaNet/SSM 层)时,发现 Flash Attention 的 f16-scratch 快速路径(`use_dequant_kv`)从未被启用。该问题导致所有量化 KV 缓存的 prefill 速度显著下降。

报错原文

[Vulkan] FA f16-scratch fast path never enabled for hybrid-model (non-unified) KV caches

原因分析

可能原因是 `ggml_vk_flash_attn()` 中的 `is_dense_kv_cache` 判定逻辑过于严格。对于混合模型,KV 缓存是非统一的(`kv_unified=false`),`get_k()` 返回的视图仅覆盖 `n_kv` 个单元,导致 `nb[3]` 是全缓存步长(kv_size 单元),而 `ne[1]` 仅为 `n_kv`(已用单元)。因此等式 `nb[3] == nb[1]*ne[1]` 永远不成立,快速路径对所有量化 KV 类型都被禁用。

Issue 作者进一步确认,该问题并非混合架构所独有——当前 `use_dequant_kv` 路径仅在 KV 缓存满载时(`n_kv == kv_size`,如 llama-bench 场景)才会启用。

环境排查

  • 确认 llama.cpp 版本是否为 2026-08-30 的 master 版本或之后
  • 确认 Vulkan 后端是否启用
  • 检查模型是否为混合架构(如 Qwen3.8,包含 SSM/DeltaNet 层)
  • 确认 KV 缓存类型为量化类型(非 f16/f32)
  • 确认是否使用了非统一 KV 缓存(`kv_unified=false`)
  • AMD Radeon RX 9070(RDNA4)或其他 Vulkan 支持显卡

解决步骤

  1. 定位 `ggml_vk_flash_attn()` 函数中的 `is_dense_kv_cache` lambda 表达式。
  2. 将原判定条件中的维度 3 检查从 `t->nb[3] == t->nb[1] * t->ne[1]` 修改为 (t->ne[3] == 1 || t->nb[3] == t->nb[1] * t->ne[1])
  3. 完整修改后的判定条件应为:
    auto is_dense_kv_cache = [](const ggml_tensor * t) {
        return t->nb[0] == ggml_type_size(t->type) &&
               t->nb[2] == ggml_row_size(t->type, t->ne[0]) &&
               t->nb[1] == t->nb[2] * t->ne[2] &&
               (t->ne[3] == 1 || t->nb[3] == t->nb[1] * t->ne[1]);
    };
  4. 重新编译 llama.cpp 并测试。

可优先尝试:如果不想自行修改代码,可以等待 Issue 作者提交的官方 PR 合并后再更新。

验证方法

使用 Qwen3.8-27B 模型和约 21.5K token 的提示进行 prefill 测试。修复前约 65 tok/s,修复后约 119 tok/s(提升约 83%)。同时建议运行 needle-test 验证输出正确性,确保结果精确无误。可通过 LLAMA_VK_FA_DEBUG=1 环境变量查看每次调用的快速路径决策。

参考来源

ggml-org/llama.cpp #28135

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 21603

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注