第二讲:量化基础概念——定点数与浮点数、比特宽度、量化参数
各位同学,欢迎来到量化基础课。这一讲的内容,说白了就是量化技术的“地基”。你后面学什么对称量化、非对称量化、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后的非负激活值。
我个人习惯:权重用对称量化,激活值用非对称量化。这样既保证了权重计算的简洁性,又能充分利用激活值的动态范围。
五、小结
今天的内容就这些。总结一下:
- 浮点数范围大但慢,定点数范围小但快。量化就是两者之间的“翻译”。
- 比特宽度决定了你能用多少个“格子”来表示数字。8-bit是工业标准。
- Scale 和 zero-point 是量化的核心参数。scale 控制映射比例,zero-point 控制零点对齐。
下一讲,我们会深入聊一聊“校准”这件事——怎么根据实际数据分布来确定最优的 scale 和 zero-point。到时候我会分享一个我在 MobileNet 上做校准的实战案例,保证干货满满。
好,今天就到这里。有问题欢迎在评论区留言,我看到会回复。
课后思考:如果让你量化一个取值范围在 [-0.5, 0.5] 的浮点数张量到 INT8,你会选择对称量化还是非对称量化?为什么?
公众号:蓝海资料掘金营,微信deep3321