SKNet讲解

news/2024/11/30 20:48:57/

SKNet讲解

  • 0. 引言
  • 1. 网络结构
    • 1.1 Split部分
    • 1.2 Fuse部分
    • 1.3 Select部分
    • 1.4 三分支的情况
  • 2. SKNet网络体系结构
  • 3. 分析与解释
  • 4. 代码
  • 总结

0. 引言

视皮层神经元的感受野大小受刺激的调节,即对不同刺激卷积核的大小应该不同,但在构建CNN时一般在同一层只采用一种卷积核,很少考虑因图片大小不同采用不同卷积核。
于是提出了SKNet。在SKNet中,不同大小的感受视野(卷积核)对于不同尺度的目标会有不同的效果。尽管在Inception中使用多个卷积核来适应不同尺度图像,但是卷积核权重相同,参数就是被计算好的了。而SKNet 对不同输入使用的卷积核感受野不同,参数权重也不同,可以根据输入大小自适应的进行处理。
SKNet中,提出了一种动态选择机制,允许每个神经元根据输入信息的多个尺度自适应调整其接受野的大小。设计了一种称为选择性内核(SK)单元的构建模块,在该模块中,由不同内核大小的多个分支的信息引导,使用softmax的注意力进行融合。对这些分支的不同关注导致融合层神经元有效感受野的大小不同。

论文地址:https://arxiv.org/pdf/1903.06586.pdf
代码地址:https://github.com/implus/SKNet

1. 网络结构

在这里插入图片描述
SKNet网络主要由三个部分组成:SplitFuseSelect。其中,Split部分将输入信息X分别输入不同的核大小(这里是2个卷积核,卷积核大小分别为:3*35*5);Fuse部分进行特征融合;Select部分根据计算得到的权重对对应的特征进行选择操作。

1.1 Split部分

对于输入信息X:[h,w,C],在Split中,分别输入两个卷积层(默认为2个,根据需要可以设计多个),两个卷积层分别为3*35*5。其中,每个卷积层都是由高效的分组/深度卷积批处理归一化ReLU函数依次组成的。另外,为了进一步提高效率,将具有5*5核的传统卷积替换为具有3×3核膨胀大小为2扩展卷积。最终得到的输出分别为 U ~ \widetilde{U} U U ^ \hat{U} U^

1.2 Fuse部分

基本思想是使用门来控制来自多个分支的信息流,这些分支携带不同尺度的信息到下一层的神经元中。为实现这一目标,门需要整合来自所有分支的信息。我们首先通过element-wise summation融合来自多个分支的结果:
U = U ~ + U ^ U=\widetilde{U}+\hat{U} U=U +U^

F g p F_{gp} Fgp全局平均池化操作 F f c F_{fc} Ffc先降维再升维的两层全连接层。需要注意的是输出的两个矩阵ab,其中矩阵b为冗余矩阵,在如图两个分支的情况下b=1-a

通过简单地使用全局平均池化以生成channel-wise统计信息 s ∈ R C s\in{R^C} sRC 来生成全局信息。具体来说,s的第C个元素是通过空间尺寸h×w收缩U来计算的:
s c = F g p ( U c ) = 1 h × w ∑ i = 1 h ∑ j = 1 w U c ( i , j ) s_c = F_{gp}(U_c) = \frac{1}{h\times{w}}\sum_{i=1}^{h}\sum_{j=1}^{w}{U_c(i,j)} sc=Fgp(Uc)=h×w1i=1hj=1wUc(i,j)

此外,还创建了一个紧凑的特征 z ∈ R d × 1 z\in{R^{d\times1}} zRd×1,以便为精确和自适应选择提供指导。这是通过一个简单的完全连接(fc)层实现的,降低了维度以提高效率:
z = F f c ( s ) = δ ( B ( W s ) ) z = F_{fc}(s)=\delta(B(Ws)) z=Ffc(s)=δ(B(Ws))
其中 δ \delta δReLU函数, B B B 表示批量标准化, W ∈ R d × C W\in{R^{d\times C}} WRd×C。为了研究d对模型效率的影响,我们使用reduction ratio (r)来控制其值:
d = m a x ( C / r , L ) d=max(C/r, L) d=max(C/r,L)

其中L表示d的最小值(L=32是我们实验中的典型设置)。

1.3 Select部分

Select操作使用ab两个权重矩阵对 U ~ \widetilde{U} U U ^ \hat{U} U^ 进行加权操作,然后求和得到最终的输出向量V

跨通道的软关注用于自适应地选择信息的不同空间尺度,空间尺度由紧凑特征描述符z引导。具体而言,softmax运算符应用于channel-wise数字:
a c = e A c z e A c z + e B c z , b c = e B c z e A c z + e B c z a_c = \frac{e^{A_cz}}{e^{A_cz}+e^{B_cz}},b_c = \frac{e^{B_cz}}{e^{A_cz}+e^{B_cz}} ac=eAcz+eBczeAcz,bc=eAcz+eBczeBcz
其中 A , B ∈ R C × d A,B\in{R^{C\times d}} A,BRC×d ,a、b表示 U ~ \widetilde{U} U U ^ \hat{U} U^soft attention A c A_c AcA的第c行,$a_c $ 是a的第c个元素。在两个分支的情况下,矩阵B是冗余的,因为 a c + b c = 1 a_c +b_c = 1 ac+bc=1。最终的特征映射V是通过各种卷积核的注意力权重获得的:
V c = a c ∗ U ~ + b c ∗ U ^ , a c + b c = 1 V_c = a_c * \widetilde{U} + b_c * \hat{U}, a_c +b_c = 1 Vc=acU +bcU^,ac+bc=1
其中 V = [ V 1 , V 2 , . . . , V C ] V=[V_1,V_2,...,V_C] V=[V1,V2,...,VC], V c ∈ R h × w V_c∈R^{h×w} VcRh×w,注意,这里我们提供了一个双分支情况的公式,并且可以通过扩展轻松推断出具有更多分支的情况。

1.4 三分支的情况

这里以三分支为例,绘制网络结构。后续多分支结构与此类似。
在这里插入图片描述

2. SKNet网络体系结构

在这里插入图片描述

  1. 与ResNeXt相似,SKNet主要由一堆重复的瓶颈(bottleneck)块组成,称为“ SK单元”。

  2. 每个SK单元由1×1卷积,SK卷积和1×1卷积的序列组成。

  3. 通常,ResNeXt中原始瓶颈块中的所有大内核卷积都将由SK卷积代替

  4. 与ResNeXt-50相比,SKNet-50仅会使参数数量增加10%,计算成本增加5%。

3. 分析与解释

为什么SKNet会取得这么好的效果?
为了理解自适应卷积核选择的工作原理,我们通过输入相同的目标对象但在不同的尺度上分析注意力。我们从ImageNet验证集中获取所有图像实例,并通过中心裁剪和随后的大小调整逐步将中心对象从1.0倍扩大到2.0倍。

图1 第一个例子
图2 第二个例子

由上述两个例子对比可知:在大多数通道中,当目标对象扩大时,大核(5×5)的注意力权重就会增加,这表明神经元的RF大小会自适应地变大,这与预期相符。
关于跨深度的自适应选择的作用,还有一个令人惊讶的特点:目标对象越大,通过低级和中级阶段(例如,SK 23,SK 34)的“选择性内核”机制,对更大内核的关注就越多。 但是,在更高的层上(例如,SK 5_3),所有比例尺信息都丢失了,这种模式消失了。

在这里插入图片描述
随着目标规模的增长5×5内核的重要性不断提高。在网络的底层部分(前部),可以根据对象大小的语义意识选择合适的内核大小,从而有效地调整这些神经元的RF大小。但是,这种模式在像SK 5_3这样的较高层中并不存在,因为对于高级表示,“比例”部分编码在特征向量中,并且与较低层的情况相比,内核大小的重要性较小

4. 代码

最后,附上SKNet的代码实现。

import torch
import torch.nn as nnclass SKConv(nn.Module):def __init__(self, features, M: int = 2, G: int = 32, r: int = 16, stride: int = 1, L: int = 32):super().__init__()d = max(features / r, L)self.M = Mself.features = features# 1.splitself.convs = nn.ModuleList([])for i in range(M):self.convs.append(nn.Sequential(nn.Conv2d(features, features, kernel_size=3, stride=stride, padding=1+i, dilation=1+i, groups=G, bias=False),nn.BatchNorm2d(features),nn.ReLU(inplace=True)))# 2.fuseself.gap = nn.AdaptiveAvgPool2d(1)self.fc = nn.Sequential(nn.Conv2d(features, d, kernel_size=1, stride=1, bias=False),nn.BatchNorm2d(d),nn.ReLU(inplace=True))# 3.selectself.fcs = nn.ModuleList([])for i in range(M):self.fcs.append(nn.Conv2d(d, features, kernel_size=1, stride=1))self.softmax = nn.Softmax(dim=1)def forward(self, x):batch_size = x.shape[0]# 1.splitfeats = [conv(x) for conv in self.convs]feats = torch.cat(feats, dim=1)feats = feats.view(batch_size, self.M, self.features, feats.shape[2], feats.shape[3])print('feats.shape', feats.shape)# 2.fusefeats_U = torch.sum(feats, dim=1)feats_S = self.gap(feats_U)feats_Z = self.fc(feats_S)print('feats_U.shape', feats_U.shape)print('feats_S.shape', feats_S.shape)print('feats_Z.shape', feats_Z.shape)# 3.selectattention_vectors = [fc(feats_Z) for fc in self.fcs]attention_vectors = torch.cat(attention_vectors, dim=1)print('attention_vectors.shape', attention_vectors.shape)attention_vectors = attention_vectors.view(batch_size, self.M, self.features, 1, 1)print('attention_vectors.shape', attention_vectors.shape)attention_vectors = self.softmax(attention_vectors)feats_V = torch.sum(feats * attention_vectors, dim=1)print('feats_V.shape', feats_V.shape)return feats_Vif __name__ == '__main__':inputs = torch.randn(4, 64, 512, 512)net = SKConv(64)outputs = net(inputs)

得到的输出如下所示:

feats.shape torch.Size([4, 2, 64, 512, 512])
feats_U.shape torch.Size([4, 64, 512, 512])
feats_S.shape torch.Size([4, 64, 1, 1])
feats_Z.shape torch.Size([4, 32, 1, 1])
attention_vectors.shape torch.Size([4, 128, 1, 1]) #a, b
attention_vectors.shape torch.Size([4, 2, 64, 1, 1]) #a, b
feats_V.shape torch.Size([4, 64, 512, 512])

总结

SKNet中使用了不同的卷积核,且卷积核权重是不同的,该创新点是突出的!相信一定能在某些情况下取得不错的效果。最后,如果有什么疑问欢迎在评论区提出,对于共性问题可能会后续添加到文章介绍中。


http://www.ppmy.cn/news/156661.html

相关文章

第20章 自动生成数据库的同时把必要数据持久化到指定表中

1 Core.Configuration.CommonConfig namespace Core.Configuration { /// <summary> /// 【常规配置--类】 /// <remarks> /// 摘要&#xff1a; /// 通过该类中的属性成员实例对“appsettings.json”文件中的常规配置相关等数据进行设定性读写操作。 /// 说…

short s1 = 1; s1 = s1 + 1; 有错吗?short s1 = 1; s1 += 1 有错吗?

前者不正确&#xff0c;后者正确。如图所示 对于 short s1 1; s1 s1 1;由于 1 是 int 类型&#xff0c;因此 s11 运算结果也是 int 型&#xff0c; 需要强制转换类型才能赋值给 short 型。 而 short s1 1; s1 1;可以正确编译&#xff0c;因为 s1 1;相当于 s1 (short)(s1 …

小米米家无线洗车机 评测

米家无线洗车机采用无线设计&#xff0c;摆脱电源束缚&#xff0c;方便用户在户外使用。该洗车机采用自吸水式设计&#xff0c;免接水龙头&#xff0c;用户可以用水桶供水。动力方面&#xff0c;米家无线洗车机拥有 2.4MPa 自吸水压&#xff0c;每小时出水量可达 180L。 小米米…

小米9电量夜间待机优化

你是否为夜间小米9手机待机时长严重不足而感到十分不满&#xff1f; 你是否遇到过小米9手机夜间忘记充电仅剩百分之40、50左右的电量&#xff0c;第二天手机没电的情况呢&#xff1f; 是否遇到过不想错过qq、微信等的消息而开着数据、wifi但是夜间损耗大量电量的情况呢&#xf…

小米10s和小米11参数配置对比哪个好 哪个更值得入手

小米11发布了一共5款颜色。分别为三款玻璃&#xff08;AG磨砂工艺&#xff0c;黑、白、蓝&#xff09;、两款素皮&#xff08;烟紫、卡其&#xff09;&#xff0c;共计5款配色。小米11采用了大量精致工艺进一步提升手机质感&#xff0c;相机模组玻璃盖板采用一体式玻璃CNC加工&…

三星手机续航测试软件,三星S21系列续航测试简报出炉

这两天我司火力全开,测试了不少机型的性能、续航等等项目,其中就包括了S21和S21 Ultra,之前三星旗舰系列是每年续航测试重点关注对象。今天就给大家分享一下这两款机型的续航、充电数据。另外,本次数据汇总还新增了vivo X60 Pro的续航,暂时没有充电数据,后续如果测试了会补入表…

联想k80微型计算机用电量,配置高端待机超长 联想K80手机低价上市

联想一款高端超长续航手机低价上市&#xff0c;它就是联系K80&#xff0c;配备了4000毫安大容量电池&#xff0c;通过联想K80评测&#xff0c;该机续航待机时间2天没问题&#xff0c;性能评测中跑分更是近5万&#xff0c;真是一款高端手机&#xff0c;仅1499元的价格超值。 低调…

蓝牙耳机超长续航哪个牌子好?超长待机蓝牙耳机排行榜

随着蓝牙耳机的流行&#xff0c;超长待机的蓝牙耳机越来越成为人们选择的要求。续航久的耳机因为可以减少充电次数而能给人带来超强的体验感&#xff0c;用着就很给力。随着蓝牙无线耳机的品质越来越完备&#xff0c;耳机续航时间也越来越长&#xff0c;下面为大家介绍四款续航…