ik_llama.cpp PR 574 技术解析:将 KQ mask 填充对齐从 16 提升到 64,以适配 Vulkan coopmat2 闪存注意力
ik_llama.cpp PR #574 技术解析将 KQ mask 填充对齐从 16 提升到 64以适配 Vulkan coopmat2 闪存注意力【免费下载链接】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 #574《Change KQ mask padding to 64》展开。该 PR 将 Flash Attention 使用的 KQ mask 在 token 维度的填充对齐padding从 16 提升到 64以解决 NVIDIA 驱动升级到 575 后 Vulkan 后端启用 cooperative matrix 2coopmat2时触发的断言失败并同步给出了同一张 RTX 4080 上 Vulkan 与 CUDA 的 sweep-bench 性能对比。读完本文你将理解 KQ mask 填充的底层原因、它与 Vulkan coopmat2 着色器分块策略之间的约束关系以及如何复现该性能测试。一、PR 概览一次由驱动升级触发的断言修复PR #574 由 ik_llama.cpp 作者 ikawrakow 于 2025-07-03 提交并当日关闭State: Closed。PR 描述非常简短但信息量不小改动内容将 KQ mask 的填充对齐从 16 改为 64直接动机Vulkan 后端在启用 coopmat2 时需要此对齐参考基准mainline上游 llama.cpp中该值同样是 64。作者在评论区补充了触发场景他在两台远程机器中的一台将 NVIDIA 驱动更新到 575该版本开始启用 Vulkan coopmat2 能力随即在 Vulkan 后端触发了断言assert本 PR 正是为修复这一断言而提出。同时作者也借机观察了性能此前 coopmat1 路径下 Vulkan 相比 CUDA 慢了约 3 倍而根据 讨论 #562 中的预期同一张 NVIDIA GPU 上 Vulkan 与 CUDA 的差距在启用 coopmat2 后应缩小到 20%25%。遗憾的是作者在 RTX 4080 上的实测结果并未达到这一预期——coopmat2 虽有改善但 prompt processingPP仍比 CUDA 慢约 2 倍。二、背景知识什么是 KQ mask为什么要填充在自回归 Transformer 的解码与训练中注意力分数矩阵需要叠加掩码mask用来屏蔽未来的 tokencausal mask以及 padding 位置。在 ggml 中这个掩码张量被称为 KQ mask其维度布局在 ggml_flash_attn_ext 的接口注释 中有明确说明// q: [n_embd, n_batch, n_head, 1] // k: [n_embd, n_kv, n_head_kv, 1] // v: [n_embd, n_kv, n_head_kv, 1] !! not transposed !! // mask: [n_kv, n_batch_pad, 1, 1] !! n_batch_pad GGML_PAD(n_batch, GGML_KQ_MASK_PAD) !! // res: [n_embd, n_head, n_batch, 1] !! permuted !!注意 mask 的第二个维度是n_batch_pad即真实 batchtoken 数经GGML_PAD向上取整到对齐粒度后的值。填充的意义在于让 GPU 着色器可以按固定分块大小无分支地加载掩码数据如果每个工作组的行数块恰好整除填充后的维度着色器就不需要做越界 clamp从而减少边界分支、提高内存访问的规整性。这个对齐粒度正是GGML_KQ_MASK_PAD宏定义在 ggml/include/ggml.h#L2486-L2490#if GGML_USE_VULKAN #define GGML_KQ_MASK_PAD 64 #else #define GGML_KQ_MASK_PAD 16 #endif也就是说PR #574 落地后的实际状态是Vulkan 后端使用 64其余后端CPU/CUDA/Metal 等维持 16。这个条件编译结构本身就说明了问题——64 是 Vulkan coopmat2 路径特有的硬性需求而非所有后端通用的改动。三、为什么是 64coopmat2 着色器的分块约束要理解为什么必须是 64需要回到 Vulkan 后端的 Flash Attention 实现。在 ggml/src/ggml-vulkan.cpp#L2154-L2173 的fa_spec_constants中Vulkan 后端为每条 Flash Attention 管线计算工作组的分块行数rows_cols[0]并在其上方写下了关键注释与断言// mask dim1 is padded to 64, we rely on this to avoid clamping mask loads GGML_ASSERT((GGML_KQ_MASK_PAD % rows_cols[0]) 0);这条断言的含义是掩码第二维的填充量64必须能被 Flash Attention 着色器每个工作组一次处理的行数整除。若填充仍为 16而 coopmat2 着色器按更大分块64 行读取掩码就会出现 16 无法整除 64 的情况断言失败——这正是驱动升级到 575、coopmat2 能力被识别后立即触发 assert 的直接原因。同样的约束在运行时非管线构建阶段再次出现于 ggml/src/ggml-vulkan.cpp#L6434-L6435// mask dim1 is padded to 64, we rely on this to avoid clamping mask loads GGML_ASSERT((nem1 % GGML_KQ_MASK_PAD) 0);即实际推理时掩码张量的ne[1]维度必须能被GGML_KQ_MASK_PAD整除。这两处断言一前一后分别守护着着色器管线构建与执行两个阶段共同保证了掩码加载无需 clamp。从讨论 #562 中的对话可以进一步印证 64 与 coopmat2 性能的关系coopmat2 之所以在较大 KV 深度下表现明显更好正是因为它一次处理更多行64 vs 16见 讨论 #562 中关于N_KV深度影响的讨论。也就是说coopmat2 的分块粒度本身就与 64 对齐掩码填充随之对齐到 64 是顺理成章的设计。四、Coopmat2 管线驱动 575 带来的新能力Vulkan 后端的 Flash Attention 目前存在三条代码路径在 ggml/src/ggml-vulkan.cpp#L2197-L2217 中可以看到它们的创建逻辑FA_SCALAR标量路径无条件创建支持 F16、Q4_0、Q8_0FA_COOPMAT1基于VK_KHR_cooperative_matrix扩展的 cooperative matrix 1需设备报告coopmat1_fa_supportFA_COOPMAT2基于VK_NV_cooperative_matrix2扩展的 cooperative matrix 2需设备报告coopmat2支持。其中 coopmat2 路径flash_attn_cm2.comp支持的量化类型最丰富包括 F16、Q4_0、Q4_1、Q5_0、Q5_1、Q8_0 与 IQ4_NL并且额外创建了 mul_mat 的_cm2系列管线见 ggml/src/ggml-vulkan.cpp#L2221-L2229。这也是 PR 描述中所说的coopmat2 启用后需要 64 填充的完整背景coopmat2 是相对较新的 NVIDIA 扩展VK_NV_cooperative_matrix2需要较新的驱动r575 起才会被枚举出来见 讨论 #562 中关于驱动版本与matrix cores: NV_coopmat2的实测输出。因此PR #574 本质上是为新硬件能力补齐了掩码布局契约。五、对模型图构建的影响掩码张量如何被填充KQ mask 的填充并不只发生在 Vulkan 后端内部模型图的构建阶段就需要按GGML_KQ_MASK_PAD分配掩码张量。以使用 Flash Attention 的通用图构建路径 src/graphs/build_dflash.cpp#L369-L419 为例const int64_t n_kv_total GGML_PAD(ctx_len n_tokens, (int64_t) llama_kv_cache::get_padding(flash_attn)); ... lctx.dflash.inputs.kq_mask ggml_new_tensor_2d(ctx0, mask_type, n_kv_total, GGML_PAD(n_tokens, GGML_KQ_MASK_PAD)); lctx.dflash.inputs.kq_mask_swa ggml_new_tensor_2d(ctx0, mask_type, n_kv_total, GGML_PAD(n_tokens, GGML_KQ_MASK_PAD));即掩码张量形状为{n_kv_total, GGML_PAD(n_tokens, GGML_KQ_MASK_PAD)}——第一个维度覆盖全部 KV 长度第二个维度把 token 数填充到 64 的倍数Vulkan 构建时。类似地DeepSeek 系列图构建中也大量使用该宏如 src/graphs/build_deepseek2.cpp#L682-L710 中关于FA 路径要求 mask 为 F16、连续、且 ne[1] 按 GGML_PAD(n_queries, GGML_KQ_MASK_PAD) 填充的注释以及 src/graphs/build_deepseek4.cpp#L251 中的dsv4_pad_mask_tokens辅助函数。从源码结构可以推断GGML_KQ_MASK_PAD已成为整个图构建层与 Vulkan 后端之间的共享契约图构建负责按对齐粒度分配张量后端负责按对齐粒度无分支消费。六、性能验证RTX 4080 上的 sweep-bench 对比PR 评论区给出了同一张 NVIDIA RTX 4080 上、Q4_0 量化的 Llama-3.1-8B-Instruct、u-batch 1024、Flash Attention 开启时的 sweep-bench 实测数据完整复现如下。Vulkan启用 coopmat2PPTGN_KVT_PP sS_PP t/sT_TG sS_TG t/s102425600.2484128.322.70094.80102425610240.2633887.372.68495.37102425620480.2723769.072.75293.03102425630720.2813639.222.80791.21102425640960.2883560.622.86589.37102425651200.3033380.022.93287.30102425661440.3243158.542.99385.53102425671680.3333074.873.02684.59102425681920.3442977.473.10082.59102425692160.3512920.003.15681.111024256102400.3562876.613.22179.471024256112640.3762725.053.27078.301024256122880.3862651.133.31977.131024256133120.3992564.513.38875.561024256143360.4152470.403.44374.361024256153600.4272400.043.49973.17CUDAPPTGN_KVT_PP sS_PP t/sT_TG sS_TG t/s102425600.1228379.712.054124.65102425610240.1258170.822.092122.39102425620480.1347615.592.154118.84102425630720.1417277.022.221115.26102425640960.1496857.342.290111.77102425651200.1566555.322.371107.97102425661440.1636273.822.412106.14102425671680.1716000.022.467103.77102425681920.1825627.802.527101.32102425692160.1885440.442.58099.231024256102400.1905400.072.66596.041024256112640.2005130.032.70094.831024256122880.2064970.972.75193.061024256133120.2154769.692.81091.101024256143360.2264538.542.86589.341024256153600.2304459.332.93687.18从数据中可以读出几个客观结论PPprompt processing差距最大空 KV 时 CUDA 达 8379.71 t/sVulkan 为 4128.32 t/s差距约 2 倍随着 N_KV 增大两者均衰减但 Vulkan 的相对劣势整体保持例如 N_KV15360 时分别为 4459.33 与 2400.04 t/sTGtoken generation差距较小空 KV 时 CUDA 124.65 t/s vs Vulkan 94.80 t/s约 24% 差距深 KV 时差距进一步缩小87.18 vs 73.17约 16%coopmat2 优于 coopmat1但仍未达到讨论 #562 中20%~25% 差距的预期作者因此将 PP 差距约 2 倍作为后续优化的观察点。需要说明的是这些数据是 PR 提交时作者在特定硬件/驱动/模型组合下的单点实测不代表普遍结论但作为 coopmat2 早期落地时的性能快照具有参考价值。七、如何复现 sweep-bench 测试PR 中使用的工具是仓库自带的 sweep-bench 基准程序源码位于 examples/sweep-bench/sweep-bench.cpp其参数解析复用 common 库的gpt_params。关键参数映射如下-m model.gguf指定模型文件-c N设置 KV 缓存上下文长度sweep 上限-b N设置 batch 大小-ub N设置 ubatch 大小——PP 列即取自params.n_ubatchsweep-bench.cpp#L226-n N设置生成 token 数——TG 列默认取n_predict未指定时为 ubatch/4sweep-bench.cpp#L227-fa开启 Flash AttentionPR 测试即在此模式下进行-ngl N设置 GPU 卸载层数。官方示例命令为./sweep-bench -m model.gguf -c 8192 -b 2048 -ub 512程序会从空 KV 开始按n_ubatch步长逐步填充 KV 缓存并测量每一档的 PP/TG 耗时与吞吐即表中N_KV递增的含义最终以表格或 JSON见 sweep-bench.cpp#L416-L425形式输出。复现 PR 数据时将-ub设为 1024、开启-fa并使用 Q4_0 量化的 Llama-3.1-8B-Instruct 即可对齐表头中的 PP/TG/N_KV 各列。八、总结与延伸阅读PR #574 是一个小而关键的对齐修复它把 Vulkan 后端 Flash Attention 的 KQ mask 填充从 16 改为 64消除了 coopmat2 着色器按 64 行分块读取掩码时的断言冲突并使 ik_llama.cpp 与上游 mainline 的对齐策略保持一致非 Vulkan 后端仍为 16。这一改动也揭示了一个通用工程原则GPU 加速器中张量布局契约shape 对齐、连续性、精度必须与着色器的分块策略严格一致任何一方的演进都可能打破另一方的假设。感兴趣的读者可以继续阅读以下源码与资料对齐宏定义ggml/include/ggml.h#L2486-L2490Vulkan FA 管线构建与断言ggml/src/ggml-vulkan.cpp#L2154-L2173、ggml/src/ggml-vulkan.cpp#L6434-L6435coopmat2 着色器ggml/src/vulkan-shaders/flash_attn_cm2.comp掩码张量分配src/graphs/build_dflash.cpp#L404-L419DeepSeek 系 FA 掩码适配说明src/graphs/build_deepseek2.cpp#L682-L710性能复现工具examples/sweep-bench/sweep-bench.cpp相关讨论Vulkan/ROCm 后端性能与 coopmat 演进见 github-data/discussions/562 - AMD GPU Vulkan _ ROCm_HIP Discussion.md【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

InteractiveViewer在OpenHarmony上的缩放平移实战

InteractiveViewer在OpenHarmony上的缩放平移实战

在 Flutter 应用里做图片预览、画布编辑、地图漫游这类功能时,“内容比视口大”是绕不开的问题。传统做法无非是缩小塞进屏幕,或者用 ScrollView 单向滚动,可一旦需要自由地查看任意区域、放大看细节,就必须引入“缩放 平移 视口…

2026/9/20 2:53:07 阅读更多 →
AI编程助手选型:Copilot替代方案与迁移实战

AI编程助手选型:Copilot替代方案与迁移实战

这两年“Copilot替代工具”在开发者社区的搜索量一路走高,我自己的技术交流群里几乎每周都会有人问一句:“你们还在用Copilot吗?”紧接着就是:“如果不用,那换什么最好?”说实话,这个问题的背后…

2026/9/20 2:53:07 阅读更多 →
CC Switch教程:统一管理DeepSeek、GLM等模型API,搞定Codex与OpenCode配置

CC Switch教程:统一管理DeepSeek、GLM等模型API,搞定Codex与OpenCode配置

最近我在折腾AI辅助编程,手上同时挂着Codex CLI、OpenCode和好几个不同厂商的大模型API。最头疼的不是模型能力,而是配置——每个工具都要单独填Base URL、API Key、模型名,想换个模型就得翻半天设置。直到同事甩给我一个叫CC Switch的开源小…

2026/9/20 2:53:07 阅读更多 →

最新新闻

C/C++ static关键字深度解析:从底层原理到工程实践

C/C++ static关键字深度解析:从底层原理到工程实践

先说结论:static修饰局部变量改变的是生命周期和存储位置,static修饰全局变量改变的是链接属性,static修饰函数同样改变链接属性,而C里static用在类成员上还有另一层含义。这个知识点几乎每个人都背过,可真到项目里&am…

2026/9/20 4:15:03 阅读更多 →
高通Adreno开源驱动Turnip详解:从下载安装到kalama显示IC开发

高通Adreno开源驱动Turnip详解:从下载安装到kalama显示IC开发

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 4:15:03 阅读更多 →
NLP-progress 对话系统全景:Dialogue 任务的基准数据集与 SOTA 追踪指南

NLP-progress 对话系统全景:Dialogue 任务的基准数据集与 SOTA 追踪指南

NLP-progress 对话系统全景:Dialogue 任务的基准数据集与 SOTA 追踪指南 【免费下载链接】NLP-progress Repository to track the progress in Natural Language Processing (NLP), including the datasets and the current state-of-the-art for the most common N…

2026/9/20 4:15:03 阅读更多 →
uni-app 开源仓库 UTS 内置对象 Error 完全指南:错误创建、属性详解与跨端异常处理

uni-app 开源仓库 UTS 内置对象 Error 完全指南:错误创建、属性详解与跨端异常处理

uni-app 开源仓库 UTS 内置对象 Error 完全指南:错误创建、属性详解与跨端异常处理 【免费下载链接】uni-app A cross-platform framework using Vue.js 项目地址: https://gitcode.com/gh_mirrors/un/uni-app 导读 本文以 uni-app 开源仓库 docs/uts/build…

2026/9/20 4:15:03 阅读更多 →
CANN ops-math 算子 Pdist:基于 Ascend NPU 的 p-范数成对距离计算详解

CANN ops-math 算子 Pdist:基于 Ascend NPU 的 p-范数成对距离计算详解

CANN ops-math 算子 Pdist:基于 Ascend NPU 的 p-范数成对距离计算详解 【免费下载链接】ops-math 本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。 项目地址: https://gitcode.com/cann/ops-math 导读 本文围绕 CANN ops-ma…

2026/9/20 4:15:03 阅读更多 →
C盘被 odis_download_dest 塞满?CAD与诊断软件缓存堆积清理全攻略

C盘被 odis_download_dest 塞满?CAD与诊断软件缓存堆积清理全攻略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/20 4:14:02 阅读更多 →

日新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/20 0:00:46 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/20 0:00:46 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/20 0:00:46 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →