SKNet(Selective Kernel Network)是一种用于图像分类和目标检测等任务的深度神经网络架构,其核心创新是引入了选择性的多尺度卷积核(Selective Kernel)以及一种新颖的注意力机制,从而在不增加网络复杂性的情况下提升了特征提取的能力。SKNet的设计旨在解决多尺度信息融合的问题,使网络能够适应不同尺度的特征。
1. 核心思想
SKNet的核心思想是通过选择性地应用不同尺度的卷积核,从而在不同层级上捕捉多尺度特征。为了实现这一点,SKNet引入了一个选择模块,用于自适应地决定在每个通道上使用哪些尺度的卷积核。这种选择性的多尺度卷积核有助于提升特征表示的能力,使网络更具适应性和泛化能力。
2. 结构
SKNet的核心结构包括两个关键组件:选择模块和SK卷积层。
选择模块是SKNet的基础,它负责在每个通道上动态地选择适合的卷积核尺度。选择模块接受来自上一层的特征图作为输入,然后通过一组平均池化和全连接层,生成每个通道的选择权重。这些选择权重表示了在当前通道上使用不同尺度卷积核的重要程度。最后,选择权重被用于调整多尺度卷积核的权重,从而生成最终的特征图。
SK卷积层是SKNet的核心卷积操作,它使用选择模块生成的选择权重来调整多尺度卷积核的权重。在SK卷积层中,每个通道都包含多个不同尺度的卷积核,但根据选择模块的权重,只有部分卷积核会对当前通道的特征进行卷积操作。这种机制使网络能够自适应地选择适合当前任务的尺度,从而提高了特征的丰富性和表征能力。
实现机制:
Split操作是将原feature map分别通过一个3×3的分组深度卷积和3×3的空洞卷积(感受野为5×5)生成两个feature map :U1(图中黄色)和U2(图中绿色),然后将这两个feature map进行相加,生成U。生成的U通过Fgp函数(全局平均池化)生成1×1×C的feature map(图中的s),该feature map通过Ffc函数(全连接层)生成d×1的向量(图中的z),公式如图中所示(δ表示ReLU激活函数,B表示Batch Noramlization,W是一个d×C的维的)。d的取值是由公式d = max(C/r,L)确定,r是一个缩小的比率(与SENet中相似),L表示d的最小值,实验中L的值为32。生成的z通过ac和bc两个函数,并将生成的函数值与原先的U1和U2相乘。由于ac和bc的函数值相加等于1,因此能够实现对分支中的feature map设置权重,因为不同的分支卷积核尺寸不同,因此实现了让网络自己选择合适的卷积核(ac和bc中的A、B矩阵均是需要在训练之前初始化的,其尺寸均为C×d)
3. 优势
SKNet的设计在以下几个方面具有优势:
通过选择性地应用不同尺度的卷积核,SKNet能够有效地融合多尺度的特征信息。这有助于网络捕捉不同层次的视觉特征,提高了特征的表征能力。
选择模块使网络能够自适应地选择卷积核的尺度,从而适应不同任务和图像的特点。这种自适应性能够使网络在各种场景下都能表现出色。
尽管引入了多尺度卷积核,但由于选择模块的存在,SKNet只会选择一部分卷积核进行计算,从而减少了计算成本,保持了网络的高效性。
4.代码实现
class SKNet(nn.Module):
def __init__(self, in_channels, out_channels, stride=1, M=2, r=16, L=32):
"""
:param in_channels: 输入通道维度
:param out_channels: 输出通道维度 原论文中 输入输出通道维度相同
:param stride: 步长,默认为1
:param M: 分支数
:param r: 特征Z的长度,计算其维度d 时所需的比率(论文中 特征S->Z 是降维,故需要规定 降维的下界)
:param L: 论文中规定特征Z的下界,默认为32
采用分组卷积: groups = 32,所以输入channel的数值必须是group的整数倍
"""
super(SKNet, self).__init__()
d = max(in_channels // r, L)
self.M = M
self.out_channels = out_channels
self.conv = nn.ModuleList()
for i in range(M):
self.conv.append(nn.Sequential(
nn.Conv2d(in_channels, out_channels, 3, stride, padding=1 + i, dilation=1 + i, groups=32, bias=False),
nn.BatchNorm2d(out_channels),
nn.ReLU(inplace=True)))
self.global_pool = nn.AdaptiveAvgPool2d(output_size=1)
self.fc1 = nn.Sequential(nn.Conv2d(out_channels, d, 1, bias=False),
nn.BatchNorm2d(d),
nn.ReLU(inplace=True)) # 降维
self.fc2 = nn.Conv2d(d, out_channels * M, 1, 1, bias=False)
self.softmax = nn.Softmax(dim=1)
def forward(self, input):
batch_size = input.size(0)
output = []
for i, conv in enumerate(self.conv):
output.append(conv(input))
U = reduce(lambda x, y: x + y, output)
s = self.global_pool(U)
z = self.fc1(s)
a_b = self.fc2(z)
a_b = a_b.reshape(batch_size, self.M, self.out_channels, -1)
a_b = self.softmax(a_b)
a_b = list(a_b.chunk(self.M, dim=1))
a_b = list(map(lambda x: x.reshape(batch_size, self.out_channels, 1, 1),
a_b))
V = list(map(lambda x, y: x * y, output,
a_b))
V = reduce(lambda x, y: x + y,
V)
return V
总结
SKNet是一种创新的深度神经网络架构,通过引入选择性的多尺度卷积核和注意力机制,提升了特征提取的能力。其核心结构包括选择模块和SK卷积层,能够有效地融合多尺度信息、自适应地调整卷积核的尺度,并减少计算成本。这使得SKNet在图像分类和目标检测等任务中取得了优越的性能。