Appearance
3.7 量化与模型压缩
1.10 本地跑模型里你学会了用 Ollama 跑模型。1.13 自托管推理部署讲了服务端部署。但有个问题还没讲清楚:Ollama 上同一个模型,为什么有 llama3:8b、llama3:8b-q4、llama3:8b-q8 等不同版本?这些后缀代表什么?质量差多少?应该选哪个?
这一节把模型压缩的核心概念讲透,让你能做出有据可查的选择。
模型参数存储的基础
神经网络里有大量浮点数(参数),每个数默认用 float32(32 位浮点) 存储,占 4 字节。
一个 70 亿参数(7B)的模型:
7,000,000,000 个参数 × 4 字节 = 28 GB28GB 只是模型权重,推理时还要分配激活值内存,实际需要约 32-40 GB 显存——消费级 GPU(如 RTX 4090 只有 24GB)直接放不下。
量化(Quantization):用更少的位数表示参数
量化的思路很简单:把高精度的浮点数"压缩"成低精度的整数。
💡 类比:温度计精确到小数点后 4 位(如 23.4152°C),但天气 App 只显示 23°(整数)。精度损失了,但对"今天穿什么衣服"这个决策没有影响。量化对模型参数做的是同样的事——大多数参数的精度损失不会影响最终输出质量,但内存占用大幅下降。
float32(4字节):0.123456789...(精确到小数点后 7 位)
float16(2字节):0.1235(精确到小数点后 4 位)
int8 (1字节):精度再降
int4 (0.5字节):只能表示 16 个不同的值,大幅压缩7B 模型在不同量化精度下的大小:
| 精度 | 每参数字节数 | 7B 模型大小 | 需要显存(约) |
|---|---|---|---|
| float32 (F32) | 4 字节 | ~28 GB | ~32 GB |
| bfloat16 (BF16) | 2 字节 | ~14 GB | ~16 GB |
| int8 (Q8) | 1 字节 | ~7 GB | ~8 GB |
| int4 (Q4) | 0.5 字节 | ~4 GB | ~5 GB |
| int2 (Q2) | 0.25 字节 | ~2 GB | ~3 GB |
量化方式:Q4 不只有一种
Ollama 和 llama.cpp 里的 GGUF 格式,Q4 后面还有不同变体:
Q4_K_M:Q4 量化,K-quants 方法,M = medium(平衡精度和速度)
Q4_K_S:Q4 量化,K-quants 方法,S = small(更小更快,精度略低)
Q5_K_M:Q5 量化,精度比 Q4 好,体积更大
Q8_0: Q8 量化,0 = 旧方法,精度接近 float16,体积是 float32 的 1/4💡 K-quants 是目前 GGUF 里最好的量化方法之一:它不是均匀地量化所有参数,而是识别出"哪些参数对输出影响大",对重要参数保留更高精度,对不重要的压得更低。结果是同样的比特数,质量比简单的均匀量化好得多。
质量损失有多大?
这是最关键的问题。量化有没有让模型"变蠢"?
结论:Q4_K_M 在大多数任务上与 float16 几乎没有可感知的差异;Q2 就开始明显变差。
| 量化 | 相对 float16 质量 | 建议 |
|---|---|---|
| BF16 / F16 | 100%(基准) | 有足够显存优先选 |
| Q8_0 | ~99% | 几乎无损,首选的量化起点 |
| Q6_K | ~98-99% | 高质量,体积中等 |
| Q5_K_M | ~97-98% | 质量和体积的好平衡 |
| Q4_K_M | ~95-97% | 消费级 GPU 的推荐默认选择 |
| Q3_K_M | ~90-93% | 内存极限时考虑 |
| Q2_K | ~80-85% | 明显变差,不推荐实际使用 |
⚠️ 这些是平均数字。推理、代码生成等对精度敏感的任务,量化损失会更明显;简单问答、总结,可能你都感觉不出来。最好是在你的实际任务上跑对比测试。
Ollama 里怎么选
bash
# 查看某个模型有哪些量化版本
ollama list # 看已有的
# 或者去 ollama.com/library 搜模型,看 Tags
# 拉取不同量化版本
ollama pull llama3.1:8b # 默认(通常是 Q4_K_M)
ollama pull llama3.1:8b-instruct-q8_0 # 高质量 Q8
ollama pull llama3.1:8b-instruct-fp16 # 原始 float16(需要 ~16GB)选择建议:
显存 ≤ 8GB:
→ 优先选 Q4_K_M 的 7B 模型(约需 5GB)
→ 勉强可以跑 Q2_K 的 13B,但质量差
显存 12-16GB:
→ Q4_K_M 的 13B,或 Q8 的 7B
显存 24GB(RTX 4090 / A10):
→ Q8 的 13B,或 fp16 的 7B,或 Q4_K_M 的 32B
显存 ≥ 40GB(A100/H100):
→ fp16 的 32B,或 Q4_K_M 的 70B其他量化方法(了解即可)
GGUF 是本地 CPU/GPU 混合推理的格式,还有几个常见的量化方案:
| 方案 | 框架 | 特点 |
|---|---|---|
| GGUF / llama.cpp | Ollama, LM Studio | CPU + GPU 混合,本地最通用 |
| GPTQ | transformers, vLLM | GPU 专用,推理速度快,精度好 |
| AWQ | vLLM, TGI | 激活感知量化,Q4 质量优于 GPTQ |
| BitsAndBytes | transformers | 8bit/4bit,方便和 HuggingFace 配合 |
| GGUF(新)vs GGML(旧) | — | GGML 已废弃,全部用 GGUF |
💡 实用原则:本地跑用 GGUF(Ollama 默认),服务端 GPU 部署用 vLLM + AWQ,需要微调再用 BitsAndBytes。
量化之外:其他压缩技术
量化压的是每个参数的精度。还有几种不同维度的压缩:
蒸馏(Distillation):用大模型的输出训练小模型,小模型"学大模型的行为"。结果是更小的模型,而不仅是精度降低的同尺寸模型。(已在 5.16 微调案例集 讲过)
剪枝(Pruning):把对输出贡献小的参数/注意力头去掉。剪掉的部分直接消失,不是压缩精度。效果取决于哪些部分是真正不重要的。
稀疏化(Sparsification):把大量参数设置为 0,然后用稀疏矩阵格式存储(存储结构只记非零值)。MoE(Mixture of Experts,专家混合)模型的原理就是每次只激活一部分"专家",本质是运行时的稀疏化。
这些技术通常由模型提供方在发布模型时做,你作为用户不需要自己实现。了解它们能帮你读懂模型卡(Model Card)里的描述。
实际性能对比
以 llama3.1:8b 在 M2 MacBook(16GB 统一内存)为例:
| 量化 | 加载时间 | 推理速度(tok/s) | 质量感知 |
|---|---|---|---|
| Q4_K_M | ~3s | ~40-50 | 正常 |
| Q8_0 | ~5s | ~25-35 | 更好 |
| fp16 | ~10s | ~15-20(内存带宽瓶颈) | 最好 |
量化之后体积缩小,但不是"越小越快"。速度主要取决于内存带宽而不是模型大小。Q4 快是因为从内存读出来的数据量少,而不是"运算更简单"。
🛠️ 实战练习:比较量化质量
- 用 Ollama 下载同一个模型的两个量化版本(如
llama3.1:8b默认 Q4 和llama3.1:8b-instruct-q8_0) - 准备 3 个任务:简单问答、代码生成、复杂推理
- 对每个任务,两个模型各跑 5 次,对比:a) 答案质量(人工评分)b) 推理速度(tokens/秒)
- 记录你自己是否能感知出质量差异
期望结果:简单问答几乎感知不到差异;代码和推理任务上 Q8 可能更稳定;Q4 明显更快。
进阶挑战:如果你有 GPU,对比 CPU 推理和 GPU 推理的速度差异,并观察量化对 GPU 推理的影响(GPU 对 Q4 的加速不如 CPU 明显)。
📌 关键结论
- 量化 = 把高精度浮点数压缩成低精度整数,7B 模型可以从 28GB 压到 4-5GB
- Q4_K_M 是消费级 GPU 的推荐默认选择,质量损失在大多数任务上可接受
- K-quants 方法比简单均匀量化好:对重要参数保留更高精度
- Q2 开始明显变差,实际使用不推荐;Q8 几乎无损
- 速度提升来自内存带宽减少,而不是"运算更简单"