llama.cpp 模型量化实战指南:llama-quantize 选项全解析与量化类型选型
本文基于 llama.cpp 仓库中 tools/quantize/README.md 展开,系统讲解如何将高精度 GGUF 模型(F32/BF16)转换为 Q4_K_M 等低比特量化格式:覆盖从 convert_hf_to_gguf.py 准备输入文件、llama-quantize 全部命令行选项、imatrix 重要性矩阵、多模态 mmproj 转换,到各量化类型的体积/速度对照表与源码级的 k-quant 混合策略原理,读完后可以独立完成从下载 HF 模型到产出一个可部署量化 GGUF 文件的完整流程。
量化在 llama.cpp 中的定位与整体流程
量化(quantization)是指降低模型权重精度(例如从 32 位浮点降到 4 位整数),以缩小模型体积并加速推理;代价是引入一定的精度损失,通常用困惑度(Perplexity, ppl)和/或 KL 散度(kld)来度量。使用合适的 imatrix(importance matrix,重要性矩阵)文件可以显著降低这种损失。
整个量化工作流分为两个阶段:
- 将原始模型转换为 GGUF 格式(高精度,如 F32/BF16);
- 对转换后的 GGUF 文件执行量化。
如果模型支持多模态输入(图像或音频),还需要额外转换并量化多模态编码器与投影器(mmproj 文件)。
执行上述 Python 侧任务前,需要先安装依赖:
python3 -m pip install -r requirements.txt
若使用 uv:
uv pip install -r requirements.txt --index-strategy unsafe-best-match
仓库还提供了在线量化服务(Hugging Face 上的 GGUF-my-repo Space),可在不搭建任何环境的情况下自行构建量化版本,其构建环境每 6 小时与 llama.cpp main 分支同步。
第一步:准备输入 GGUF 文件
要从 Hugging Face 仓库转换模型,可执行如下命令(以 Gemma 4 E2B 为例):
python convert_hf_to_gguf.py --outfile gemma-4-E2B-it-bf16.gguf --outtype bf16 --remote google/gemma-4-E2B-it
仓库根目录下的 convert_hf_to_gguf.py 是这一阶段的入口脚本。关于 --outtype 的几个要点:
- 在模型通常以 16 位格式发布的常见情况下,
--outtype auto(或干脆省略--outtype)同样有效; - 如果模型已经下载到本地,指定本地目录并去掉
--remote标志即可; - 出于兼容性考虑,Python 依赖默认安装 transformers 4,但越来越多的模型(如 Gemma 4)需要 transformers 5,可以安全地执行
pip install -U transformers升级。
第二步:执行量化
得到高质量的高精度 GGUF 后,使用 llama-quantize 应用量化。例如量化为 Q4_K_M:
./build/bin/llama-quantize gemma-4-E2B-it-bf16.gguf gemma-4-E2B-it-Q4_K_M.gguf Q4_K_M
该命令的最终实现位于 llama-quantize 主体逻辑,其入口 main.cpp 只是简单转发到 llama_quantize()。
基础选项
| 选项 | 说明 |
|---|---|
--allow-requantize |
允许对已量化的张量再次量化。警告:与从 16bit/32bit 直接量化相比,这会造成严重的质量下降 |
--leave-output-tensor |
让 output.weight 保持不(再)量化。会增加模型体积,但可能提升质量,重新量化场景下尤其明显 |
--pure |
禁用 k-quant 混合策略,所有张量量化为同一类型 |
--imatrix file_name |
使用指定文件中的重要性矩阵数据来优化量化 |
--include-weights tensor_name |
仅对指定张量使用重要性矩阵(可多次指定;与 --exclude-weights 互斥) |
--exclude-weights tensor_name |
对未指定的张量使用重要性矩阵(与 --include-weights 互斥) |
--output-tensor-type |
为 output.weight 张量指定特定量化类型 |
--token-embedding-type |
为 token 嵌入张量指定特定量化类型 |
--keep-split |
按输入文件的分片(shards)生成量化模型,而不是输出单一文件 |
高级选项
| 选项 | 说明 |
|---|---|
--tensor-type |
将特定张量量化为特定类型,张量名支持正则语法,可多次指定 |
--prune-layers |
剪掉(删除)列表中指定的层 |
--override-kv |
在量化后模型中按 key 覆盖模型元数据,可多次指定 |
源码中还有几个 README 未逐一展开、但 --help 会展示的参数,同样值得了解(见 quantize.cpp 的 usage()):
--tensor-type-file tensor_types.txt:以文件形式提供一批tensor_name=ggml_type映射,格式与--tensor-type相同,以空格或换行分隔,适合批量处理很长的张量清单;--dry-run:只计算并打印量化后的最终体积,不实际执行量化,例如llama-quantize --dry-run model-f32.gguf Q4_K;--max-buffer-size MiB:限制量化单个张量时保留在内存中的张量行数上限(默认 8192 MiB)。在 RAM 有限的机器上量化拥有超大张量的模型时可以调小该值。
命令行末尾还有一个可选的 nthreads 位置参数(见 usage() 签名 model-f32.gguf [model-quant.gguf] type [nthreads]),指定量化线程数;省略时由库使用默认线程数。
输出文件名的自动推导
从 参数解析逻辑 可以看到,命令支持两种写法:
<input.gguf> <ftype>:省略输出路径时,自动导出为输入文件同目录下的ggml-model-<ftype>.gguf(这也是下文示例中"输出为 ggml-model-Q4_K_M.gguf"的由来);<input.gguf> <output.gguf> <ftype>:显式指定输出路径。
量化类型参数同时接受名称(大小写不敏感,如 q4_k_m)或数值 ftype 编号。完整可用的类型列表可以通过 llama-quantize 的帮助输出查看,源码中的 QUANT_OPTIONS 表 定义了全部类型,例如:
Q2_K : 2.96G, +3.5199 ppl @ Llama-3-8B
Q4_K : alias for Q4_K_M
Q4_K_M : 4.58G, +0.1754 ppl @ Llama-3-8B
Q5_K_M : 5.33G, +0.0569 ppl @ Llama-3-8B
Q6_K : 6.14G, +0.0217 ppl @ Llama-3-8B
Q8_0 : 7.96G, +0.0026 ppl @ Llama-3-8B
COPY : only copy tensors, no quantizing
值得注意的是 COPY 类型:它只复制张量、不做任何量化,可用于纯元数据修改或层剪枝场景(见下文示例)。另外,--keep-split 时输出名会去掉 .gguf 后缀,按分片命名。
imatrix:用校准数据提升低比特量化质量
低比特(尤其是 1~3 bit 的 i-quants)的质量高度依赖 imatrix。仓库中 tools/imatrix/README.md 对配套的 llama-quantize --imatrix 工作流有完整说明:
# 生成重要性矩阵(默认文件名 imatrix.gguf),99 层卸载到 GPU 加速
./llama-imatrix -m ggml-model-f16.gguf -f calibration-data.txt -ngl 99
# 使用 imatrix 执行 Q4_K_M 量化
./llama-quantize --imatrix imatrix.gguf ggml-model-f16.gguf ./ggml-model-q4_k_m.gguf q4_k_m
imatrix 的核心思想是:先用一批校准文本(如 wiki.train.raw)跑前向传播,统计每个张量各行激活的均方值,量化时据此给"更重要"的行分配更精细的量化步长。llama-quantize 侧的实现见 quantize.cpp 的 load_imatrix()/prepare_imatrix():
- 新版 GGUF 格式的 imatrix 会记录 per-expert 的激活计数,加载时按专家维度归一化(
sums/counts),这使 MoE 模型的每个专家都能拥有独立的 imatrix 切片; - 旧版二进制(
.dat)格式仍兼容,加载时除以总调用次数ncall做归一化; - 一旦提供 imatrix,其来源文件、数据集、条目数和 chunk 数会作为
quantize.imatrix.*元数据写进输出模型,便于追溯量化配置。
--include-weights / --exclude-weights 则用于控制 imatrix 生效的范围:从 prepare_imatrix() 的实现看,两者都是按张量名做子串匹配——include 保留命中项、exclude 剔除命中项,且两者不能同时使用(源码中有显式检查)。
量化类型与细粒度控制示例
README 给出了一组典型用法,全部保留如下:
# 朴素 Q4_K_M 量化:默认设置 + 8 个 CPU 线程,输出为 "ggml-model-Q4_K_M.gguf"
./llama-quantize input-model-f32.gguf q4_k_m 8
# 开启重量化,output 张量不量化,其余张量统一量化到同一级别(Q4_K,即 --pure)
./llama-quantize --allow-requantize --leave-output-tensor --pure input-model-f32.gguf q4_k_m 8
# 仅对指定张量(attn_v 和 ffn_down)使用重要性矩阵
./llama-quantize --imatrix imatrix.gguf --include-weights attn_v --include-weights ffn_down input-model-f32.gguf q4_k_m 8
# output 张量设为 Q5_K_M、token 嵌入设为 Q3_K_M,并保持输入文件的分片结构
./llama-quantize --imatrix imatrix.gguf --output-tensor-type q5_k --token-embedding-type q3_k --keep-split input-model-f32.gguf q4_k_m 8
# 用正则按层奇偶性指定类型:奇数层的 attn_k 量化为 Q5_K_M,偶数层的 attn_q 量化为 Q3_K_M
./llama-quantize --imatrix imatrix.gguf --tensor-type "\.(\d*[13579])\.attn_k=q5_k" --tensor-type "\.(\d*[02468])\.attn_q=q3_k" input-model-f32.gguf q4_k_m 8
# attn_v 与 ffn_down 设为 Q5_K_M,并剪掉第 20、21、22 层
./llama-quantize --imatrix imatrix.gguf --tensor-type attn_v=q5_k --tensor-type ffn_down=q5_k --prune-layers 20,21,22 input-model-f32.gguf q4_k_m 8
# 覆盖 expert used count 元数据为 16、剪掉 20/21/22 层,且不做量化(仅复制张量 COPY),并指定输出文件名
./llama-quantize --imatrix imatrix.gguf --override-kv qwen3moe.expert_used_count=int:16 --prune-layers 20,21,22 input-model-f32.gguf pruned-model-f32.gguf copy 8
这些选项在源码中的落点是:--tensor-type 经 parse_tensor_type() 解析为 tensor_name=ggml_type 对,最终通过 params.tt_overrides 数组传给量化核心;--prune-layers 经 parse_layer_prune() 解析为去重排序后的层号数组,并以 -1 结尾作为数组终止符传入 params.prune_layers;--override-kv 走 string_parse_kv_override() 解析成 llama_model_kv_override 列表,连同 imatrix 元数据一起经 params.kv_overrides 写入输出模型。对应的 C 头文件字段定义在 include/llama.h 的 llama_model_quantize_params 结构中。
可选:转换多模态组件(mmproj)
llama.cpp 转换的 LLM 部分对纯对话应用已经足够。如果模型接受多模态输入并希望利用这一能力,需要单独生成一个 GGUF 文件——通称 mmproj(multimedia projector),除投影层外还可能包含视觉/音频编码器。
多模态组件通常远小于其配套的 LLM,但它们的精度直接影响生成质量,因为这类组件负责为 LLM 准备输入:输入越接近训练时见过数据,LLM 效果越好。因此多模态组件一般保留在 bf16 或 q8 这类较高质量格式上——使用更小量化对速度和内存的影响可以忽略,但整体质量可能受损。
python convert_hf_to_gguf.py --mmproj --outfile mmproj-gemma-4-E2B-it-Q8_0.gguf --outtype q8_0 --remote google/gemma-4-E2B-it
运行量化后的模型
./build/bin/llama cli -m ./gemma-4-E2B-it-Q4_K_M.gguf --mmproj ./mmproj-gemma-4-E2B-it-Q8_0.gguf --image <input_image> --prompt "Describe this image"
量化类型对比:体积与速度
不同量化方式在磁盘体积与推理速度上各有差异。以下以 meta-llama/Llama-3.1-8B 为例(数据来自 README 的基准表格):
| Measure | IQ1_S | IQ1_M | IQ2_XXS | IQ2_XS | IQ2_S | IQ2_M |
|---|---|---|---|---|---|---|
| bits/weight | 2.0042 | 2.1460 | 2.3824 | 2.5882 | 2.7403 | 2.9294 |
| size (GiB) | 1.87 | 2.01 | 2.23 | 2.42 | 2.56 | 2.74 |
| prompt processing t/s @ 512 | 858.88 ±1.22 | 847.99 ±0.47 | 852.39 ±0.85 | 826.99 ±12.51 | 783.55 ±13.73 | 787.68 ±7.00 |
| text generation t/s @ 128 | 79.73 ±0.79 | 72.92 ±0.14 | 79.86 ±0.22 | 78.04 ±0.46 | 77.30 ±2.47 | 74.44 ±0.15 |
| Measure | IQ3_XXS | IQ3_XS | IQ3_S | IQ3_M | IQ4_XS | IQ4_NL |
|---|---|---|---|---|---|---|
| bits/weight | 3.2548 | 3.4977 | 3.6606 | 3.7628 | 4.4597 | 4.6818 |
| size (GiB) | 3.04 | 3.27 | 3.42 | 3.52 | 4.17 | 4.38 |
| prompt processing t/s @ 512 | 813.88 ±6.53 | 708.71 ±1.26 | 798.78 ±8.81 | 768.70 ±13.73 | 771.80 ±11.38 | 806.03 ±7.07 |
| text generation t/s @ 128 | 73.95 ±0.20 | 71.67 ±0.54 | 69.31 ±0.63 | 70.15 ±0.33 | 77.51 ±0.20 | 76.63 ±0.28 |
| Measure | Q2_K_S | Q2_K | Q3_K_S | Q3_K_M | Q3_K_L | Q4_K_S |
|---|---|---|---|---|---|---|
| bits/weight | 2.9697 | 3.1593 | 3.6429 | 3.9960 | 4.2979 | 4.6672 |
| size (GiB) | 2.78 | 2.95 | 3.41 | 3.74 | 4.02 | 4.36 |
| prompt processing t/s @ 512 | 798.91 ±6.40 | 784.45 ±7.85 | 752.17 ±7.94 | 783.44 ±9.92 | 761.17 ±7.55 | 818.55 ±9.58 |
| text generation t/s @ 128 | 90.01 ±0.12 | 79.85 ±0.20 | 69.84 ±0.18 | 71.68 ±0.22 | 69.38 ±0.49 | 76.71 ±0.20 |
| Measure | Q4_K_S | Q4_K_M | Q5_K_S | Q5_K_M | Q6_K | Q8_0 |
|---|---|---|---|---|---|---|
| bits/weight | 4.6672 | 4.8944 | 5.5704 | 5.7036 | 6.5633 | 8.5008 |
| size (GiB) | 4.36 | 4.58 | 5.21 | 5.33 | 6.14 | 7.95 |
| prompt processing t/s @ 512 | 818.55 ±9.58 | 821.81 ±21.44 | 752.52 ±0.99 | 758.69 ±7.43 | 812.01 ±10.82 | 865.09 ±8.30 |
| text generation t/s @ 128 | 76.71 ±0.20 | 71.93 ±1.52 | 69.53 ±0.18 | 67.23 ±1.08 | 58.67 ±3.13 | 50.93 ±0.08 |
| Measure | F16 |
|---|---|
| bits/weight | 16.0005 |
| size (GiB) | 14.96 |
| prompt processing t/s @ 512 | 923.49 ±0.53 |
| text generation t/s @ 128 | 29.17 ±0.04 |
从表中可以读出几个实用结论:i-quants(IQ 系列)在 2~3 bit 区间提供了比 Q2_K/Q3_K 更低的 bpw;Q4_K_M 与 Q5_K_M 是体积/质量折中的主流选择;Q6_K、Q8_0 在生成速度上明显更慢,因为量化越高,访存开销越大。这些数字是仓库文档给出的参考基准,实际数值取决于硬件与 prompt 长度,选型时建议结合 llama-bench 自行验证。
内存与磁盘需求
处理大模型时,务必为中间文件预留足够的磁盘空间。由于模型目前是完整加载进内存的,需要足够的磁盘保存文件、足够的 RAM 加载模型——目前两者需求量相同。以 Llama 3.1 为例:
| Model | Original size | Quantized size (Q4_K_M) |
|---|---|---|
| 8B | 32.1 GB | 4.9 GB |
| 70B | 280.9 GB | 43.1 GB |
| 405B | 1,625.1 GB | 249.1 GB |
这也解释了 --max-buffer-size 与 --keep-split 存在的意义:前者压低单张量量化时的峰值内存,后者避免超大模型重新合并分片时的额外磁盘占用。
源码深潜:k-quant 混合策略与 --pure 的本质
--pure 选项的完整定义是"禁用 k-quant 混合(k-quant mixtures),所有张量量化为同一类型"。所谓"k-quant 混合",指的是 Q4_K_S/Q4_K_M 这类混合精度方案:并非所有张量都量化成 Q4_K,而是按张量角色分配不同精度。核心决策逻辑在 src/llama-quant.cpp 的张量类型选择函数中,从源码结构看:
Q4_K_M/Q5_K_M会对attn_v张量升级到 Q5_K/Q6_K(GQA 头数 ≥ 4 时更激进),注释解释了原因:attn_v行数只有attn_q的 1/8(GQA 下 q 头数是 v 头数的若干倍),因此即使升两档,attn_v的体积仍远小于attn_q,却能显著提升量化精度——这正是"混合"省体积又保质量的关键;- 层序靠前的
ffn_down(前 1/8 层)也会按 ftype 升级类型,配合 imatrix 时还会对早期层的ffn_down做"防失控"保护,因为 Q4_1/Q5_1 在没有 imatrix 时容易在这些层出现异常; - 低比特 i-quants(如 IQ1_S、IQ2_XS)有硬性要求:
tensor_requires_imatrix()会判定目标类型是否需要 imatrix 数据,缺失时直接抛出this quantization requires an imatrix!;而 k-quants 作为通则不强制要求; - MoE 模型的量化按专家分块处理:由于 imatrix 切片从不在专家边界中间切分(见
llama_tensor_quantize_impl()中imatrix_for_row()按nrows_per_expert取行偏移的实现),每个专家都使用自己对应的激活统计。
所以 --pure 的价值在于:当你明确希望所有张量同精度(例如便于对比实验或特定部署约束)时,可以关闭上述自动升档逻辑。同理,--tensor-type 提供的正则覆盖能力可以在混合策略之上做手工微调(如上文奇偶层示例),这是"自动混合 + 手工干预"两层控制的组合。
仓库还附带了 tools/quantize/tests.sh 端到端脚本,演示了分片与重新量化的组合用法:先用 llama-gguf-split 把模型切成 12 个分片,再分别用 --allow-requantize --keep-split(保持分片)和合并模式(单文件)对 Q8_0 分片重新量化为 Q4_K,并用 llama-completion 验证重量化后的模型可正常加载生成——这是验证"分片 → 重量化"工作流的官方参照。
背景资料:量化技术的演进脉络
README 的"Background information"一节列出了 k-quants 与 i-quants 的关键演进 PR(此处以文字概述,不含外部链接):k-quants 的引入、k-quants 改进与 i-quants 的诞生、2-bit i-quants(含推理内核与编码支持两批工作)、MoE 模型支持、imatrix 机制本身、imatrix 推广到所有 k-quants、GPU 上计算 imatrix、legacy 量化格式的 imatrix 支持、k-quants 调优,以及 Q3_K_XS、3-bit i-quants 等后续类型补齐,另有若干轮专门的量化调优 PR。阅读这些 PR 的提交信息与讨论,是理解各量化类型设计动机(为什么 Q4_K_M 是默认推荐、为什么 i-quants 需要 imatrix)的最直接途径。
快速检查清单
完成一次完整的量化前,可以按以下清单核对:
- 输入是否为高精度 GGUF(F32/BF16/Q8_0 均可,但避免从低比特直接
--allow-requantize); - 目标类型 ≤ 3 bit 时,是否已生成 imatrix 并通过
--imatrix传入; - 是否需要
--leave-output-tensor(重量化场景推荐)与--pure(同精度需求); - 超大模型是否配置了
--keep-split与--max-buffer-size,并确认磁盘/RAM 满足"磁盘 ≈ 内存"的需求; - 多模态模型是否单独转换了 mmproj 并保持 q8_0/bf16 级别精度;
- 输出模型是否用
llama-bench或 llama-perplexity 工具对比量化前后的 ppl/kld,确认精度损失可接受。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00