[1]葛道辉,李洪升,张亮,等. 轻量级神经网络架构综述[J]. 软件学报, 2020, 31(9): 2627-2653.
主要介绍3种构建轻量级神经网络的方法:
- 人工设计轻量级神经网络
- 神经网络模型压缩算法
- 基于网络架构搜索的自动化神经网络架构设计
博客主要总结人工设计轻量级网络的方法
0. 总结
方法 | 优点 | 相关模型 |
---|---|---|
小卷积替换大卷积 | 保持感受野不变,减少参数量 | VGGNet |
卷积分解 | 使用1*3和3*1实现3*3卷积核的效果,减少参数量 | |
降低中间通道数量 | 压缩通道数-运算-扩张通道数,保持网络规模时,降低运算量 | SqueezeNet |
深度可分离卷积 | 先深度卷积,再逐点卷积,显著降低参数量,同时强化通道间联系 | MobileNetV1 |
分组卷积 | 使用同等参数量和运算量,得到更多的feature map,再加上混洗操作强化通道间联系 | ShuffleNet |
改造残差网络 | 在残差分支中,将特征数升高运算后,再降低,提取更多特征时保持网络规模 | MobileNetV2 |
IGC | 利用分组卷积,扩宽网络宽度,提高性能 | IGCV1 |
IGCV2 | 将IGCV中第二次分组卷积改为IGC模式,形成IGC中使用IGC套娃 | IGCV2 |
ShuffleNetV2作者的建议 |
1. 人工设计的轻量级神经网络模型
人工设计的轻量级神经网络主要从减少卷积核的冗余、减少输入特征的通道数、设计更加高效的模块等方面实现
1.1 使用小卷积核代替大卷积(VGGNet)
图a中可以看出,使用1个5*5的卷积核两个3*3的卷积核都能够对5*5的区域实现卷积效果。1个5*5的卷积核有参数5*5=25个,2个3*3卷积核有参数2*3*3=18个,明显参数更少。所以使用更小的多个卷积核代替大卷积和能够减少参数。
图b中可以看出,使用1x3和3x1两个卷积核可以实现3*3的卷积效果(空间可分离卷积/卷积分解),参数量从3*3=9下降到1*3*2=6,降低33%
1.2 限制中间特征的通道数量(SqueezeNet)
在构建轻量化卷积神经网络时,一个显而易见的方法时降低中间通道数量,能够降低参数量和运算量。比如对于[-1,3,64,64]和[-1,8,64,64]两个输入,明显通道数更多的在进行运算时,运算量更大。但实际上通道数代表提取的特征数量,特征数减少会影响网络的精度,即通道数太多影响运算效率,通道数太少影响网络精度。
在SqueezeNet中提出了Fire module,通过进行卷积运算之前,对通道数进行压缩(squeeze),然后对通道数进行扩张(expand),保证运算时通道数较少,结束后通道数正常:
上图展示一个输入96通道数,输出128通道数的FireModule,按正常卷积时,我们通常定义一个[in_channel=96,out_channel=128]的卷积层即可实现,但在SqueezeNet中先进行压缩,再放入不同的branch进行运算(同时实现expand),然后进行通道合并。这样减少了参数量,实现模型轻量化。
这里给出Pytorch实现的FireModule:
# ic:input channel,输入通道数
# sc:squeeze channel,压缩后通道数
# e1c:expand branch 1 channel:分支1的输出通道数
# e2c:分支2的输出通道数
class FireModule(nn.Module):
def __init__(self,ic,sc,e1c,e2c):
super(FireModule, self).__init__()
self.conv=nn.Conv2d(ic,sc,1,padding=0)
self.branch1=nn.Conv2d(sc,e1c,1,padding=0)
self.branch2=nn.Conv2d(sc,e2c,3,padding=1)
def forward(self,x):
x=self.conv(x)
b1=self.branch1(x)
b2=self.branch1(x)
out=torch.cat([b1,b2],1)
return out
1.3 分解卷积运算
1.3.1 深度可分离卷积(MobileNetV1)
普通卷积操作如图:
对于[input_channel=3,output_channel=4]的卷积层,会生成w*h*3*4个参数
深度可分离卷积,首先进行逐通道的卷积:
可以看出,逐通道卷积无法改变输出的通道数,因为这一步主要是对输入的每一个通道做二维的平面卷积而已。
然后进行逐点卷积:
在逐通道卷积的结果上,进行逐点卷积,逐点卷积就是1x1卷积(1x1卷积是1x1xd,省略了深度),逐点卷积是可以改变输出通道数的。
深度可分离卷积参数是:w*h*3+1*1*4,而通常w*h是很大的,所以深度可分离参数是比普通卷积数量更少的
其实逐点卷积也加强了通道间的信息交流,提升了网络的性能。
1.3.2 Group逐点卷积(或分组卷积,ShuffleNet)
分组卷积主要是提升逐点卷积的运算效率,因为当我们使用深度可分离卷积时,假定卷积核尺寸为常用的3*3,运算量=3*3*W*H*C+1*1*W*H*C*N,前部分是深度卷积的计算量,后部分是逐点卷积的运算量
W、H:特征图的尺寸
C:输入特征图通道数
N:卷积核数量,数量上和输出通道数相同
可以看出,当N>9时,深度可分离卷积的运算量主要集中在逐点卷积上,而一般网络中输出通道数都是远大于9的。为了进一步提高逐点卷积的运算效率,ShuffleNet提出了分组卷积
,同时为了解决通道间的信息交流,提出了通道混洗操作(shuffle)
1.3.2.1 分组卷积
分组卷积就是将feature map分成g组,将1个逐点卷积也分成g组,对每组进行逐点卷积,每一组都会产生一个feature map。
原先对feature map进行一个逐点卷积,会产生1个feature map。
现在分组卷积将1个逐点卷积分成g组后,会产生g个feature map。在相同的参数量和计算量下,得到的feature map数变成了之前的g倍。
g的取值范围为:1≤g≤c
当g=1时,其实就是没有分组,就是普通的逐点卷积
当g=c时,其实就是深度卷积(即对每个channel单独进行卷积操作,输出的feature map的channle和之前是一样的)
1.3.2.2 混洗操作(shuffle)
分组卷积可以得到g个feature map,但是通道间没有交流,如图所示:
图a是没有混洗操作的,input有3个通道,在整个网络流里,通道间没有交流,这样的网络没有充分利用通道信息。图b和图c是经过混洗操作的效果,如果将每个feature map比作一个部落,每个部落都派出一些人穿插进其他部落,显然这些会加强部落间的沟通,充分利用每个部落的资源。
1.4 改造残差结构(MobileNetV2)
在保持网络规模的前提下,进一步提高网络性能,MobileNetV2引入并改造了残差结构。
从图中可以看出,改造的残差网络主要是先提高维度,计算后再降低维度(感觉和SqueezeNet相反,只不过Squeeze是使用逐点卷积升降维度,使用普通卷积运算,MobileNetV2使用逐点卷积升降维度,深度卷积运算)
为什么要提高维度?因为当输入特征数较少时,而深度卷积又无法增减特征数,造成无法更好的提取特征。在MobileNetV2中的深度卷积前提高维度,增加了特征数,之后再降维,保持了网络的规模。
关于激活函数,激活函数在高维能够有效增强非线性能力,但是在低维却会破坏特征的表达能力,因此当第一个逐点卷积提升维度后使用激活函数,第二个逐点卷积降低维度后,则不使用激活函数。
1.5 IGCV系列
1.5.1 IGCV1
该网络如图,将输入feature map分成2组,对每个组进行分组卷积(这个分组卷积输出和输入feature map一样),然后将2组分组卷积结果cat和打乱,然后再分成3组(此时每组的feature map其实经过打乱后来自不同通道),再次进行分组卷积和打乱
1.5.2 IGCV2
作为V1的升级版,改进之处在于将V1第二次分组卷积改成了IGC,即将IGC中的第二次卷积改成IGC模式(其中又进行2次分组卷积)(套娃)
1.5 指导意见(ShuffleNetV2的作者)
作者表示FLOPs作为一个间接的指标,只能大致估计运算速度,实际中我们应当注意以下几点:
- FLOPs
- 内存访问成本MAC
- 并行化程度
- 计算平台影响
相应的指导建议:
- 相同输入输出通道能减少MAC成本(比如逐点卷积的输入输出通道一样)
- 过多的分组卷积会增加MAC成本(比如不使用/少使用分组卷积)
- 网络碎片化程序会减少并行化程度
- 不能忽视元素及操作(比如使用cat,而不是残差网络的相加)
ShuffleNetV2是在以下指导意见下的改进版:
相比V1,速度提升63%