写在前面:
在 PTQ量化模型的过程中,往往存在一些敏感节点,如Conv算子,matmul算子等,我们通常倾向于将其设定为高精度的int16输入。但由于硬件原因限制,即使指定Conv算子的精度为int16,但实际指定结果是只有其中一个以int16精度输入,另一个仍然是int8,例如激活是int16.而权重weight是int8.如下图所示:



其中激活的量化数据类型是int16,而权重的量化数据类型是int8,明明我们是设置的all_node_type=int16,为什么还是会出现int8类型数据呢,这在前面我们也已经说过了,主要由于硬件原因限制,为此,
一种解决思路是:
将卷积权重拆分为两部分(高权重+低权重)分别构造两个卷积算子,再通过加法融合,得到与原始卷积等价的结果。
将卷积权重拆分为两部分(高权重+低权重)分别构造两个卷积算子,再通过加法融合,得到与原始卷积等价的结果。
这样既能减少单个算子的量化误差,又能保持整体计算图的正确性。
代码实现:


原理解析:
拆分逻辑的关键步骤:
- 权重最大值归一化
每个卷积通道独立找到最大绝对值,计算 scale 因子 moded。 权重拆分
- conv_weight_high:通过量化公式约束在 [-127, 127] 范围内的部分,相当于主分量。
- conv_weight_low:残差部分,补偿量化损失。
这样就避免了单次量化对所有权重“一刀切”的问题。
双卷积 + Add 融合
第一个卷积算子处理主要信息(high)。
第二个卷积算子处理残差(low)。
Add 节点融合两个结果,恢复接近原始 Conv 的精度。
好处
双卷积结果相加可以近似还原原始高精度双int16卷积。
误差相比单 Conv 量化更小。
使用方法:
定义好上面的split函数之后,可以参考如下代码在下面主函数调用:

可以看到需要定义需要拆分的原始模型和算子列表,需要注意被拆分的原始模型需要选择ptq输出目录下的optimized的模型,至于敏感算子的信息可通过精度debug工具的get_sensitivity_of_node获取( debug工具的使用可自行查看用户手册,这里不赘述)。算子拆分后会生成新的onnx模型,可以将之作为ptq流程的原始模型进行输入,再次校准转化查看拆分效果。
总结:
这段实现展示了一种Conv算子拆分技巧模拟双int16输入:
通过High+Low的方式拆分权重,构建两个卷积节点;
最终用 Add 节点融合输出,替代原始卷积;
有效降低了量化误差,提升模型在低精度推理下的表现。

