
人工智能大模型推理引擎本地部署模型量化模型优化【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp点击查看免费下载导读本文深入剖析 ik_llama.cppllama.cpp 的衍生分支中一项针对 MLAMulti-head Latent Attention多头潜在注意力架构的 Prompt ProcessingPP提示词预填充加速优化方案。该方案通过将 K/Q 的 no- 与 rotational 位置编码部分拼接、消除独立的 k_r 缓存并把原先两次独立的 kq_nope、kq_pe 矩阵乘法合并为一次从而显著提升长上下文下的预填充吞吐同时保持 MLA 的核心优势——生成TG阶段的 KV 缓存压缩。读完本文你将掌握该优化的核心设计思想、源码实现位置、实测性能数据以及如何在当前仓库中通过-mla参数与MLA_USE_TRANSPOSED_CACHE编译开关配置、验证这项优化。背景MLA 的机制与性能困境MLA 的核心思想压缩 KV 缓存MLAMulti-head Latent Attention是一种注意力机制变体由 DeepSeek-V2 系列模型引入并得到广泛应用。它的核心思想是在 KV 进入注意力计算之前先用低秩投影将其压缩到一个低维的潜在空间从而大幅缩减 KV 缓存的大小这是 MLA 相比标准 MHAMulti-Head Attention的关键优势。在 ik_llama.cpp 中这一设计主要体现在 DeepSeek2、GLM、Qwen4 等模型的图构建代码中例如 src/graphs/build_deepseek2.cpp 就是 MLA 的核心实现文件。具体来说在 MLA 中K 被拆成两部分k_nopeno position encoding无位置编码部分维度为n_embd_head_qk_nope只包含语义信息k_roperotational position encoding旋转位置编码部分维度为n_embd_head_qk_rope即hparams.n_rot包含位置信息需要经过 RoPE 旋转位置编码处理。Q 同样被拆成q_nope与q_rope两部分压缩后的潜在向量kv_compressed维度为kv_lora_rank即hparams.n_lora_kv通过wkv_a_mqa投影得到并经过 RMS Normattn_kv_a_norm归一化。预填充阶段的两大性能瓶颈在未优化的实现中MLA 的预填充计算存在两个明显的开销点两次独立的矩阵乘法K 与 Q 的 no- 与 rope 部分分别计算注意力分数即kq_nope k_nope × q_nope与kq_pe k_rope × q_rope各自独立执行随后还需要一次昂贵的加法将它们合并为最终注意力分数独立的 k_r 缓存旋转编码部分的 K 需要单独维护一份缓存增加了缓存管理与访存开销。正是这两点使得 MLA 在预填充阶段比无 MLA 的标准注意力更慢——这也是 PR #205 需要解决的问题。核心优化拼接 K/Q、合并矩阵乘法、消除 k_r 缓存优化思路一拼接 no- 与 rope 部分PR #205 的核心改动非常直接将 no- 与 rotational 位置编码部分直接拼接concatenate起来。这样 K 的完整维度就变为kv_lora_rank n_embd_head_qk_ropeQ 的完整维度变为n_embd_head_qk_nope n_embd_head_qk_rope二者共享同一个矩阵乘法运算。在源码中这一拼接操作在 src/graphs/build_deepseek2.cpp 中体现为// 写入缓存前的拼接rope 在前、压缩潜在在后 ggml_tensor * kvr ggml_concat(ctx0, ggml_permute(ctx0, k_rope, 0, 2, 1, 3), kv_compressed, 0);即缓存中的每一行存储的完整 K 为[k_rope | kv_compressed]的拼接形式。相应地在 PP 优化路径中K 与 Q 也按一致顺序拼接见 src/graphs/build_deepseek2.cpp 中的k ggml_concat(ctx0, k_rope_rep, k_nope, 0)与q ggml_concat(ctx0, q_rope, q_nope, 0)。优化思路二两次乘法合并为一次拼接的直接收益是原先的kq_nope与kq_pe两次矩阵乘法可以合并为一次并且省去了二者相加的ggml_add操作。在合并后的计算图中一次ggml_mul_mat或 Flash Attention 的ggml_flash_attn_ext即可同时完成 nope 与 rope 两部分的注意力分数计算。这既减少了算子调度开销又提升了计算密度。优化思路三消除独立的 k_r 缓存由于 K 的 rope 部分与 no- 部分拼接存储原先为旋转编码 K 单独维护的k_r缓存被完全消除。缓存中不再需要区分K 的哪一段属于 rope 部分、哪一段属于 no- 部分——它们天然地在同一行内连续排布通过偏移量即可切分访问例如源码中的ggml_row_size(cache_local-type, n_embd_head_qk_rope)用于定位 no- 部分的起始位置。源码级验证拼接与吸收路径的完整实现PP 优化路径pp_opt在 src/graphs/build_deepseek2.cpp 中当满足pp_opt条件MLA 模式大于 1、n_tokens 128、n_kv k_pp_opt_min_kv1024时走的是物化路径从潜在缓存中恢复出完整的 K/V然后使用标准 Flash Attentionggml_flash_attn_ext计算注意力。这一路径的关键片段为// V 与 k_nope 从压缩缓存中恢复 ggml_tensor * v_2d ggml_mul_mat(ctx0, wv_b_2d, kv_cache_nope); ggml_tensor * k_nope_2d ggml_mul_mat(ctx0, wk_b_T_2d, kv_cache_nope); // ... ggml_tensor * k ggml_concat(ctx0, k_rope_rep, k_nope, 0); // 拼接后的完整 K ggml_tensor * q ggml_concat(ctx0, q_rope, q_nope, 0); // 拼接后的完整 Q ggml_tensor * kqv ggml_flash_attn_ext(ctx0, q, k, v, KQ_mask, kq_scale, hparams.f_max_alibi_bias, 0.f);注意其中的wk_b_pp是transpose(wk_b)的预物化张量在llm_prepare_mla中生成其形状为[kv_lora_rank, n_embd_head_qk_nope, n_head_local]用于将压缩潜在向量直接恢复为各头的 K。这与 PR #205 描述的合并 kq_nope 与 kq_pe在计算层面完全对应。吸收路径FlashMLA-3对于 token 数较少、不满足pp_opt条件的情况走的是吸收路径将wk_b吸收进 Q 的投影直接在压缩潜在空间计算注意力。此时 Q 被拼接为q_combined [q_rope | q_nope2]K 直接使用缓存kv_cache完整潜在 ropeV 使用kv_cache_lora仅潜在部分同样是一次ggml_flash_attn_ext完成全部计算ggml_tensor * q_combined ggml_concat(ctx0, ggml_permute(ctx0, q_rope, 0, 2, 1, 3), q_nope2, 0); ggml_tensor * kqv_compressed ggml_flash_attn_ext(ctx0, q_combined, kv_cache, kv_cache_lora, KQ_mask, kq_scale, hparams.f_max_alibi_bias, 0.f);非 Flash Attention 路径在不使用 Flash Attention 的 MLA 模式下mla_attn 1注意力通过两次ggml_mul_mat完成先用kv_cache × q得到注意力分数并 softmax再用kv_cache_trans × softmax 结果加权聚合 V。此时 V 缓存以转置形式存储ggml_transpose(kv_compressed)写入v_l这正是 PR #205 附带引入的转置 KV 缓存机制的由来// note: storing transposed c^KV in the transposed KV cache ggml_build_forward_expand(gf, ggml_cpy(ctx0, ggml_transpose(ctx0, kv_compressed), kv_cache_trans_view));转置 KV 缓存与 MLA_USE_TRANSPOSED_CACHE 开关为什么需要转置缓存在非 Flash Attention 的 MLA 实现中为了支持kv_cache_trans供ggml_mul_mat(kv_cache_trans, kq)使用的转置 K/V 视图需要在 V 缓存中额外保存一份转置后的潜在向量。PR #205 同时新增了一个编译期开关在llama.cpp中查找MLA_USE_TRANSPOSED_CACHE并将其设为 0即可禁用 MLA 的转置 KV 缓存。从关联文档中的说明可知开启转置缓存默认KV 缓存大小几乎翻倍但长上下文下的 TG生成性能更优关闭转置缓存设为 0KV 缓存大小几乎减半PP 性能基本不变但长上下文 TG 性能有所下降。这一点在仓库的 github-data/pull_requests/206 - MLA_ allow Q8_0 K-cache for MLA.md 中有直接印证kvl_t即kv_l的转置版本无法被量化。可以通过在llama.cpp中将MLA_USE_TRANSPOSED_CACHE设为 0 来消除它但那样kv_l也无法量化因为目前从量化张量构造连续转置张量以用于推理是不可行的。也就是说转置缓存与量化 KV 缓存是两个互斥的选项想要量化 K 缓存就必须放弃转置缓存。这是选择该开关时的重要权衡。实测对比开启与关闭转置缓存PR #205 附带的对比数据DeepSeek-Lite 的IQ4_XS量化版K 缓存为 Q8_0Ryzen 7950XTG 测试为llama-bench -gp -Np,64模型测试t/s带 c^Tt/s不带 c^Tdeepseek2 16B IQ4_XStg64pp12833.58 ± 0.0633.05 ± 0.05deepseek2 16B IQ4_XStg64pp25632.67 ± 0.0031.54 ± 0.07deepseek2 16B IQ4_XStg64pp51232.38 ± 0.0830.26 ± 0.33deepseek2 16B IQ4_XStg64pp102431.50 ± 0.0228.50 ± 0.01deepseek2 16B IQ4_XStg64pp204830.01 ± 0.0124.75 ± 0.01deepseek2 16B IQ4_XStg64pp409627.08 ± 0.0320.67 ± 0.09deepseek2 16B IQ4_XStg64pp819222.82 ± 0.0014.89 ± 0.01可以看到上下文越长转置缓存的 TG 优势越明显8192 token 上下文时差距约 53%。这印证了以 KV 缓存空间换 TG 速度的设计取向。实测性能PP 加速效果与 TG 无损验证PP 加速效果本 PR 的核心目标PR 作者在 Ryzen-7950X 上使用 DeepSeek-LiteIQ4_XS量化、K 缓存 Q8_0对比了 main 分支与本 PR 的 PP 吞吐模型测试t/smaint/sPR加速比deepseek2 16B IQ4_XSpp512478.58 ± 5.14489.40 ± 1.081.023deepseek2 16B IQ4_XSpp1024438.56 ± 0.75458.37 ± 1.511.045deepseek2 16B IQ4_XSpp2048378.95 ± 1.40407.83 ± 2.071.076deepseek2 16B IQ4_XSpp4096294.71 ± 2.86327.88 ± 0.181.113deepseek2 16B IQ4_XSpp8192204.52 ± 0.27234.17 ± 0.371.145deepseek2 16B IQ4_XSpp16384126.31 ± 0.13148.35 ± 0.381.174关键发现加速比随上下文长度增长而提升从 512 token 的约 2.3%到 16384 token 的约 17.4%。这是因为长上下文中注意力计算矩阵乘法占比更大合并乘法的收益也随之放大作者本人也谨慎指出16k token 时约 9% 的提升可能是真实的也可能只是由于预填充阶段更早结束、热降频thermal throttling减轻所致。这说明长上下文下的加速数据需要结合硬件功耗状态谨慎解读。TG 性能不受影响PR 同时用llama-bench -gp -Np,64验证了 TG生成性能没有因为 PP 优化而退化模型测试t/smaint/sPR加速比deepseek2 16B IQ4_XStg64pp12833.58 ± 0.0633.80 ± 0.001.007deepseek2 16B IQ4_XStg64pp25632.67 ± 0.0032.76 ± 0.011.003deepseek2 16B IQ4_XStg64pp51232.38 ± 0.0832.68 ± 0.051.009deepseek2 16B IQ4_XStg64pp102431.50 ± 0.0232.02 ± 0.001.017deepseek2 16B IQ4_XStg64pp204830.01 ± 0.0130.31 ± 0.031.010deepseek2 16B IQ4_XStg64pp409627.08 ± 0.0327.54 ± 0.101.017deepseek2 16B IQ4_XStg64pp819222.82 ± 0.0023.12 ± 0.011.013deepseek2 16B IQ4_XStg64pp1638417.24 ± 0.0018.74 ± 0.091.087结论TG 吞吐在各上下文长度下基本持平多数在 1.0~1.7% 之间即TGMLA 的立身之本未被牺牲。数据可复现性说明需要强调的是上述数据是 PR 作者在单一硬件平台Ryzen 7950X CPU上、针对单一模型的测量结果并非普适性保证。作者在 PR 描述中也明确表达了希望社区在其他系统上验证的意愿它仍然比无 MLA 慢所以我先将其作为草稿再尝试一些改进。不过如果其他人能帮忙测试确认 a) 我没有引入 bugb) 它确实在自己的系统上更快那就太好了。因此在实际项目中建议用当前仓库的llama-bench工具在自己目标硬件上复测。关于如何使用llama-bench可参考 examples/llama-bench/README.md。如何在当前仓库中启用与验证通过 -mla 参数启用 MLA 注意MLA 注意力模式在 ik_llama.cpp 中通过命令行参数-mla--mla-use启用定义于 common/common.cpp 的参数解析中if (arg -mla || arg --mla-use) { CHECK_ARG params.mla_attn std::stoi(argv[i]); return true; }其取值定义于 common/common.hint mla_attn 3; // MLA 0: standard, 1: MLA with K and V^T cache, // 2: MLA with just K cache, 3: the best of both worlds各取值含义结合 src/llama.cpp、src/graphs/build_deepseek2.cpp 的实现取值含义说明0标准注意力不使用 MLA 优化路径1MLA K 与 V^T 缓存非 Flash Attention 路径V 缓存以转置形式存储2MLA 仅 K 缓存仅维护 K 缓存3两者最佳结合默认结合模式兼顾 PP 与 TG 性能在实际图构建中mla_attn的取值还会与 Flash Attention 组合出更细的分支例如mla_attn 1 flash_attn pp_opt走物化路径mla_attn 1时还涉及kv_cache_trans ggml_cont(ggml_transpose(kv_cache_lora))的转置构造。值得注意的是PR #205 的 PP 优化拼接 K/Q、合并乘法需要mla_attn 1才能生效因为物化路径只在mla_attn 1的分支中执行。启用 MLA 的示例命令以llama-server为例-c为上下文长度./build/bin/llama-server -m /path/to/deepseek2-16b-iq4_xs.gguf -mla 3 -c 8192编译期开关 MLA_USE_TRANSPOSED_CACHE如前所述MLA_USE_TRANSPOSED_CACHE是一个编译期宏用于控制是否生成转置 KV 缓存。默认开启若需要压缩 KV 缓存占用例如内存受限场景可将其设为 0。注意该开关与量化 K 缓存互斥——这是选择时的关键权衡。复测脚本与工具仓库提供了多个适合复测的工具与脚本examples/llama-bench/llama-bench基准工具PR 中的-gp -Np,64、pp512等测试即由此工具产出支持指定 prompt 长度-p/-Np相关参数与生成长度scripts/run-all-perf.sh 与 scripts/compare-commits.sh可用于批量对比不同提交的性能scripts/compare-llama-bench.py解析llama-bench输出并对比。对于 MLA 模型仓库还提供了专门的深挖工具例如 examples/spec-bench/ 与 MLA 相关讨论可参考 github-data/discussions/306 - Confused by the -mla flag. Whats supported_.md。进一步阅读MLA 在 ik_llama.cpp 中的完整图构建实现src/graphs/build_deepseek2.cpp、src/graphs/build_glm5next.cpp、src/graphs/build_qwen4exp.cppMLA 相关超参数n_lora_kv、n_rot等定义src/llama-hparams.h、src/llama-hparams.cppKV 缓存结构k_l、v_l、v_trans定义src/llama-context.h同一时期的后续工作Q8_0 K 缓存支持 MLAgithub-data/pull_requests/206 - MLA_ allow Q8_0 K-cache for MLA.md-mla参数的社区答疑github-data/discussions/306 - Confused by the -mla flag. Whats supported_.md仓库的 PR 讨论归档目录github-data/pull_requests/赞分享人工智能大模型推理引擎本地部署模型量化模型优化【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp点击查看免费下载相关推荐ik_llama.cpp 中 DeepSeek MLA 注意力优化的演进从 PR 180 到可选的 -mla 实现ik_llama.cpp 中 DeepSeek MLA 注意力优化的演进从 PR 180 到可选的 mla 实现 导读 本文基于 ik_llama.cpp 仓人工智能大模型推理引擎本地部署模型量化模型优化ik_llama.cpp 中的 MLA 矩阵吸收基于压缩 KV 缓存的长上下文预填充优化原理与实现ik_llama.cpp 中的 MLA 矩阵吸收基于压缩 KV 缓存的长上下文预填充优化原理与实现 本文围绕 ik_llama.cpp 社区讨论《MLA ma人工智能大模型推理引擎本地部署模型量化模型优化ik_llama.cpp 为 IQ4_KS 引入 CUDA MMQ量化矩阵乘法实现与 Prompt Processing 性能提升解析ik_llama.cpp 为 IQ4_KS 引入 CUDA MMQ量化矩阵乘法实现与 Prompt Processing 性能提升解析 本文聚焦 ik_lla人工智能大模型推理引擎本地部署模型量化模型优化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考