BN 融合应该在量化前还是量化后?

发布时间:2026/7/31 18:14:41
BN 融合应该在量化前还是量化后? Gemini 输出用于记录结论很明确BNBatch Normalization融合必须发生在量化确定 Scale/ZeroPoint之前。如果先量化再做 BN 融合会导致量化参数Scale/Zero Point与融合后的实际权重不匹配产生巨大的精度崩塌。但在PTQ后训练量化和QAT量化感知训练中BN 融合的具体实现方式有所不同1. PTQ后训练量化先融合后量化在 PTQ 流程中整个网络处于eval()状态BN 的μ\muμ和σ2\sigma^2σ2已经固定第一步BN 融合将算法推导出的 BN 参数直接数学折叠进卷积层Conv的权重WWW和偏置BBB中生成一个新的 FP32 卷积权值WfusedW_{fused}Wfused​。第二步校准与量化对融合后的WfusedW_{fused}Wfused​以及融合后的激活值进行数据集校准计算出正确的量化参数Scale 和 ZeroPoint。核心原因量化节点的计算是极其脆弱的线性映射。如果先对原始 ConvWWW做量化后面再乘以 BN 的系数γσ2ϵ\frac{\gamma}{\sqrt{\sigma^2 \epsilon}}σ2ϵ​γ​这相当于在 INT8 运算后强行改动了数值的 Scaling 比例导致之前计算的所有量化 Scale 全部失效。2. QAT量化感知训练BN 折叠BN Folding在 QAT 训练阶段由于 BN 的均值和方差还在动态更新不能简单地像 PTQ 那样直接把 BN 删掉。因此QAT 使用的是模拟 BN 折叠Simulated BN Folding前向传播Forward将当前 Batch 的 BN 参数临时折叠到 Conv 权重中得到WfusedW_{fused}Wfused​。对折叠后的WfusedW_{fused}Wfused​施加FakeQuant伪量化节点。将伪量化后的权重送入计算。导出 ONNX 阶段必须切换为model.eval()模式。在eval()模式下BN 的统计量冻结 PyTorch/NVIDIA 工具链会自动将 BN 物理融合进 Conv 权重中。此时导出的 ONNX 图中**BN 节点彻底消失只留下Quantize - Dequantize - Fused_Conv**。避坑指南针对你的 PyTorch/NVIDIA 工具链如果你在导出的 ONNX 中看到了未融合的 BN 节点如你上一张截图所示通常是触发了以下两个坑之一常见错误原因解决方案导出时未切换到eval()模式在torch.onnx.export之前必须显式执行model.eval()。train()模式下导出强行保留了 BN 的动态前向逻辑。使用了自定义/非标准的 CBR 结构如果你的代码里把 Conv 和 BN 的前向逻辑拆得很散例如有中间变量分叉PyTorch 的 ONNX Tracer 无法识别出它是一个标准的 CBR 模式导致导出时未能正确触发算子融合。