深度学习系列9:基础网络结构(更新中)

1. 基本卷积

卷积可以看作对某个局部的加权求和;它是对应局部感知,它的原理是在观察某个物体时我们既不能观察每个像素也不能一次观察整体,而是先从局部开始认识,这就对应了卷积。CNN使用卷积方法能够获取对平移、缩放和旋转不变的观测数据的显著特征,因为图像的局部感受区域允许神经元或者处理单元可以访问到最基础的特征,例如定向边缘或者角点。
一般CNN网络会使用多个卷积层来进行训练基本特征,然后使用flatten方法将数据“拍平”,然后加上多个全连接层进行分类(高层的特征与位置是有关系的,因此需要用全连接层)。
卷积核作为卷积神经网络的核心,通常被看做是在局部感受野上,将空间上(spatial)的信息和特征维度上(channel-wise)的信息进行聚合的信息聚合体。
卷积神经网络由一系列卷积层、非线性层和下采样层构成,这样它们能够从全局感受野上去捕获图像的特征来进行图像的描述。
有很多研究提出来从空间维度层面来提升网络的性能,如 Inception 结构中嵌入了多尺度信息,聚合多种不同感受野上的特征来获得性能增益;在 Inside-Outside 网络中考虑了空间中的上下文信息,还有将 Attention 机制引入到空间维度上,他们都获得了很不错的效果;

1.1 参数计算

卷积核的大小一般有1x1,3x3和5x5的尺寸。卷积核的个数就对应输出的通道数,这里需要说明的是对于输入的每个通道,输出每个通道上的卷积核是不一样的。比如输入是28x28x192(WxDxK,K代表通道数),然后在3x3的卷积核,卷积通道数为128,那么卷积的参数有3x3x192x128,其中前两个对应的每个卷积里面的参数,后两个对应的卷积总的个数。
卷积核的参数(参数W和b)一般可以“初始化”成很小的“随机值”。LeCun和Bengio教授的文章中建议在处理图像问题时,可以选择将W和b按照 U ( 3 / k , 3 / k ) U(-\sqrt{3/k},\sqrt{3/k}) 初始化。其中k是W和b的连接总数。假如滤波器的大小是4*4,那么k为16,U表示均匀分布。

1.2 空洞卷积

空洞卷积:Dilated/Atrous Convolution 或者是 Convolution with holes 从字面上就很好理解,是在标准的 convolution map 里注入空洞,以此来增加 reception field。相比原来的正常convolution,dilated convolution 多了一个 hyper-parameter 称之为 dilation rate 指的是kernel的间隔数量。
在这里插入图片描述
首先,vgg网络的作者提出,堆叠卷积核和大卷积核的效果一样,但是计算量小很多,这也是现在绝大部分基于卷积的深层网络都在用小卷积核的原因。假设卷积层的输入和输出的特征图大小相同为C,那么三个3x3的卷积层参数个数3x((3x3xC)xC)=27C2;一个(7x7xC)xC的卷积层参数为49C2。前者可以表达出输入数据中更多个强力特征,使用的参数也更少。唯一的不足是,在进行反向传播时,中间的卷积层可能会导致占用更多的内存。
在这里插入图片描述
如下图,使用空洞卷积,能够轻松扩大感受野。此外,多个3x3的卷基层比一个大尺寸filter卷基层有更多的非线性(更多层的非线性函数,使用了3个非线性激活函数),使得判决函数更加具有判决性。
在这里插入图片描述

1.3 组卷积

组卷积已成为当前轻量型网络设计的一个核心模块,它具有简洁性与参数节省特点,比如ResNeXt以更少的参数更高的精度优于ResNet。
在这里插入图片描述

1.4 可形变卷积

然后介绍一下DCN:可形变卷积。卷积对于几何形变的处理能力较弱,因此需要对数据做缩放、旋转、裁剪等数据增强工作,以增加卷积核的泛化能力。DCN则通过设计新结构来处理这个问题:
在这里插入图片描述

从下图可以看到可变形卷积的结构,分为上下两个部分,上面那部分是基于输入的特征图生成offset,而下面那部分是基于特征图和offset通过可变形卷积获得输出特征图。其中N是卷积核通道数,2表示x和y两个方向的offset,k代表卷积核尺寸。
注意,和卷积不一样,在同一通道内offset参数并不共享,因此offset参数数量为2×k×k×w×h×group(每个group共享一套),计算量为2×k×k×w×h×输入通道×输出通道/group。在这里插入图片描述

2 其他操作

2.1 普通池化

卷积后面一般每一个特征提取层后面都会跟一个用来求局部平均与二次提取的计算层(池化+激活),这种特有的两次特征提取结构使网络在识别时对输入样本有较高的畸变容忍能力。
首先是普通池化,对输入的特征图进行压缩,一方面使特征图变小,简化网络计算复杂度;一方面进行特征压缩,提取主要特征。池化可以理解为一种采样,获取图像的概要统计特征。就好像在太空上俯瞰地球,看到的只有山脊和雪峰。这即是对特征进行宏观上的进一步抽象。 经过池化后,得到的是概要统计特征 。它们不仅具有低得多的维度 (相比使用所有提取得到的特征),同时还会改善结果(不容易过拟合) 。夜晚的地球俯瞰图,灯光耀眼的穿透性让人们只注意到最max的部分,产生亮光区域被放大的视觉错觉。故而 max_pooling 对较抽象一点的特征(如纹理)提取更好;白天的地球俯瞰图,幅员辽阔的地球表面,仿佛被经过了二次插值的缩小,所有看到的都是像素点取平均的结果。故而 average_pooling 对较形象的特征(如背景信息)保留更好。

2.2 ROI pooling

接下来是ROI pooling,广泛适用于两阶段目标检测中,最初是由Ross Girshick在2015年4月提出的(文章可以在这里找到),它实现了显著加速,还保持高检测精度。
在这里插入图片描述

所谓的两阶段,是指
① 区域建议(Region proposal):给定输入图像查找可以定位对象的所有可能位置。此阶段的输出应该是对象的可能位置的边界框列表。这些通常被称为区域提案或感兴趣的区域。
② 在Faster RCNN中,候选框是经过RPN产生的,然后再把各个“候选框”映射到特征图上,得到rois;② 最终分类(Final classification):对于前一阶段的每个区域提案,确定它是属于目标类别之一还是属于背景。在这里,我们可以使用深度卷积网络。
如下图,RoI Pooling的过程就是将一个个大小不同的box矩形框,都映射成大小固定(w * h)的矩形框;
在这里插入图片描述
我们先把roi中的坐标映射到feature map上,映射规则比较简单,就是把各个坐标除以“输入图片与feature map的大小的比值”,得到了feature map上的box坐标后,我们使用Pooling得到输出;由于输入的图片大小不一,所以这里我们使用的类似Spp Pooling,在Pooling的过程中需要计算Pooling后的结果对应到feature map上所占的范围,然后在那个范围中进行取max或者取average。
假设原图是如下的256×256图片,第一个ROI坐标为(6.4,128,153.6,172.8),卷积后特征图大小为8×8。首先将ROI也映射到特征图上,坐标缩小32倍得到(0.2,0.4,4.8,6.4),然后向上取整,得到(1,1,4,5)。我们假设池化为3×3max pooling,但是(1,1,4,5)无法被3整除,因此要调整某些cell的大小,比如第一个区域原本是(1,1,1+3/3-δ,1+4/3-δ),向下取整得到(1,1,1,1)。
当然我们也可以不进行取整操作,然后计算值的时候使用采样+双线性差值等方法进行计算(见彩色的部分),也就是将离散值连续化。
在这里插入图片描述
下图是双线性插值的计算原理。圆圈代表像素值,色块面积代表权重。以红色点为例,待计算点(黑色点)距离红色点最远,因此它权重最小,反映在色块面积上就是红色色块面积最小。说明红色对黑色点的影响比较小。使用双线性差值,一方面得到的像素准确,另一方面可以进行反向传播
在这里插入图片描述

2.3 Deformable ROI pooling

在这里插入图片描述
整体上仍然可以分成上下两部分,上面那部分是基于输入特征图生成offset,下面的部分是基于输入特征图和offset通过可变形RoI+Pooling生成输出RoI特征图,整体上仍然可以分成上下两部分,上面那部分是基于输入特征图生成offset,下面的部分是基于输入特征图和offset通过可变形RoI+Pooling生成输出RoI特征图。Deformable RoI Pooling为前面的RoI池化的常规bin分区中的每个bin位置添加一个偏移量。类似地,从前面的特征映射和RoI中学习偏移量,使得具有不同形状的目标能够自适应的进行部件定位。注意这里offsets的参数需要学习,不再像普通的pooling一样。

接下来是Deformable PS(位置敏感) RoI Pooling,对比一下和上图的差别,每一个类别+背景都有一个 k 2 k^2 的offsets(以及feature map),因此参数量大了(c+1)倍
在这里插入图片描述

2.4 Activation

激活函数给神经元引入了非线性因素,使得神经网络可以任意逼近任何非线性函数,这样神经网络就可以应用到众多的非线性模型中。常用激活函数包括sigmoid函数、Tanh函数、ReLU、softmax函数。一般情况下,在多分类问题中,softmax函数通常用作全链接层的激活函数,而中间层一般使用ReLU。

2.5 Dropout

为了获得更高的稳健性,在训练过程中会使用dropout策略,随机丢弃一些神经元,通过阻止特征检测器的共同作用来提高神经网络的性能。这种策略在一定程度上可以达到正则化的效果。Dropout被大量利用于全连接网络,而且一般认为设置为0.5或者0.3,而在卷积网络隐藏层中由于卷积自身的稀疏化以及稀疏化的ReLu函数的大量使用等原因,Dropout策略在卷积网络隐藏层中使用较少。

2.6 BatchNormalization

神经网络里面有个重要的概念BatchNormalization。
网络一旦train起来,那么参数就要发生更新,除了输入层的数据外(因为输入层数据,我们已经人为的为每个样本归一化),后面网络每一层的输入数据分布是一直在发生变化的。

3 网络变形

最近通过对卷积操作进行不同方式的设计而达到提升模型性能的方法还挺多的,比如前两天亚马逊张航、李沐等人提出的ResNeSt、港中文贾佳亚团队提出的SAN、密歇根州立大学提出的MUXConv、南开大学程明明团队提出的Res2Net、蔡司公司提出的BSConv、华为提出的DyNet、MSRA提出的DynamicConv、谷歌提出的CondConv、清华大学提出的XSepConv与ACNet、新加坡国立大学颜水成团队提出的OctConv以及字节跳动提出并用于图像超分领域的SCN。

3.1 Inception:横向堆叠

除了堆叠结构外,还有一种inception结构,将深度方向的特征提取转化成了宽度方向,
如下图:
image.png

卷积的stride都是1,使用零填充保持特征响应图大小一致。每个卷积层之后立即接一个ReLU层。卷积核堆叠是为了减少计算量,如下图:
image.png

以前每一层线性卷积需要之后跟一个Relu激活函数或者pooling层增加非线性。而Inception V1直接通过DepthConcat在每个block后合成特征,获得非线性属性。此外,最后阶段的全连层FC不再是必要的,传说中的global average pooling可以替代FC减少过拟合的风险。
Inception V2 和V3讨论集成了Inception中的许多Tricks,包括在Inception block中,与其用7×7 尺寸的卷积,不如用一对 1×7 和 7×1 卷积更高效。另外引入Batch Normalize等等。Inception V4则引入了标准化模块;Inception-ResNet则是在Inception模块中加入ResNet的跳层。

3.2 ResNet:跳层

ResNet是在卷积层旁边增加一个分支,将之前的数据直接加进来。
正是由于ResNet的提出,“深度”学习才真正变成可以很深的网络。由于每做一次卷积(包括对应的激活操作)都会浪费掉一些信息:比如卷积核参数的随机性(盲目性)、激活函数的抑制作用等等。这时,ResNet中的shortcut相当于把以前处理过的信息直接再拿到现在一并处理,起到了减损的效果。
在这里插入图片描述
另外,为了减少计算量,增加bottleneck结构:
在这里插入图片描述

3.3 ResNeXt:分组卷积

ResNeXt和Inception比较像。卷积层的参数中有一个group参数,其意思是将对应的输入通道与输出通道数进行分组,组内使用bottleNeck结构。group默认值为1, 也就是说默认输出输入的所有通道各为一组. 比如输入数据大小为
90x100x100x32,90是batchSize 100x100是图像数据shape,32是通道数,要经过一个3x3x48的卷积,group默认是1,就是全连接的卷积层,乘法计算量为90×3×3×32×48。
如果group是2,那么对应要将输入的32个通道分成2个16的通道,将输出的48个通道分成2个24的通道。对输出的2个24的通道,第一个24通道与输入的第一个16通道进行全卷积,第二个24通道与输入的第二个16通道进行全卷积。此时的乘法计算量为90×3×3×16×24×2,直接减小一半的计算量。
极端情况下,输入输出通道数相同,比如为24,group大小也为24,那么每个输出卷积核,只与输入的对应的通道进行卷积,此时输出通道等于输入通道,轻松实现了所谓depthwize separable convolution结构,此时的计算量为90×3×3×(1×1×24)。
总结来说,设置group后,计算量降为原来的1/group。
性能上提升非常惊人,从ResNet到ResNeXt,> 1 kernel的计算量从原来52.9%的占比下降到了6.6%,几乎下降了一个数量级,但却让ResNeXt的分类性能提升了。
在ResNeXt中,这种group的方式称为Cardinal。此外,作者将全连接层线性函数wx替换成了更一般的函数:t(x)。
最后补充一下下面三个结构等价,因此最后代码变成了最右边的这个:
在这里插入图片描述
论文链接:https://arxiv.org/abs/1611.05431
PyTorch代码:https://github.com/miraclewkf/ResNeXt-PyTorch

3.4 EfficientNet:多维度模型缩放

类似Inception,但是更加自由,可以在卷积层的深度、每一层里面通道的数量、每个通道里面的图片大小上进行缩放。
有三个参数要调整,搜索空间也是非常的大,因此EfficientNet的设想是一个卷积网络所有的卷积层必须通过相同的比例常数进行统一扩展,这句话的意思是,三个参数乘上常数倍率。使用最优化模型进行求解:在这里插入图片描述

3.5 SENet:channel级别attention

SENet通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征。
SENet主要是在原有的网络中插入一个Sequeeze和Excitation结构,如下:
在这里插入图片描述
在这里插入图片描述
SE模块首先对卷积得到的特征图进行Squeeze操作,得到channel级的全局特征,然后对全局特征进行Excitation操作,学习各个channel间的关系,也得到不同channel的权重,最后乘以原来的特征图得到最终特征。本质上,SE模块是在channel维度上做attention或者gating操作,有点像bagging算法,这种注意力机制让模型可以更加关注信息量最大的channel特征,而抑制那些不重要的channel特征。另外一点是SE模块是通用的,这意味着其可以嵌入到现有的网络架构中。
下面是pytorch代码:

from torch import nn

class SEBlock(nn.Module):
    def __init__(self, channel, r=16):
        super(SEBlock, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Sequential(
            nn.Linear(channel, channel//r, bias=False),
            nn.ReLU(inplace=True),
            nn.Linear(channel//r, channel, bias=False),
            nn.Sigmoid(),
        )

    def forward(self, x):
        b, c , _, _ = x.size()
        # Squeeze
        y = self.avg_pool(x).view(b, c)
        # Excitation
        y = self.fc(y).view(b, c, 1, 1)
        # Fscale
        y = torch.mul(x, y)
        return y

3.6 SKNet:split kennel级别attention

Selective Kernel Networks可以看做是SENet的升级版,出自CVRP2019,github地址为:https://github.com/pppLang/SKNet,启发自皮质神经元根据不同的刺激可动态调节其自身的receptive field,是结合了SE operator,Merge-and-Run Mappings,以及 attention on inception block 思想的产物。从设计理念上来讲也比较simple,即对所有的 > 1 的卷积kernel进行 Selective Kernel 改造,充分利用group/depthwise卷积带来的较小的理论parameters和flops的红利,从而使增加多路与动态选择的设计也不会带来很大的overhead(但实际group/depthwise的加速优化目前还不是特别好,导致实际速度还是略有一些慢的)。这样的设计使得任何网络进行Selective Kernel化就变得非常容易,只需要对 > 1的卷积进行无脑切换即可。
下图不同的通道其实是不同size的卷积核,selective kernel也正是由此而来。

在这里插入图片描述
具体步骤如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import torch.nn as nn
import torch
from functools import reduce
class SKConv(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
        '''
        super(SKConv,self).__init__()
        d=max(in_channels//r,L)   # 计算向量Z 的长度d
        self.M=M
        self.out_channels=out_channels
        self.conv=nn.ModuleList()  # 根据分支数量 添加 不同核的卷积操作
        for i in range(M):
            # 为提高效率,原论文中 扩张卷积5x5为 (3X3,dilation=2)来代替。 且论文中建议组卷积G=32
            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(1) # 自适应pool到指定维度    这里指定为1,实现 GAP
        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) # 指定dim=1  使得两个全连接层对应位置进行softmax,保证 对应位置a+b+..=1
    def forward(self, input):
        batch_size=input.size(0)
        output=[]
        #the part of split
        for i,conv in enumerate(self.conv):
            #print(i,conv(input).size())
            output.append(conv(input))
        #the part of fusion
        U=reduce(lambda x,y:x+y,output) # 逐元素相加生成 混合特征U
        s=self.global_pool(U)
        z=self.fc1(s)  # S->Z降维
        a_b=self.fc2(z) # Z->a,b 升维  论文使用conv 1x1表示全连接。结果中前一半通道值为a,后一半为b
        a_b=a_b.reshape(batch_size,self.M,self.out_channels,-1) #调整形状,变为 两个全连接层的值
        a_b=self.softmax(a_b) # 使得两个全连接层对应位置进行softmax
        #the part of selection
        a_b=list(a_b.chunk(self.M,dim=1))#split to a and b   chunk为pytorch方法,将tensor按照指定维度切分成 几个tensor块
        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)) # 权重与对应  不同卷积核输出的U 逐元素相乘
        V=reduce(lambda x,y:x+y,V) # 两个加权后的特征 逐元素相加
        return V
class SKBlock(nn.Module):
    '''
    基于Res Block构造的SK Block
    ResNeXt有  1x1Conv(通道数:x) +  SKConv(通道数:x)  + 1x1Conv(通道数:2x) 构成
    '''
    expansion=2 #指 每个block中 通道数增大指定倍数
    def __init__(self,inplanes,planes,stride=1,downsample=None):
        super(SKBlock,self).__init__()
        self.conv1=nn.Sequential(nn.Conv2d(inplanes,planes,1,1,0,bias=False),
                                 nn.BatchNorm2d(planes),
                                 nn.ReLU(inplace=True))
        self.conv2=SKConv(planes,planes,stride)
        self.conv3=nn.Sequential(nn.Conv2d(planes,planes*self.expansion,1,1,0,bias=False),
                                 nn.BatchNorm2d(planes*self.expansion))
        self.relu=nn.ReLU(inplace=True)
        self.downsample=downsample
    def forward(self, input):
        shortcut=input
        output=self.conv1(input)
        output=self.conv2(output)
        output=self.conv3(output)
        if self.downsample is not None:
            shortcut=self.downsample(input)
        output+=shortcut
        return self.relu(output)
class SKNet(nn.Module):
    '''
    参考 论文Table.1 进行构造
    '''
    def __init__(self,nums_class=1000,block=SKBlock,nums_block_list=[3, 4, 6, 3]):
        super(SKNet,self).__init__()
        self.inplanes=64
        # in_channel=3  out_channel=64  kernel=7x7 stride=2 padding=3
        self.conv=nn.Sequential(nn.Conv2d(3,64,7,2,3,bias=False),
                                nn.BatchNorm2d(64),
                                nn.ReLU(inplace=True))
        self.maxpool=nn.MaxPool2d(3,2,1) # kernel=3x3 stride=2 padding=1
        self.layer1=self._make_layer(block,128,nums_block_list[0],stride=1) # 构建表中 每个[] 的部分
        self.layer2=self._make_layer(block,256,nums_block_list[1],stride=2)
        self.layer3=self._make_layer(block,512,nums_block_list[2],stride=2)
        self.layer4=self._make_layer(block,1024,nums_block_list[3],stride=2)
        self.avgpool=nn.AdaptiveAvgPool2d(1) # GAP全局平均池化
        self.fc=nn.Linear(1024*block.expansion,nums_class) # 通道 2048 -> 1000
        self.softmax=nn.Softmax(-1) # 对最后一维进行softmax
    def forward(self, input):
        output=self.conv(input)
        output=self.maxpool(output)
        output=self.layer1(output)
        output=self.layer2(output)
        output=self.layer3(output)
        output=self.layer4(output)
        output=self.avgpool(output)
        output=output.squeeze(-1).squeeze(-1)
        output=self.fc(output)
        output=self.softmax(output)
        return output
    def _make_layer(self,block,planes,nums_block,stride=1):
        downsample=None
        if stride!=1 or self.inplanes!=planes*block.expansion:
            downsample=nn.Sequential(nn.Conv2d(self.inplanes,planes*block.expansion,1,stride,bias=False),
                                     nn.BatchNorm2d(planes*block.expansion))
        layers=[]
        layers.append(block(self.inplanes,planes,stride,downsample))
        self.inplanes=planes*block.expansion
        for _ in range(1,nums_block):
            layers.append(block(self.inplanes,planes))
        return nn.Sequential(*layers)
def SKNet50(nums_class=1000):
    return SKNet(nums_class,SKBlock,[3, 4, 6, 3]) # 论文通过[3, 4, 6, 3]搭配出SKNet50
def SKNet101(nums_class=1000):
    return SKNet(nums_class,SKBlock,[3, 4, 23, 3])
if __name__=='__main__':
    x = torch.rand(2, 3, 224, 224)
    model=SKNet50()
    y=model(x)
    print(y) # shape [2,1000]

3.7 SPConv:split kernel分轻重

SPConv:分离卷积。
代码参见 https://github.com/qiulinzhang/SPConv.pytorch ,该文是北邮&南开大学联合提出了一种“即插即用”计算单元,它基于特征冗余而设计,它将输入特征分成两组分别进行处理最后采用简化版SK进行融合。相比常规卷积,所提方法不仅更高精度,同时具有更快推理速度。而它的更快推理速度则是其最关键的亮点,要知道其他“即插即用”型改进卷积(如OctConv、GhostConv、Res2Conv等等)都不可避免的导致推理速度变慢,相当于用速度换时间;而所提方法不仅精度,而且速度快,同时具有更低的FLOPs与参数量,这是非常难得的一点。
在conv层内的许多特征具有相似却不平等的表现模式,然而这类具有相似模式的特征却难以判断是否存在冗余或包含重要的细节信息。因此,不同于直接移除不确定的冗余特征方案,作者提出了一种基于Split的卷积计算单元(称之为SPConv)。首先,将输入特征拆分为representative部分与uncertain部分;然后,对于representative部分特征采用相对多的计算复杂度操作提取重要信息,对于uncertain部分采用轻量型操作提取隐含信息;最后,为重新校准与融合两组特征,作者采用了无参特征融合模块。该文所提SPConv是一种“即插即用”型模块,可用于替换现有网络中的常规卷积。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下图是ResNet-50的第二卷积层,可以看出模式都差不多,因此我们可以选择一个representative特征图作为主图进行复杂计算(kk卷积),其他的作为redundant特征图,仅用来补充额外信息(11卷积)。因此,卷积变为:
在这里插入图片描述
这里的大写表示组卷积,小写表示点卷积。
在这里插入图片描述
这样拆分以后,Representative可能仍存在冗余问题。也就是说,Representative可以进一步进行拆分,不同部分表示不同的类别特征。因此,作者提出采用组卷积进一步降低Representative的冗余,见SPConv示意图的中间部分。作者认为:尽管组卷积可以降低冗余问题,但同时可能会导致部分信息损失。为补偿这部分信息损失,作者添加了额外的Point卷积(这里的组卷积与Point卷积是并行关系。最后通过Add方式对两者的输出特征进行融合),该过程可以描述为:
在这里插入图片描述

接下来对两者进行Parameter Free Feature Fusion Module。由于两类特征源自不同的输入通道,所以需要进行特征融合以控制信息流。作者并未采用Add或者Concat方式进行融合,而是设计了一种新颖的特征融合模块,该融合模块不会引入额外的参数并能取得更好的性能(见SPConv图示右部分)。这里的PFFF其实就是SKNet中的Select Kernel机制的简化版。
最终,卷积变为:
在这里插入图片描述
在这里插入图片描述
下面是cifar-10上的测试结果:
在这里插入图片描述
当α从1逐渐过渡到1/16的过程中,FLOPs与参数量急剧下降,但模型性能并无严重影响。当α=0.5时,模型具有最佳性能,参数量与计算量仅为常规卷积时的33%。

3.8 ResNeSt:SKNet+ResNeXt

ResNeSt的作者@张航也提到了这篇文章主要是基于 SENet,SKNet 和 ResNeXt,把 attention 做到 group level。对比一下上一节的ResNeXt的中间图,非常像。
在这里插入图片描述
主要的差别是每个group里面的attention结构,中间的部分用来计算权值,然后分配给每一个input
在这里插入图片描述

pdf:https://hangzhang.org/files/resnest.pdf
code:https://github.com/zhanghang1989/ResNeSt

3.9 SCNet:一半channel用attention模型

SC是self-calibrated的缩写,是南开大学程明明团队 & 字节跳动AI实验室联合投于CVPR2020的一篇关于自矫正卷积的改进方案。
又是一个即插即用的网络结构,结构如下:
在这里插入图片描述
首先,将输入X均匀划分为X1和X2,他们分别经过不同的处理操作;然后,将X1送入到第一分支(该分支为自矫正分支),将X2送入第二分支(该分支为常规卷积变换分支);最后,将处理后的特征拼接作为输出。在自矫正分支,对于输入X1先对其进行均值下采样、卷积特征变换、双线性上采样,然后再与输入相加得到空域层面的注意力特征图(是不是有点类似于SEBlock),其次将所得空域注意力图与变换后的X1进行融合。
这个模型也可以看做是多尺度卷积:
在这里插入图片描述

代码相当简洁:

# Note: 作者在实现代码中并未进行K1部分特征变换。
class SCConv(nn.Module):
    def __ini__(planes, stride, pooling_ratio):
        super().__init__()
        self.k2 = nn.Sequential(
            nn.AvgPool2d(kernel_size=pooling_ratio, stride=pooling_ratio)
            nn.Conv2d(planes, planes, 3, 1, 1, bias=False),
            nn.BatchNorm(planes)
        )
        self.k3 = nn.Sequential(
            nn.Conv2d(planes, planes, 3, 1, 1, bias=False),
            nn.BatchNorm2d(planes)
        )
        self.k4 = nn.Sequential(
            nn.Conv2d(planes, planes, 3, 1, 1, bias=False),
            nn.BatchNorm2d(planes),
            nn.ReLU()
        )
    def forward(self, x):
        identity = x
        out = torch.sigmoid(torch.add(identity, F.interpolate(self.k2(x), identity.size()[2:])))
        out = torch.mul(self.k3(x), out)
        out = self.k4(out)
        return out

3.10 OctConv:压缩低频信息

即插即用。思路如下:提取低频和高频两部分进行卷积
在这里插入图片描述
拆分高低频特征,然后压缩低频特征,保持两者之间的信息交换。
在这里插入图片描述
具体计算过程如下图:
在这里插入图片描述
卷积核可以用下图表示:
在这里插入图片描述

3.11 CondConv:多个卷积组合

条件计算是构建一种动态的网络结构,每次推断的时候先由决策网络(或模块)根据模型输入(甚至每一层的输入)推断出所要使用网络部件,然后利用原始网络的一个子集完成实际的推断过程。
CondConv的核心思想是带条件计算的分支集成的一种巧妙变换,首先它采用更细粒度的集成方式,每一个卷积层都拥有多套权重,卷积层的输入分别经过不同的权重卷积之后组合输出,如右图所示。
但这计算量依旧很大,作者将多套权重加权组合之后,只做一次卷积就能完成相当的效果。简单来说,CondConv在卷积层设置多套卷积核,在推断时对卷积核施加SE模块,根据卷积层的输入决定各套卷积核的权重,最终加权求和得到一个为该输入量身定制的一套卷积核,最后执行一次卷积即可。
事实上作者只使用了一层全连接,而不是标准的SE模块~
在这里插入图片描述
论文见 https://arxiv.org/pdf/1904.04971v2.pdf

3.12 SlimConv:SENet原版+翻转堆叠

又是一个即插即用的模型模块,虽然代码没有公开,但是github上有复现。作者所设计的SlimConv包含下面三个主要步骤(Reconstruct, Transform, Fuse),特征能够以更有效的方式进行拆分与重组。而SlimConv的关键核心在于weight flipping,它可以极大的提升特征的多样性,从而有助于性能提升。
(1) 注意力部分:这部分采用的是类似于SEBlock的注意力机制,作者在原始SEBlock的基础上进行了微调
(2) 特征重建部分:这个部分是该文的核心改进,原始的SEBlock只有一个分支的特征增强,而这篇论文则有两个分支的输出,上分支与SEBlock输出类似,而下分支则是先对注意力权值进行镜像再进行注意力融合;
(3) 特征拆分与融合:在这个部分作者对所得到的两个分支特征分别进行拆分与Add融合。
(4) 特征变换与融合:前面得到了两个分支的特征,作者提出上分支直接应用3x3卷积,而下分支则采用1x1卷积+3x3卷积的组合。其中1x1卷积还有降维作用,最终对两个分支通过Concat方式进行融合。默认输入C通道,输出3C/4通道。
在这里插入图片描述
在这里插入图片描述
参考代码:
在这里插入图片描述

3.13 PyConv:不同尺寸核的组卷积

作者引入一种金字塔卷积(PyConv),它包含不同尺度与深度的卷积核,进而确保了多尺度特征的提取;此外,为语义分割任务提出了一个新的框架:一种新颖的Head用于对backbone提取的特征可以从局部到全局进行上下文信息特征提取,并在场景解析方面取得了SOTA性能;基于PyConv而设计的网络架构在目标检测与视频分类任务上取得了性能的极大提升。
首先类似MixNet,进行组卷积:
在这里插入图片描述
需要注意哈:组卷积中每组的通道数是相同的。MixNet中的也是相同的,而PyConv则是不相同的,这也是为啥叫金字塔卷积的原因:
在这里插入图片描述

3.14 VoVNet:密集跳层对齐

VoVNet将DenseNet的密集连接调整为One-Shot-Aggregation方式,见下图。VoVNet的这种连接方式不仅具有DenseNet的多感受野灵活特征表达能力,同时克服了稠密连接的低效问题(仅需要一次特征聚集)。相比基于DenseNet的检测器,基于VoVNet的检测器具有更快的速度(2x),更低的功耗(1.6x-4.1x)。
在这里插入图片描述
VoVNetV2引入了ResNet的残差连接和SENet的SE模块。改进的OSA模块直接将输入加到输出上,增加短路连接,使得VoVNet可以训练更深的网络,论文中是VoVNet-99。从图c可以看到,改进的另外一个点是在最后的特征层上加上了sSE模块来进一步增强特征,原始的SE模块包含两个FC层,其中中间的FC层主要是为降维,这在一定程度上会造成信息丢失。而sSE模块是去掉了这个中间FC层。VoVNetV2相比VoVNet增加了少许的计算量,但是模型性能有提升:
在这里插入图片描述

3.15 Res2Net:金字塔多尺度特征

南开大学提出,将原来的resnet中间的3x3卷积换成了右侧红色部分,该部分最少是不经过3x3卷积,直接连接。最多会经过3个3x3的卷积,这样就能理解感受野比原结构多的原因了。再来讲一下里面的结构,经过1x1卷积之后,将特征图分成4部分。第一部分线路很简单,x1不做处理,直接传到y1;第二部分线路,x2经过3x3卷积之后分为两条线路,一条继续向前传播给y2,另一条传到x3,这样第三条线路就获得了第二条线路的信息;第三条线路、第四条线路,以此类推。每条线路的通道数为n/s。
在这里插入图片描述

3.16 Big-LittleNet:分叉多尺度特征

由IBM提出,文中多尺度特征表达的实现是通过多分支的网络结构,每个分支有不同的尺度,通过不断的融合不同尺度的特征来获得多尺度的特征。
BLM包含两个分支,一个分支表示深度模型(deep model),即精度高,但是计算花费也高;一个表示浅度模型(less deep),即计算花费低,但是精度低。这两个分支在末尾被融合通过一个单位权重进行线性融合。连个分支融合前,低分辨率的特征图通过双线性插值上采样到更高分辨率的空间大小;相似的更高分辨率的特征图通过一个 卷积将通道数增加到输出的最大通道数。文中的设计是基于ResNet,添加一个残差模块去进一步结合特征
在这里插入图片描述

4 常用backbone

4.1 LeNet:2卷积+2FC

一种典型的用来识别数字的卷积网络是LeNet-5,如下图:
在这里插入图片描述
LeNet奠定了特征图不断缩小、在深度上进行堆叠的基本结构。

输入图像为32x32大小。第一层C1使用6个5x5的卷积核得到,特征图大小为28x28。第一层的参数个数为:(5x5+1)x6=156个;第二层S2进行下采样,对2x2的区域进行求和+线性变换+sigmoid,跨度为2,特征图大小为14x14。每个卷积核对应的线性变换参数不一致,因此第二层的参数个数为2x6=12个;第三层C3使用16个5x5的卷积核得到,特征图大小为10x10。第三层与第二层以不对称的结构进行连接,参数个数为1516个;第四层S4继续下采样,采样区域同样是2x2,跨度为2,特征图大小5x5,参数个数为2x16=32个;第五层C5继续卷积,120个5*5卷积核,特征图大小1x1,全连接共120x(16x5x5+1)=48120个参数;第六层F6全连接,84个神经元。输出层10个类别,径向基函数连接。
如今的LeNet已经是改进版,比如把sigmoid都改为了relu函数。

4.2 AlexNet:5卷积+3FC+ReLU/Dropout

AlexNet在2012年ImageNet竞赛中以超过第二名10.9个百分点的绝对优势一举夺冠,从此深度学习和卷积神经网络名声鹊起。
image.png

其主要特点包括:
(1)更深的网络:5个卷积层+3个全连接层
(2)数据增广:图像进行平移、缩放、旋转等
(3)ReLU
(4)dropout

4.3 VGG-16:5卷积+3FC+堆叠小卷积核

VGG-Nets是由牛津大学VGG(Visual Geometry Group)提出,是2014年ImageNet竞赛定位任务的第一名和分类任务的第二名的中的基础网络。VGG和AlexNet的结构极为类似. 都是5个conv layer + 3个FC layer,不同的是,VGG去除了AlexNet中11×11和7×7的大卷积核,改成了多层小卷积核堆叠
image.png

其主要特点包括:
(1)层数更多
(2)使用更小尺寸的卷积核(都是1x1或者3x3)和stride。

4.4 GooLeNet:引入Inception

GoogLeNet在2014的ImageNet分类任务上击败了VGG-Nets夺得冠军,其实力肯定是非常深厚的,GoogLeNet跟AlexNet,VGG-Nets这种单纯依靠加深网络结构进而改进网络性能的思路不一样,它另辟幽径,在加深网络的同时(22层),也在网络结构上做了创新,引入Inception结构代替了单纯的卷积+激活的传统操作,这样就能在同样层数的情况下,引入更多的卷积特征。
此外注意到中间层还有2个额外的loss层,两者的权重都是0.3,和最终的loss函数一起。
另外,网络最后的全连接层被改为全局平均池化,最后才和输出层做全连接。
在这里插入图片描述

总图如下
在这里插入图片描述

4.5 ResNet:横扫天下,5个特征尺寸,n个block(跳层+bottleNeck)

2015年何恺明推出的ResNet在ISLVRC和COCO上横扫所有选手,获得冠军。ResNet在网络结构上做了大创新,引入了残差的概念,而不再是简单的堆积层数。此外,为了便于计算,在网络较深时,ResNet引入了bottleNeck结构:
在这里插入图片描述

这两种结构分别针对ResNet34(左图)和ResNet50/101/152(右图),一般称整个结构为一个”building block“。其中右图又称为”bottleneck design”,目的一目了然,就是为了降低参数的数目,第一个1x1的卷积把256维channel降到64维,然后在最后通过1x1卷积恢复,整体上用的参数数目:1x1x256x64 + 3x3x64x64 + 1x1x64x256 = 69632,而不使用bottleneck的话就是两个3x3x256的卷积,参数数目: 3x3x256x256x2 = 1179648,差了16.94倍。
对于常规ResNet,可以用于34层或者更少的网络中,对于Bottleneck Design的ResNet通常用于更深的如101这样的网络中,目的是减少计算和参数量。
下面是几种ResNet的结构。
在这里插入图片描述

所有的网络都分成5部分,分别是:conv1,conv2_x,conv3_x,conv4_x,conv5_x,之后的其他论文也会专门用这个称呼指代ResNet50或者101的每部分。
拿101-layer那列,我们先看看101-layer是不是真的是101层网络,首先有个输入7x7x64的卷积,然后经过3 + 4 + 23 + 3 = 33个building block,每个block为3层,所以有33 x 3 = 99层,最后有个fc层(用于分类),所以1 + 99 + 1 = 101层,确实有101层网络。101层网络仅仅指卷积或者全连接层,而激活层或者Pooling层并没有计算在内。对比50-layer和101-layer这两列,可以发现,它们唯一的不同在于conv4_x,ResNet50有6个block,而ResNet101有23个block,差了17个block,也就是17 x 3 = 51层。

4.6 DenseNet:跳层pro版

CVPR 2017最佳论文DenseNet提出的DenseNet(Dense Convolutional Network),每个block中采用密集连接,网络每一层的输入都是前面所有层输出的并集,而该层所学习的特征图也会被直接传给其后面所有层作为输入。这样可以加强特征传播,鼓励特征复用,极大的减少了参数量。
下面是一个DenseBlock,跳层都连成一张网了:
在这里插入图片描述
下面是一个DenseNet的示例,CNN网络一般要经过Pooling或者stride>1的Conv来降低特征图的大小,而DenseNet的密集连接方式需要特征图大小保持一致。为了解决这个问题,DenseNet网络中使用DenseBlock+Transition的结构,其中DenseBlock是包含很多层的模块,每个层的特征图大小相同,层与层之间采用密集连接方式。而Transition模块是连接两个相邻的DenseBlock,并且通过Pooling使特征图大小降低。
在这里插入图片描述
下面是几种不同深度的DenseNet结构:
在这里插入图片描述
DenseNets可以自然地扩展到数百个层,而没有表现出优化困难。在实验中,DenseNets趋向于随着参数数量的增加,在精度上产生一致的提高,而没有任何性能下降或过拟合的迹象。
DesnseNet和ResNet的性能对比如下:
在这里插入图片描述

4.7 SpineNet:跳层+取消尺度递减+Nas

尺度递降的架构设计准则在分类任务中取得了成功,但这种设计规则真的适合于目标检测这种需要同时进行识别和定位的任务吗?针对该问题,谷歌研究员进行了研究并提出了一种尺度排列网络:SpineNet(它与常规网络架构的区别见下图)。它具有这样的两个重要特性:(1)中间特征的尺度可以随时提升或下降,因此模型可以随深度增加而保持空间信息;(2)特征图之间的连接可以跨尺度以促进多尺度特征融合。
至于如何搭建跳层和每一层的尺度,采用了NAS方法。作者采用REsNet50的bottleNeck模块作为候选特征模块,需要进行两个方面的学习:(1)特征模块排列;(2)每个特征模块的输入连接。

在这里插入图片描述
跨尺度特征融合的一个重要挑战在于:分辨率与特征维度可能不一致。此时,需要进行空域和特征维度重采样以匹配目标模块的分辨率和维度,重采样方式见下图。
在这里插入图片描述
作者猜想:最优模型可能具有不同的特征分辨率、不同的模块类型,而非ResNet中的固定类型。因此,作者进一步扩展搜索中间的模块类型,此时所学习到的模型命名为SpineNet49.下图给出了不同搜索空间配置下搜索到的网络架构示意图。
在这里插入图片描述
基于SpineNet49,作者构建四种改进版以在延迟与性能之间寻求均衡,这四种模型分别命名为SpineNet49S/96/146/190.

SpineNet49S:它是在SpineNet49的基础上低特征维度以0.65进行缩放;
SpineNet96:通过对每个模块重复两次将模型大小加倍,见下图加倍方式;
SpineNet146:通过对每个模块重复三次进行加大模型,见下图加倍方式;
SpineNet190:通过对每个模块重复四次更进一步加大模型
下面是在检测和实例分割上的性能:
在这里插入图片描述
在这里插入图片描述
此外,作者还研究了适用于终端部署的SpineNet,见下表。基于MBConv模块,SpineNet以更少的计算量优于MobileNetV2/V3以及MnasNet等目标检测器。
在这里插入图片描述

4.8 HRNet:小特征辅助,大特征图一直在

High-Resoultion Net,模型的主要特点是在整个过程中特征图(Feature Map)始终保持高分辨率,这与之前主流方法思路上有很大的不同。在HRNet之前,所有的网络都是将高分辨率特征图下采样至低分辨率,再从低分辨率特征图恢复至高分辨率的思路(单次或重复多次),因此,其方法能够保持高分辨率,而不是通过一个低到高的过程恢复分辨率,因此预测的heatmap可能在空间上更精确。
HRNet的基本结构如下:
在这里插入图片描述

4.9 FPN:金字塔结构

一个自底向上的线路,一个自顶向下的线路,横向连接(lateral connection)。图中放大的区域就是横向连接,这里11的卷积核的主要作用是减少卷积核的个数,也就是减少了feature map的个数,并不改变feature map的尺寸大小。
自底向上其实就是网络的前向过程。在前向过程中,feature map的大小在经过某些层后会改变,而在经过其他一些层的时候不会改变,作者将不改变feature map大小的层归为一个stage,因此每次抽取的特征都是每个stage的最后一个层输出,这样就能构成特征金字塔。
自顶向下的过程采用上采样(upsampling)进行,而横向连接则是将上采样的结果和自底向上生成的相同大小的feature map进行融合(merge)。在融合之后还会再采用3
3的卷积核对每个融合结果进行卷积,目的是消除上采样的混叠效应(aliasing effect)。并假设生成的feature map结果是P2,P3,P4,P5,和原来自底向上的卷积结果C2,C3,C4,C5一一对应。

在这里插入图片描述

4.10 DetNet:只缩小16倍尺寸

DetNet是在FPN的架构上进行修改的,前4个stage和FPN完全一样,从第5个stage开始有变化。
在这里插入图片描述
后面几层的结构如下。stage4-6这三个stage的stride都是16,也就是这三个stage的特征图都是原图尺寸的1/16,而原本的ResNet50的stage5的特征图是原图尺寸的1/32;此外提出了dilated bottleneck,分成A和B两种,具体的使用顺序如图D;使用dilation技术的目的是增大感受野(保证了特征图的尺寸),然而考虑到计算量和内存,stage5和stage6保持了相同的通道数目(256的输入通道,而不是像传统的backbone一样,每个阶段通道数增加一倍)。
在这里插入图片描述

4.11 DLA:DenseNet+FPN

Deep Layer Aggregation,设计原则如下图所见:
在这里插入图片描述
融合的关键轴是语义和空间。 跨语音和深度的语义融合或聚合可以改善对内容的推断。 空间融合,或跨决议和规模汇总,改善对地点的推断。 深层聚合网络可以看作是两种融合形式的结合。
密集连接的网络(DenseNets)是语义融合的主要架构系列,旨在通过跳过连接来更好地传播特性和损失,这些跳过连接可以分阶段连接所有层。 我们的分层深度聚合分享了对短路径和重用的重要性的相同见解,并扩展了与跨越阶段和比串联更深层融合的树的跳过连接。 密集连接和深度聚合的网络可实现更高的准确性以及更好的参数和内存效率。
特征金字塔网络(FPN)是空间融合架构的主要系列,旨在通过自上而下和横向连接在金字塔特征层次的层次上均衡分辨率和标准化语义。 我们的迭代深度聚合同样提高了分辨率,但通过非线性和渐进式融合进一步加深了表示。 FPN连接是线性的,较早的级别不会更多地聚合以抵消它们的相对语义弱点。 金字塔和深度聚合的网络能够更好地解决结构化输出任务的内容和位置。

5. Mobile backbone

MobileNet快的主要原因是因为大量使用1×1conv:
在这里插入图片描述

5.1 MobileNetV1:标准卷积+13个(dw+pw)+标准卷积

Depth-Wise Conv(简称dw),也称深度可分离卷积,它将卷积核的每个通道分别应用于输入特征图的每个通道(这样,输入和输出的通道数维持一致),而非如标准卷积般将输入特征图的所有通道加权组合在一起。 Point-Wise Conv(简称pw), 也称逐点卷积,它使用1x1大小的卷积核,用于组合深度可分离卷积的输出结果(将深度可分离卷积的输出通道数映射到目标通道数)。 标准卷积将提取空间特征和通道之间的相关性组合在一起,而MobileNet将其分解为Depth-Wise + Point-Wise,这样的效果是先基于各个通道提取空间特征(空间相关性),之后再组合通道之间的相关性,这种因式分解操作具有大幅度减少计算和模型大小的效果。
在这里插入图片描述
下面是网络结构:
在这里插入图片描述

5.2 MobileNetV2:跳层+线性激活+逆bottleNeck

MobileNetV1会有很多空洞:
在这里插入图片描述
主要是因为在channel比较少时,用ReLU激活很容易丢失信息,改进方法有:
(1)增加channel数,添加Expansion Layer,使用逐点卷积进行升维
(2)将最后一个PW的激活层改为线性激活函数,也叫Linear BottleNeck
(3)加入残差
在这里插入图片描述
网络结构如下:
在这里插入图片描述
在这里插入图片描述

5.3 MobileNetV3:h-swish激活+SENet+NAS

首先是h-swish激活函数
在这里插入图片描述
h-swish则是把sigmod函数改为ReLU6。
此外,在bottleneck中加入了SE结构,并且放在了dw之后。另外,由于SE部分的计算会消耗一定的时间,因此在SE结构的第1个FC层中,压缩了通道数(paper原文是变为原来的1/4),在最后的FC层再复原,通过实验证明,这样在减少时耗的同时也提高了精度,这是属于MobileNet的轻量级SE结构。
在这里插入图片描述
此外修改部分结构:
(1). 修改头部卷积核的通道数 v2中的头部卷积核是 32 x 3 x 3,v3中改成了 16 x 3 x 3,作者发现这样在保证了精度的前提下还降低了3ms的时耗。 (2). 修改尾部结构 v2中,在最后的 Avg-Pooling 之前,使用了1个pw来升维,有利于结构的预测,但这同时引入了一定的计算量,于是作者在v3中作了修改: 先去掉这个 pw 前的 bottleneck 中的 dw 和后面的 pw,然后将原本位于 Avg-Pooling 前的 pw 放置于 Avg-Pooling 后,这样就变为先用 Avg-Pooling 将feature map大小由 7 x 7 降到了 1 x 1(Avg-Pooling 的 kernel size 是 7 x 7),然后再使用 pw 升维度,减少了计算量和时耗,同时发现精度并没有得到损失,最终变为如下所示的结构:
在这里插入图片描述
相比于v2:
在这里插入图片描述
此外,增加网络结构搜索:资源受限的NAS(Platform-Aware NAS)与 NetAdapt。总体过程就是先用资源受限的NAS,在计算和参数量受限的前提下搜索网络来优化各个块(block),称之为模块级搜索(Block-wise Search)。然后再使用 NetAdapt 算法对各个模块确定每一层的卷积核数量,称之为层级搜索(Layer-wise Search)

5.4 ShuffleNetV1:group+channel shuffle

group在前面已介绍过,这里说下channel shuffle,其含义就是对group convolution之后的特征图进行“重组”,这样可以保证接下了采用的group convolution其输入来自不同的组,因此信息可以在不同组之间流转。
在程序上实现channel shuffle是非常容易的:假定将输入层分为 g 组,总通道数为 g× n ,首先你将通道那个维度拆分为 (g,n) 两个维度,然后将这两个维度转置变成 (n,g) ,最后重新reshape成一个维度g× n:
在这里插入图片描述
下图a是ResNet,下图b展示了增加channel shuffle之后的结构。
下图c展示了其他改进,对原输入采用stride=2的3x3 avg pool,在depthwise convolution卷积处取stride=2保证两个通路shape相同,然后将得到特征图与输出进行连接(concat,借鉴了DenseNet?),而不是相加。极致的降低计算量与参数大小。
在这里插入图片描述
下图是ShuffleNetV1结构:
在这里插入图片描述

5.5 ShuffleNetV2:split+channel shuffle放在concat之后

(a)和(b)是ShuffleNet v1的两种不同block结构,两者的差别在于后者对特征图尺寸做了缩小,这和ResNet中某个stage的两种block功能类似,同理(c)和(d)是ShuffleNet v2的两种不同block结构:
在这里插入图片描述
(c)在开始处增加了一个channel split操作,这个操作将输入特征的通道分成c-c’,然后(c)中取消了1*1卷积层中的group操作,前面的channel split其实已经算是变相的group操作了。channel shuffle的操作移到了concat后面,最后是将element-wise add操作替换成concat

5.6 HBONet:空间和通道同时bottleneck

HBONet是基于MobileNetV2设计的,采用HBO替换MobileNetV2中的瓶颈层构建HBONet取得了性能的极大提升(不高于40MFLOPs维度);所提HBONet在300MFLOPs层面超过了其他轻量型架构,取得了73.1%的分类精度。
有鉴于现有轻量型网络(含MobileNet系列、ShuffleNet系列)在不高于40MFLOPs时的低性能,作者基于MobileNetV2设计一种新颖的瓶颈层以提升其性能。ShuffleNet、MobileNet主要是从特征通道间变换角度入手,而忽视了探索其其正交维(空间维)。作者从通道维与空间维两个层面设计一种新颖的瓶颈层HBO以提升其表达能力。在每个HBO模块内,空间维收缩用于降低输入尺度,后接通道扩张收缩补偿空间维降低的副作用,最后接上空间维扩张以保证输出具有原始输入相同的空间分辨率。
上面是mobileNetV2,下面是HBONet。总体来看,无非是增加了一个空间维度的下采样和上采样。
在这里插入图片描述

5.8 GhostNet:叠加线性变换后的层

该文是华为诺亚方舟提出了一种轻量型网络架构。作者也是从特征冗余的角度对现有卷积提出改进:通过简单的线性变换进一步提升特征的多样性。
在这里插入图片描述
下面是对比图:
在这里插入图片描述

5.9 DGConv:动态组卷积

动态组卷积定义如下:
在这里插入图片描述
即普通的卷积前点乘一个稀疏矩阵U。作者不直接优化稀疏矩阵U,而是将其分解为多个子矩阵进行优化。

动态组卷积具有以下几个优点:
(1)动态聚合成组,DGConv可以自适应的学习组策略(组数与连接方式),而且添加正则项后还可以进一步控制模型大小与计算负载;
(2)可微分性,DGConv是全可微的,可以采用SGD通过端到端的方式进行训练;
(3)参数节省,训练过程中仅需额外的 l o g 2 ( c ) \mathcal{log}_2(c) 参数,这远远小于其节省的参数量,更进一步,在训练完成后,该参数可以被忽略掉。

动态组卷积可以直接替换group conv:
在这里插入图片描述
在这里插入图片描述

5.10 squeezeNet:类似inception,squezze+expand

左图是SqueezeNet的整体结构,中图和右图是将ResNet网络中的shortcut引入所构建的网络,所以只是一种提升策略与SqueezeNet无关,本文不多做解释。
在这里插入图片描述
其中的fireModular如下图:
在这里插入图片描述
FireModule由squeeze模块和expand模块。该模块的主要有两大特性。

(1)squeeze模块:利用1×1卷积进行降维(所以如图中的16<128)
(2)expand模块:利用11卷积+33卷积组合升维。
(3)将poolint采样操作延后,可以给卷积层提供更大的激活图:更大的激活图保留了更多的信息,可以提供更高的分类准确率

6 各种Nas方法

6.1 GPU Nas

GENet:该文是阿里巴巴提出了一种GPU端高效&高精度网路架构设计新方案。不同于之前的MobileNet、EfficientNet以及RegNet等网络采用相同的模块构建整个网络,该文对不同阶段的模块进行分析并得出这样的结论:在网络的low-level阶段采用BasicBlock,而在high-level阶段采用Bottleneck/InvertedResidualBlock可以最大化的利用GPU并得到更快的推理速度与模型精度(精度高达81.3%且速度超快)。
在这里插入图片描述
作者将该架构形态称之为MasterNet,它的每个阶段称之为Super-Block,每个Super-Block由同类型的多个BasicBlock构成,每个BasicBlock由深度、宽度以及stride等参数进行描述。一般而言,Super-Block的第一个模块采用stride=2进行特征下采样,后续模块采用stride=1的模式。而MasterNet的第一层是一个stride=2的stem模块;MasterNet的最后为GAPHead模块(它包含一个全局均值池化与一个全连接层,用于分类)。现有研究已经证实:上述网络架构形态足以得到GPU端的高性能低延迟的网络架构。
在BasicBlock方面,作者考虑了三种类型的模块(见上图b),分别如下:
XX-Block(ResNet18、ResNet34中的基本模块);
BL-Block(ResNet50、ResNet101中的基本模块);
DW-Block(MobileNetv2的基本模块)。
上图c则给出了上述模块嵌入到残差模块中的示意图以及stride=2时的模块示意图。
作者提出采用NAS方式搜索MasterNet的结构,所用的NAS称之为LLR-NAS。作者分别设置延迟耗时为0.34/0.2/0.1三种约束得到了GENet-Large/GENet-normal/GENet-light。
在这里插入图片描述
在这里插入图片描述

6.2 移动端Nas

实在是太多了,下面是一个比较陈旧的性能对比,大家挑着看吧。
在这里插入图片描述
这里介绍MixNet作为一个示例:
MixNet是谷歌大牛Quoc V. Le的在AutoML领域的又一力作。通过集成MDConv到AutoML框架中,作者进一步研发一种新的模型:MixNets。它优于已有轻量型网络,包含MobileNetV2(+4.2%), ShuffleNetV2(+3.5%), MnasNet(+1.3%), ProxylessNas(+2.2%), FBNet(+2.0%)。特别的,MixNet-L取得了78.9%的top-1分类精度(ImageNet),同时FLOPs小于600M。
在这里插入图片描述
作者提出一种混合深度分离卷积(MDConv),它将不同尺寸卷积核混叠到同一个卷积OP单元中,故而它可以轻易的捕获不同分辨率的特征模式。
在这里插入图片描述
作者将MDConv集成到AutoML框架中进行轻量型网络搜索,按照FLOPs划分,作者共涉及了三个网络:MixNet-S, MixNet-M, MixNet-L。他们与其他轻量型网络的性能对比如下所示。从中可以看出:MixNet取得了完胜。

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/kittyzc/article/details/107444373
今日推荐