读 ncnn 源码(XXXIII):激活融合——`ConvDW`、`Deconv` 与 `InnerProduct` 的“一体化”改造
读 ncnn 源码(XXXIII):激活融合——ConvDW、Deconv 与 InnerProduct 的“一体化”改造
在第三十二篇中,我们深入剖析了 fuse_convolution_activation 这一至关重要的优化 Pass。其核心思想是:将 Conv -> Activation 这一内存密集型(Memory-bound)的两步操作,融合为 Conv 计算微核内部的一次计算密集型(Compute-bound)操作,从而消除昂贵的内存读写。
ncnn 将这一优化思想贯彻到底,并将其推广到了几乎所有可能后接激活层的计算密集型层。本篇,我们就将集中分析 fuse_convolutiondepthwise_activation、fuse_deconvolution_activation、fuse_deconvolutiondepthwise_activation 和 fuse_innerproduct_activation 这四个 Pass,探究 ncnn 如何实现激活融合的全面覆盖。
TL;DR
目标: 将 ConvDW, Deconv, DeconvDW, In ...
读 ncnn 源码(XXXII):`fuse_convolution_activation`——将“激活”压入计算核心
读 ncnn 源码(XXXII):fuse_convolution_activation——将“激活”压入计算核心
在 ncnnoptimize 的优化篇章中,我们已经见证了多种基于代数等价的“算子融合”(如 Conv+BN)和“算子替换”(如 PReLU->ReLU)。本篇,我们将分析一种不同但更为重要的优化类型:性能驱动的算子融合(Performance-driven Fusion)。fuse_convolution_activation 正是其典型代表。
Conv -> Activation(例如 Conv -> ReLU)是 CNN 中最常见的计算组合。ncnnoptimize 不会放过这个巨大的优化机会。它的目标是将激活(Activation)函数的计算,“压入” 到 Convolution 层的计算核心中,从而消除一次代价高昂的内存读写。
TL;DR
目标: 融合 Convolution(或 Convolution1D)层与其后紧跟的非线性激活层(ReLU, Clip, Sigmoid, Mish, HardSwish 等)。
瓶颈分析: Conv ...
读 ncnn 源码(XXXI):`replace_prelu_with_leaky_relu`——算子退化:用高效实现替换冗余
读 ncnn 源码(XXXI):replace_prelu_with_leaky_relu——算子退化:用高效实现替换冗余
在 ncnnoptimize 的优化 Pass 中,我们已经见证了大量的“算子融合”(如 Conv+BN)和“算子消除”(如 eliminate_dropout)。本篇,我们将探讨另一种优化思路:算子退化与替换 (Operator Degradation and Replacement)。replace_prelu_with_leaky_relu 函数是这一思想的绝佳范例。
它的核心任务是识别出某个通用但复杂的层(PReLU)在特定参数配置下,其功能退化成了一个简单但高效的层(ReLU / Leaky ReLU),并执行这种替换。
TL;DR
目标: 识别并替换 PReLU (Parametric ReLU) 层。
核心条件: 只替换那些 num_slope == 1 的 PReLU 层。
PReLU vs. Leaky ReLU:
PReLU: yi=max(0,xi)+αimin(0,xi)y_i = \max(0, x_i) + \alpha ...
读 ncnn 源码(XXX):`replace_reduction_with_global_pooling`——算子替换:识别低效模式
读 ncnn 源码(XXX):replace_reduction_with_global_pooling——算子替换:识别低效模式
在 ncnnoptimize 的优化 Pass 中,我们已经见证了大量“算子融合”(Operator Fusion)操作,它们通过合并相邻的线性层(如 Conv+BN)来减少计算和访存开销。本篇,我们将探讨另一种同样重要的优化技术:算子替换 (Operator Replacement)。replace_reduction_with_global_pooling 函数就是其典型代表。
它的核心任务是识别出一种低效的、由多个通用层组合而成的计算模式,并将其替换为一个功能等价但性能高得多的专用层。
TL;DR
目标: 识别并替换一种用两次连续的 Reduction (Mean) 操作来实现“全局平均池化”(Global Average Pooling) 的低效模式。
模式匹配: 遍历 layers,查找 Reduction -> Reduction 的直接连接模式。
严格条件: 两个 Reduction 层都必须是 Mean 操作 (operat ...
读 ncnn 源码(XXIX):`fuse_innerproduct_dropout`——推理时移除 Dropout
读 ncnn 源码(XXIX):fuse_innerproduct_dropout——推理时移除 Dropout
在本系列的图优化篇章中,我们已经分析了多种针对线性计算链(如 Conv/InnerProduct 后接 BN/Scale/Add/Mul)的融合优化。Dropout 层是神经网络训练时常用的一种正则化手段,但在推理阶段,它的行为通常是恒等映射(Identity)或者乘以一个固定的缩放因子。fuse_innerproduct_dropout 正是利用了 Dropout 在推理时的这一特性,将其与前驱的 InnerProduct 层进行融合或直接消除。
本篇,我们将剖析 fuse_innerproduct_dropout 的源码,理解其如何处理 Dropout 层以优化推理性能。
TL;DR
目标: 将 InnerProduct (全连接) 层后紧随的 Dropout 层进行融合或消除,因为 Dropout 在推理时通常是恒等操作或固定缩放。
模式匹配: 遍历网络 layers,查找 InnerProduct -> Dropout 的直接连接模式。
数学原理:
...
读 ncnn 源码(XXVIII):`fuse_innerproduct_add`——合并全连接层的偏置链
读 ncnn 源码(XXVIII):fuse_innerproduct_add——合并全连接层的偏置链
在本系列的图优化篇章中,我们已经见证了 ncnnoptimize 如何系统性地融合各种卷积变体以及全连接层 (InnerProduct) 后续的 BatchNorm 和逐通道乘法 (Mul)。为了进一步简化计算图中的线性计算链,ncnn 还提供了针对全连接层后接逐通道加法 (Add) 的融合优化:fuse_innerproduct_add。
本篇,我们将剖析该函数的源码,理解其如何将偏置合并的通用逻辑应用于 InnerProduct 这一关键层类型。
TL;DR
目标: 将 InnerProduct (全连接) 层后接一个执行逐通道/单元加法 (Per-Output Bias Addition,由 BinaryOp(Add) + MemoryData 实现) 的操作进行融合。
模式匹配: 查找 InnerProduct -> BinaryOp 结构,附加条件与 fuse_convolution_add 完全一致:BinaryOp 必须是 Add (op_type == ...
读 ncnn 源码(XXVII):`fuse_innerproduct_batchnorm`——全连接层的 BN 融合
读 ncnn 源码(XXVII):fuse_innerproduct_batchnorm——全连接层的 BN 融合
在本系列的前几篇中,我们已经详细探讨了 ncnnoptimize 如何将 BatchNorm 层融合到各种卷积变体(Convolution, ConvolutionDepthWise, Deconvolution, DeconvolutionDepthWise)中。InnerProduct 层,即全连接层(Fully Connected Layer),作为神经网络(尤其是分类头部)的另一个关键组件,同样可能后接 BatchNorm 层。为了实现彻底的优化,ncnn 提供了 fuse_innerproduct_batchnorm Pass 来处理 InnerProduct -> BatchNorm 这一模式。
本篇,我们将剖析该函数的源码,理解其如何将 BN 融合的通用原理应用于全连接层。
TL;DR
目标: 将 InnerProduct (全连接) 层后紧随的 BatchNorm 层进行融合,消除 BatchNorm 在推理时的计算开销。
模式匹配: 遍历 ...
读 ncnn 源码(XXVI):`fuse_deconvolutiondepthwise_batchnorm`——深度反卷积的 BN 融合
读 ncnn 源码(XXVI):fuse_deconvolutiondepthwise_batchnorm——深度反卷积的 BN 融合
在 ncnn 的图优化系列 Pass 中,我们已经见证了针对标准卷积 (Convolution)、深度卷积 (ConvolutionDepthWise) 和标准反卷积 (Deconvolution) 后续 BatchNorm 层的融合优化。为了构建一个完备的优化体系,ncnn 自然也覆盖了相对不那么常见、但同样可能存在的 DeconvolutionDepthWise -> BatchNorm 模式。
本篇,我们将剖析 fuse_deconvolutiondepthwise_batchnorm 的源码,理解其如何将 BN 融合的通用原理应用于深度反卷积 (DeconvolutionDepthWise) 这一特定层类型。
TL;DR
目标: 将 DeconvolutionDepthWise 层后紧随的 BatchNorm 层进行融合,消除 BatchNorm 在推理时的计算开销。
模式匹配: 遍历网络 layers,查找 Deconvolu ...
读 ncnn 源码(XXV):`fuse_deconvolution_add`——合并反卷积层的偏置链
读 ncnn 源码(XXV):fuse_deconvolution_add——合并反卷积层的偏置链
在本系列的前几篇中,我们已经系统性地分析了 ncnnoptimize 如何融合 Convolution, ConvolutionDepthWise 后续的 BatchNorm, Mul, Add 等线性操作。为了确保优化策略的完整性,ncnn 也为反卷积层 (Deconvolution) 提供了类似的融合能力。继上一篇分析 fuse_deconvolution_mul 之后,本篇我们将聚焦于 fuse_deconvolution_add,探讨其如何合并反卷积层后的逐通道加法操作。
TL;DR
目标: 将 Deconvolution 层后接一个执行逐通道加法 (Per-Channel Bias Addition,由 BinaryOp(Add) + MemoryData 实现) 的操作进行融合。
模式匹配: 查找 Deconvolution -> BinaryOp 结构,附加条件与 fuse_convolution_add 完全一致:BinaryOp 必须是 Add (op_ ...
读 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 ...
读 ncnn 源码(XXIII):`fuse_deconvolution_batchnorm`——反卷积层的 BN 融合
读 ncnn 源码(XXIII):fuse_deconvolution_batchnorm——反卷积层的 BN 融合
在之前的篇章中,我们已经深入探讨了标准卷积 (Convolution) 和深度可分离卷积 (ConvolutionDepthWise) 如何与后续的 BatchNorm 层进行融合。Deconvolution(也称为转置卷积或分数步长卷积)作为上采样操作中常用的层,其后同样可能跟随 BatchNorm 层。为了保持优化策略的一致性和覆盖度,ncnn 提供了 fuse_deconvolution_batchnorm Pass 来处理 Deconvolution -> BatchNorm 这一特定模式。
本篇,我们将剖析该函数的源码,理解其如何将 BN 融合的通用原理应用于反卷积层。
TL;DR
目标: 将 Deconvolution 层后紧随的 BatchNorm 层进行融合,消除 BatchNorm 在推理时的计算开销。
模式匹配: 遍历网络 layers,查找 Deconvolution -> BatchNorm 的直接连接模式。
数学原理: 与 ...
读 ncnn 源码(XXII):`fuse_convolutiondepthwise_add`——合并深度卷积的偏置链
读 ncnn 源码(XXII):fuse_convolutiondepthwise_add——合并深度卷积的偏置链
在第十九篇中,我们分析了标准 Convolution 如何融合后续的逐通道加法 (fuse_convolution_add)。与乘法融合类似,深度可分离卷积 (ConvolutionDepthWise) 后也可能跟随一个执行逐通道加法的 BinaryOp 层。fuse_convolutiondepthwise_add 正是 ncnn 针对这一模式提供的专属优化 Pass。
本篇,我们将剖析该函数的源码,理解其如何将偏置合并的逻辑应用于 ConvolutionDepthWise 场景。
TL;DR
目标: 将 ConvolutionDepthWise 层后接一个执行逐通道加法 (Per-Channel Bias Addition,由 BinaryOp(Add) + MemoryData 实现) 的操作进行融合。
模式匹配: 查找 ConvolutionDepthWise -> BinaryOp 结构,附加条件与 fuse_convolution_add 完全一致 ...
读 ncnn 源码(XXI):`fuse_convolutiondepthwise_mul`——为深度可分离卷积“乘”胜追击
读 ncnn 源码(XXI):fuse_convolutiondepthwise_mul——为深度可分离卷积“乘”胜追击
在第十八篇中,我们分析了标准 Convolution 如何融合后续的逐通道乘法 (fuse_convolution_mul)。鉴于深度可分离卷积(Depthwise Separable Convolution)在现代轻量级网络中的广泛应用,ncnn 自然也提供了针对 ConvolutionDepthWise 后接逐通道乘法的特定融合优化:fuse_convolutiondepthwise_mul。
本篇,我们将剖析该函数的源码,理解其如何将 fuse_convolution_mul 的逻辑应用于 ConvolutionDepthWise 这一特殊卷积形式。
TL;DR
目标: 将 ConvolutionDepthWise 层后接一个执行逐通道乘法(Per-Channel Scaling,由 BinaryOp(Mul) + MemoryData 实现)的操作进行融合。
模式匹配: 查找 ConvolutionDepthWise -> BinaryOp ...
读 ncnn 源码(XX):`fuse_convolutiondepthwise_batchnorm`——为深度可分离卷积“减负”
读 ncnn 源码(XX):fuse_convolutiondepthwise_batchnorm——为深度可分离卷积“减负”
在第十七篇中,我们深入分析了标准 Convolution 与 BatchNorm 的融合机制。深度可分离卷积(Depthwise Separable Convolution)作为现代轻量级网络(如 MobileNet, EfficientNet)的基础构件,其 ConvolutionDepthWise 部分后通常也紧跟着 BatchNorm 层。因此,针对性地优化 ConvolutionDepthWise -> BatchNorm 这一常见模式,对于提升这些模型的推理性能至关重要。
本篇,我们将剖析 fuse_convolutiondepthwise_batchnorm 的源码,理解 ncnn 如何将针对标准卷积的融合原理,平滑地应用于深度可分离卷积的 Depthwise 部分。
TL;DR
目标: 将 ConvolutionDepthWise 层后紧随的 BatchNorm 层进行融合,消除 BatchNorm 在推理时的计算开销。
模式匹配 ...
读 ncnn 源码(XIX):`fuse_convolution_add`——融合逐通道加法,进一步合并线性计算
读 ncnn 源码(XIX):fuse_convolution_add——融合逐通道加法,进一步合并线性计算
本篇,我们将继续沿着合并连续线性计算的优化思路,分析 ncnn 中另一个重要的融合 Pass:fuse_convolution_add。
此 Pass 专门针对 **Convolution 层后紧跟一个特定模式的逐通道加法(通过 BinaryOp 实现)**的场景。这种情况可能出现在某些网络结构(如 ResNet bottleneck 中的 residual connection 如果退化为加偏置)或者模型转换过程中。将其融合,可以消除冗余的加法操作,进一步提升推理效率。
TL;DR
目标: 将 Convolution 层后接一个扮演逐通道加法 (Per-Channel Bias Addition) 角色的 BinaryOp 层(操作类型为 Add,且第二个输入来自 MemoryData)进行融合。
模式匹配: 查找 Convolution -> BinaryOp 结构,并附加严格条件:
BinaryOp 的类型必须是加法 (op_type == 0)。
Bi ...
读 ncnn 源码(XVI):`ncnnoptimize`——神经网络图优化的“炼金术”
读 ncnn 源码(XVI):ncnnoptimize——神经网络图优化的“炼金术”
在之前的篇章中,我们已经深入了解了 ncnn 如何加载模型 (Net::load_param/model)、执行推理 (Extractor::extract) 以及内部精巧的设计模式 (Pimpl)。现在,我们将目光投向一个独立但至关重要的工具——ncnnoptimize。这个工具扮演着“炼金术士”的角色,它接收原始的 ncnn 模型文件,通过一系列图优化 (Graph Optimization) 操作,将其“精炼”成一个更小、更快、更高效的版本,而完全不改变模型的数学等价性。
本篇,我们将剖析 ncnnoptimize.cpp 的 main 函数流程,并以 fuse_batchnorm_scale 为例,初步探索 ncnn 图优化的基本原理和实现方式。
TL;DR
ncnnoptimize 的定位: 一个离线 (Offline) 模型优化工具。它读取 ncnn 的 .param 和 .bin 文件,执行一系列图优化 Pass,然后输出优化后的新 .param 和 .bin 文件。
核心机制 ...













