量化精度与数据类型:FP32、FP16、BF16、INT8、INT4 详解

大家好,我是你们的老朋友。今天我们来聊聊大模型推理里一个绕不开的话题——量化精度与数据类型。

说实话,我刚入行那会儿,觉得精度这玩意儿越高越好。FP32 多香啊,精度高、范围广,跑起来稳稳的。但后来发现,模型越来越大,显存越来越贵,推理延迟越来越长。这时候我才意识到,精度不是越高越好,而是够用就好

今天我们就来掰扯掰扯,FP32、FP16、BF16、INT8、INT4 这些数据类型到底有什么区别,以及在实际项目中该怎么选。

一、先聊聊浮点数:FP32、FP16、BF16

浮点数,说白了就是用科学计数法来表示实数。一个浮点数由三部分组成:符号位、指数位、尾数位。不同的数据类型,这三部分的位数分配不一样,决定了它们的精度和动态范围。

1. FP32(单精度浮点数)

FP32 是深度学习里的“老大哥”。它用 32 位来表示一个数:1 位符号、8 位指数、23 位尾数。

  • 动态范围:约 ±3.4×10³⁸,非常宽
  • 精度:约 7 位有效数字
  • 优点:精度高,范围广,训练和推理都能用
  • 缺点:占内存大,计算慢

我在项目中遇到过,一个 7B 的模型用 FP32 存,光权重就要 28GB 显存。这还没算中间激活值呢。所以现在很少有人直接用 FP32 做推理了,除非你显存多到用不完。

2. FP16(半精度浮点数)

FP16 用 16 位表示:1 位符号、5 位指数、10 位尾数。

  • 动态范围:约 ±6.5×10⁴,比 FP32 小很多
  • 精度:约 3-4 位有效数字
  • 优点:内存减半,计算速度快
  • 缺点:动态范围窄,容易溢出或下溢

嗯,这里要注意。FP16 的动态范围只有 65504,大模型的权重和激活值很容易超出这个范围。我见过不少项目,FP16 推理时 loss 突然炸掉,就是因为数值溢出了。

3. BF16(脑浮点数)

BF16 是 Google 搞出来的,也是 16 位:1 位符号、8 位指数、7 位尾数。

  • 动态范围:和 FP32 一样,约 ±3.4×10³⁸
  • 精度:约 2-3 位有效数字,比 FP16 差
  • 优点:动态范围大,不容易溢出
  • 缺点:精度低,但大模型训练时够用

你想想看,BF16 的指数位和 FP32 一样多,所以动态范围完全一致。这意味着你不用担心数值溢出问题。虽然尾数少了,精度低了点,但大模型训练时,梯度更新的随机性本来就大,这点精度损失完全可以接受。

我个人习惯,训练大模型时首选 BF16。推理时如果硬件支持,BF16 也是不错的选择。

核心对比:FP32 动态范围宽、精度高;FP16 动态范围窄、精度中等;BF16 动态范围宽、精度低。选哪个,看你的需求。

二、再聊聊整数:INT8 和 INT4

浮点数虽然好,但毕竟占位多。为了进一步压缩模型,我们开始用整数来表示权重和激活值。

1. INT8(8位整数)

INT8 用 8 位表示:1 位符号、7 位数值(有符号),或者 0 位符号、8 位数值(无符号)。

  • 动态范围:有符号 [-128, 127],无符号 [0, 255]
  • 精度:固定步长,精度取决于量化参数
  • 优点:内存只有 FP32 的 1/4,计算极快
  • 缺点:精度损失明显,需要校准

INT8 量化是目前最主流的推理加速手段。我记得有一次,把一个 13B 的模型从 FP16 量化到 INT8,显存占用从 26GB 降到了 7GB,推理速度提升了 2 倍多。效果嘛,只掉了不到 1% 的准确率。

但要注意,INT8 量化不是随便就能做的。你需要做校准,找到合适的缩放因子和零点。不然精度损失会很大。

2. INT4(4位整数)

INT4 用 4 位表示:范围更小,精度更低。

  • 动态范围:有符号 [-8, 7],无符号 [0, 15]
  • 精度:极低,只有 16 个离散值
  • 优点:内存只有 FP32 的 1/8,极致压缩
  • 缺点:精度损失大,需要特殊硬件支持

INT4 量化,说实话,不是所有模型都适合。我试过把一些小型模型量化到 INT4,结果输出完全乱掉了。但对于大模型,尤其是 70B 以上的,INT4 反而效果不错。为什么?因为模型够大,冗余够多,量化掉一些信息不影响最终结果。

避坑指南:我曾经把一个 7B 的对话模型量化到 INT4,结果对话质量明显下降,用户反馈说“像换了一个人”。后来我改成 INT8,效果就好多了。所以,不要盲目追求低比特,一定要先评估效果。

三、精度与动态范围对比

为了让大家看得更清楚,我整理了一张对比表:

数据类型 位数 动态范围 精度(有效数字) 内存占用(相对 FP32) 典型应用
FP32 32 ±3.4×10³⁸ ~7 位 1x 训练、高精度推理
FP16 16 ±6.5×10⁴ ~3-4 位 0.5x 训练、推理
BF16 16 ±3.4×10³⁸ ~2-3 位 0.5x 训练(推荐)、推理
INT8 8 [-128, 127] 固定步长 0.25x 推理(主流)
INT4 4 [-8, 7] 固定步长 0.125x 推理(极致压缩)

从这张表可以看出,动态范围和精度是矛盾的。你想保留大动态范围,就得牺牲精度;你想提高精度,就得缩小动态范围。这就是量化里的“不可能三角”。

四、选择数据类型的考量因素

说了这么多,到底该怎么选?我总结了几个关键因素:

1. 硬件支持

这是最现实的问题。你的 GPU 或 NPU 支持哪种数据类型?

  • NVIDIA 的 GPU:从 Volta 架构开始支持 FP16,从 Ampere 开始支持 BF16 和 INT8
  • Intel 的 CPU:支持 FP32,部分支持 BF16 和 INT8
  • 手机芯片:大部分支持 INT8,部分支持 FP16

我建议,先查清楚你的硬件支持哪些数据类型,再决定用哪个。不然你选了 BF16,结果硬件不支持,那就尴尬了。

2. 模型大小

模型越大,量化带来的收益越大,同时精度损失越小。

  • 小模型(< 1B):建议用 FP16 或 BF16,INT8 可能损失较大
  • 中等模型(1B-10B):INT8 是 sweet spot,效果和速度的平衡点
  • 大模型(> 10B):可以尝试 INT4,但需要仔细评估

我个人习惯,对于 7B 以上的模型,先试 INT8。如果效果可以接受,再考虑 INT4。如果效果不行,退回 BF16。

3. 精度要求

不同的应用场景,对精度的要求不一样。

  • 对话系统:对精度要求高,用户能感知到质量变化
  • 代码生成:对精度要求中等,只要语法正确就行
  • 分类任务:对精度要求低,准确率掉 1-2% 可以接受

嗯,这里要注意。如果你的模型是给客户用的,一定要先做 A/B 测试。我见过一个项目,量化后模型效果在测试集上只掉了 0.5%,但用户反馈说“回答变傻了”。所以,测试集上的指标不代表用户体验

4. 推理延迟

量化不仅能省内存,还能加速计算。但加速效果取决于硬件和算子实现。

  • FP16/BF16:比 FP32 快 2 倍左右
  • INT8:比 FP32 快 4-8 倍
  • INT4:比 FP32 快 8-16 倍(需要特殊硬件)

但要注意,量化后的计算需要反量化,这个过程会引入额外开销。如果硬件不支持直接计算低精度数据,那加速效果会打折扣。

5. 量化方法

不同的量化方法,对精度的影响也不同。

  • 对称量化:简单,但动态范围利用率低
  • 非对称量化:动态范围利用率高,但计算复杂
  • 逐层量化:每层独立量化,效果好但计算量大
  • 逐通道量化:每个通道独立量化,精度更高

我建议,刚开始做量化时,先用对称逐层量化。等熟悉了,再尝试更复杂的方法。

我的经验:选数据类型时,先看硬件支持,再看模型大小,最后看精度要求。如果拿不准,就从 INT8 开始试。INT8 是目前最成熟、最通用的量化方案。

五、知识体系结构图

为了让大家更直观地理解这些数据类型的关系和选择逻辑,我画了一张图:

量化数据类型选择决策树 选择数据类型 硬件支持 模型大小 支持 BF16/FP16 支持 INT8 小模型 < 1B 大模型 > 10B 推荐 BF16 推荐 INT8 推荐 FP16/BF16 可尝试 INT4 精度要求 高精度要求 低精度要求 保留 FP32/BF16 可降级到 INT8 决策节点 条件分支 推荐结果

这张图展示了选择数据类型的基本逻辑:先看硬件支持,再看模型大小,最后看精度要求。当然,实际项目中还会有更多因素,但这张图可以帮你快速定位。

六、总结

好了,今天的内容就到这里。我们聊了 FP32、FP16、BF16、INT8、INT4 这五种数据类型,它们的精度、动态范围、优缺点,以及在实际项目中该怎么选。

最后送大家一句话:量化不是目的,加速才是。不要为了量化而量化,要为了更好的用户体验而量化。

如果你在项目中遇到量化相关的问题,欢迎随时交流。我们下期再见!


专注资料整理