读 ncnn 源码(XXXVII):`eliminate_orphaned_memorydata`——图优化的“垃圾回收”
读 ncnn 源码(XXXVII):eliminate_orphaned_memorydata——图优化的“垃圾回收”
在 ncnnoptimize 的图优化篇章中,我们已经见证了多种“算子融合”和“算子消除” Pass。这些优化操作(如 fuse_memorydata_binaryop)在将计算合并、烘焙参数的同时,往往会使原图中的某些层(如 MemoryData)的输出不再被任何其他层所需要,从而使其成为“孤儿”节点。
本篇,我们将剖析 eliminate_orphaned_memorydata 这一优化 Pass,它扮演着图优化流水线中**“垃圾回收器”(Garbage Collector)**的角色,专门负责清理这些因上游优化而产生的冗余数据层。
TL;DR
目标: 识别并消除那些输出不再被任何有效层(non-fused)所消费的 MemoryData 层。
动机: 这是一个清理(Cleanup)Pass。在 fuse_memorydata_binaryop, fuse_convolution_add 等 Pass 中,MemoryData 层(作为常量/偏置的提供者 ...
读 ncnn 源码(XXXVI):算子消除——`eliminate_dropout/pooling1x1/noop/split`
读 ncnn 源码(XXXVI):算子消除——eliminate_dropout/pooling1x1/noop/split
在 ncnnoptimize 的图优化工具箱中,除了“算子融合”(如 Conv+BN)和“算子替换”(如 PReLU->ReLU),还有一类至关重要的优化 Pass:算子消除 (Operator Elimination)。这类优化的目标是识别并彻底移除那些在推理阶段计算无效或结构冗余的层。
本篇,我们将集中分析 eliminate_dropout, eliminate_pooling1x1, eliminate_noop, 和 eliminate_split 这四个函数。它们虽然处理的层类型不同,但其核心思想和图修改手法几乎完全一致:找到“无效层”,并将其从计算图中“短路”掉。
TL;DR
目标: 识别并消除四种在特定条件下对计算图无实际贡献的层:Dropout(推理时)、Pooling(1x1, s1)、Noop、Split(单路输出)。
核心原理 (Identity Mapping): 这些层在特定配置下都退化成了恒等映射 (Identity ...
读 ncnn 源码(XXXV):`fuse_binaryop_eltwise`——识别加权求和并替换为 Eltwise
读 ncnn 源码(XXXV):fuse_binaryop_eltwise——识别加权求和并替换为 Eltwise
在 ncnnoptimize 的图优化篇章中,我们已经见证了多种“算子融合”(如 Conv+BN)和“算子消除”(如 eliminate_dropout)。本篇,我们将探讨一种更高级的优化:基于模式识别的算子替换 (Pattern-based Operator Replacement)。fuse_binaryop_eltwise 就是其典型代表。
它的核心任务是识别出一种由多个 BinaryOp 层构成的、在语义上等价于**“加权求和”的计算模式,并将其替换**为一个功能更强、性能更高的 Eltwise 专用层。
TL;DR
目标: 识别 Y = (A * C0) + (B * C1) 这样的加权求和模式。A 和 B 是特征图(Tensor),C0 和 C1 是标量(Scalar)。
模式匹配: ncnnoptimize 查找一个 BinaryOp(Add, Tensor, Tensor) 作为中心,然后反向查找其两个输入 A 和 B 的生产者:
Case 1 ...
读 ncnn 源码(XXXIV):`fuse_memorydata_binaryop`——将“常量”烘焙进“算子”
读 ncnn 源码(XXXIV):fuse_memorydata_binaryop——将“常量”烘焙进“算子”
在 ncnnoptimize 的图优化篇章中,我们已经见证了多种“算子融合”(Operator Fusion),它们将两个计算层(如 Conv 和 BN)合并为一个。本篇,我们将探讨一种不同但同样重要的优化:将数据层(MemoryData)与计算层(BinaryOp)融合。
这在本质上是一种常量折叠 (Constant Folding) 或 常量传播 (Constant Propagation)。fuse_memorydata_binaryop 的核心任务是识别出 BinaryOp(如加、减、乘、除)的一个输入是来自 MemoryData 的标量(Scalar),并将这个标量“烘焙”到 BinaryOp 的参数中,将其从一个昂贵的“张量-张量”操作,降级为一个高效的“张量-标量”操作。
TL;DR
目标: 识别 BinaryOp 的一个输入是来自 MemoryData 层的单个标量值的模式。
优化: 将 BinaryOp 转换为其高效的**“标量模式”**(with ...
读 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 完全一致 ...












