
ik_llama.cpp 量化实战IQ4_KS在 Gemma-3-27B QAT 模型上的质量与性能实测【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp本篇文章基于 ik_llama.cpp 社区讨论《iq4_ksperforms great on gemma-3-27b-it-qat-q4_0-unquantized》整理而成聚焦于一个非常具体的实战问题Google 官方发布的gemma-3-27b-it-qat-q4_0-unquantizedQAT 模型在转换为 GGUF 后用 ik_llama.cpp 独有的IQ4_KS量化格式能拿到怎样的困惑度PPL与推理性能。文中完整保留了原讨论的原始测试数据与复现命令并结合 ggml/include/ggml.h、ggml/src/ggml-common.h、ggml/src/iqk/iqk_quantize.cpp 等源码解释IQ4_KS与IQ4_XS的底层差异。读完本文你将掌握如何用llama-perplexity与llama-sweep-bench复现量化质量/性能评测、如何理解 QAT 模型的评测陷阱以及IQ4_KS类量化的适用边界。背景什么是 QAT 模型为什么它值得单独量化Google 发布的gemma-3-27b-it-qat-q4_0-unquantized是一个基于量化感知训练Quantization Aware TrainingQAT的模型官方在训练阶段就模拟了q4_0量化带来的误差使得模型在 4-bit 量化后依然能保持接近 bfloat16 的质量同时显著降低加载模型所需的内存。官方说明的原话是得益于 QAT该模型能够在显著降低加载模型内存需求的同时保持与 bfloat16 相近的质量。这意味着这类模型的权重分布已经被调教得特别适合 4-bit 量化因此社区作者 ubergarm 决定先用主线的 llama.cpp 将官方.safetensors转成bf16的 GGUF再用 ik_llama.cpp 从 bf16 出发烹饪出多种量化版本逐一对比文件大小与 WikiText-2 困惑度。测试得到的结论很反直觉iq4_ks量化版的 PPL 甚至低于原版 bf16q8_0也是如此。这也是本讨论的核心价值所在。认识IQ4_KSik_llama.cpp 独有的 4-bit 量化格式在深入数据之前先看IQ4_KS在 ik_llama.cpp 中的真实身份。在 ggml/include/ggml.h 中IQ4_KS与IQ4_XS属于不同的类型编号体系GGML_TYPE_IQ4_XS 23与主线 llama.cpp 兼容的旧编号段GGML_TYPE_IQ4_KS 144ik_llama.cpp 扩展编号段与IQ2_K、IQ3_K、IQ4_K、IQ5_K、IQ6_K同一系列对应文件类型GGUF ftype为GGML_FTYPE_MOSTLY_IQ4_KS 137从 ggml/src/ggml-common.h 的块结构定义可以直观看到它与IQ4_XS的差异// IQ4_XS每个 256 权重的 super-block 拥有独立的 fp16 scale typedef struct { ggml_half d; // 每 256 权重一个 fp16 尺度 uint16_t scales_h; uint8_t scales_l[QK_K/64]; uint8_t qs[QK_K/2]; // 每 32 权重块的低位量化值 } block_iq4_xs; // IQ4_KS块内没有 d 字段单一尺度按 tensor 行存储 typedef struct { uint8_t scales[QK_K/32]; // 每 32 权重一个 scale 索引 uint8_t qs[QK_K/2]; // 每 32 权重块的量化值 } block_iq4_ks; static_assert(sizeof(block_iq4_ks) QK_K/32 QK_K/2, wrong iq4_ks block size/padding);正如 ik_llama.cpp 作者 ikawrakow 在讨论中的原话解释两者的区别本质上是尺度预算的再分配IQ4_XS在每 256 权重的 super-block 上保存一个fp16的 scaleIQ4_KS改为每个 tensor 行只保存一个 scale把省下来的 16 bit/每 256 权重转化为每个 32 权重块多出的 2 bit其中 1 bit 用于提高块尺度block scale的精度另外 1 bit 用于在两张非线性查找表lookup table之间做选择。能够从两张查找表中挑选更合适的一张使得量化结果与原始权重之间的误差略低。这也是为什么二者 BPWbits per weight完全相同、性能特征几乎一致但IQ4_KS在大多数模型上 PPL 略优。值得注意的是由于IQ4_KS不再需要 256 权重的 super-block理论上可以放宽tensor 行大小必须是 256 的倍数这一限制作者表示尚未实现留待此类模型变多后再做。相关量化/反量化与点积实现位于 ggml/src/iqk/iqk_quantize.cppquantize_row_iq4_ks、dequantize_row_iq4_ks、vec_dot_iq4_ks_q8_k等并已覆盖 CUDA、Vulkan、Metal 等后端参见 ggml/src/ggml-cuda/template-instances/mmq-instance-iq4_ks.cu、ggml/src/vulkan-shaders/dequant_iq4_ks.comp 与 ggml/src/ggml-metal.m。在 src/llama-quantize.cpp 中IQ4_KS也深度参与了量化策略例如 GQA ≥ 2 的模型在量化IQ4_XS/IQ4_KS/IQ4_K等 ftype 时会自动升级注意力相关张量到IQ5_K见 src/llama-quantize.cpp而IQ3_KS、IQ2_KL在 GQA ≥ 2 时会被映射为IQ4_KS见 src/llama-quantize.cpp这也解释了混合量化 GGUF 中为什么会自然出现iq4_ks张量。复现方法PPL 与性能基准的完整命令讨论中给出了完整可复现的评测流程测试环境为 Ubuntu 24.04 x86_64、ik_llama.cpp 版本3639 (3bb64d93)用 GCC 13.3.0 编译。困惑度Perplexity评测# 获取评测语料 wiki.test.raw解压后校验 $ gunzip wiki.test.raw.gz $ sha256sum wiki.test.raw 173c87a53759e0201f33e0ccf978e510c2042d7f2cb78229d9a50d79b9e7dd08 wiki.test.raw # 对每个待测 GGUF 运行以 iq4_nl 版本为例 $ ./build/bin/llama-perplexity \ --model /mnt/raid/models/ubergarm/gemma-3-27b-it-qat-GGUF/gemma-3-27B-it-qat-iq4_nl.gguf \ --ctx-size 512 \ --ubatch-size 512 \ -f wiki.test.raw \ --seed 1337 \ --n-gpu-layers 99 \ --threads 4关键参数说明--ctx-size 512与--ubatch-size 512评测时上下文窗口与微批次都设为 512 token保证所有模型在完全一致的切分方式下计算 PPL结果可横向比较--seed 1337固定随机种子保证采样/加载过程可复现--n-gpu-layers 99将全部 62 个重复层加非重复层整体卸载到 GPUGemma-3-27B 共 63 层张量--threads 4CPU 线程数。长上下文性能Sweep Bench评测性能部分使用 ik_llama.cpp 自带的llama-sweep-bench在单张 48GB 的 RTX A6000 上完成覆盖 KV cache 从 0 一直扫到 32k 的 Prompt ProcessingPP与 Token GenerationTG表现CUDA_VISIBLE_DEVICES0, \ ./build/bin/llama-sweep-bench \ --model $model \ -ctk q8_0 -ctv q8_0 \ -fa \ -amb 512 \ -fmoe \ -c 32768 \ -ub 512 \ -ngl 99 \ --threads 4-ctk q8_0 -ctv q8_0KV cache 使用q8_0量化此参数在 Gemma3 上可用能显著降低 KV 内存占用-fa开启 Flash Attention-fmoeMoE 相关开关Gemma3 为稠密模型此处实际无专家层命令沿用于其他测试-c 32768总上下文 32k-ub 512u-batch 512。关于llama-sweep-bench与llama-bench的差异ikawrakow 在讨论中给出了重要澄清llama-sweep-bench测的是KV cache 中已有N_KV个 token再计算n_ubatch个新 token的场景而llama-bench是从 0 个 token 开始计算N个新 token。若性能随N_KV近似线性下降则llama-bench在N上的 PP 结果约等于llama-sweep-bench在N_KV N/2的结果。因此sweep-bench更贴近真实服务器单槽位single slot在固定上下文深度上的表现。相关实现可参考 examples/sweep-bench/sweep-bench.cpp其中每个批次解码后都会调用llama_synchronize(ctx)以取得准确计时见 examples/sweep-bench/sweep-bench.cpp。完整原始数据WikiText-2 困惑度对比下表完整继承了讨论中公布的原始测量结果模型均从同一个 QAT bf16 来源量化除非注明模型文件大小BPW张量构成PPL越低越好google gemma-3-27b-it BF16非 QAT 原版50.311 GiB16.001f32×373 bf16×4358.4276 ± 0.06705google gemma-3-27b-it-qat bf16QAT 未量化50.311 GiB16.001f32×373 bf16×4358.2021 ± 0.06387google gemma-3-27b-it q4_0官方 GGUF16.040 GiB5.101f32×373 f16×1 q4_0×4348.2500 ± 0.06375ubergarm q8_026.730 GiB8.501f32×373 q8_0×4358.1890 ± 0.06369ubergarm q4_0部分张量 q4_1/q8_014.857 GiB4.725q4_0×427 q4_1×7 q8_0×18.2264 ± 0.06350ubergarm pure q4_014.810 GiB4.710q4_0×434 q8_0×18.2235 ± 0.06345ubergarm iq4_xs14.085 GiB4.480iq4_xs×372 q4_0×62 q8_0×18.2290 ± 0.06365ubergarm iq4_ksik_llama.cpp 独有14.099 GiB4.484iq4_ks×372 q4_0×62 q8_0×18.1755 ± 0.06296ubergarm COSSIM-iq3_k 混合12.875 GiB4.095iq3_k×192 iq4_ks×180 q4_0×62 q8_0×18.2642 ± 0.06359ubergarm mix-iq3_k 混合12.733 GiB4.050iq3_k×124 iq4_ks×248 q4_0×62 q8_0×18.2367 ± 0.06329ubergarm iq4_nl14.810 GiB4.710iq4_nl×372 q4_0×62 q8_0×18.2477 ± 0.06390ubergarm q4_k_m14.810 GiB4.710q4_K×372 q4_0×62 q8_0×18.2303 ± 0.06364几点关键观察iq4_ks是这批 4-bit 方案中 PPL 最低的8.1755甚至低于 QAT bf168.2021与非 QAT bf168.4276同时体积仅 14.099 GiB4.484 BPW约为 bf16 的 28%。q8_0同样低于 bf16。iq4_ks比iq4_xs更优相同 BPW 档位4.48 vs 4.48PPL 从 8.2290 降到 8.1755印证了两张查找表 更高精度块尺度带来的收益。由于attn_v张量尺寸不满足iq4_ks/iq3_k的行长要求这些量化方案中 62 个blk.*.attn_v.weight张量退回到q4_0这正好对应了前文IQ4_KS尚未取消行长必须是 256 倍数限制的实现现状。作者还尝试了基于--layer-similarity余弦相似度分数的各种层混合方案COSSIM 混合、ffn gate/up 用 iq3_k ffn_down 用 iq4_ks 的 mix 方案但在该模型上未能进一步压低 PPL。作者的直觉是这个 QAT 模型确实是为 q4_0 而生有时对部分层使用略高精度的量化反而会带来轻微更差的 PPL。性能数据32k 上下文下的 PP 与 TG 扫描llama-sweep-bench在单张 RTX A600048GB上以 PP512、TG128、KV 从 0 到 32256 步进扫描。为了控制篇幅这里给出关键档位的对比完整扫描曲线见原讨论的 Raw Data 段落以iq4_ks版本为例PP 速度KV0 时 1157.61 t/sKV16384 时 749.28 t/sKV32256 时 538.16 t/sTG 速度KV0 时 33.29 t/sKV16384 时 21.37 t/sKV32256 时 15.81 t/s。横向对比几个同档量化KV0 / KV32256模型版本PP 0 / 32k (t/s)TG 0 / 32k (t/s)pure q4_01585.65 / 595.1336.40 / 16.56q4_k1461.01 / 578.7435.91 / 16.39iq4_xs1445.31 / 573.2933.09 / 15.67iq4_ks1157.61 / 538.1633.29 / 15.81mix-iq3_k1145.52 / 538.4432.44 / 15.59COSSIM-iq3_k1191.53 / 536.3134.01 / 15.58q8_01539.91 / 591.6121.98 / 12.86可以看到q4_0在纯 PP 吞吐上依然最快其反量化路径最简单iq4_ks/iq3_k混合方案在 TG 上与q4_0相当、PPL 却更低而q8_0的 TG 明显更慢。因此用iq4_ks换取最低 PPL 且 TG 不落后是该讨论的核心结论。评测可信度之争QAT 模型是否过拟合了 WikiText讨论中最具方法论价值的部分是作者 ikawrakow 对这批数据的质疑QAT 版本 bf16 的 Wiki2 PPL8.2021显著低于非 QAT 原版 bf168.4276而 q4_0 量化版8.2500又低于非 QAT bf16——这在常规量化评测中几乎不会出现。ikawrakow 在 Gemma3-12B 上做了快速实验发现q4_0量化版的 Wiki2 PPL 明显低于 bf16 或其他任何量化由此推断Google 的 QAT 训练很可能在 WikiText 类语料上严重过拟合尤其针对 q4_0 量化。这意味着Wiki2 不再适合作为该系列 QAT 模型的质量评测集PPL、KLD 或其他量化质量指标都不可靠一个量化后比 bf16 更好的结果不能直接解读为量化格式更优更可能是评测语料恰好命中了训练数据。作者本人也承认在我的标准里这也意味着不能太把该模型当回事one cannot take this model seriously。社区其他参与者saood06、bartowski1182补充了观点这与用 wikitext 做 imatrix 校准、再用 wikitext 测 PPL的循环论证问题同构——语料本身没问题只是需要换一个与校准/训练集不同的语料来做最终评测。二次验证换语料后结论是否仍然成立为回应上述质疑ubergarm 随后拼装了一个与 WikiText 无关的自制语料主要英文文本掺入少量中文与 XML来源包括 Gutenberg 电子书、Archive.org 文本等SHA-256 为456de7da9d5eec01d357f5ccb7fc7207884a706efe94535aca146f8646771bcc用相同的llama-perplexity命令重新评测模型PPL自制语料非 QAT BF166.0568 ± 0.03981QAT BF165.8897 ± 0.03774官方 q4_06.0588 ± 0.03904ubergarm q4_k5.9405 ± 0.03799观察结论换语料后绝对 PPL 整体降到 ~6.0QAT BF16 依然优于非 QAT BF16在量化版本中作者的 q4_k 优于 Google 官方 q4_0但这次没有任何量化版本能反超 BF16——这正好印证了 WikiText 上的反超现象很可能是语料重叠造成的假象同时也说明不同量化方案之间的相对排序而非绝对数值才是可靠的参考。把IQ4_KS用好的实践要点结合原讨论与 src/llama-quantize.cpp 的量化逻辑落地建议如下评测语料务必与训练/校准集隔离对 QAT 模型尤其如此至少准备一份自制或第三方语料与 WikiText 交叉验证避免得出量化超越原模型的误导性结论。同 BPW 档位优先iq4_ks而非iq4_xs二者 BPW、速度基本一致iq4_ks依靠更高的块尺度精度与双查找表选择获得更低的 PPL唯一限制是 tensor 行大小需为 256 的倍数不满足的张量如本例中的attn_v会自动回退到q4_0属正常现象。混合量化是压体积的手段COSSIM / 层混合方案iq3_kiq4_ks可在 ~4.05-4.10 BPW 下把 PPL 维持在 8.24 附近适合 VRAM 紧张场景但若目标是质量优先纯iq4_ks的 4.484 BPW 是这批测试的最优解。全量 GPU 推理时优先-t 1讨论中实测在完全卸载到 GPU 的情况下-t 1反而比多线程略快且稳定同时确认编译模式应为 Release——Debug 模式会出现ggml_backend_sched_alloc_splits: failed to allocate graph一类的额外日志并拖慢性能这不是代码问题。长上下文下关注 KV 内存而非模型体积Gemma3 的 KV cache 相对模型体积占比很高讨论日志中 32k 上下文、f16 KV 达 15.87 GiB对 27B 模型建议像测试一样使用-ctk q8_0 -ctv q8_0量化 KV cache。延伸讨论IQ4_KS家族与 KV cache 的边界讨论后期还延伸出几个值得记录的事实均出自 ikawrakow 之口非本文推断IQ4_KS与IQ5_KS理论上可用于 KV cache 量化但有前提需要采用更简单、精度略低的量化算法否则写 cache 太慢IQ4_NL已采用该策略IQ4_KS/IQ5_KS会类似同时会面临与 DeepSeekQ8_KV相同的问题——V cache 只是 K cache 的视图会缺少行尺度row scale。IQ4_NL量化 KV cache 时能把Q4_0相对fp16的 PPL 差距减半但略高于Q5_0KV作者推测IQ4_KS的表现会接近IQ4_NL。后续出现的iqN_ktTrellis 风格量化体积更小但作者在 2025-06 时表示实现尚未完全成熟未正式发布相关量化iq4_kt在 Gemma-3-QAT 上体积更小但初始 PPL 略高于iq4_ks。关于量化后 PPL 是否还能更低的社区补充测试Nexesenex 在 Gemma-3-4B 与 27B 上使用 imatrix 校准显示27B 上iq4_ksimatrixPPL 8.2450配合 embed/output 使用q6_0、attn_v保持q4_0时可到 8.1783说明embedding/output 与注意力 V 投影是 4-bit 档位下最值得保留精度的张量而在 4B 小模型上结论会因张量尺寸过小而改变iq4_xs反而优于iq4_ks提醒我们量化方案的最优解是与模型规模强相关的。小结本讨论用一组完整、可复现的实测数据回答了ik_llama.cpp 的IQ4_KS在 QAT 模型上到底值不值得用在 Gemma-3-27B QAT 上iq4_ks以 4.484 BPW 拿到全组最低 PPLWikiText-2 上甚至低于 bf16TG 速度与q4_0相当是质量优先场景下 4-bit 档位的推荐选择同时它也再次提醒所有量化实践者评测语料的选择决定了结论的可靠性面对 QAT 模型尤其要警惕训练语料重叠带来的虚高表现。若你想在自己的模型上复现仓库中的 examples/perplexity、examples/sweep-bench 与 examples/quantize 即是对应的工具入口源码级细节可继续阅读 ggml/src/iqk/iqk_quantize.cpp 与 src/llama-quantize.cpp。【免费下载链接】ik_llama.cppllama.cpp fork with additional SOTA quants and improved performance项目地址: https://gitcode.com/GitHub_Trending/ik/ik_llama.cpp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考