1. INT8推理概述
1.1 为什么需要INT8量化?
先问大家一个问题:一个深度学习模型,从训练到部署,到底经历了什么?
训练的时候,我们用的是FP32,甚至FP16。精度高,但代价也大。模型跑在数据中心,功耗几百瓦,没人管你。但到了推理阶段,尤其是边缘端——手机、摄像头、IoT设备——功耗和延迟就成了硬约束。
我做过一个项目,把一个人脸识别模型塞进一块嵌入式板子。FP32版本跑一次推理要120ms,功耗直接飙到5W。板子烫得能煎鸡蛋。后来做了INT8量化,推理时间降到30ms,功耗降到1.2W。效果几乎没变。你说,量化香不香?
说白了,INT8量化就是用更少的比特数去表示模型的权重和激活值。8位整数,相比32位浮点,存储小了4倍,计算快了2-4倍。对于卷积、全连接这类计算密集型算子,INT8的加速效果尤其明显。
- 模型体积缩小4倍(FP32 → INT8)
- 推理速度提升2-4倍(取决于硬件)
- 功耗降低50%-80%
- 内存带宽压力大幅减小
1.2 量化原理:对称 vs 非对称
量化听起来玄乎,其实核心就一句话:把一个浮点数范围,映射到一个整数范围。
举个例子。假设你的权重值分布在[-1.0, 1.0]之间,你要把它映射到INT8的范围[-128, 127]。怎么做?
这里有两个流派:对称量化和非对称量化。
对称量化
对称量化,顾名思义,零点就是0。映射公式很简单:
int8_value = round(float_value / scale)
scale = max(|float_min|, |float_max|) / 127
我习惯用对称量化处理权重。为什么?因为权重分布通常是对称的,均值接近0。用对称量化,零点对齐,计算起来干净利落。
非对称量化
非对称量化引入了零点(zero point),可以灵活地偏移映射范围:
int8_value = round(float_value / scale) + zero_point
scale = (float_max - float_min) / 255
zero_point = round(-float_min / scale)
你看,非对称量化能把整个浮点范围都利用起来。对于ReLU后的激活值,分布全在正半轴,非对称量化就特别合适。
我曾经踩过一个坑:用对称量化去量化一个偏置很大的激活层,结果精度直接掉了3个点。换成非对称量化,立马回来了。嗯,这里要注意:激活值量化,优先考虑非对称。
| 对比项 | 对称量化 | 非对称量化 |
|---|---|---|
| 零点位置 | 固定为0 | 可偏移 |
| 计算复杂度 | 低(无零点偏移) | 高(需处理零点) |
| 适用场景 | 权重、分布对称的数据 | 激活值、分布偏斜的数据 |
| 表示效率 | 可能浪费一半范围 | 充分利用全部范围 |
1.3 精度与性能的权衡
量化不是免费的午餐。你省了计算,但可能丢了精度。这个权衡,是每个做推理优化的工程师都要面对的。
为什么会掉精度?说白了,量化引入了误差。你把一个连续的浮点值,硬生生塞进256个离散的整数格子里,信息必然有损失。误差主要来自两方面:
- 截断误差:超出映射范围的值被强行截断
- 舍入误差:浮点值落在两个整数之间,只能四舍五入
我做过一个实验:在ResNet-50上,用INT8量化,ImageNet Top-1准确率从76.1%掉到75.8%。只掉了0.3个点,但推理速度翻了2.5倍。这个trade-off,我觉得值。
但有些模型就没这么幸运了。比如轻量级模型MobileNet,本身参数就少,量化后精度掉得厉害。我记得有一次,MobileNetV2量化后掉了1.5个点,怎么调都回不来。后来用了逐通道量化(per-channel quantization),才勉强稳住。
所以,精度和性能的权衡,没有银弹。你需要:
- 先评估:量化后跑一遍验证集,看精度损失是否可接受
- 再定位:如果掉点严重,用逐层对比找出敏感层
- 最后调优:对敏感层做混合精度(部分层INT8,部分层FP16)
你想想看,量化就像给模型减肥。有的人减完肥更精神了,有的人减完肥就虚了。关键看你减的是脂肪还是肌肉。
1.4 量化流程概览
下面这张图,是我自己总结的INT8量化标准流程。每次做量化项目,我都会先过一遍这个流程,确保不遗漏关键步骤。
这个流程我用了很多年。核心思想就一句话:先量化,再验证,不行就调。别想着一步到位,量化是个迭代的过程。
好了,第一章就到这里。量化这件事,说难不难,说简单也不简单。关键是你得理解背后的原理,知道什么时候该用什么策略。后面的章节,我们会深入每个技术细节,包括如何实现量化算子、如何做校准、如何处理特殊层等等。