news 2026/9/19 17:05:43

ik_llama.cpp 的 Metal 后端 Trellis 量化(IQ_KT)实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ik_llama.cpp 的 Metal 后端 Trellis 量化(IQ_KT)实现解析

ik_llama.cpp 的 Metal 后端 Trellis 量化(IQ_KT)实现解析

【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp

Trellis 量化是 ik_llama.cpp 引入的一系列新型低比特量化格式(IQ1_KTIQ2_KTIQ3_KTIQ4_KT),其核心思想来自 QTIP 论文的"3INST"算法:用一个 L 比特的 seed 通过线性同余递推一次性生成一组 N 个(近似正态分布的)量化值,从而以极低的比特率描述权重。本文以 PR #475(Metal implementation for the trellis quants)为核心,结合仓库内ggml/src/ggml-metal.mggml/src/ggml-metal.metal的源码实现,讲解 Trellis 量化在 Apple GPU(Metal)后端上的落地方式、kernel 种类与当前状态,帮助读者理解如何在 macOS 上让 IQ_KT 量化模型跑起来,以及为什么部分类型尚未启用。

背景:Trellis 量化(IQ_KT)是什么

Trellis 量化最初由 PR #113(Trellis quantization)引入 ik_llama.cpp。与主流 i-/k-quants 不同,它不是为每个权重独立存储量化值,而是借助 QTIP 论文提出的"3INST"算法:给定一个 seed,通过以下递推产生 N 个量化值:

uint32_t u32; float16_t * h = reinterpret_cast<float16_t*>(&u32); for i in 0...N-1 seed = a * seed + b u32 = (mask1 & seed) ^ mask2 q_i = h[0] + h[1] end

其中abmask1mask2为合适的常数,生成的序列近似正态分布。这样一组 N 个量化值只需用一个 L 比特的 seed(索引)描述,量化时仍按 i-/k-quants 的风格组织为 block 与 super-block,并用聚类算法搜索最优 seed。新增的量化类型与比特率如下:

类型seed 位数 L每组量化数 Nblock 大小block scale总比特率
IQ2_KT16 bit8324 bit2.125 bpw
IQ3_KT12 bit4324 bit3.125 bpw
IQ4_KT15 bit4328 bit4.0 bpw
IQ1_KT1.75 bpw(后续由 PR #616 加入)

在 ggml/include/ggml.h 中可以确认这些类型在 GGML 中的枚举值:GGML_TYPE_IQ2_KT = 153GGML_TYPE_IQ3_KT = 154GGML_TYPE_IQ4_KT = 155GGML_TYPE_IQ1_KT = 158;对应的 GGUF 文件类型常量GGML_FTYPE_MOSTLY_IQ2_KT = 142GGML_FTYPE_MOSTLY_IQ1_KT = 147也定义在同一文件中。

需要注意的是,后续 PR #529 将实现换成了全新的"integer-based trellis"(整数基 Trellis),使得 CPU 上也能获得合理性能(详见 README.md)。这意味着当前仓库中的IQ_KT系列是整数递推版本,Metal 后端实现基于这套新方案。

PR #475 的核心内容与状态

PR #475(Metal implementation for the trellis quants)的目标是为 Trellis 量化在 Apple GPU 上提供推理支持。作者在描述中明确给出了当时的进展状态:

  • IQ2_KTIQ3_KT可以正常工作,其中IQ2_KT已有相当不错的性能("has a pretty decent performance");
  • IQ4_KT存在一个未能定位的 bug,因此在 Metal 后端被暂时禁用("disabled for now as there is a bug that I don't find")。

该 PR 的状态为Closed(创建于 2025-05-30,更新于 2025-06-01)。README 的 Quantization additions 一节也将 Metal 列为 Trellis quants 的补充实现之一:Additional implementations: Metal [PR 475], Neon [PR 471], CPU [PR 441](README.md)。

这个"部分可用、部分禁用"的状态在今天的源码中仍然清晰可见,是理解 Metal 后端 KT 支持现状的钥匙。

源码验证:Metal 中的 kernel 注册与禁用痕迹

kernel 枚举与注册

在 ggml/src/ggml-metal.m 中,Trellis 相关的 kernel 枚举分布于多个类别,且IQ4_KT全部以注释形式禁用:

  • GET_ROWS(取行/embedding 操作)GGML_METAL_KERNEL_TYPE_GET_ROWS_IQ2_KTGET_ROWS_IQ3_KT正常,GET_ROWS_IQ4_KT被注释(ggml/src/ggml-metal.m);
  • MUL_MV(矩阵-向量乘,token 生成阶段核心)MUL_MV_IQ2_KT_F32MUL_MV_IQ3_KT_F32注册,MUL_MV_IQ4_KT_F32注释(ggml/src/ggml-metal.m);
  • MUL_MV_ID(MoE 专家矩阵的 MUL_MV 变体):同上,IQ2/IQ3 正常、IQ4 注释(ggml/src/ggml-metal.m);
  • MUL_MM(矩阵-矩阵乘,prompt 处理阶段核心)MUL_MM_IQ2_KT_F32MUL_MM_IQ3_KT_F32MUL_MM_IQ2_KT_F16MUL_MM_IQ3_KT_F16正常,IQ4 版本注释(ggml/src/ggml-metal.m);
  • MUL_MM_ID(MoE 的 MUL_MM 变体):同上(ggml/src/ggml-metal.m)。

对应的 kernel 加载使用GGML_METAL_ADD_KERNEL宏,例如:

GGML_METAL_ADD_KERNEL(GGML_METAL_KERNEL_TYPE_GET_ROWS_IQ2_KT, get_rows_iq2_kt, true); GGML_METAL_ADD_KERNEL(GGML_METAL_KERNEL_TYPE_GET_ROWS_IQ3_KT, get_rows_iq3_kt, true); //GGML_METAL_ADD_KERNEL(GGML_METAL_KERNEL_TYPE_GET_ROWS_IQ4_KT, get_rows_iq4_kt, true);

(ggml/src/ggml-metal.m)

在 dispatch 阶段,ggml-metal.m中同样用注释保留了IQ4_KT的分支(例如 ggml/src/ggml-metal.m 的 MUL_MM_F32 选择逻辑、ggml/src/ggml-metal.m 的 MUL_MV 选择逻辑),并在一些条件判断中写为src0t == GGML_TYPE_IQ2_KT || src0t == GGML_TYPE_IQ3_KT // || src0t == GGML_TYPE_IQ4_KT(ggml/src/ggml-metal.m)。这些被注释的代码正是 PR #475 中"bug 未定位、先禁用"决策的源码级痕迹:实现本身已经写了大半,只差最后一步问题排查。

Metal shader 实现

在 ggml/src/ggml-metal.metal 中,三个类型的 kernel 均有实际实现:

  • kernel_mul_mv_iq2_kt_f32_impl:针对block_iq2_kt,每行有一个额外的 float scale(row_size = sizeof(float) + nb*sizeof(block_iq2_kt)),并在读取 block scale 时乘上系数1.05f(ggml/src/ggml-metal.metal)。去量化核心调用Trellis3::gen8(q2[2*it+0]+4096, v1, v2),一次生成 8 个量化值(ggml/src/ggml-metal.metal);
  • kernel_mul_mv_iq3_kt_f32_impl:结构类似,行大小同样带一个 float scale(ggml/src/ggml-metal.metal);
  • kernel_mul_mv_iq4_kt_f32_impl:注意其行大小是2*sizeof(float) + nb*sizeof(block_iq4_kt),即每行带两个float scale(ggml/src/ggml-metal.metal),这与IQ4_KT8-bit block scale 的格式细节相关。

此外还有:

  • 模板化的去量化器dequantize_iq2_kt/dequantize_iq3_kt/dequantize_iq4_kt(ggml/src/ggml-metal.metal),供 GET_ROWS 与 MUL_MM 复用;
  • MUL_MM 的模板实例化:kernel_mul_mm_iq2_kt_f32/f16kernel_mul_mm_iq3_kt_f32/f16kernel_mul_mm_iq4_kt_f32/f16(ggml/src/ggml-metal.metal);
  • MUL_MM_ID(MoE)模板实例化(ggml/src/ggml-metal.metal)与 MUL_MV_ID 模板实例化(ggml/src/ggml-metal.metal)。

可以看到 Metal 侧的 shader 体系是完备的(IQ4 的 shader 同样存在,只是没有被.m侧注册和 dispatch),与 CUDA 侧的mmq-instance-iq*_kt.cummvq-instance-iq*_kt.cu模板实例(位于 ggml/src/ggml-cuda/template-instances/)形成对应:不同后端各有一套 KT kernel。

如何在 macOS 上使用 IQ_KT 量化模型

构建 Metal 后端

构建时通过 CMake 选项启用 Metal(这是 ggml 的通用 Metal 构建路径,ggml/src/CMakeLists.txt 中可见GGML_METALGGML_METAL_NDEBUGGGML_METAL_EMBED_LIBRARYGGML_METAL_SHADER_DEBUGGGML_METAL_MACOSX_VERSION_MINGGML_METAL_STD等选项):

cmake -B build -DGGML_METAL=ON -DGGML_METAL_EMBED_LIBRARY=ON cmake --build build --config Release -j

GGML_METAL_EMBED_LIBRARY将编译好的.metallib嵌入二进制,便于分发;调试 shader 时可关闭它以从外部加载。需要说明的是,本文讨论的是源码层面的 kernel 支持情况,实际运行效果以你的 macOS 硬件与系统版本为准。

生成 IQ_KT 模型

examples/quantize/quantize.cpp已注册全部 KT 类型对应的LLAMA_FTYPE

{ "IQ3_KT", LLAMA_FTYPE_MOSTLY_IQ3_KT, " 3.125 bpw trellis quantization" }, { "IQ4_KT", LLAMA_FTYPE_MOSTLY_IQ4_KT, " 4.0 bpw trellis quantization" }, { "IQ1_KT", LLAMA_FTYPE_MOSTLY_IQ1_KT, " 1.75 bpw trellis quantization" }, { "IQ2_KT", LLAMA_FTYPE_MOSTLY_IQ2_KT, " 2.125 bpw trellis quantization" },

(examples/quantize/quantize.cpp 与 examples/quantize/quantize.cpp)

使用方式:

./build/bin/llama-quantize ./model.gguf ./model-IQ2_KT.gguf IQ2_KT

生成IQ2_KT(2.125 bpw)或IQ3_KT(3.125 bpw)模型后,即可在 Metal 后端上以正常的llama-cli/llama-server流程加载推理。根据 PR #475 与当前源码状态,IQ2_KTIQ3_KT是 Metal 上已验证可用的类型,而IQ4_KT建议在 CUDA/CPU 后端使用(那里有完整的 mmq/mmvq 实例),等待 Metal 侧的 bug 修复。

从 PR #475 看 Trellis 量化的工程落地要点

  1. Trellis 的"按需解压"特性决定了 kernel 形态3INST递推在 kernel 内通过Trellis3::gen8等函数即时生成量化值,而不是预先把整个 block 解量化到显存,因此 MUL_MV/MUL_MM kernel 都直接操作block_iq*_kt的原始内存并内联生成值,这对寄存器与 threadgroup 内存(threadgroup int8_t * shared_values)的利用提出了要求;
  2. 每个类型的存储布局有细微差异:如IQ2_KT/IQ3_KT每行一个 float scale(并带1.05f修正系数),IQ4_KT每行两个 float scale,kernel 中通过row_size精确计算行偏移——新增量化类型时后端 kernel 必须逐一对齐这种布局;
  3. 禁用不是删除IQ4_KT的 shader、枚举、dispatch 分支都以注释形式保留在 ggml/src/ggml-metal.m 与 ggml/src/ggml-metal.metal 中,方便后续排查修复后直接恢复注册,这也是 PR #475 留下的明确工程痕迹。

小结

PR #475 为 ik_llama.cpp 的 Trellis 量化补齐了 Metal 后端:IQ2_KTIQ3_KT的 GET_ROWS、MUL_MV、MUL_MV_ID、MUL_MM、MUL_MM_ID 全套 kernel 已注册并可用,其中IQ2_KT性能表现不错;IQ4_KT因未知 bug 被暂时禁用,但 shader 与 dispatch 代码均已保留。若要继续深入,可对比阅读 CPU(ggml/src/iqk/iqk_mul_mat.cpp)、CUDA(ggml/src/ggml-cuda/mmq.cu)中的对应实现,以及后续的 PR #505(New IQ4_KT trellis implementation) 与 PR #529(New IQ2_KT, IQ3_KT and IQ4_KT V2),了解 Trellis 量化在后来的演进。

【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/19 17:04:47

marked 中缩进表格(Indented Tables)的处理行为与源码解析

marked 中缩进表格&#xff08;Indented Tables&#xff09;的处理行为与源码解析 【免费下载链接】marked A markdown parser and compiler. Built for speed. 项目地址: https://gitcode.com/gh_mirrors/ma/marked 导读 本文围绕 marked&#xff08;一个以速度为设计…

作者头像 李华
网站建设 2026/9/19 17:00:44

Minitab质量统计应用指南:从概率分布到假设检验的完整操作解析

简介&#xff1a;面向工商管理&#xff08;质量工程师方向&#xff09;本科生及质量管理从业者的《质量统计软件应用》课程实训指导书&#xff0c;以Minitab为教学工具&#xff0c;系统讲解概率论基础与描述性统计两大实验。内容涵盖正态分布、二项分布的概率计算&#xff0c;图…

作者头像 李华