2. INT8量化数学基础
要把一个 FP32 张量塞进 INT8,本质上是在做一次“带偏移的线性映射”。理解这条映射公式,是理解 TensorRT 量化校准、精度损失和调优手段的起点。本节从数学定义出发,逐步过渡到 TensorRT 中的实际映射关系。
一、量化与反量化的基本公式
设实数张量中的元素为 x,量化后的整数为 q,则最通用的仿射量化定义为:
q = round(x / scale) + zero_point
x_hat = (q - zero_point) * scale
其中 scale(缩放因子)是浮点数,表示“一个整数刻度代表多大的实数范围”;zero_point(零点)是一个整数,表示实数 0 对应的量化整数值。反量化得到的 x_hat 是 x 的近似,二者之差即为量化误差。INT8 的整数范围是 [-128, 127](有符号)或 [0, 255](无符号),TensorRT 的激活量化通常使用有符号 INT8,权重也使用有符号 INT8。
二、对称量化与非对称量化
对称量化强制 zero_point = 0,即实数 0 精确映射到整数 0。此时量化范围关于 0 对称,scale 由绝对值最大的元素决定:
scale = max(|x|) / 127
q = clamp(round(x / scale), -128, 127)
对称量化的优点是计算简单、反量化时无需减去零点,且 0 映射无误差,非常适合权重(权重分布通常近似零均值)以及卷积、矩阵乘等以乘加为主的算子。缺点是当数据分布明显不对称(例如 ReLU 之后的激活全部非负)时,会浪费一半的整数区间。
非对称量化允许 zero_point ≠ 0,把实际数据区间 [min, max] 线性映射到 [-128, 127]:
scale = (max - min) / 255
zero_point = round(-min / scale) - 128
q = clamp(round(x / scale) + zero_point, -128, 127)
非对称量化能充分利用整数区间,对 ReLU 输出、Sigmoid 输出等单边分布更友好,代价是反量化多一次减法,且零点本身会引入额外舍入误差。TensorRT 在 PTQ 校准中会为每个张量自动选择对称或非对称方案,通常权重走对称、激活走非对称。
三、量化误差的来源
量化误差并非单一来源,工程上通常拆成三类:
- 舍入误差:
round()把实数压到最近整数,最大误差为scale/2。scale 越大,单点误差越大,因此动态范围大的张量精度天然更差。 - 截断误差:当
x超出[min, max]时被 clamp 到边界,误差可能远大于scale/2。这是离群点(outlier)最危险的地方。 - 范围估计误差:校准阶段用有限样本估计
min/max,若校准集不能代表真实分布,scale 会偏大或偏小,导致整体分辨率下降或截断加剧。
此外,反量化时 (q - zero_point) 的整数减法本身是精确的,但乘以 scale 后重新引入浮点舍入,这一项通常可忽略。真正需要关注的是前两项。
四、饱和与截断策略
“饱和”指主动把量化范围收窄到比实际数据更小的区间,让少量离群点被截断,从而换取大多数正常点的更高分辨率。这与“直接取 min/max”是两种相反的策略:
- min-max 策略:范围覆盖全部数据,无截断,但 scale 被离群点拉大,正常点分辨率下降。
- 饱和策略:例如只取 99.9% 分位数作为边界,牺牲 0.1% 的离群点,换取更小的 scale。TensorRT 的 KL 校准本质上就是在寻找这个“饱和阈值”。
选择哪种策略取决于离群点的比例和重要性。如果离群点集中在少数通道且对最终输出影响大,饱和会带来明显精度下降;如果离群点是噪声,饱和反而提升整体精度。
五、TensorRT 中的实际映射
在 TensorRT 中,上述数学概念对应到具体的 API 和配置项:
| 数学概念 | TensorRT 对应 | 说明 |
|---|---|---|
| scale | per-tensor / per-channel scale | 权重默认 per-channel,激活默认 per-tensor |
| zero_point | 非对称量化时的零点 | 权重通常为 0,激活可能非 0 |
| 饱和阈值 | 校准算法(KL / min-max / percentile) | IInt8EntropyCalibrator2 使用 KL 散度 |
| 截断 | clamp 到 [-128, 127] | 超出范围的值被饱和处理 |
| 量化误差 | 逐层输出对比 | 用 FP32 与 INT8 引擎输出差异评估 |
一个常见的实操流程是:先用 IInt8EntropyCalibrator2 在校准集上跑一遍,得到每个激活张量的 scale 和 zero_point;然后构建 INT8 引擎;最后用同一批验证数据分别跑 FP32 和 INT8,逐层或逐输出对比余弦相似度、相对误差和最终任务指标。如果某层误差突然放大,通常意味着该层的校准范围估计不准,可以尝试换校准算法、增加校准样本,或对该层回退到 FP32。
x_hat = q × scale;非对称量化下必须保留 zero_point,否则会引入系统性偏移。TensorRT 在导出 Q/DQ 节点时会显式记录 zero_point,手工实现时不要遗漏。
理解这些数学关系后,后续的校准、精度验证和调优才有明确的抓手:scale 决定分辨率,zero_point 决定零点对齐,饱和策略决定离群点与正常点的取舍,而误差分析则告诉我们问题出在哪一层。