4. 混合精度原理
在深度学习推理部署中,精度选择从来不是“越高越好”或“越低越快”的单选题。FP32 精度最高但显存和算力开销大,INT8 速度最快、内存最省,却可能让部分敏感层输出失真。混合精度部署的核心思想是:把不同精度分配给不同层、不同算子、不同数据通路,让对精度不敏感的矩阵乘、卷积走 INT8,让对数值范围敏感的归一化、激活、残差累加、Softmax 等保留 FP16,从而在精度、速度、内存三者之间取得工程最优解。
4.1 核心原理:精度差异来自哪里
INT8 是 8 位定点整数,表示范围通常为 [-128, 127],它用 scale(缩放因子)和 zero-point(零点)把浮点张量映射到整数域。FP16 是 16 位半精度浮点,包含 1 位符号、5 位指数、10 位尾数,动态范围约 6×10⁴,能表示极小和极大的数。两者本质差异在于:INT8 牺牲动态范围和尾数精度换取 4 倍于 FP32 的吞吐和 1/4 的显存占用;FP16 保留浮点指数结构,适合数值跨度大的中间结果。
混合精度不是简单地把模型一半量化成 INT8、一半保持 FP16,而是要在计算图中识别“量化友好区”和“量化敏感区”。典型规律是:卷积、全连接、矩阵乘等线性算子对量化误差容忍度高;LayerNorm、BatchNorm、Softmax、GELU、Sigmoid、残差相加、注意力分数缩放等非线性或跨通道统计操作对量化误差敏感。因此,混合精度引擎通常以算子为单位做精度分配,并在 INT8 与 FP16 交界处插入反量化/量化节点,保证数据格式衔接正确。
4.2 精度-速度-内存的三角权衡
混合精度的收益不是线性的,而是受限于三个瓶颈:计算吞吐、显存带宽、数值稳定性。在 GPU 上,INT8 Tensor Core 的峰值算力通常是 FP16 的 2 倍、FP32 的 4 倍;显存占用方面,INT8 权重和激活各占 1 字节,FP16 占 2 字节,FP32 占 4 字节。但实际推理速度还取决于算子融合、内存访问模式、反量化开销以及是否触发回退。
| 精度模式 | 权重/激活位宽 | 典型算力比 | 显存占用 | 精度风险 | 适用层 |
|---|---|---|---|---|---|
| FP32 | 32 bit | 1× | 4 bytes | 无 | 训练、基准 |
| FP16 | 16 bit | 2× | 2 bytes | 极低 | 归一化、激活、残差 |
| INT8 | 8 bit | 4× | 1 byte | 中,需校准 | 卷积、全连接、矩阵乘 |
| 混合 INT8+FP16 | 8/16 bit | 2.5~3.5× | 1.2~1.6 bytes | 低,可控 | 端到端推理 |
从表中可以看出,纯 INT8 虽然理论收益最大,但端到端精度损失可能不可接受;纯 FP16 精度几乎无损,但速度和显存收益只有 2 倍。混合精度通过把 INT8 集中在计算密集且量化友好的算子上,把 FP16 留给数值敏感路径,通常能拿到 2.5~3.5 倍加速、显存降低 40%~60%、精度损失控制在 0.5% 以内 的综合效果。
4.3 方法流程:如何做混合精度分配
- 算子画像:统计每个算子的计算量、访存量、数值范围、是否含跨通道归约。计算密集且范围稳定的算子优先标记为 INT8 候选。
- 敏感度分析:逐层替换为 INT8,观察验证集精度下降。下降超过阈值的层回退到 FP16。
- 校准:对 INT8 层使用校准集统计激活分布,计算 scale 和 zero-point。常用方法有 MinMax、KL 散度、百分位截断。
- 图重写:在 INT8 与 FP16 边界插入 Quantize/Dequantize 节点,确保数据格式正确衔接,并尽量把反量化融合进前一个算子。
- 回归验证:在目标硬件上跑端到端 benchmark,同时检查精度、延迟、显存峰值和功耗。
# 以 TensorRT 为例,开启混合精度并设置层回退
trtexec --onnx=model.onnx \
--int8 \
--fp16 \
--calib=calibration.cache \
--layersPrecision=layer_norm:fp16,softmax:fp16,residual:fp16 \
--saveEngine=model_mixed.engine
# 查看每层精度分配
trtexec --loadEngine=model_mixed.engine --dumpLayerInfo --profilingVerbosity=detailed
4.4 典型应用场景
- 云端大模型推理:Transformer 的 QKV 投影和 FFN 走 INT8,LayerNorm、Softmax、残差走 FP16,显存节省可支持更大 batch 或更长上下文。
- 边缘视觉检测:CNN 主干卷积 INT8,检测头中的坐标回归和 NMS 保留 FP16,避免框位置偏移。
- 实时语音识别:声学模型卷积/循环层 INT8,注意力与归一化 FP16,满足低延迟同时保持字错率稳定。
- 多模态融合:视觉编码器 INT8,文本解码器 FP16,兼顾吞吐与生成质量。
4.5 常见误区与复盘
误区二:FP16 一定安全。FP16 动态范围有限,遇到极大激活值仍可能溢出为 Inf,需要配合 loss scaling 或部分层保留 FP32。
误区三:只看理论算力,忽略反量化开销。频繁在 INT8 和 FP16 之间切换会引入额外 kernel 和内存搬运,可能抵消收益。应尽量让连续多个算子保持同一精度,减少边界节点。
复盘时建议记录三组数据:每层精度分配、端到端精度变化、各阶段耗时占比。如果发现反量化节点耗时超过总延迟的 10%,说明精度切换过于频繁,应合并相邻同精度算子或调整分配策略。混合精度的本质是用工程手段把“精度预算”花在刀刃上,而不是追求单一精度的极致。