Eval bug: Vulkan: count_experts.comp zero_skipped_rows() loops over every id in every thread

该报错出现在 llama.cpp 的 Vulkan 后端使用 MoE(混合专家)模型进行 prompt processing 时, count_experts.comp 中 zero_skipped_rows() 的循环写法导致每个线程遍历所有专家 id,处理大 prompt 时性能明显下降。优先排

快速结论:该报错出现在 llama.cpp 的 Vulkan 后端使用 MoE(混合专家)模型进行 prompt processing 时,count_experts.comp 中 zero_skipped_rows() 的循环写法导致每个线程遍历所有专家 id,处理大 prompt 时性能明显下降。优先排查是否使用了含 MUL_MAT_ID 的 Vulkan MoE 路径,以及是否存在对应的性能回归/修复补丁。

适用环境:Issue 中已确认的环境包括:llama.cpp(Vulkan 后端)、Linux 6.8、AMD RX 7800 XT 显卡、RADV 驱动(Mesa 25.2.8 / Mesa 26.2.5);对照测试使用了 HIP 路径(ROCm 7.0.3,gfx1101)。未提及 Python、CUDA、PyTorch 版本。

最快修复方案:暂无确认的一步修复方案。Issue 中提供了针对 count_experts.comp 的补丁,并已开草稿 PR #31266,可在该环境优先尝试;测试者反馈补丁生效,pp2048 提升约 5%–42%(随模型和驱动版本不同),test-backend-ops 全部通过。

注意事项:该补丁主要恢复的是 #26631 引入的回归,issue 讨论中对“单个线程清零整行”在跳过行数很多或每行很大时是否变慢仍有顾虑,因此该改法尚未被认定为最终方案。生成阶段(tg128)基本不受影响。

问题场景

用户在 llama.cpp 的 Vulkan 后端上运行 MoE(混合专家)模型,例如 granite-3.1-3b-a800m、DeepSeek-V2-Lite-Chat 16B、gpt-oss-20b、Qwen3.6-35B-A3B 等,并使用 llama-bench 做 prompt processing(pp2048)基准测试时触发问题。在 ggml/src/ggml-vulkan/vulkan-shaders/count_experts.comp 中,zero_skipped_rows()(来自 #26631)的循环把专家 id 遍历放在外层、线程 id 放在内层,导致每个线程都遍历所有专家 id,而不是只处理属于自己的 id。表现为 prompt processing 性能下降,prompt 需要的 block 越多,问题越明显。

报错原文

Eval bug: Vulkan: count_experts.comp zero_skipped_rows() loops over every id in every thread

原因分析

最可能的原因是 zero_skipped_rows() 中的循环顺序写反了:原实现为

for (uint idx = 0; idx < num_elements; idx++) {
    ...
    for (uint i = tid; i < p.ne0_dst; i += BLOCK_SIZE) {
        data_dst[d_off + i] = 0.0f;
    }
}

这使得外层每个线程都遍历全部 num_elements,而不是按线程分片处理。讨论中指出这是一个线性问题:每个 block 都重复对专家做循环,prompt 需要的 block 越多,Vulkan 上的劣化越明显。这属于性能缺陷而非崩溃性错误,生成阶段因只处理一个 token,基本不受影响。

环境排查

  • 确认是否使用 Vulkan 后端运行含 MoE 的模型(触发 MUL_MAT_ID 路径),并记录 prompt 长度相关参数(如 -ub 2048)。
  • 确认 llama.cpp 提交版本;Issue 的基准测试基于 master 2280f0fd,与 #26631 之后的行为相关。
  • 确认 Vulkan 驱动版本(Issue 中为 RADV / Mesa 25.2.8 与 Mesa 26.2.5)。
  • 若做 HIP 对照,确认 ROCm 版本(Issue 中为 ROCm 7.0.3,gfx1101)。
  • 确认显卡型号(Issue 中为 RX 7800 XT);Issue 未给出 Python、CUDA、PyTorch 版本信息。

解决步骤

  1. 在 Vulkan 环境下用 llama-bench 复现基线性能,例如:llama-bench -m <model.gguf> -ngl 99 -fa 1 -lm none -ub 2048 -p 512,2048 -n 128 -r 3,记录 pp2048 与 tg128。
  2. 确认问题源自 ggml/src/ggml-vulkan/vulkan-shaders/count_experts.comp 中 zero_skipped_rows() 的循环结构。
  3. 可优先尝试 Issue 中给出的补丁(Opus 5.5 编写、提交者已测试):外层改为 for (uint idx = tid; idx < num_elements; idx += BLOCK_SIZE),内层改为 for (uint i = 0; i < p.ne0_dst; i++)。
  4. 或优先尝试草稿 PR #31266 中的潜在修复。
  5. 应用后重新编译 Vulkan 后端,并运行 test-backend-ops -b Vulkan0(Issue 中 21303 项全部通过,含 MUL_MAT_ID 1109/1109 与 170 个 skip case)以及 test-backend-ops -o MUL_MAT_ID(1109/1109 通过)。
  6. 用相同命令重跑基准测试,对比 pp2048 变化;tg128 预期基本不变。

验证方法

功能上,test-backend-ops(Vulkan 全量或 -o MUL_MAT_ID)全部通过即说明算子行为未被破坏。性能上,在相同模型和参数下对比补丁前后 pp2048:测试者在 RX 7800 XT 上得到 granite-3.1-3b-a800m 约 +35%~+42%、Qwen3-16B-A3B 约 +14.5%~+17.7%、GPT-OSS-20B 约 +6%~+7.5%,密模型对照组约 -1%(噪音范围);tg128 几乎不变。不同模型、驱动版本的增幅不同,以本机实测为准。

参考来源

ggml-org/llama.cpp #31163

相关 PR:ggml-org/llama.cpp #31266(草稿修复);相关回归来源:ggml-org/llama.cpp #26631。

GamsGo AI

AI 工具推荐

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

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

了解 GamsGo AI

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

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 32041

发表回复

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