量化理论基础:浮点数与定点数表示,线性量化与非线性量化,对称量化与非对称量化
量化,说白了就是把模型里那些高精度的浮点数,换成低精度的整数。为什么要这么干?因为嵌入式设备上的算力有限,内存也紧张。我刚开始接触这个领域时,总觉得量化会损失很多精度,心里有点抵触。后来在项目里被逼着做了一次,才发现——嗯,其实损失没想象中那么大,收益却非常可观。
这一章,我们先把量化最核心的几个概念掰扯清楚。你搞懂了这些,后面实战才不会踩坑。
1. 浮点数与定点数:计算机怎么表示小数?
先问个问题:你在模型里看到的权重,比如 0.123456,计算机里到底是怎么存的?
有两种主流方式:
- 浮点数:用科学计数法表示,比如 0.123456 = 1.23456 × 10⁻¹。在计算机里,它分成符号位、指数位、尾数位三部分。FP32(32位浮点)是深度学习默认的精度。
- 定点数:小数点的位置是固定的。比如 Q1.7 格式,1位整数,7位小数,能表示的范围很小,但计算快、硬件开销低。
我在项目中遇到过一个问题:用浮点模型在 PC 上跑得好好的,一部署到 ARM Cortex-M 上,速度慢得离谱。为什么?因为那个芯片没有 FPU(浮点运算单元),所有浮点运算都要用软件模拟,效率极低。换成定点数之后,速度直接提升了 10 倍。
核心结论:嵌入式端做量化,本质就是把浮点模型转成定点模型,用精度换速度。
2. 线性量化与非线性量化:映射方式不同
量化就是找一个映射关系,把浮点数范围映射到整数范围。这个映射可以是线性的,也可以是非线性的。
2.1 线性量化
线性量化是最常用的方式。它假设浮点数和整数之间是简单的线性关系:
q = round(r / scale) + zero_point
其中:
r是原始浮点数q是量化后的整数scale是缩放因子zero_point是零点偏移
反量化就是反过来:
r = (q - zero_point) × scale
我建议你把这个公式记牢,后面所有量化算法都绕不开它。
2.2 非线性量化
非线性量化不要求均匀映射。比如对数值大的区域用更粗的粒度,对数值小的区域用更细的粒度。典型代表是 对数量化 和 查表量化。
非线性量化在 YOLO 里用得不多,为什么?因为 YOLO 的权重和激活值分布比较均匀,线性量化已经够用了。但如果你做语音模型或者某些特殊网络,非线性量化可能会有优势。
| 对比项 | 线性量化 | 非线性量化 |
|---|---|---|
| 实现复杂度 | 低,硬件友好 | 高,需要查表 |
| 精度损失 | 均匀分布时较小 | 非均匀分布时更优 |
| YOLO适用性 | ✅ 主流选择 | ❌ 很少使用 |
| 推理速度 | 快 | 较慢(查表开销) |
我的经验:做 YOLO 量化,优先选线性量化。除非你发现精度损失不可接受,再考虑非线性方案。
3. 对称量化与非对称量化:零点怎么处理?
这是量化里最容易搞混的地方。我刚开始也绕了很久,后来画了一张图才彻底明白。
3.1 对称量化
对称量化假设浮点数的范围关于 0 对称。也就是说,最大值和最小值的值相等。零点直接映射到整数 0。
zero_point = 0
q = round(r / scale)
优点:实现简单,不需要存储 zero_point。缺点:如果数据分布不对称(比如全是正数),会浪费一半的量化范围。
3.2 非对称量化
非对称量化允许零点偏移。它用 zero_point 来补偿数据分布的不对称性。
zero_point = round(-min_float / scale)
q = round(r / scale) + zero_point
优点:能充分利用量化范围,精度更高。缺点:需要额外存储 zero_point,计算时多一步减法。
避坑指南:我曾经在一个项目中,对 ReLU 后的激活值用了对称量化。ReLU 输出全是非负数,对称量化把一半的整数范围浪费在了负数区域,导致精度掉了 3 个点。后来换成非对称量化,精度就回来了。
| 对比项 | 对称量化 | 非对称量化 |
|---|---|---|
| 零点 | 固定为 0 | 可偏移 |
| 存储开销 | 小(无需 zero_point) | 大(多存一个值) |
| 适用场景 | 权重(分布近似对称) | 激活值(分布常偏移) |
| YOLO推荐 | 权重用对称 | 激活用非对称 |
4. 知识结构总览
下面这张图把本章的核心概念串起来了。你把它存下来,后面学量化的时候随时回来对照。
5. 实战中的选择建议
说了这么多理论,你可能会问:那我做 YOLO 量化时到底怎么选?
我直接给你一个清单:
- 权重:用对称量化。因为训练好的权重分布通常近似对称,用对称量化不会浪费范围。
- 激活值:用非对称量化。尤其是 ReLU 后的激活值全是非负数,对称量化会浪费一半的整数范围。
- 量化方式:用线性量化。YOLO 的卷积和全连接层对线性量化非常友好,非线性量化带来的收益微乎其微。
- 位宽选择:优先试 INT8。如果精度不够,再考虑 INT16 或混合精度。
一个小技巧:如果你不确定某个层该用对称还是非对称,可以先用非对称量化跑一遍,然后看 zero_point 的值。如果 zero_point 接近 0,说明数据分布是对称的,可以换成对称量化来省一点存储。
好了,这一章的内容就到这里。你把这些概念吃透了,后面讲量化算法和实战部署时,就不会觉得吃力了。