端侧 AI · 15 天工程路线
目录首页 English
DAY 12

LLM 量化与 GGUF

把低比特权重与 metadata 封装成可部署模型包

建议阅读:约 18 分钟

学习目标

理解 block quantization、混合精度、权重元数据及 GGUF 容器的关系。

本章关键词

关键词解释ESP32 工程类比
GGUFGGML 系执行器使用的模型容器格式。像固件镜像加可扩展的描述区。
Block quantization按块共享 scale 等参数的低比特编码。像压缩一批采样值并附带该批量程。
Weight-only只量化权重、激活保持较高精度的策略。像压缩固件常量而保留计算工作区精度。
mmap将文件映射到虚拟内存按需访问。像按页读取固件资源,减少一次性复制。

承上:回顾与定位

上一章已经为逐 token 增长的 KV 状态建立容量账本;本章进一步压缩跨请求复用的权重,并把 GGUF metadata 视为可验证的模型包契约。

从源头看今天

历史发展脉络

低比特模型的历史并不是把 float 简单截成整数。早期压缩研究已经把剪枝、量化与编码视作不同层次;LLM 时代又暴露出离群通道、层敏感度和专用 kernel 的问题。GGUF 则解决另一个维度:怎样把张量、量化类型和解释模型所需的元数据可靠装进一个可快速读取的容器。

2015

Deep Compression 将量化放进系统化模型压缩流程

Deep Compression 把剪枝、训练后量化与 Huffman 编码组合起来,说明“位宽降低”只是压缩链路的一环。它也确立了重要工程习惯:压缩后必须回到任务精度与实际存储收益验证,而不能只报告理论 bit 数。

Deep Compression 原始论文 ↗
2022

LLM.int8 揭示大模型离群特征的代价

LLM.int8 观察到部分隐藏维度出现系统性大幅值,并以混合精度路径保留这些离群计算。这推动量化从“所有权重统一降位”走向按统计特征分流,也解释了为何同为 int8,不同算法的质量和 kernel 要求会明显不同。

LLM.int8 原始论文 ↗
2022

GPTQ 让超大模型的一次性权重量化更实用

GPTQ 使用近似二阶信息逐层量化权重,在无需完整重新训练的条件下把大模型压到 3 至 4 bit 区间。它强化了“误差需按权重相互作用补偿”的认识,也让校准样本与量化顺序成为部署产物的一部分。

GPTQ 原始论文 ↗
2023

GGUF 统一张量容器与可扩展元数据

GGUF 作为 GGML、GGMF、GGJT 的后继格式,用类型化键值元数据、对齐的 tensor 区和版本字段降低歧义,并面向 mmap 读取。它并不规定模型必须采用哪一种量化;同一容器中可以存放不同类型的张量。

GGUF 官方规范 ↗
2023—至今

混合量化配方成为面向目标硬件的构建步骤

llama.cpp 的量化工具支持 K-quants、importance matrix 与按 tensor 覆盖类型,实践由选择单个“Q4”标签转向保留敏感张量、匹配 kernel、检查困惑度代理并在目标硬件测量。重新量化低比特文件也被明确视为高风险操作。

llama.cpp Quantize 官方文档 ↗
今天为什么仍然重要: 因此,本章不能把 GGUF、Q4_K_M 与“4 bit 模型”画成同义词。应拆成三层:量化算法怎样选择码值,块格式怎样保存码值与 scale,GGUF 怎样描述并定位这些张量。只有三层都被目标 runtime 正确理解,文件变小才可能转化为可用的内存、速度与质量收益。
借熟悉的系统建立直觉

类比图解

把量化模型想成装进航运集装箱的压缩调色板

原始 FP16 权重像画室里几万种细微颜料。量化时不是随手丢掉颜色,而是把相近色按一小块分组,为每块制作有限色卡;整数码是色卡编号,scale 与最小值是还原说明。敏感层像人物眼睛,可留用更细色卡。GGUF 则是带清单的集装箱:箱头记录架构、tokenizer 和对齐规则,货位表指明每块张量在哪里、用哪种编码,runtime 才能直接搬到正确 kernel。

原始颜料 FP16/BF16 基线权重与可信来源
分块色卡 量化值与每块共享的 scale、min 等附加参数
精细局部 输出层、嵌入或高敏感 tensor 保留更高精度
货运清单 GGUF header、metadata、tensor 描述与对齐数据区

类比的边界: 颜料类比没有体现矩阵乘 kernel:压缩率高并不自动加速,若硬件缺少对应解码与乘法实现,运行时可能先反量化再计算。感知上的“颜色接近”也不是语言模型质量;最终仍需困惑度或任务集、长文本稳定性和目标设备基准来判断。

本章讲解

先算真实 BPW,不要被 Q4 名字迷惑

块量化除低比特码值外,还要保存每块的 scale、min、对齐填充,有些格式又混用不同 tensor 精度,所以文件平均 bits per weight 通常不等于名称中的数字。验算时读取 GGUF tensor 类型和元素数,分别汇总数据字节与元数据开销,再与 FP16 基线比较。容量预算还要另加 tokenizer、KV cache 和 runtime workspace,模型文件大小不是峰值 RAM。

块大小决定压缩与局部适应能力

一组权重共享量化参数时,块越大,scale 开销占比越低,却越难同时覆盖小值和离群值;块越小,更能贴合局部范围,但额外参数、索引与 kernel 处理成本上升。per-tensor、per-channel 与 block-wise 不是抽象标签,而是在统计适配和存储访问之间选粒度。应查看目标格式的准确布局,不能拿通用公式硬套所有 Q4。

混合精度要由敏感度与 kernel 共同决定

嵌入、输出投影、注意力或某些 MoE tensor 对误差的敏感度并不一致,K-quants 的后缀往往表示一套混合配方。选择时从高精度 GGUF 生成多个候选,使用相同校准样本与任务集比较,并确认 backend 对其中每种 tensor type 都有高效 kernel。若少数层频繁回退或反量化,省下的带宽可能被边界转换抵消。

GGUF 是自描述容器,不是质量证书

加载器依据 magic、版本、alignment、tensor shape/type 和架构 metadata 解释文件,tokenizer 与 chat template 相关字段还决定输入语义。格式合法只说明字节可解析,不证明权重来源、量化过程或模型输出正确。部署前应保存源模型修订号、转换器 commit、量化命令与哈希,并用 dump 工具核对关键 metadata,防止“能打开但稳定答错”的静默故障。

建立不可逆转换的单向发布链

量化会丢失信息,从 Q4 再量化到 Q5 并不会恢复精度,反而加入第二轮舍入误差。工程仓库应保留可信 FP16/BF16 或官方原始权重,把转换和量化做成可重放构建:输入哈希固定、工具版本固定、产物另名输出。验收同时测文件大小、峰值常驻内存、PP/TG 速度、任务正确率和长输出异常,任一项退化都能追溯到配方。

让数据真正跑起来

动态过程演示

一份高精度权重如何变成可验证的 GGUF

动画把“转换容器”和“量化张量”分开显示,避免将格式、算法和最终部署性能混为一步。

步骤 1 / 6

冻结基线 · BF16/FP16 weights + tokenizer + revision

记录来源、许可证、哈希与基线输出

观察点

后续任何低比特产物都应可回溯到同一高精度起点

循环 / 返回条件: 若质量超限,回到“采集敏感度”扩大代表性样本或提高敏感 tensor 精度;若速度不升,回到“分块量化”检查 kernel 支持与反量化边界。始终从高精度基线重新生成,禁止串行重复量化。

查看静态全景图
FP16 tensor → blocks → quantized values + scales/mins → GGUF tensor + metadata → runtime kernel

代码或命令示例

python convert_hf_to_gguf.py ./model --outfile model-f16.gguf
llama-quantize model-f16.gguf model-q4_k_m.gguf Q4_K_M
llama-cli -m model-q4_k_m.gguf -p "hello"

动手实验

对同一模型比较 F16/Q8/Q4 的文件大小、困惑度代理指标、首 token 延迟和峰值内存。
实验记录与导出

工程陷阱

避免误判: 从已经量化的 GGUF 再量化会累积误差;应从 F16/BF16 或更高精度源产物生成各个目标量化版本。

核心测试

完成 3 道单选题后提交;提交前不会显示答案。

1. GGUF metadata 的重要用途是什么?
2. “Q4”为何不必然等于每参数精确 4 bit?
3. 比较两种 GGUF 量化时最不充分的指标是?

一起把本章讲清楚

在 GitHub 上讨论本章

登录 GitHub 后提问、补充实测或分享你的实现;评论会保存在本课程的 GitHub Discussions 中。

评论区需要 JavaScript;也可以直接打开 GitHub 讨论区: 打开 GitHub 讨论区 ↗

延伸阅读

启下:下一章如何使用本章能力

下一章把模型包真正交给 runtime 和端侧推理框架,检查加载、采样、调度、backend 分区、fallback 与取消路径。

下一天: Day 13 · LLM Runtime