读 ncnn 源码(XXIV):`fuse_deconvolution_mul`——反卷积层的乘法融合
读 ncnn 源码(XXIV):fuse_deconvolution_mul——反卷积层的乘法融合
在前文中,我们已经分析了
ncnnoptimize如何融合标准卷积 (Convolution) 和深度可分离卷积 (ConvolutionDepthWise) 后续的BatchNorm、Mul和Add操作。为了进一步完善对线性计算链的优化,ncnn 也提供了针对反卷积层 (Deconvolution) 后接逐通道乘法的融合 Pass:fuse_deconvolution_mul。本篇,我们将剖析该函数的源码,理解其如何将
fuse_convolution_mul的逻辑应用于Deconvolution这一上采样场景中的常见层。
TL;DR
- 目标: 将
Deconvolution层后接一个扮演逐通道乘法 (Per-Channel Scaling) 角色的BinaryOp层(Mul操作,第二输入来自MemoryData)进行融合。 - 模式匹配: 查找
Deconvolution -> BinaryOp结构,附加条件与fuse_convolution_mul完全一致:BinaryOp必须是Mul(op_type == 2),非标量 (!with_scalar),且第二输入来自形状匹配通道数的MemoryData向量。 - 数学原理: 与
fuse_convolution_mul完全一致。Deconvolution作为线性变换,后接逐通道乘法构成连续线性链。融合公式为:- 新权重 (第
o个输出通道的反卷积核乘以缩放系数 )。 - 新偏置 (第
o个输出通道的偏置乘以 )。
- 新权重 (第
- 代码实现: 几乎与
fuse_convolution_mul完全相同。- 遍历
Deconvolution层的每个输出通道i。 - 将该通道对应的所有权重 (
weight_per_outch个元素) 乘以memorydata->data[i]。 - 如果存在偏置,则将
bias[i]也乘以memorydata->data[i]。
- 遍历
- 图结构修改: 将
Deconvolution层的top指向原BinaryOp的top,更新blob的producer,并将BinaryOp标记为"ncnnfused"。 - 效果: 消除了
BinaryOp层引入的逐元素乘法计算和额外的内存读写,优化了包含反卷积和逐通道缩放的网络结构。
1. 融合动机:线性链合并原理的延伸
Deconvolution 作为一种线性变换 ,如果其后紧跟一个逐通道乘法 ,那么这两个操作可以合并。将缩放因子 提前吸收到 和 中,可以得到一个等效的 Deconvolution 操作 ,从而在推理时消除 BinaryOp 的开销。
2. 代码实现:复用乘法融合逻辑
fuse_deconvolution_mul 的代码实现与 fuse_convolution_mul 高度一致,仅在层类型匹配上有所不同,再次体现了融合逻辑的通用性。
1 | int NetOptimize::fuse_deconvolution_mul() |
关键点:
- 模式匹配: 查找
Deconvolution -> BinaryOp(Mul)结构,且第二个输入来自符合广播条件的MemoryData。 - 参数更新: 将
MemoryData中的缩放系数memorydata->data[ch]乘到Deconvolution层对应输出通道ch的所有权重和偏置上。 - 图修改: 标准的重定向连接 + 标记融合操作。
3. 意义:完善对反卷积的优化覆盖
Deconvolution 层常用于生成对抗网络(GANs)、图像分割等需要上采样的任务中。虽然 Deconvolution -> Mul(per-channel) 模式不如 Deconvolution -> BN 常见,但 fuse_deconvolution_mul Pass 的存在,保证了 ncnn 优化工具箱对这类潜在的线性计算链也具备优化能力。
4. 结语
fuse_deconvolution_mul 是 ncnnoptimize 中针对反卷积线性链优化的又一补充。它复用了与标准卷积融合乘法相同的逻辑,将逐通道缩放操作合并到 Deconvolution 层中。这进一步体现了 ncnn 图优化策略的系统性和一致性——尽可能地识别并消除计算图中可合并的连续线性变换,以达到简化结构、减少计算和访存开销的最终目的。
该封面图片由Mykyta Tretiakov在Pixabay上发布





