量化基础理论:浮点数与定点数、精度与性能的权衡
大家好,我是你们的老朋友。今天咱们来聊聊量化里最基础、也最绕不开的话题——浮点数与定点数。说实话,我刚开始接触大模型量化时,也被这些概念搞得有点晕。但后来我发现,搞懂了这些,后面的路就好走了。
浮点数:我们熟悉的“高精度选手”
浮点数,说白了就是用科学计数法来表示数字。比如 3.14159 × 10^0,或者 1.5 × 2^3。在计算机里,它由三部分组成:符号位、指数位和尾数位。
FP32(单精度浮点数)是我们最常用的。它用 1 位符号、8 位指数、23 位尾数。能表示的范围很大,精度也够用。但问题来了——它太占地方了。一个 FP32 参数就是 4 个字节,大模型动辄几十亿参数,你想想看,光存参数就得几百 GB。
FP16(半精度浮点数)就省了一半空间。它用 1 位符号、5 位指数、10 位尾数。我在项目中遇到过,用 FP16 做推理,显存占用直接砍半,速度也快了不少。但代价是精度下降,尤其是小数值容易“消失”。
BF16(脑浮点数)是 Google 搞出来的。它跟 FP16 一样是 16 位,但指数位用了 8 位,尾数位只有 7 位。说白了,它牺牲了精度,但保留了跟 FP32 一样的动态范围。嗯,这里要注意:BF16 在训练时特别好用,因为梯度不会轻易溢出。
核心区别一句话总结:
- FP32:精度高,但占地方
- FP16:省空间,但动态范围窄
- BF16:动态范围跟 FP32 一样,精度略低
定点数:硬件的“老朋友”
定点数就简单多了。它没有指数位,小数点位置是固定的。比如 Q7.8 格式,就是 1 位符号、7 位整数、8 位小数。
为什么会用到定点数?因为硬件喜欢它。定点数的计算就是整数运算,没有浮点运算那么复杂。你想想看,在嵌入式设备或者专用 AI 芯片上,定点数运算又快又省电。
但定点数有个致命问题:动态范围太小。数值一大就溢出,数值一小就精度丢失。所以我们需要做“量化”——把浮点数映射到定点数的范围内。
我个人习惯:在做量化时,先看看模型的权重分布。如果分布比较集中,用定点数效果就很好。如果分布很散,那还是老老实实用浮点数或者 BF16 吧。
精度与性能的权衡:没有免费的午餐
量化说白了就是一场交易——用精度换性能。你量化得越狠,模型跑得越快、占得越少,但精度损失也越大。
我曾经在一个项目里,把模型从 FP32 量化到 INT8,推理速度提升了 3 倍,显存占用降了 75%。但准确率掉了 0.5%。客户一开始不满意,后来我跟他们解释:这 0.5% 的损失换来的是 3 倍的吞吐量,值不值?他们想了想,接受了。
所以,关键是要找到那个平衡点。我建议你这样做:
- 先跑一遍 FP32 的基线,记录准确率
- 量化到 FP16,看看损失
- 再量化到 INT8,看看损失
- 如果 INT8 损失太大,试试混合精度——部分层用 FP16,部分层用 INT8
避坑指南:我曾经在一个语音模型上直接量化到 INT4,结果准确率掉了 8%。后来发现是某些层的激活值范围特别大,INT4 根本装不下。所以,量化前一定要做校准,看看每层的数值分布。
常见量化数据类型:FP16、BF16、INT8、INT4
咱们来逐个看看这些数据类型,我结合自己的经验说说它们的适用场景。
| 数据类型 | 位数 | 动态范围 | 精度 | 适用场景 |
|---|---|---|---|---|
| FP16 | 16 | ~65K | 中等 | 推理加速,显存节省 |
| BF16 | 16 | ~3.4e38 | 较低 | 训练,梯度稳定 |
| INT8 | 8 | 256 | 低 | 推理加速,部署到边缘设备 |
| INT4 | 4 | 16 | 极低 | 极致压缩,移动端 |
FP16:我最常用的推理格式。大部分 GPU 都原生支持,速度提升明显。如果你只是做推理,FP16 是首选。
BF16:训练时的好帮手。我记得有一次用 FP16 训练,梯度一直溢出,换成 BF16 就稳了。因为它指数位多,能表示更大的范围。
INT8:量化里的“万金油”。精度损失通常可控,速度提升明显。但要注意,INT8 需要校准数据,不然很容易翻车。
INT4:这是最激进的量化方式。我建议只在模型特别大、显存特别紧张时用。而且一定要做细致的逐层分析,看看哪些层可以扛住 INT4 的精度损失。
我的经验法则:
- 能跑 FP16 就别用 INT8
- 能用 INT8 就别用 INT4
- 如果非要用 INT4,先做逐层敏感度分析
知识体系图:量化数据类型全景
下面这张图帮你理清这些数据类型之间的关系和选择路径。
好了,这一章的内容就到这里。量化基础理论其实不难,关键是理解每种数据类型的特性和适用场景。下一章我们会深入 GGUF 的量化流程,到时候会用到这些知识。