量化基础:FP16、INT8、INT4 到底怎么选?
聊到大模型部署,量化是个绕不开的话题。说白了,量化就是用更少的比特数去表示模型的权重和激活值。我刚开始接触这玩意儿的时候,也觉得挺玄乎——把 FP16 砍成 INT4,模型还能好好干活吗?
后来踩过几次坑,才慢慢摸清楚门道。今天咱们就把量化的原理、影响和选型策略掰开揉碎讲清楚。
量化到底在做什么?
先看一个最简单的例子。一个 FP32 的浮点数,占 4 个字节。一个 INT8 整数,只占 1 个字节。你把模型里所有参数从 FP32 换成 INT8,模型体积直接缩到四分之一。
但问题来了——浮点数能表示的小数精度,整数根本表示不了。所以量化要做的事,就是「把浮点数的取值范围,映射到整数的取值范围上」。这个映射过程,我们叫它 校准(Calibration)。
核心公式(对称量化):
scale = max(abs(weights)) / 127
quantized = round(weights / scale)
dequantized = quantized * scale
scale 是缩放因子,127 是 INT8 的最大正值。就这么简单的一除一乘,模型就「瘦身」了。
我在项目中遇到过一种情况:某个层的权重分布特别不均匀,大部分值集中在 0 附近,但有几个离群点特别大。这时候用对称量化,scale 会被那几个离群点拉得很大,导致中间那些正常值的精度全丢了。嗯,这就是量化里最常见的坑之一。
FP16、INT8、INT4 的差异
咱们直接上表格,看得更清楚。
| 量化类型 | 位宽 | 模型体积缩减 | 典型精度损失 | 推理速度提升 |
|---|---|---|---|---|
| FP16 | 16 bit | 50%(相对 FP32) | 几乎无损失 | 1.5x - 2x |
| INT8 | 8 bit | 75%(相对 FP32) | 0.5% - 2% | 2x - 4x |
| INT4 | 4 bit | 87.5%(相对 FP32) | 2% - 8% | 3x - 6x |
你可能会问:FP16 也算量化?严格来说,FP16 是低精度浮点,不是整数量化。但在部署场景里,大家习惯把它归到「量化」这个大类里讨论。我个人习惯把 FP16 叫做「无损瘦身」,INT8 叫「均衡方案」,INT4 叫「极限压缩」。
量化对性能的影响
性能提升主要来自三个方面:
- 内存带宽:数据量小了,从显存搬到计算单元的时间就短了。大模型推理的瓶颈往往就在这。
- 计算吞吐:INT8 的乘加运算比 FP16 快得多,现代 GPU 和 CPU 都有专门的 INT8 加速单元。
- 缓存命中率:更小的数据更容易塞进缓存,减少 cache miss。
我记得有一次调优一个 7B 模型,FP16 推理时显存占用 14GB,换成 INT8 直接降到 7GB。不仅单卡能跑了,而且 batch size 还能翻倍。你想想看,这带来的吞吐提升可不是一星半点。
小技巧:在 llama.cpp 里,你可以用 -t 参数控制线程数,用 -ngl 控制 GPU 层数。量化后的模型,CPU 推理也能有不错的体验。我一般先用 INT8 跑一遍,看看精度能不能接受,再决定要不要上 INT4。
量化对精度的影响
精度损失是量化绕不开的代价。但损失多少,取决于几个因素:
- 模型本身:大模型(70B+)对量化的容忍度通常比小模型高。因为参数冗余多,砍掉一些精度,模型还能「将就」。
- 量化粒度:per-tensor 量化(整个张量用一个 scale)精度最差,per-channel 量化(每个通道一个 scale)好一些,per-group 量化(比如每 32 个参数一组)最好。
- 校准数据集:选什么样的数据来做 scale 校准,直接影响最终精度。我见过有人随便拿几个样本校准,结果模型输出全是乱码。
避坑指南:我曾经在量化一个代码生成模型时,用了通用文本做校准,结果模型生成的代码逻辑全乱了。后来换成代码片段做校准,精度才恢复正常。校准数据集一定要和你的使用场景匹配。
如何选择合适的量化类型?
这个问题没有标准答案,但我可以给你一个决策框架:
- 先看硬件:你的 GPU 支持 INT8 加速吗?如果不支持,INT8 可能比 FP16 还慢。老一点的卡(如 GTX 1080)对 INT8 支持不好。
- 再看精度要求:做聊天机器人,INT4 可能够用。做代码生成或数学推理,建议至少 INT8。做医疗、金融等敏感场景,老老实实 FP16。
- 最后看部署规模:大规模部署时,INT4 能省下大量显存和电费。小规模实验,FP16 更省心。
我个人习惯的选型路径是这样的:先用 FP16 跑通,然后试 INT8,如果精度损失在 1% 以内,就上 INT8。如果显存不够,再考虑 INT4。千万别一上来就 INT4,否则排查问题会非常痛苦。
量化流程示意图
下面这张图展示了从 FP16 模型到 INT4 模型的完整量化流程。你可以看到,校准和评估是两个关键环节,缺一不可。
你看,量化不是一步到位的事。校准完一定要做评估,如果精度掉得太多,就得换校准数据集或者调整量化粒度。我一般会准备 3-5 个不同的校准集,逐个试,选效果最好的那个。
实战建议:在 llama.cpp 里,你可以用 --quantize 命令直接做量化。比如 ./quantize model.gguf model-q4_0.gguf q4_0。q4_0 是 4 位量化的一种格式,还有 q4_1、q5_0、q5_1、q8_0 等。我建议先从 q8_0 开始试,精度损失极小,体积也能减半。
最后说一句:量化不是银弹。它是在精度、速度、体积之间做 trade-off。你选哪种类型,取决于你的场景和容忍度。没有最好的量化,只有最合适的量化。