ik_llama.cpp GQA 模型 CPU 解码提速:PR #332 的 TG 性能优化与 FA 收益分析
【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp
本篇技术指南围绕 ik_llama.cpp 合并自 PR #332 的改进展开,介绍该项目如何在纯 CPU 环境下针对 GQA(Grouped-Query Attention)架构模型(LLaMA-2+、Gemma 系列等)提升 TG(Token Generation,逐 token 解码)性能。文章完整复现了 PR 中使用的llama-sweep-bench基准方法与关键数据,并结合仓库源码剖析K*Q与V*softmax(K*Q)矩阵乘法在 Flash Attention(FA)开关下的线程分配差异,帮助读者理解 GQA 模型在 CPU 上的计算瓶颈与优化思路,同时掌握在 ik_llama.cpp 中复现这套基准实验的完整操作。
背景:GQA 模型在 CPU 解码阶段的性能瓶颈
在多轮对话与长上下文的实际使用中,模型的生成阶段(TG)是主要的耗时环节。对于 LLaMA-2 及之后的 LLaMA 系列、Gemma 系列等 GQA 架构模型,每次生成一个 token 都需要执行两次关键的矩阵运算:
K*Q:查询向量与键缓存(KV cache)的注意力分数计算;V*softmax(K*Q):注意力分数加权后的值缓存聚合。
这两个矩阵乘法的形状由「KV 头的数量」与「KV cache 中已缓存的 token 数(N_KV)」共同决定。当只生成 1 个 token 时,Q 矩阵的行数等于 KV 头数(而非全部注意力头数),这使得传统上按 GEMV(矩阵-向量乘)方式调度的计算,在头数较少、行数很少时无法充分利用多核 CPU 的并行能力。
在 PR #332 之前,ik_llama.cpp 的 CPU 路径对这两个乘法在开启与关闭 FA 时的收益并不均衡;PR #332 的核心思路是:改变K*Q与V*softmax(K*Q)两个矩阵乘法之间的线程(threads)分配方式,将计算更合理地分摊到各线程上,从而在 GQA 模型上获得 TG 性能提升。从仓库当前的注意力构建代码可以看到,这两个乘法位于 build_llama.cpp 的llm_build_kv与build_std_attention调用链中(KQ_mask、kq_scale、kv_head、n_kv等参数均在此处汇聚),PR 正是围绕这一调用链的 CPU 后端实现进行的调度调整。
优化效果概述:FA 在 TG 阶段由劣势转为优势
根据 PR 描述,改进带来的收益分两种情况:
- 未启用 FA(no-FA):性能提升相对较小,主要来源于上述线程分配的重新平衡;
- 启用 FA(Flash Attention):性能提升非常显著,且FA 在 TG 阶段首次全面超越 no-FA。
这一结论很重要:此前在部分场景中 FA 主要被视作提示词处理(PP)阶段的加速手段,而 TG 阶段往往因为单 token 的形状限制而收益有限。PR #332 之后,GQA 模型在 CPU 上开启 FA 进行解码同样能获得可观收益。
从实现层面看,ik_llama.cpp 的 FA 路径由ggml_flash_attn_ext提供(例如 build_deepseek2.cpp 中ggml_flash_attn_ext_set_prec(kqv, GGML_PREC_F32)的用法),其开关由cparams.flash_attn控制,最终通过公共参数-fa, --flash-attn (auto|on|off|0|1)暴露给用户,参数解析位于 common/common.cpp 的选项表(第 3079-3080 行),同时支持环境变量LLAMA_ARG_FLASH_ATTN与-no-fa, --no-flash-attn反向关闭。FA 关闭时若 V-cache 为量化类型,框架还会强制将 V-cache 视作 f16 处理(common/common.cpp 中if (!cparams.flash_attn && ggml_is_quantized(cparams.type_v))的检查),这与 PR 中「V-cache 在未启用 FA 时为 f16」的测试前提完全对应。
基准方法:使用 llama-sweep-bench 复现实验
PR 作者使用仓库自带的llama-sweep-bench工具完成全部测量,其源码位于 examples/sweep-bench/sweep-bench.cpp,说明文档见 examples/sweep-bench/README.md。
工具原理
sweep-bench与普通 benchmark 的区别在于:它不是对整个上下文长度做一次平均,而是按 ubatch 大小的窗口对整个上下文做扫描,在每个窗口内分别测量 PP 与 TG 性能,从而绘制「性能随上下文长度(N_KV)变化」的曲线。其基准流程(摘自 README)为:
- 为上下文中每个 ubatch 大小的窗口:生成
ubatch/4个 token(节省时间,不生成整个窗口); - 测量生成(TG)性能;
- 将生成的 token 从 KV cache 中移除;
- 准备一批
ubatch大小的随机 token; - 处理该批次(PP);
- 测量提示词处理(PP)性能。
复现命令
PR 中给出的完整命令为:
./bin/llama-sweep-bench -m $model -c 10240 -ctk q8_0 -ctv q8_0 -t 32 -fa各参数含义如下:
| 参数 | 含义 | PR 测试取值 |
|---|---|---|
-m, --model | 模型文件路径(GGUF) | LLaMA-3.1-8B-Instruct / Gemma3-12B-Instruct,均Q4_0量化 |
-c, --ctx-size | 上下文总长度 | 10240(后续复跑扩展到 16k) |
-ctk, --cache-type-k | K-cache 量化类型 | q8_0 |
-ctv, --cache-type-v | V-cache 量化类型 | q8_0(no-FA 时实际按 f16 生效) |
-t, --threads | CPU 线程数 | 32 |
-fa, --flash-attn | 是否启用 Flash Attention | 启用 |
sweep-bench每次运行会以 JSON 行格式输出每个窗口的测量结果,字段包括n_kv_max(最大上下文)、n_batch、n_ubatch、flash_attn、n_threads、pp(每窗口 PP token 数)、tg(每窗口 TG token 数)、n_kv(当前 KV cache 大小)、t_pp/speed_pp/t_tg/speed_tg等(对应输出代码位于 sweep-bench.cpp 第 416-425 行)。仓库还提供了绘图脚本 examples/sweep-bench/sweep-bench-plot.py,可将多次运行的 JSON 结果按label分组,绘制 PP/TG 吞吐量随n_kv变化的误差条曲线——PR 讨论中用户正是用该脚本生成了对比曲线并定位了两实现的「交叉点」。
测试环境
- CPU:AMD Ryzen 5975WX(vanilla
AVX2,即未启用 AVX-512 的常规 x86-64 路径); - 模型:LLaMA-3.1-8B-Instruct 与 Gemma3-12B-Instruct,均以
Q4_0量化; - KV cache:
Q8_0(K 与 V);FA 关闭时 V-cache 实际为f16; - 对照组:主线 llama.cpp(build 5139)开启 FA 的结果。
需要说明的是,作者在讨论中指出:该测试机对运行间缓存(page cache)的丢弃与否较为敏感,且结果对 KV cache 分配量也有一定依赖,因此不同批次运行之间存在小幅波动;本文所列数据均为 PR 讨论中作者亲测的原始输出,具体数字会随硬件、量化组合与上下文分配而变,不应视为绝对性能结论。
结果分析:LLaMA-3.1-8B-Instruct(head size = 128)
在 16k 上下文的复跑中,ik_llama.cpp 与主线 llama.cpp 的对比数据如下(PP=512, TG=128,S_TG为生成速度 t/s):
主线 llama.cpp(build 5139,FA 开启)
| PP | TG | N_KV | T_PP s | S_PP t/s | T_TG s | S_TG t/s |
|---|---|---|---|---|---|---|
| 512 | 128 | 0 | 2.737 | 187.04 | 7.548 | 16.96 |
| 512 | 128 | 512 | 3.185 | 160.76 | 7.953 | 16.09 |
| 512 | 128 | 1024 | 3.721 | 137.60 | 8.409 | 15.22 |
| 512 | 128 | 1536 | 4.219 | 121.35 | 8.826 | 14.50 |
| 512 | 128 | 2048 | 4.711 | 108.68 | 9.199 | 13.91 |
| 512 | 128 | 2560 | 5.206 | 98.34 | 9.592 | 13.34 |
| 512 | 128 | 3072 | 5.704 | 89.76 | 9.980 | 12.83 |
| 512 | 128 | 3584 | 6.252 | 81.89 | 10.370 | 12.34 |
| 512 | 128 | 4096 | 6.867 | 74.55 | 10.765 | 11.89 |
| 512 | 128 | 4608 | 7.507 | 68.20 | 11.157 | 11.47 |
| 512 | 128 | 5120 | 8.231 | 62.21 | 11.552 | 11.08 |
| 512 | 128 | 5632 | 9.214 | 55.57 | 11.941 | 10.72 |
| 512 | 128 | 6144 | 10.467 | 48.91 | 12.330 | 10.38 |
| 512 | 128 | 6656 | 11.646 | 43.96 | 12.713 | 10.07 |
| 512 | 128 | 7168 | 13.104 | 39.07 | 13.109 | 9.76 |
| 512 | 128 | 7680 | 14.813 | 34.56 | 13.500 | 9.48 |
| 512 | 128 | 8192 | 16.570 | 30.90 | 13.885 | 9.22 |
| 512 | 128 | 8704 | 18.246 | 28.06 | 14.277 | 8.97 |
| 512 | 128 | 9216 | 20.142 | 25.42 | 14.675 | 8.72 |
| 512 | 128 | 9728 | 21.729 | 23.56 | 15.072 | 8.49 |
| 512 | 128 | 10240 | 23.615 | 21.68 | 15.454 | 8.28 |
| 512 | 128 | 10752 | 25.406 | 20.15 | 15.840 | 8.08 |
| 512 | 128 | 11264 | 27.299 | 18.76 | 16.236 | 7.88 |
| 512 | 128 | 11776 | 29.122 | 17.58 | 16.625 | 7.70 |
| 512 | 128 | 12288 | 31.079 | 16.47 | 17.012 | 7.52 |
| 512 | 128 | 12800 | 33.052 | 15.49 | 17.407 | 7.35 |
| 512 | 128 | 13312 | 34.958 | 14.65 | 17.796 | 7.19 |
| 512 | 128 | 13824 | 37.170 | 13.77 | 18.188 | 7.04 |
| 512 | 128 | 14336 | 39.425 | 12.99 | 18.570 | 6.89 |
| 512 | 128 | 14848 | 41.661 | 12.29 | 18.959 | 6.75 |
| 512 | 128 | 15360 | 43.766 | 11.70 | 19.350 | 6.62 |
| 512 | 128 | 15872 | 46.129 | 11.10 | 19.730 | 6.49 |
ik_llama.cpp(FA 开启)
| PP | TG | N_KV | T_PP s | S_PP t/s | T_TG s | S_TG t/s |
|---|---|---|---|---|---|---|
| 512 | 128 | 0 | 1.638 | 312.56 | 7.739 | 16.54 |
| 512 | 128 | 512 | 1.661 | 308.28 | 7.852 | 16.30 |
| 512 | 128 | 1024 | 1.705 | 300.35 | 7.961 | 16.08 |
| 512 | 128 | 1536 | 1.766 | 289.90 | 8.075 | 15.85 |
| 512 | 128 | 2048 | 1.806 | 283.52 | 8.170 | 15.67 |
| 512 | 128 | 2560 | 1.860 | 275.34 | 8.261 | 15.50 |
| 512 | 128 | 3072 | 1.914 | 267.51 | 8.363 | 15.31 |
| 512 | 128 | 3584 | 1.981 | 258.45 | 8.468 | 15.11 |
| 512 | 128 | 4096 | 2.022 | 253.22 | 8.592 | 14.90 |
| 512 | 128 | 4608 | 2.076 | 246.61 | 8.706 | 14.70 |
| 512 | 128 | 5120 | 2.132 | 240.12 | 8.800 | 14.55 |
| 512 | 128 | 5632 | 2.189 | 233.92 | 8.902 | 14.38 |
| 512 | 128 | 6144 | 2.240 | 228.58 | 8.998 | 14.23 |
| 512 | 128 | 6656 | 2.298 | 222.81 | 9.093 | 14.08 |
| 512 | 128 | 7168 | 2.352 | 217.66 | 9.191 | 13.93 |
| 512 | 128 | 7680 | 2.407 | 212.69 | 9.297 | 13.77 |
| 512 | 128 | 8192 | 2.462 | 207.92 | 9.409 | 13.60 |
| 512 | 128 | 8704 | 2.519 | 203.22 | 9.514 | 13.45 |
| 512 | 128 | 9216 | 2.573 | 199.02 | 9.619 | 13.31 |
| 512 | 128 | 9728 | 2.630 | 194.71 | 9.702 | 13.19 |
| 512 | 128 | 10240 | 2.683 | 190.82 | 9.796 | 13.07 |
| 512 | 128 | 10752 | 2.739 | 186.91 | 9.904 | 12.92 |
| 512 | 128 | 11264 | 2.795 | 183.19 | 10.018 | 12.78 |
| 512 | 128 | 11776 | 2.851 | 179.62 | 10.124 | 12.64 |
| 512 | 128 | 12288 | 2.905 | 176.24 | 10.228 | 12.51 |
| 512 | 128 | 12800 | 2.963 | 172.78 | 10.321 | 12.40 |
| 512 | 128 | 13312 | 3.018 | 169.64 | 10.413 | 12.29 |
| 512 | 128 | 13824 | 3.078 | 166.34 | 10.538 | 12.15 |
| 512 | 128 | 14336 | 3.133 | 163.43 | 10.632 | 12.04 |
| 512 | 128 | 14848 | 3.192 | 160.40 | 10.738 | 11.92 |
| 512 | 128 | 15360 | 3.249 | 157.61 | 10.838 | 11.81 |
| 512 | 128 | 15872 | 3.305 | 154.91 | 10.942 | 11.70 |
从数据可以读出两个关键点:
- PP 差距巨大:ik_llama.cpp 的 PP 从零上下文时的 312.56 t/s 衰减到 16k 时的 154.91 t/s,而主线从 187.04 t/s 暴跌至 11.10 t/s。在 16k 时主线 PP 仅为 ik_llama.cpp 的约 7.2%(约 14 倍差距)。作者据此解释了其在别处对 DeepSeek-V3/R1 观察到的「PP 性能 6 倍下滑」的惊讶——相比之下 ik_llama.cpp 在 16k 时 PP 仅下降约 2 倍(LLaMA-3.1)至 2.3 倍(Gemma3)。
- TG 差异:在零上下文时两者 TG 几乎相同(16.96 vs 16.54 t/s),但随着
N_KV增长,主线的生成速度衰减更快;到 16k 时主线 S_TG(6.49 t/s)仅为 ik_llama.cpp(11.70 t/s)的约 55.5%。不过两条曲线呈现逐渐收敛的走势,说明差距主要来自对长 KV cache 的调度效率,而非短上下文的峰值能力。
作者还指出,主线为优化 head size = 256 场景所做的改动,对 head size = 128(最常见的 head size)产生了严重的负面效果,这正是两个实现在不同架构模型上表现迥异的重要原因。
结果分析:Gemma3-12B-Instruct(head size = 256,8 个 KV 头)
作者在另一组运行中给出了 Gemma3-12B-Instruct 的完整数据(同样Q4_0模型、Q8_0KV cache、FA 开启):
主线 llama.cpp(build 5139,FA 开启)
| PP | TG | N_KV | T_PP s | S_PP t/s | T_TG s | S_TG t/s |
|---|---|---|---|---|---|---|
| 512 | 128 | 0 | 4.669 | 109.67 | 12.164 | 10.52 |
| 512 | 128 | 512 | 4.811 | 106.42 | 13.061 | 9.80 |
| 512 | 128 | 1024 | 5.049 | 101.40 | 13.818 | 9.26 |
| 512 | 128 | 1536 | 5.164 | 99.15 | 13.960 | 9.17 |
| 512 | 128 | 2048 | 5.280 | 96.97 | 14.107 | 9.07 |
| 512 | 128 | 2560 | 5.423 | 94.40 | 14.248 | 8.98 |
| 512 | 128 | 3072 | 5.619 | 91.11 | 14.395 | 8.89 |
| 512 | 128 | 3584 | 5.823 | 87.92 | 14.535 | 8.81 |
| 512 | 128 | 4096 | 6.070 | 84.35 | 14.677 | 8.72 |
| 512 | 128 | 4608 | 6.306 | 81.19 | 14.825 | 8.63 |
| 512 | 128 | 5120 | 6.547 | 78.20 | 14.969 | 8.55 |
| 512 | 128 | 5632 | 6.890 | 74.31 | 15.131 | 8.46 |
| 512 | 128 | 6144 | 7.227 | 70.85 | 15.281 | 8.38 |
| 512 | 128 | 6656 | 7.513 | 68.15 | 15.394 | 8.32 |
| 512 | 128 | 7168 | 7.918 | 64.67 | 15.537 | 8.24 |
| 512 | 128 | 7680 | 8.334 | 61.43 | 15.680 | 8.16 |
| 512 | 128 | 8192 | 8.800 | 58.18 | 15.830 | 8.09 |
| 512 | 128 | 8704 | 9.200 | 55.65 | 15.971 | 8.01 |
| 512 | 128 | 9216 | 9.523 | 53.76 | 16.101 | 7.95 |
| 512 | 128 | 9728 | 10.048 | 50.95 | 16.242 | 7.88 |
| 512 | 128 | 10240 | 10.495 | 48.78 | 16.371 | 7.82 |
| 512 | 128 | 10752 | 10.955 | 46.73 | 16.507 | 7.75 |
| 512 | 128 | 11264 | 11.375 | 45.01 | 16.662 | 7.68 |
| 512 | 128 | 11776 | 11.837 | 43.26 | 16.798 | 7.62 |
| 512 | 128 | 12288 | 12.320 | 41.56 | 16.949 | 7.55 |
| 512 | 128 | 12800 | 12.613 | 40.59 | 17.085 | 7.49 |
| 512 | 128 | 13312 | 12.815 | 39.95 | 17.208 | 7.44 |
| 512 | 128 | 13824 | 13.100 | 39.08 | 17.364 | 7.37 |
| 512 | 128 | 14336 | 13.466 | 38.02 | 17.518 | 7.31 |
| 512 | 128 | 14848 | 13.669 | 37.46 | 17.655 | 7.25 |
| 512 | 128 | 15360 | 13.789 | 37.13 | 17.797 | 7.19 |
| 512 | 128 | 15872 | 13.874 | 36.90 | 17.937 | 7.14 |
ik_llama.cpp(FA 开启)
| PP | TG | N_KV | T_PP s | S_PP t/s | T_TG s | S_TG t/s |
|---|---|---|---|---|---|---|
| 512 | 128 | 0 | 2.593 | 197.46 | 12.301 | 10.41 |
| 512 | 128 | 512 | 2.662 | 192.34 | 12.501 | 10.24 |
| 512 | 128 | 1024 | 2.756 | 185.77 | 12.703 | 10.08 |
| 512 | 128 | 1536 | 2.854 | 179.42 | 12.946 | 9.89 |
| 512 | 128 | 2048 | 2.946 | 173.78 | 13.143 | 9.74 |
| 512 | 128 | 2560 | 3.040 | 168.42 | 13.331 | 9.60 |
| 512 | 128 | 3072 | 3.136 | 163.26 | 13.507 | 9.48 |
| 512 | 128 | 3584 | 3.235 | 158.25 | 13.711 | 9.34 |
| 512 | 128 | 4096 | 3.336 | 153.48 | 13.907 | 9.20 |
| 512 | 128 | 4608 | 3.432 | 149.20 | 14.088 | 9.09 |
| 512 | 128 | 5120 | 3.530 | 145.05 | 14.290 | 8.96 |
| 512 | 128 | 5632 | 3.632 | 140.99 | 14.483 | 8.84 |
| 512 | 128 | 6144 | 3.729 | 137.31 | 14.673 | 8.72 |
| 512 | 128 | 6656 | 3.834 | 133.53 | 14.879 | 8.60 |
| 512 | 128 | 7168 | 3.934 | 130.14 | 15.074 | 8.49 |
| 512 | 128 | 7680 | 4.046 | 126.55 | 15.266 | 8.38 |
| 512 | 128 | 8192 | 4.140 | 123.67 | 15.443 | 8.29 |
| 512 | 128 | 8704 | 4.243 | 120.66 | 15.616 | 8.20 |
| 512 | 128 | 9216 | 4.342 | 117.91 | 15.838 | 8.08 |
| 512 | 128 | 9728 | 4.450 | 115.06 | 16.008 | 8.00 |
| 512 | 128 | 10240 | 4.552 | 112.48 | 16.197 | 7.90 |
| 512 | 128 | 10752 | 4.721 | 108.46 | 16.429 | 7.79 |
| 512 | 128 | 11264 | 4.762 | 107.51 | 16.622 | 7.70 |
| 512 | 128 | 11776 | 4.869 | 105.16 | 16.823 | 7.61 |
| 512 | 128 | 12288 | 4.973 | 102.96 | 16.982 | 7.54 |
| 512 | 128 | 12800 | 5.077 | 100.84 | 17.208 | 7.44 |
| 512 | 128 | 13312 | 5.175 | 98.93 | 17.419 | 7.35 |
| 512 | 128 | 13824 | 5.278 | 97.02 | 17.603 | 7.27 |
| 512 | 128 | 14336 | 5.461 | 93.75 | 17.798 | 7.19 |
| 512 | 128 | 14848 | 5.560 | 92.08 | 19.126 | 7.12 |
| 512 | 128 | 15360 | 5.717 | 89.55 | 19.383 | 7.06 |
| 512 | 128 | 15872 | 5.891 | 86.91 | 19.640 | 7.00 |
Gemma3 数据呈现出与 LLaMA-3.1 不同的对比格局:
- TG 差距明显缩小:在 16k 上下文,主线 TG(7.14 t/s)甚至略优于 ik_llama.cpp(7.00 t/s);两条 TG 曲线在中长上下文处存在交叉点(这正是讨论中用 sweep-bench-plot.py 绘制的图所呈现的现象)。作者在首轮测试中多次复跑主线并切换缓存策略,确认主线「前 1024 token 出现突发性能下降」的现象稳定存在。
- PP 依旧全面领先:ik_llama.cpp 的 PP 从零上下文的 197.46 t/s 衰减到 16k 的 86.91 t/s(约 55.5% → 42.4% 的下降幅度),而主线从 109.67 t/s 跌至 36.90 t/s,两者始终存在明显差距。
为什么 Gemma3 的 TG 增益小于 LLaMA-3?
作者给出了清晰的解释,这也是理解 PR #332 收益边界的核心:
- Gemma3 总共 16 个注意力头、8 个 KV 头。在 TG 阶段生成单个 token 时,
K*Q与V*softmax(K*Q)两个 GEMM 的矩阵只有2 行; - 而 LLaMA-3 系列在该阶段对应矩阵为4 行;
- PR #332 的本质收益来自「把原本按 GEMV 处理的运算升级为多行 GEMM 并按行分配线程」。行数越多,GEMM 相对 GEMV 的并行优势越明显。当只有 2 行时,该收益自然被摊薄。
此外,Gemma3 的 head size 为 256(LLaMA-3 为 128),而主线 llama.cpp 的 CPU 代码在 PR 讨论时已经过多轮改动,其中针对 head size = 256 场景的优化在 Gemma3 上表现出相对优势,但对 head size = 128 的模型(如 LLaMA-3 系列)却造成了明显的性能拖累。作者明确表示「主线的 CPU 代码在我离开项目后有大量变化,我无法确定其具体实现」,因此对主线的内部机制不做断言。
从 ik_llama.cpp 的架构构建代码可以佐证 head size 与注意力形状如何影响 GEMM 维度:在 build_llama.cpp 中,n_embd_head = hparams.n_embd_head_v(0)与n_embd_head_k(0)被断言相等,注意力分数缩放系数kq_scale取1/sqrtf(n_embd_head),KV 头维度kv_head、n_kv直接决定llm_build_kv中两个乘法张量的形状。这些参数在不同架构间差异很大,直接决定线程分配优化的收益上限。
实践建议与结论
综合 PR #332 的描述与数据,可以得出以下可用于实际部署的结论:
- GQA 模型在 CPU 上应优先开启 FA:PR 之后 FA 在 TG 阶段已全面超越 no-FA,使用
-fa(或环境变量LLAMA_ARG_FLASH_ATTN)即可启用; - KV cache 使用
q8_0量化:-ctk q8_0 -ctv q8_0在保持精度的同时显著减少显存/内存占用,且与 FA 路径兼容;注意 FA 关闭时 V-cache 会被框架按 f16 处理(common/common.cpp 第 4304、4393 行的类型检查); - 收益与模型形状强相关:KV 头越少、TG 阶段 GEMM 行数越少,本优化的绝对收益越小(Gemma3 的 2 行 vs LLaMA-3 的 4 行);head size = 128 的主流模型(LLaMA-2/3 系)收益最大;
- 复现实验请使用 sweep-bench:它按窗口扫描上下文,能清晰呈现性能随
N_KV的衰减曲线,配合 sweep-bench-plot.py 可做多实现对比;测试时注意缓存状态与 KV cache 分配量对结果的扰动; - 结论有边界:本文数据来自单一 CPU(Ryzen 5975WX,AVX2)与特定量化组合,不同硬件(AVX-512、AMX、ARM)和量化(如
Q8_0、IQ4_KS)下的相对差距会变化,建议在目标机器上自行复测。
PR #332 的价值不仅在于一组漂亮的数字,更在于它揭示了 CPU 解码优化的一个关键维度:在 GQA 架构下,K*Q与V*softmax(K*Q)的线程分配方式直接决定多核利用率。对于希望深入理解 llama.cpp 系 CPU 后端调度逻辑的读者,可以从 src/graphs 目录下各架构的build_*文件入手,对照 build_llama.cpp 的注意力构建流程,并结合 examples/sweep-bench 的测量工具验证自己的改动。
【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考