1、量化基础回顾:什么是模型量化?为什么需要量化?量化的数学原理
好,咱们直接进入正题。模型量化,说白了就是给神经网络模型「减减肥、降降压」。你想想看,一个训练好的模型,里面全是 FP32(单精度浮点数)的权重和激活值。每个数占 4 个字节,算起来慢,存起来也大。量化的目标,就是用更少的比特来表示这些数——比如 INT8,每个数只占 1 个字节。
核心定义:模型量化是将浮点数模型参数(权重、激活值)从高精度格式(如 FP32)映射到低精度格式(如 INT8、INT4)的过程,同时尽量保持模型精度。
1.1 为什么需要量化?
我在项目中遇到过不少这样的场景:模型在 GPU 上跑得飞快,一部署到手机或者边缘设备上,直接卡成 PPT。为什么?因为资源受限啊。
量化带来的好处,我总结为三点:
- 模型体积缩小:FP32 转 INT8,体积直接缩到原来的 1/4。一个 500MB 的模型,量化完就 125MB 左右。这对移动端部署来说,简直是救命。
- 推理速度提升:INT8 的计算比 FP32 快得多。现代 CPU 和 NPU 都有专门的 INT8 指令集,比如 ARM 的 SDOT 指令。我实测过,量化后推理速度能提升 2-4 倍。
- 功耗降低:低精度计算需要的晶体管更少,内存访问也更少。说白了,就是省电。这对电池供电的设备来说,太重要了。
我的经验:量化不是万能的。如果你的模型对精度极其敏感(比如医疗影像诊断),直接量化可能会掉点。这时候就需要后面章节要讲的量化误差修复技术了。
1.2 量化的数学原理
量化本质上是一个映射问题。我们要把浮点数范围映射到整数范围。最常见的映射方式就是线性量化,也叫均匀量化。
公式其实很简单:
r = S * (q - Z)
其中:
r是真实的浮点数值q是量化后的整数值S是缩放因子(scale),一个浮点数Z是零点偏移(zero point),一个整数
反过来,从浮点数量化到整数:
q = round(r / S) + Z
嗯,这里要注意。round 操作会引入舍入误差。这就是量化误差的根本来源。
1.3 量化参数怎么算?
S 和 Z 怎么确定?这取决于你选择的量化范围。我习惯用两种方式:
| 量化方式 | 范围确定 | 适用场景 |
|---|---|---|
| 对称量化 | 取绝对值最大值,范围对称 | 权重量化(权重分布通常对称) |
| 非对称量化 | 取实际最小值和最大值 | 激活值量化(激活值分布可能偏斜) |
举个例子。假设我们有一组权重值:[-1.5, 0.0, 3.2, -0.8]。用 INT8 量化(范围 -128 到 127):
- 对称量化:最大绝对值是 3.2,所以 S = 3.2 / 127 ≈ 0.0252,Z = 0
- 非对称量化:最小值 -1.5,最大值 3.2,所以 S = (3.2 - (-1.5)) / 255 ≈ 0.0184,Z = round(-1.5 / 0.0184) + 128 ≈ 46
避坑指南:我曾经在量化一个 NLP 模型时,直接用了对称量化处理激活值。结果模型精度掉了 5 个点。后来发现激活值分布严重偏斜,换成非对称量化后,精度损失降到了 0.5% 以内。所以,选对量化方式很重要。
1.4 量化误差从哪来?
量化误差主要有两个来源:
- 舍入误差:round 操作导致的。比如 3.14159 量化到 INT8 再反量化回来,可能变成 3.14。这个误差范围是 ±0.5 * S。
- 截断误差:当浮点数值超出量化范围时,会被截断到边界值。比如 INT8 范围是 [-128, 127],如果有个值是 200,量化后就是 127。这种误差影响更大。
你想想看,这两种误差叠加起来,如果模型对某些层特别敏感,精度就会明显下降。这就是为什么我们需要做量化误差修复——后面几章我会详细讲各种修复技术。
1.5 小结
量化不是简单的「降精度」,而是一个系统工程。你需要理解:
- 量化的本质是浮点到整数的映射
- 对称量化和非对称量化各有适用场景
- 量化误差不可避免,但可以控制和修复
我个人习惯在开始量化之前,先跑一遍模型的激活值分布统计。这样能提前知道哪些层容易出问题。下一章,我会带你看看量化误差的具体表现,以及如何用工具定位问题。