量化基础:FP16、BF16、INT8、INT4 这些数据类型到底怎么选?

大家好,我是你们的老朋友。今天咱们聊聊量化。

说实话,我刚入行那会儿,觉得量化这事儿挺玄乎的。不就是把模型变小点嘛,能跑就行。后来被线上事故教育了几次,才明白——选错数据类型,轻则精度掉点,重则模型直接崩掉

这一章,我就把 FP16、BF16、INT8、INT4 这几个常见数据类型的底裤扒干净。咱们不搞理论堆砌,直接说人话。

1. 浮点数的基本逻辑:为什么要有这么多格式?

先问个问题:一个 32 位浮点数(FP32),能表示多大范围?

大概 ±3.4×10³⁸,精度大约 7 位有效数字。但问题是,大模型动辄几十亿参数,全用 FP32 存,显存根本扛不住。

所以大家开始想:能不能砍掉一些位数?

嗯,这就是量化的核心思路——用更少的比特,去近似原来的数值

核心原则: 量化不是魔法,是精度和效率的 trade-off。你省了多少显存,就得接受多少精度损失。

2. FP16 vs BF16:两个 16 位浮点数的恩怨

FP16(半精度)和 BF16(脑浮点)都是 16 位,但内部结构完全不同。

特性 FP16 BF16
符号位 1 bit 1 bit
指数位 5 bits 8 bits
尾数位 10 bits 7 bits
表示范围 ±65504 ±3.4×10³⁸(同 FP32)
精度 约 3.3 位有效数字 约 2.3 位有效数字

看到区别了吗?BF16 保留了 FP32 的指数范围,但牺牲了精度。FP16 精度更高,但范围窄,容易溢出。

我在项目中遇到过一件事:用 FP16 跑一个 LLaMA 模型,训练到一半 loss 突然变成 NaN。查了半天,发现是某个中间激活值超过了 65504。换成 BF16 后,问题立刻消失。

我的建议: 推理场景优先用 BF16。它几乎不会溢出,精度损失也小。FP16 更适合训练,尤其是梯度值比较小的时候。

3. INT8 和 INT4:整数量化的实战选择

整数量化,说白了就是把浮点数映射到整数范围。比如 INT8 是 [-128, 127],INT4 是 [-8, 7]。

映射过程很简单:

# 伪代码示意
scale = (max_val - min_val) / 255
quantized_val = round((float_val - min_val) / scale) - 128

但这里有个坑:校准数据集的选择。如果你用了一堆不具代表性的数据去算 scale,量化后的模型可能在某些输入上表现极差。

我曾经踩过这个坑。当时给一个对话模型做 INT8 量化,测试集上精度只掉了 0.5%,感觉稳了。结果上线后,用户反馈某些长对话回复质量明显下降。后来发现,校准数据里缺少长文本样本,导致 scale 没覆盖到极端情况。

避坑指南: 校准数据集一定要覆盖真实场景的分布。别偷懒,拿几百条数据就完事。至少准备几千条,而且要包含边界情况。

4. 四种数据类型的选型决策树

你可能会问:那我到底该用哪个?

我一般按这个逻辑来选:

  • 显存够用? 直接用 FP16 或 BF16,省心。
  • 显存紧张? 上 INT8,精度损失通常可控。
  • 显存爆炸? 考虑 INT4,但要做好精度下降的心理准备。
  • 对精度极度敏感? 别碰 INT4,老老实实用 BF16。

另外,不同层对量化的敏感度不一样。比如 attention 层的 QKV 投影,量化后精度掉得厉害;而 FFN 层相对鲁棒。所以现在很多框架支持混合精度量化——敏感层用 FP16,其他层用 INT8。

下面这张图是我自己总结的量化选型流程,你参考下:

量化数据类型选型决策流程 模型部署需求 显存是否充足? BF16 / FP16 精度要求高? INT8 混合精度 显存极度紧张? INT4(谨慎) INT8 全量化

5. 量化后的精度验证:别信 benchmark,信自己的测试

最后说一句:量化后的模型,一定要用你的业务数据做端到端测试

我见过太多人只看公开 benchmark 的指标,觉得掉点不多就上线了。结果呢?业务场景里某些 case 直接崩了。

为什么?因为 benchmark 数据集和你的真实数据分布不一样。比如对话模型,量化后可能对长尾词汇的生成质量下降明显,但 benchmark 里这些词出现频率低,看不出来。

我的习惯: 量化后至少跑 1000 条真实业务数据,人工抽检 100 条。如果发现 5 条以上有明显质量下降,就考虑回退到更高精度的格式。

好了,这一章就聊到这儿。量化这事儿,说白了就是「用空间换时间,用精度换效率」。选对了,事半功倍;选错了,debug 到天亮。


专注资料整理