分组卷积、SEnet模块、CBAM模块
一、分组卷积
1、分组卷积的目的
分组卷积的目的是:类似于并行计算,通过分组卷积,降低参数的个数,从而提高模型效果。
2、分组卷积的过程
在高阶卷积部分我们简单的介绍了分组卷积机动原理,这里我们详细的看一看,我们还是从下图进行分析: 上面的图片中,左边的是传统的卷积机制,右边的是分组卷积机制,我们对比着看 首先你要有如下概念,这个概念贯穿分组卷积的全过程,说多少遍也不为过。
这里我们定义: 输入输出的高:H ,卷积核高:h1 输入输出的宽:W , 卷积核宽:w1 这两个都是空间维度 通道数:C 重点来了,一定要熟记于心:
- 输入C(输入通道数) = kernel C(卷积核通道数)
- kernel 个数 = out C (输出通道数)
我们先来看左边的,常规的卷积过程: 左边的是输入,右边的是输出,输入输出的H,W相同 分析卷积的过程,计算出参数的个数使我们的目的:
分析: 1、参数的个数等于什么?
- 参数的个数 = 一个卷积核的一个通道有多少参数 x 一个卷积核的通道数 x 卷积核的个数
2、一个卷积核的一个通道的参数 = h1 x w1 3、一个卷积核的通道数 = 输入的通道数 = C1 4、卷积核的个数 = 输出通道数 = C2 故 参数总个数Q = h1 x w1 x C1 x C2
接下来,我们再看分组卷积的过程: 首先你要知道,所谓的分组分的是谁?
同样,左边的是输入,右边的是输出,输入输出的H,W相同,但是这里我们定义了一个新的参数
定义:分成的组数 = g
分析卷积的过程,计算出参数:
分析: 1、参数的个数等于什么?
2、每一组参数的个数等于什么?
- 每一组参数的个数 = 一个卷积核的一个通道有多少参数 x 每一组一个卷积核的通道数 x 每一组卷积核的个数
3、一个卷积核的一个通道的参数 = h1 x w1 4、每一组一个卷积核的通道数 = 输入的通道数/z组数 = C1/g 5、每一组卷积核的个数 = 输出通道数的个数/组数 = C2/g 故: 参数总个数 = h1 x w1 x C1/g x C2/g x g = h1 x w1 x C1/g x C2 = Q/g
两种卷积方式的参数对比可得,分组卷积的参数个数仅仅为不分组的1/g,降低了参数的个数。
二、SEnet
SEnet相当于一个模块,这个模块可以嵌入到任何一个网络结构中,下面我们就来看一下这个模块都能作什么是事情。 简单的来书,就是行提高通道注意力上来提高模型效果。
已经有很多工作在空间维度上来提升网络的性能,那么很自然的想到,网络是否可以从其他层面来考虑去提升性能,比如考虑特征通道之间的关系? 我们的工作就是基于这一点并提出Squeeze-and-Excitation Networks(简称SENet)。在我们提出的结构中Squeeze和Excition是两个非常关键的操作,所以我们以此来命名。 我们的机动是希望显示的建模特征通道之间的相互依赖的关系。另外,我们不打算引入一个新的空间维度来进行特征通道之间的融合,而是采用一种全新的特征重标定策略,具体的说:就是通过学习的方式来自动获取到每个特征通道的重要程度,然后通过这个重要程度取提升有用的特征并抑制对当前任务用处不大的特征
说白了就是说每一个通道的特征都有一个权值在里边。决定了通道特征的重要程度。 给定一个输入X,特征通道数为C_1,通过一系列卷积等一般变换后,得到一个特征通道数为C_2的特征,与传统的CNN不一样的是,接下来我们通过三个操作来重标定前面得到的特征。 第一步: Squeeze操作,我们顺着空间维度来进行特征压缩,将每个二维的特征通道变成一个实数,这样,这个实数某种程度上具有全局的感受野,并且输出的维度特输入的特征通道数相匹配。他表征着在特征通道上相应的全局分布,而且使得靠近输入的层也可以获得全局的感受野,这一点在很多任务中都是非常有用的 第二步: Excitation操作,他是一个类似于循环神经网络中门的机制,通过参数w,为每个特征通道生成权重,其中参数w被学习用来显示的建模特征通道之间的相关性 第三步: Reweight操作,我们将Excitation的输出的权重看做是通过特征选择后 的每个特征通道的重要性,然后通过乘法逐通道加权到向前的特征上,完成在通道维度上的对原始特征的重标定。 55
下面看一下代码的实现,会更明白一些,这里是
这里引用
看代码:
class SELayer(nn.Module):
def __init__(self,channel,reduction = 16):
super(SELayer, self).__init__()
self.avg_pool = nn.AdaptiveAvgPool2d(1)
self.fc = nn.Sequential(
nn.Linear(channel,channel // reduction,bias=False),
nn.ReLU(True),
nn.Linear(channel // reduction,channel,bias=False),
nn.Sigmoid()
)
def forward(self, x):
b,c,_,_, = x.size()
y = self.avg_pool(x).view(b,c)
y = self.fc(y).view(b,c,1,1)
return x * y.expand_as(x)
然后就是怎们把这个模块添加到网络中:作为网络中的一个组件放到网络中去
参考知乎文章: https://zhuanlan.zhihu.com/p/65459972
三、CBAM
根据SEnet又有人做出了改进,产生了CBAM,他据他又是什么样的机制呢。
参考知乎文章: https://zhuanlan.zhihu.com/p/102035273
他和SEnet很像,不同的是他的目的是保留的是空间上的维度,消除深度(通道),第一步操作时,他是对每一个通道进行两个池化,均值和最大值池化,这样池化以后就得到了2通道的特征,且特征的空间维度不变,然后在对这两个通道做一个1x1的卷积,目的是压缩通道,编程单通道。在作为组件添加到网络中,具体还是看代码。
通道注意力机制:空间注意力机制 加到网络中 最后的使用一个类进行两个模块的集成,得到的通道注意力和空间注意力以后,使用广播机制对原有的feature map进行信息提炼,最终得到提炼后的feature map。以上代码以ResNet中的模块作为对象,实际运用可以单独将以下模块融合到网络中:
|