第二讲:量化基础概念——定点数与浮点数、比特宽度、量化参数

各位同学,欢迎来到量化基础课。这一讲的内容,说白了就是量化技术的“地基”。你后面学什么对称量化、非对称量化、KL散度校准,都得先搞懂今天这几个概念。

我记得刚入行那会儿,带我的老工程师丢给我一句话:“量化就是拿精度换速度,但怎么换得聪明,才是本事。”今天我们就来聊聊这个“换”字背后的门道。

一、定点数与浮点数:计算机怎么表示数字?

先问个问题:1.0 和 1.0000001,在计算机里占的内存一样吗?

答案是不一样。这取决于你用定点数还是浮点数来存。

1. 浮点数(Floating-point)

浮点数就像科学记数法。比如 3.14 × 10²,它把数字拆成三部分:符号位、指数、尾数。

常见的浮点格式有两种:

  • FP32(单精度):1位符号 + 8位指数 + 23位尾数。范围大,精度高,但占4字节。
  • FP16(半精度):1位符号 + 5位指数 + 10位尾数。范围小一些,但只占2字节。

我在项目中遇到过一个问题:用FP16训练一个语音模型,结果loss死活不降。后来排查发现,是梯度值太小,FP16的指数范围兜不住,直接变零了。这就是浮点数的“动态范围”陷阱。

2. 定点数(Fixed-point)

定点数就简单多了。它把小数点固定在一个位置。比如 Q7.8 格式,表示7位整数位,8位小数位。

定点数的好处是:

  • 硬件实现简单,没有浮点运算单元也能跑
  • 计算速度快,功耗低
  • 确定性好,同样的输入永远得到同样的输出

但缺点也很明显:范围固定,精度固定。你想想看,如果小数位只有8位,那 0.00390625 就是你能表示的最小精度了。再小?只能截断或舍入。

核心区别一句话总结:浮点数用指数换范围,定点数用固定位宽换速度。量化,本质上就是把浮点数“拍扁”成定点数。

二、比特宽度:8-bit、16-bit、4-bit 到底差在哪?

比特宽度,说白了就是“用多少位来表示一个数”。位数越多,能表示的值越精细,但占的内存和计算量也越大。

我习惯把比特宽度比作“尺子的刻度”:

  • 32-bit:毫米刻度尺,量什么都准,但尺子又大又重
  • 16-bit:厘米刻度尺,日常够用,轻便不少
  • 8-bit:分米刻度尺,量个桌子长度还行,量螺丝就废了
  • 4-bit:大概就是“长、中、短”三档,只能分个大概

来看看实际数据:

比特宽度 可表示数值个数 内存占用(相比FP32) 典型场景
FP32 约 42 亿 1x 训练、高精度推理
FP16 约 6.5 万 0.5x 混合精度训练
INT8 256 0.25x 边缘端推理
INT4 16 0.125x 极致压缩场景

看到没?从32位降到8位,内存直接省了4倍。但代价是,你只能用256个不同的数来表示原来42亿个浮点数。这中间的“压缩”怎么做到尽量不丢精度?这就是量化参数要解决的问题。

我的经验:8-bit量化是目前工业界最成熟的方案。4-bit虽然省,但精度损失往往需要特殊技巧来弥补,比如QAT(量化感知训练)。新手建议先从INT8入手。

三、量化参数:Scale 和 Zero-point

好,现在到了最核心的部分。量化参数就两个:scale(缩放因子)zero-point(零点偏移)

它们的作用是什么?说白了,就是建立浮点数和定点数之间的“翻译规则”。

1. Scale(缩放因子)

Scale 决定了浮点数范围到定点数范围的映射比例。公式很简单:

float_value = scale × (quantized_value - zero_point)

反过来:

quantized_value = round(float_value / scale) + zero_point

Scale 怎么算?举个例子:

假设你的浮点数范围是 [-1.0, 1.0],要量化到 INT8(范围 -128 到 127)。

那 scale = (1.0 - (-1.0)) / (127 - (-128)) = 2.0 / 255 ≈ 0.00784

嗯,这里要注意:scale 越小,量化精度越高。但 scale 太小会导致量化后的数值范围覆盖不全,出现“截断”。

2. Zero-point(零点偏移)

Zero-point 解决的是“浮点数0对应定点数几”的问题。

为什么需要这个?因为很多神经网络层(比如ReLU)的输出是非负的,或者有偏置。如果浮点数的0不对应定点数的0,那计算时就会引入误差。

我举个例子:

假设浮点数范围是 [2.0, 6.0],量化到 INT8 [0, 255]。

scale = (6.0 - 2.0) / 255 ≈ 0.0157

那浮点数 2.0 对应定点数 0,浮点数 6.0 对应定点数 255。

但浮点数 0 呢?它不在这个范围内。这时候 zero-point 就派上用场了:

zero_point = round(0 / scale) - min_quantized = 0 - 0 = 0

等等,这里浮点数0对应的定点数其实是负数?不对,因为浮点数0不在 [2.0, 6.0] 范围内,所以它会被截断到 2.0。

这就是为什么实际量化时,我们通常会让浮点数的0精确映射到定点数的某个值,避免计算误差。

避坑指南:我曾经在一个图像分类模型上踩过坑。模型量化后精度掉了5个点,排查了两天才发现是 zero-point 设置错了。浮点数的0没有对齐到定点数的0,导致卷积计算时偏置项全部偏移。从那以后,我每次做量化都会先检查 zero-point 对不对。

四、对称量化 vs 非对称量化

根据 zero-point 的设置方式,量化分为两种:

  • 对称量化:zero-point = 0。浮点数的0精确对应定点数的0。适合权重分布对称的场景(比如经过LayerNorm的激活值)。
  • 非对称量化:zero-point ≠ 0。可以更灵活地匹配浮点数的实际分布。适合ReLU后的非负激活值。

我个人习惯:权重用对称量化,激活值用非对称量化。这样既保证了权重计算的简洁性,又能充分利用激活值的动态范围。

五、小结

今天的内容就这些。总结一下:

  1. 浮点数范围大但慢,定点数范围小但快。量化就是两者之间的“翻译”。
  2. 比特宽度决定了你能用多少个“格子”来表示数字。8-bit是工业标准。
  3. Scale 和 zero-point 是量化的核心参数。scale 控制映射比例,zero-point 控制零点对齐。

下一讲,我们会深入聊一聊“校准”这件事——怎么根据实际数据分布来确定最优的 scale 和 zero-point。到时候我会分享一个我在 MobileNet 上做校准的实战案例,保证干货满满。

好,今天就到这里。有问题欢迎在评论区留言,我看到会回复。

课后思考:如果让你量化一个取值范围在 [-0.5, 0.5] 的浮点数张量到 INT8,你会选择对称量化还是非对称量化?为什么?


公众号:蓝海资料掘金营,微信deep3321