分组卷积的思想神了

本文讲述了如何在专用芯片上处理大通道数的卷积运算,通过分组卷积将大卷积拆分为多个小卷积,利用内积指令和推理框架如PyTorch和TVM进行优化。作者介绍了分组卷积的原理、起源和在解决计算和内存问题上的应用。

大家好啊,我是董董灿。

最近,分组卷积帮我解决了一个大忙,事情是这样的。

这几天遇到一个头疼的问题,就是要在某一芯片上完成一个神经网络的适配,这个神经网络中卷积居多,并且有一些卷积的通道数很大,比如2048个输入通道。

问题是,该芯片是专用芯片,所对应的硬件模块无法直接支持这种通道数很大的卷积运算。

于是开始了头脑风暴,因为芯片中有良好的向量指令集来支持内积运算,因此第一反应便是拿内积运算来拼凑出卷积。

但实验结果表明,利用内积指令来拼凑的卷积效果不如人意,主要在于内积指令调用次数过多,导致神经网络的整体性能太差。

就在一筹莫展时,一个声音传过来,“我们改图吧”。

改图,指的是改神经网络的结构,很多推理框架都具备这个能力,比如pytorch,tvm等。

这些推理框架可以针对性的适配某些专用AI芯片加速器,为此魔改一些神经网络结构,通过增加一些优化节点(pass),来使原本不支持的运算变为可支持的运算。

比如这个卷积的例子,可以将一个大卷积(指的是通道数很大),魔改为两个或多个小卷积,分别计算,计算完成后再将结果合并。

这就要提一下将卷积在通道维度分成多个卷积计算的操作——分组卷积(Group Convolution)了。

1、 什么是分组卷积

网上有很多关于分组卷积的资料。说的简单点,分组卷积是将卷积在channel 维度分组来计算,以达到将一个大卷积分成多个小卷积的目的。

为了清晰,我们将卷积操作简化为一次最简单的乘累加运算,channel维度只有2个数据,如下图。

图片

正常的卷积操作,A和B的乘累加,计算的是 1x3 + 2x4 = 11。

而如果将其在channel维度分组(例子中channel维度只有两个数据,我们就分成两组),那么会是这样

图片

第一组只计算channel 维度的前半部分,第二组只计算channel维度的后半部分。

分组的过程是不是很好理解。

2、为什么需要分组卷积

分组卷积最早由Alex等人在2012年的ImageNet图像分类竞赛中提出并使用,提出的初衷是为了解决卷积神经网络训练期间的计算和内存开销问题。

2012年的GPU不像现在的GPU内存那么大,当初GPU内存还很有限,一个channel通道数很大的卷积直接计算,放在整个网络中,是很耗费内存的。

于是,他们把大卷积在通道方向拆分成多个小卷积来分别计算,这样可以让拆分出来的多个小卷积分别运行在多张GPU卡上,达到一个模型多卡并行计算的目的,从而提高训练性能。

需要说明的是,论文中的分组卷积不仅将输入通道进行了分组,同时将输出通道进行了分组。

由此而来的分组卷积,在计算量上变为原来的1/G,G为分组的组数。

3、分组卷积和原始卷积在数学上等价吗?

细心的小伙伴可能会问这个问题。

如果仅仅说分组卷积,那么结果肯定和原始大卷积不等价,因为把channel维度给拆开了。

并且如果不做处理,还会影响最终的推理精度,对于这个问题,有个很好的解决办法。

我们知道,卷积算法的核心是特征提取和融合:5分钟理解什么是卷积的特征提取

如果不进行其他操作,那么分组卷积仅仅进行了组内小卷积的特征融合,而缺少了分组间的特征融合,这样对于最终的训练推理结果会有影响。

为了解决这个问题,往往在分组卷积前在channle维度进行 shuffle 操作,也就是洗牌,使得特征可以随机的分配到每一个组内,能够更好的完成组间的特征融合。

4、“分组卷积“”的思想神了

回到上面我遇到的问题,我们需要在自己的需求下,利用分组卷积的思想,魔改大卷积运算。

如下示意图:一个输入channel 为 ci 的卷积,通过 split 在输入 channel 维度拆成两个 ci/2 的卷积,然后“分组”进行卷积操作,然后通过加法进行相加。

图片

这里并没有对输出channel 进行分组,因为我们解决的问题不一样,内存对我们来说不是问题,问题仅仅在于输入channel太大。

而通过上面的魔改变换,便可以使得最终的结果和原始卷积计算一致,借用“分组卷积”的思想,可以很好的解决我遇到的问题。

### 3.1 分组卷积的概念 分组卷积是一种在标准卷积基础上改进的卷积操作方式,旨在通过将输入通道划分为多个独立的组别,并分别对每组进行卷积计算,从而降低整体计算复杂度。这种技术可以在保持模型性能的同时显著减少参数数量和计算量,广泛应用于深度学习中的高效网络设计。 ### 3.2 分组卷积的原理 在标准卷积中,所有输入通道都会与一组卷积核进行全连接运算,以生成输出特征图。而在分组卷积中,输入通道被沿深度方向划分为若干个组,每组包含固定数量的通道。每组的卷积运算是相互独立的,即每个组内的通道只与其对应的卷积核进行运算,而不与其他组的数据交互。 例如,假设输入数据具有C个通道,若指定分组数g,则每组将包含C/g个通道。相应地,每组的卷积核也仅作用于其对应的输入组,且每组的卷积核数量与输出通道数成比例分配。经过各组独立卷积后,得到的输出特征图同样分为g组,最后将这些组在通道维度上拼接,形成最终的输出结果。 这种方式使得卷积操作的计算负担大幅降低,因为每组卷积的输入通道数仅为原始通道数的1/g,从而减少了单次卷积的参数总量[^4]。 ### 3.3 分组卷积的优势 分组卷积相较于标准卷积具有以下几个显著优势: - **降低计算复杂度**:由于每组卷积仅处理部分输入通道,总的参数数量和计算量都明显减少,有助于构建轻量化模型。 - **提升模型效率**:在相同计算资源下,可以支持更宽或更深的网络结构,从而提升模型表达能力。 - **增强并行计算能力**:各组之间互不依赖,便于在硬件层面实现并行化计算,提高运行效率。 这一方法最早在ResNeXt等网络架构中被广泛应用,其中“cardinality”(即分组的数量)被视为一个关键超参数,实验表明增加cardinality可以有效提升模型性能,相比单纯增加宽度或深度更具性价比[^3]。 ### 3.4 示例代码 以下是一个使用PyTorch实现的分组卷积示例: ```python import torch import torch.nn as nn # 定义一个分组卷积层 group_conv = nn.Conv2d( in_channels=64, # 输入通道数 out_channels=128, # 输出通道数 kernel_size=3, # 卷积核大小 groups=4 # 分组数 ) # 创建一个随机输入张量 (batch_size, channels, height, width) input_tensor = torch.randn(1, 64, 32, 32) # 执行前向传播 output_tensor = group_conv(input_tensor) print("Input shape:", input_tensor.shape) print("Output shape:", output_tensor.shape) ``` 上述代码展示了如何定义并使用一个分组卷积层,其中`groups=4`表示将输入通道分成4组进行独立卷积操作。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董董灿是个攻城狮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值