恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
卷积神经网络变体全解析:从分组卷积到深度可分离卷积
首页
资讯中心
/
卷积神经网络变体全解析:从分组卷积到深度可分离卷积
卷积神经网络变体全解析:从分组卷积到深度可分离卷积
发布时间:2026/8/2 4:05:04
1. 卷积操作的核心从“普通”说起在计算机视觉和深度学习领域卷积神经网络CNN是当之无愧的基石。而卷积操作本身则是这块基石中最核心的运算单元。很多朋友在入门时对“卷积”这个概念感到抽象更别提后来衍生出的各种变体比如分组卷积、深度卷积、逐点卷积以及将它们组合起来的深度可分离卷积。今天我就从一个一线工程师的视角掰开揉碎了讲讲这些概念重点放在输入、卷积核和输出的形状上。形状是理解一切的基础形状对了模型才能跑起来形状理解了你才能灵活设计网络结构。首先我们得统一一个最基础的认知在深度学习的语境下我们讨论的“卷积”绝大多数时候指的是二维离散卷积并且是“互相关”操作。别被数学定义吓到你可以把它想象成拿着一把小刷子卷积核在一张图片输入特征图上从左到右、从上到下地滑动。每滑动到一个位置就把刷子覆盖的区域和刷子本身的图案权重做对应位置的乘法再全部加起来得到一个数值这个数值就是输出特征图在该位置的值。那么一个最基础的“普通卷积”也叫标准卷积或2D卷积是怎么运作的呢我们来看它的三个核心要素输入、卷积核、输出。假设我们有一批输入数据其形状通常表示为(B, C_in, H, W)。这里B是批次大小一次处理多少张图C_in是输入通道数比如RGB图片就是3H和W是特征图的高度和宽度。卷积核的形状是(C_out, C_in, K, K)。C_out是我们期望得到的输出通道数K是卷积核的尺寸比如3x3。注意每一个输出通道都对应一个独立的、形状为(C_in, K, K)的卷积核。这个核会与输入的所有C_in个通道分别进行卷积然后将C_in个卷积结果相加最终得到一个单通道的输出特征图。因为有C_out个这样的核所以最终输出形状是(B, C_out, H_out, W_out)。H_out和W_out由输入尺寸、卷积核尺寸、填充Padding和步长Stride共同决定。举个例子输入一张224x224的RGB图片 (C_in3)我们用64个3x3的卷积核C_out64, K3采用填充1保持尺寸、步长1。那么输入形状是(1, 3, 224, 224)卷积核形状是(64, 3, 3, 3)输出形状就是(1, 64, 224, 224)。这个操作的计算量以乘法加法次数衡量大约是C_out * H_out * W_out * C_in * K * K在这个例子里非常庞大。正是为了优化这个庞大的计算量后续的各种卷积变体才被发明出来。注意这里说的“形状”是深度学习框架如PyTorch, TensorFlow中最常用的内存布局格式即“通道在前”Channels First。有些框架或场景可能使用“通道在后”格式但原理完全一致只是维度顺序不同。2. 分组卷积化整为零的团队协作当模型越来越深、通道数越来越多时普通卷积的计算负担呈平方级增长。分组卷积Grouped Convolution是一种非常直观的“分治”策略。它的核心思想是将输入通道和输出通道分成若干组组与组之间的计算完全独立。假设我们将分组数设为G。在分组卷积中输入形状不变(B, C_in, H, W)。卷积核形状变为(C_out, C_in/G, K, K)。注意这里C_in和C_out必须能被G整除。输出形状依然是(B, C_out, H_out, W_out)。它是如何工作的呢我们把输入通道C_in平均分成G组每组有C_in/G个通道。同时把输出通道C_out也平均分成G组。第1组输出通道只与第1组输入通道进行卷积第2组输出通道只与第2组输入通道进行卷积以此类推。你可以想象成有G个小型的、独立的卷积团队在并行工作每个团队只负责处理一部分输入并生成一部分输出。最经典的应用是AlexNet当年因为GPU显存限制将网络部署在两个GPU上本质上就是使用了分组数G2的分组卷积。当分组数G等于输入通道数C_in时它就变成了我们接下来要说的深度卷积。分组卷积的优势非常明显大幅减少参数量和计算量。参数量从普通卷积的C_out * C_in * K * K减少到C_out * (C_in/G) * K * K变为原来的1/G。计算量也同比减少。引入稀疏连接可能提升泛化能力。由于组间无连接这强制模型学习组内更紧密的特征组合类似于一种正则化有时能带来更好的效果。但缺点也需要留意组间信息隔离。特征只能在组内融合如果分组不当可能阻碍了不同组间本应存在的特征交互影响模型表达能力。所以分组数G是一个需要调节的超参数。极端情况当GC_inC_out时就是深度卷积参数量最小但表达能力也最受限制通常不会单独使用。在实际代码中PyTorch的nn.Conv2d和 TensorFlow的tf.keras.layers.Conv2D都有一个groups参数来实现此功能。# PyTorch 示例普通卷积 vs 分组卷积 import torch.nn as nn # 普通卷积 std_conv nn.Conv2d(in_channels128, out_channels256, kernel_size3, groups1) print(f普通卷积核形状: {std_conv.weight.shape}) # torch.Size([256, 128, 3, 3]) # 分组卷积 (G4) grouped_conv nn.Conv2d(in_channels128, out_channels256, kernel_size3, groups4) print(f分组卷积核形状: {grouped_conv.weight.shape}) # torch.Size([256, 32, 3, 3]) 注意 C_in/G 128/4 323. 深度卷积与逐点卷积深度可分离卷积的两大支柱为了极致地追求效率尤其是在移动端和嵌入式设备上深度可分离卷积Depthwise Separable Convolution成为了主流选择。它不是一个单一的卷积操作而是深度卷积Depthwise Convolution和逐点卷积Pointwise Convolution的串联组合。理解它必须先拆解这两个组成部分。3.1 深度卷积通道独立的“单兵作战”深度卷积是分组卷积的一个极端特例即分组数G等于输入通道数C_in。这意味着每一个输入通道都被分配到一个独立的“组”中并且对应一个独立的卷积核。输入形状(B, C_in, H, W)卷积核形状(C_in, 1, K, K)。 注意这里的输出通道数被强制等于输入通道数C_out C_in因为每个输入通道对应一个卷积核产生一个输出通道。核的形状是(1, K, K)因为它只作用于单个通道。输出形状(B, C_in, H_out, W_out)关键点深度卷积的每个卷积核只负责过滤一个输入通道它完全不进行跨通道的信息融合。它的输出特征图在通道维度上与输入是一一对应的关系。如果输入是RGB三通道经过深度卷积后输出还是三个通道但每个通道的信息已经根据其对应的卷积核进行了空间上的滤波。计算量对比普通卷积急剧下降因为没有了C_in与C_out的乘积项。但代价是输出通道数被锁定且通道间无交互。3.2 逐点卷积通道融合的“联络官”逐点卷积顾名思义就是卷积核的尺寸为1x1的普通卷积。它的核心作用不是进行空间滤波因为1x1的核几乎不感知空间邻域信息而是专门负责跨通道的信息融合与升维/降维。输入形状(B, C_in, H, W)。 注意这里的输入通常是深度卷积的输出。卷积核形状(C_out, C_in, 1, 1)。输出形状(B, C_out, H, W)。 因为核是1x1所以输出空间尺寸H, W通常与输入相同在步长为1且无填充的情况下。你可以把逐点卷积看作是对每个空间位置H, W上的一个点的所有C_in个通道值进行的一次加权求和从而得到该位置在新的C_out个通道上的值。它高效地实现了通道间的线性组合。3.3 深度可分离卷积高效组合拳现在我们把深度卷积和逐点卷积串联起来就构成了深度可分离卷积输入 → 深度卷积空间滤波 → 逐点卷积通道融合 → 输出阶段一深度卷积输入(B, C_in, H, W)卷积核(C_in, 1, K, K)输出(B, C_in, H_out, W_out)。 假设深度卷积步长为1填充保持尺寸则H_out H, W_out W。阶段二逐点卷积输入深度卷积的输出(B, C_in, H, W)卷积核(C_out, C_in, 1, 1)最终输出(B, C_out, H, W)我们来算一笔账对比一下普通卷积和深度可分离卷积的参数量与计算量近似乘法加法次数。假设输入为(C_in, H, W)使用C_out个KxK卷积核输出为(C_out, H, W)忽略批次假设步长1填充保持尺寸。普通卷积参数量C_out * C_in * K * K计算量C_out * H * W * C_in * K * K深度可分离卷积深度卷积部分参数量C_in * 1 * K * K C_in * K * K计算量C_in * H * W * K * K逐点卷积部分参数量C_out * C_in * 1 * 1 C_out * C_in计算量C_out * H * W * C_in总计参数量C_in * K * K C_out * C_in计算量C_in * H * W * (K * K C_out)比例关系计算量之比约为(C_in * H * W * K * K C_in * H * W * C_out) / (C_out * H * W * C_in * K * K) 1/C_out 1/(K*K)通常C_out较大如256K较小如3所以这个比例大约在1/9到1/8左右。这意味着深度可分离卷积可以将计算量减少到普通卷积的约1/9参数量也有类似比例的下降。这就是MobileNet、EfficientNet等轻量级网络的核心秘诀。实操心得虽然深度可分离卷积效率极高但它将空间滤波和通道融合两个步骤解耦了。有论文指出这种解耦可能在某些任务上导致特征提取能力稍弱于同等条件下的普通卷积。因此在实际设计中有时会通过增加通道数即宽度乘子或使用更先进的激活函数如Swish、注意力机制如SE模块来弥补这一潜在的性能损失。“用结构换效率再用其他技巧补回性能”是轻量化网络设计的常见思路。4. 形状演变全流程与实战对比为了让大家有一个更直观的认识我们用一个具体的例子从头到尾演示一下这几种卷积操作的形状变化。我们设定一个统一的输入场景输入张量(B4, C_in32, H28, W28)。 代表一个批次有4张图每张图有32个通道分辨率28x28。目标输出通道数C_out64。卷积核大小K3。填充与步长为简化均假设为padding1,stride1以保证空间尺寸H, W不变。卷积类型卷积核形状输出形状计算量近似参数量说明普通卷积(64, 32, 3, 3)(4, 64, 28, 28)64*28*28*32*3*3 ≈ 14.5M64*32*3*3 18,432基准模型分组卷积 (G4)(64, 8, 3, 3)(4, 64, 28, 28)(64*28*28*8*3*3)*4 ≈ 14.5M64*8*3*3*4 18,432计算/参数量与普通卷积相同但组内独立。注意这里总计算量看似没变是因为我们简化了公式。实际框架实现中由于组间并行计算效率可能更高但理论浮点运算次数FLOPs在G整除C_in和C_out时是相等的。更准确的说法是单个卷积核的参数和计算涉及的通路数减少为1/G。深度卷积(32, 1, 3, 3)(4, 32, 28, 28)32*28*28*1*3*3 ≈ 0.23M32*1*3*3 288输出通道数被迫等于输入32无法直接得到64通道。逐点卷积(64, 32, 1, 1)(4, 64, 28, 28)64*28*28*32*1*1 ≈ 1.6M64*32*1*1 2,048单独使用只融合通道不进行空间滤波。深度可分离卷积深度(32, 1, 3, 3)逐点(64, 32, 1, 1)(4, 64, 28, 28)0.23M 1.6M ≈ 1.83M288 2048 2,336计算量仅为普通卷积的12.6%参数量仅为12.7%。从上表可以清晰看到分组卷积在输入输出通道数、分组数满足特定关系时理论FLOPs与普通卷积相同但其内部连接变得稀疏这是一种结构上的改变可能带来正则化好处且在实际硬件上可能因并行度提高而加速。深度卷积极其高效但功能受限。逐点卷积计算量相对较小主要开销在于通道数的乘积。深度可分离卷积通过串联两者用极小的性能损失有时通过调优可忽略甚至反超换来了一个数量级的计算与参数节省。这就是它统治移动端CNN的底气。5. 常见误区与工程实践要点在实际项目和阅读代码时围绕这些卷积操作有几个容易混淆和出错的点。误区一混淆“分组卷积”与“深度卷积”的实现在PyTorch中设置groupsC_in且C_out是C_in的整数倍时实现的就是分组卷积。当C_out C_in时就是深度卷积。但框架通常不提供名为DepthwiseConv2d的独立层而是通过Conv2d(groupsC_in)来实现。许多高效的移动端网络实现如MobileNetV2会封装一个DepthwiseConv2d模块其内部就是一个groupsin_channels的卷积。# 实现一个深度卷积模块 class DepthwiseConv2d(nn.Module): def __init__(self, in_channels, kernel_size, stride1, padding0): super().__init__() self.depthwise nn.Conv2d( in_channelsin_channels, out_channelsin_channels, # 关键输出通道数等于输入 kernel_sizekernel_size, stridestride, paddingpadding, groupsin_channels # 关键分组数等于输入通道数 ) def forward(self, x): return self.depthwise(x)误区二忽略逐点卷积的重要性有些人会认为深度卷积后直接接非线性激活函数输出就够了。这是错误的。深度卷积没有跨通道融合能力其输出特征的信息组合是受限的。逐点卷积正是负责将深度卷积提取的各个通道的空间特征以最优的方式组合起来形成新的、更有效的特征表示。缺少了这一步模型的表达能力会大打折扣。误区三盲目使用深度可分离卷积虽然它效率高但并非在所有位置都是最优的。在网络浅层输入分辨率高、通道数少普通卷积的计算开销本身不大但特征抽象能力要求高此时使用普通卷积可能更好。在网络深层分辨率低、通道数多计算瓶颈突出深度可分离卷积的收益才最大。像EfficientNet这样的网络会通过神经架构搜索NAS来智能地决定每一层使用哪种卷积类型。工程实践要点通道对齐在使用分组卷积或深度可分离卷积时要时刻注意输入输出通道数是否能被分组数整除。否则框架会报错。在设计网络时通常将通道数设置为8或16的倍数这既能满足整除要求也符合大多数计算硬件如GPU的优化内存对齐。激活函数与归一化层的放置在深度可分离卷积块中标准的顺序通常是深度卷积 → 批归一化BN → 激活函数如ReLU6 → 逐点卷积 → 批归一化 → 激活函数。BN层和激活函数的插入位置对训练稳定性和最终性能有显著影响。残差连接在MobileNetV2中引入了倒残差结构Inverted Residual。其核心是在深度卷积之前先用一个逐点卷积1x1 Conv进行通道升维例如扩展6倍然后进行深度卷积再用一个逐点卷积降维。升维后在高维空间进行非线性变换深度卷积激活被认为能捕获更丰富的特征。同时在降维后的输出与模块输入降维后之间添加残差连接以缓解梯度消失。理解这个结构必须建立在清晰掌握逐点卷积升维降维作用的基础上。计算量FLOPs不等于推理速度FLOPs是一个重要的理论指标但最终在手机或嵌入式芯片上的推理速度还受内存访问量MAC、算子并行度、硬件优化程度如是否支持深度卷积专用指令等因素影响。有时FLOPs稍高的模型因为内存访问更友好反而更快。我个人在移动端模型部署的实践中深有体会理解这些卷积变体不仅仅是学术上的它直接关系到你在模型压缩、量化、选择部署后端时所做的每一个决策。比如知道某个层是深度卷积你就能预期它对于支持NEON指令集的ARM CPU会非常友好而如果某个自定义模块里混用了奇怪的分组数可能会导致某些推理引擎如TensorRT的优化器无法识别和融合算子从而拖慢整体速度。把这些基础概念的形状、计算、数据流在心里刻清楚就像木匠熟悉他的刨子和锯子一样是做出好活的前提。