程序地带

[全部开源]魔改shufflenetv2,注意力机制,csp,卷积裁剪...


 


目录结构


1、背景介绍


2、提升精度措施


3、降低计算量措施


      shufflenet_se网络


      shufflenet_sk网络


      shufflenet_liteconv网络


      shufflenet_k5网络


      shufflenet_csp网络


4、实验测试


5、总结


所有网络开源地址:https://github.com/DL-Practise/ShufflenetV2_PLUS


更多DL相关实践,请关注公众号"DL工程实践"


 


1、背景介绍


在移动端场景中,目前有很多不错的轻量级网络可以选择,例如google的mobilenet系列,efficient lite系列,旷世的shufflenet系列,华为的ghostnet等。在这些模型中,我尤其喜欢shufflenetV2,因为它结构清晰,简洁(如下图所示为shufflenetv2 1.0x的结构图:红色标注为各个模块的flops),并且在设计之初就考虑了MAC(访存代价),使得在移动端部署的时候具有很低的延时。在多个数据集上的测试也验证了其较好的泛化性能。不过有时候为了实现在更低计算资源的嵌入式场景中使用shufflenet,或者在轻量级检测框架中使用shufflenet作为bakbone,那么仍然需要对shufflenet做一些优化。本次实践将围绕对shufflenetV2 1.0X版本进行改进,包括提升精度与降低计算量两个维度。看看能否创造出一个比基线版本更优的shufflenet结构。在不加注释的情况下,下文的shufflenet默认指的是shufflenet v2 1.0x版本。



 


2、提升精度措施


结合目前比较火的注意力机制,例如senet,sknet等,这里分别设计四个网络:


增加se注意力机制的:shufflenet_se网络


增加sk注意力机制的:shufflenet_sk网络


将3*3的depthwise卷积扩大为5*5:shufflenet_k5网络


 


3、降低计算量


使用卷积裁剪以及csp技术,分别设计两个网络 :


裁剪block中不重要的1*1卷积,这里设计一个shufflenet_liteconv网络


使用csp对网络进行重组,这里设计一个shufflenet_csp网络


 


shufflenet_se网络


主要是借鉴senet中的通道注意力机制,将其应用到shufflenet中。下面简单回顾一下senet中的注意力机制:



主要有两个操作:squeeze和excitation。squeeze指的是将特征通过GAP压缩空间信息,将原来的c*h*w维度信息压缩为c*1*1. Excitation使用了两个全连接层,第一个降低维度,将c*1*1降维为c/r *1*1(带有relu激活),第二个fc层将特征重新映射回c*1*1(没有relu激活),然后经过sigmoid之后得到各个通道的权重系数。然后将权重系数与原来的特征相乘,从而得到一个新的特征。下面是seattention的pytroch代码实现,非常的简单,就是按照上面的思路实现一遍。


class SeAttention(nn.Module):
def __init__(self, channel_num, r=4):
""" Constructor
"""
super(SeAttention, self).__init__()
self.channel_num = channel_num
self.r = r
self.inter_channel = int( float(self.channel_num) / self.r)
self.fc_e1 = torch.nn.Linear(channel_num, self.inter_channel)
self.relu_e1 = nn.ReLU(inplace=True)
self.fc_e2 = torch.nn.Linear(self.inter_channel, channel_num)
def forward(self, x):
y = torch.nn.functional.adaptive_avg_pool2d(x, (1, 1)).squeeze()
y = self.fc_e1(y)
y = self.relu_e1(y)
y = self.fc_e2(y)
y = torch.sigmoid(y).unsqueeze(-1).unsqueeze(-1)
return x*y

 


shufflenet_sk网络


主要是借鉴了sknet中的注意力机制,用于选择大卷积核的输出还是小卷积核的输出。其原理图如下所示:



将特征X分别经过小卷积核(3*3)得到新的特征U3*3(图中黄色部分);另外一路经过大卷积核(5*5)得到新的特征U5*5(图中绿色部分)。然后加两个新的特征U相加,然后经过SE相同的squeeze和excitation得到权重向量,注意这里的权重向量有两个,一个是针对U3*3的权重向量,另一个是针对U5*5的权重向量。最后用权重向量分别与对应的U相乘,最后相加得到新的特征输出V。主要代码如下:


class SKConv(nn.Module):
def __init__(self, in_channels):
""" Constructor
Args:
in_channels: input channel dimensionality.
M: the number of branchs.
"""
super(SKConv, self).__init__()
r = 2.0
L = 32
d = max(int(in_channels / r), L)
self.in_channels = in_channels
self.conv1 = nn.Sequential(
self.depthwise_conv(in_channels, in_channels, kernel_size=3, dilation=1, padding=1),
nn.BatchNorm2d(in_channels),
#nn.ReLU(inplace=False)
)
self.conv2 = nn.Sequential(
self.depthwise_conv(in_channels, in_channels, kernel_size=3, dilation=2, padding=2),
nn.BatchNorm2d(in_channels),
# nn.ReLU(inplace=False)
)
self.fc1 = nn.Linear(in_channels, d)
self.fc2 = nn.Linear(d, in_channels*2)
self.softmax = nn.Softmax(dim=1)
def forward(self, x):
U1 = self.conv1(x)
U2 = self.conv2(x)
U = U1 + U2
S = U.mean(-1).mean(-1)
Z1 = self.fc1(S)
Z2 = self.fc2(Z1)
A = self.softmax(Z2)
V = U1 * A[:,:self.in_chanels].unsqueeze(-1).unsqueeze(-1) +
U2 * A[:,self.in_channels:].unsqueeze(-1).unsqueeze(-1)
return V

 


shufflenet_liteconv网络


通过观察shufflenet的block,可以分为两种结构,一种是每个stage的第一个block,该block由于需要降采样,升维度,所以对输入直接复制成两份,经过branch1,和branch2之后再concat到一起,通道翻倍,如下图中的降采样block所示。另外一种普通的block将输入split成两部分,一部分经过branch2的卷积提取特征后直接与branch1的部分进行concat。如下图中的普通block所示:



一般在DW卷积(depthwise卷积)的前或后使用1*1的卷积处于两种目的,一种是融合通道间的信息,弥补dw卷积对通道间信息融合功能的缺失。另一种是为了降维升维,例如mobilenet v2中的inverted reddual模块。而shufflenet中的block,在branch2中用了2个1*1卷积,实际上有一些多余,因为此处不需要进行升维降维的需求,那么只是为了融合dw卷积的通道间信息。实际上有一个1*1卷积就够了。为了剪裁的方便,将上图中的红色虚线框中的1*1卷积删除。实现shufflenet_liteconv版本。


 


shufflenet_k5网络


进一步观察shufflenet的计算量分布,实际上在dw卷积上的计算量占比是很小的,主要的计算量都在1*1的卷积上面。因此对dw卷积进行一个卷积核的扩张,既不会增加太多的计算比重,又能提升效果,何乐而不为呢。Shufflenet_k5将所有的3*3dw卷积替换成5*5的dw卷积,注意在pytroch实现中,需要将padding从1修改为2,这样输出的特征图才能保持与原来一致的分辨率。


 


shufflenet_csp网络


csp在大型网络上取得了很大的成功。它在每个stage,将输入split成两部分,一部分经过原来的路径,另一部分直接shortcut到stage的尾部,然后concat到一起。这既降低了计算量,又丰富了梯度信息,减少了梯度的重用,是一个非常不错的trip。在yolov4,yolov5的目标检测中,也引入了csp机制,使用了csp_darknet。此处将csp引入到shufflenet中。并且对csp做了一定的精简,最终使用csp stage精简版本作为最终的网络结构。



 


4、实验测试


对上述:shufflenet_se、shufflenet_sk、shufflenet_liteconv、shufflenet_k5、shufflenet_csp在cifar10数据集上进行训练,统计其最终的精度和flops,并与baseline的shufflenet进行对比,结果如下表所示:


 


网络结构

Top1

实测flops

(M)

参数规模

(M)

模型文件大小

shufflenet(baseline)

0.880

147.79

1.263

5116K

shufflenet_se

0.884

147.93

1.406

5676K

shufflenet_sk

0.885

152.34

1.555

6872K

shufflenet_liteconv

0.879

104.77

0.923

3736K

shufflenet_k5

0.891

155.18

1.303

5268K

shufflenet_csp

0.862

101.96

0.924

3776K


对其中最重要的指标flops与top1精度进行可视化:



 


5、总结


从提升精度的角度看,shufflenet_k5的效果是最好的,比注意力机制的se和sk都要好。说明在轻量级网络中,注意力机制的收益并没有那么明显,没有直接提升dw卷积的卷积核来的收益高。最降低计算量方面,精简1*1卷积在几乎不降低精度的情况下,大约降低了约30%的计算量。Shufflenet_csp网络虽然能大幅降低计算量,但是精度降低的也很明显。分析原因,主要有两个,一是shufflenetv2本身已经使用了在输入通道split,然后concat的blcok流程,与csp其实是一样的,知识csp是基于一个stage,shufflenetv2是基于一个block,另外csp本来就是在densenet这种密集连接的网络上使用有比较好的效果,在轻量级网络上不见得效果会好。综上所述,如果为了提升精度,将卷积核扩大是最简单也最有效的,并且计算量只提升了5%。如果为了降低计算量,那么通过剪裁1*1卷积效果是最好的。


 


 


 


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cjnewstar111/article/details/112689151

随机推荐

6 获取session_nodejs小程序一键获取手机号码

1、先去微信公众号官网下载解密算法微信官网2、进行解压,选择你要用来解密的语言3、在nodejs文件下,引入WXBizDataCrypt.js文件4、通过微信的openTy...

weixin_39644713 阅读(301)

第三阶段笔记

0、运行全第一步:Filter拦截图(Shiro用于认证/授权/缓存/记着我/Cookie)等拦截)第二步:DispatcherS...

♛strawberry 阅读(501)

解除文件锁定

解除文件锁定Streamsv1.6streams.exe-d文件路径streams.exe-d-s文件夹路径...

frozleaf 阅读(611)

2020-12-21 实验六 动态规划算法之计算矩阵连乘积

计算矩阵连乘积在科学计算中经常要计算矩阵的乘积。矩阵A和B可乘的条件是矩阵A的列数等于矩阵B的行数。若A是一个p×q的矩阵,B是一个q×r的矩阵,则其乘积C=AB是...

Aita_ZteP 阅读(989)

校门外的树(数组的新用法)

一般情况下,数组是用来标记输入的数值的,以便于对其进行操作。但有时数组还可以区分类别等作用。如下题:此题较为灵活,作为新萌,就是个boss。所以...

白色o_O月光 阅读(611)