图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2

文章目录

    • 一、Vision Transformer详解
      • 1.1 前言
      • 1.2 Vision Transformer模型详解
        • 1.2.1 整体结构
        • 1.2.2 Embedding层结构详解
        • 1.2.3 Transformer Encoder详解
        • 1.2.4 MLP Head和`ViT-B/16`模型结构图
        • 1.2.5 ViT模型的三个size
      • 1.3 Hybrid模型详解
      • 1.4 模型效果对比
      • 1.5 PyTorch代码实现
        • 1.5.1 PatchEmbed层
        • 1.5.2 Attention层(实现多头注意力Multi-Head Attention)
        • 1.5.3 待续
      • 1.6 PyTorch应用实例(待补充)
    • 二、 Swin-Transformer
      • 2.1 模型简介
      • 2.2 模型结构
      • 2.3 Patch Merging
      • 2.4 W-MSA和SW-MSA
        • 2.4.1 W-MSA
        • 2.4.2 SW-MSA(Shifted Windows Multi-Head Self-Attention)
        • 2.4.3 Masked MSA
      • 2.5 Relative Position Bias
      • 2.6 模型详细配置参数
      • 2.7 代码讲解(待补充)
    • 三、MobileViT
      • 3.1 为什么引入CNN与Transformer的混合架构
      • 3.2 性能对比
      • 3.3 模型结构
      • 3.4 MobileViT block
      • 3.5 Patch Size对性能的影响
      • 3.6 模型详细配置
    • 四、MobileNet系列模型
      • 4.1 前言
      • 4.2 MobileNetV1
        • 4.2.1 深度可分离卷积Depthwise separable convolution
        • 4.2.2 MobileNetV1网络结构
      • 4.3 MobileNet v2
        • 4.3.1 Inverted residual block
        • 4.3.2 MobileNet v2网络结构
        • 4.3.3 MobileNet v2性能对比
      • 4.4 MobileNetv3
        • 4.4.1 SE模块
        • 4.4.2 bneck
        • 4.4.3 swish/sigmoid替换为h-swish/h-sigmoid
        • 4.4.4 重新设计耗时层结构
        • 4.4.5 NAS
        • 4.4.6 MobileNetv3网络结构
    • 五、ConvNeXt
      • 5.1 前言
      • 5.2 实验设计
      • 5.3 Macro design
      • 5.4 ResNeXt-ify
      • 5.5 Inverted Bottleneck
      • 5.6 Large Kernel Sizes
      • 5.7 Micro Design
      • 5.8 ConvNeXt模型结构和不同版本的参数
      • 5.9 代码讲解(待补充)
    • 六、EfficientNet系列
      • 6.1 EfficientNetV1
        • 6.1.1 前言
        • 6.1.2 论文思想
        • 6.1.3 网络详细结构
        • 6.1.4 MBConv结构
        • 6.1.5 EfficientNet(B0-B7)参数及性能对比
      • 6.2 EfficientNetV2
        • 6.2.1EfficientNetV2性能对比
        • 6.2.2 V1中存在的问题和V2的改进
        • 6.2.3 EfficientNetV2网络框架
        • 6.2.4 Progressive Learning渐进学习策略
        • 6.2.5 配置文件

一、Vision Transformer详解

  • 参考《Vision Transformer详解》、bilibili视频讲解
  • 论文名称: An Image Is Worth 16x16 Words: Transformers For Image Recognition At Scale、论文源码
  • PytorchAPI、Pytorch官方源码、Tensorflow2实现代码:tensorflow_classification/vision_transformer
  • transformer原理可参考我的博文《多图详解attention和mask。从循环神经网络、transformer到GPT2》

1.1 前言

  Transformer最初提出是针对NLP领域的,并且在NLP领域大获成功。这篇论文也是受到其启发,尝试将Transformer应用到CV领域。过这篇文章的实验,给出的最佳模型在ImageNet1K上能够达到88.55%的准确率,说明Transformer在CV领域确实是有效的,而且效果还挺惊人。

下图Ours-JFT表示在在Google自家的JFT数据集上进行了预训练
Ours-I21K表示在ImageNet 21K上预训练,再在ImageNet 1K上测试。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第1张图片
  在这篇文章中,作者主要拿ResNetViT(纯Transformer模型)以及Hybrid(卷积和Transformer混合模型)三个模型进行比较,所以本博文除了讲ViT模型外还会简单聊聊Hybrid模型。

1.2 Vision Transformer模型详解

1.2.1 整体结构

下图是原论文中给出的关于Vision Transformer(ViT)的模型框架。简单而言,模型由三个模块组成:

  • Linear Projection of Flattened Patches(Embedding层)
  • Transformer Encoder(图右侧有给出更加详细的结构)
  • MLP Head(最终用于分类的层结构)

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第2张图片
如上图所示:

  1. 图片输入embedding
    • 一张图片先分割成n个patchs,然后这些patchs一个个输入Linear Projection of Flattened Patches层(Embedding层)。比如ViT-L/16表示每个patchs大小是16×16。
    • 通过Embedding层得到每个patchs对应的输出向量(token)。在所有tokens前面加一个新的class token作为这些patchs的全局输出,相当于transformer中的CLS。
    • transformer的self-attention本身没有考虑输入的位置信息,因此无法对序列进行建模。为了解决这一点,引入位置信息,这里是在每个token前面加上位置向量,即position embedding。
  2. token+position+class token一起输入Transformer Encoder层得到其输出。
  3. class token的输出(只是用于分类,所以只使用class token的输出。)经过MLP Head得到分类结果。

1.2.2 Embedding层结构详解

  对于标准的Transformer模块,要求输入的是token(向量)序列,即二维矩阵[num_token, token_dim]。对于图像数据而言,其数据为[H, W, C]格式的三维矩阵,明显不是Transformer想要的。所以需要先通过一个Embedding层来对数据做个变换。

  1. 如下图所示,首先将一张图片按给定大小分成一堆Patches。以ViT-B/16为例(后面都是以此模型举例),将输入图片(224x224)按照16x16大小的Patch尺寸进行划分,划分后会得到 ( 224 / 16 ) 2 = 196 (224/16)^2=196 (224/16)2=196个Patches。
  2. 接着通过线性映射将每个Patch映射到一维向量中。具体的,每个Patche数据shape为[16, 16, 3],通过映射得到一个长度为768的向量(token)。[16, 16, 3] -> [768]

  在代码实现中,直接通过一个卷积层来实现。卷积核大小为16x16,步距为16,卷积核个数为768。通过卷积[224, 224, 3] -> [14, 14, 768],然后把H以及W两个维度展平即可[14, 14, 768] -> [196, 768],此时正好变成了一个二维矩阵,正是Transformer想要的。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第3张图片
3. 加上[class]token以及Position Embedding。

  在原论文中,作者说参考BERT,在刚刚得到的一堆tokens中插入一个专门用于分类的[class]token,这个[class]token是一个可训练的参数,数据格式和其他token一样也是768维向量。然后与之前从图片中生成的tokens拼接在一起,Cat([1, 768], [196, 768]) -> [197, 768]
  这里的Position Embedding采用的是一个可训练的参数(1D Pos. Emb.),是直接叠加在tokens上的(add),所以shape要一样,也是[197, 768]

  对于Position Embedding作者也有做一系列对比试验,在源码中默认使用的是1D Pos. Emb.,对比不使用Position Embedding准确率提升了大概3个点,和2D Pos. Emb.比起来没太大差别。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第4张图片

1.2.3 Transformer Encoder详解

Transformer Encoder其实就是重复堆叠Encoder Block L次,主要由以下几部分组成:

  • Layer Norm层标准化:这种Normalization方法主要是针对NLP领域提出的,对每个token进行Norm处理。
  • Multi-Head Attention:多头注意力
  • Dropout/DropPath:在原论文的代码中是直接使用的Dropout层,在但rwightman实现的代码中使用的是DropPath(stochastic depth),可能后者会更好一点。
  • MLP Block,如图右侧所示,就是全连接+GELU激活函数+Dropout组成。需要注意的是第一个全连接层会把输入节点个数翻4倍[197, 768] -> [197, 3072],第二个全连接层会还原回原节点个数[197, 3072] -> [197, 768],原来跟transformer中做法一样。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第5张图片

画法不一样啊,其实还是跟NLP中transformer的encoder结构差不多:(Feed Forword前馈网络就是类似MLP)
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第6张图片

为什么Transformer用Layer Normalization而不是Batch Normalization?

  1. NLP领域输入的句子序列,在一个batch中是不定长的,即输入的一连串句子,每句话长度不等。通过pad之后在句子结尾补0(也可以是其它的pad字符),使一个batch保持等长。如果使用BN,等于不同句子之间在每列单词维度进行Nrom,就涉及到会将pad字符Norm的情况,这样明显是不对的。
  2. 对于文字序列来说,一个序列的输入同一”维度“上的信息可能不是同一个维度,比如下面两个句子,按BN方式,在第一”维度“进行归一化的话就是将”你“和”机“的特征进行归一化,但这明显不是一个维度的信息。显然BN在此处使用是很不合理的。NLP中同一batch样本的信息关联不大(差异很大,但要学习的就是这种特征),更多应该概率句子内部(单个样本内部)维度的归一化。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第7张图片

为什么MLP Block先升维再降维?
神经网络中线性连接可以写成 d l = W l ⋅ x d^l=W^{l}\cdot x dl=Wlx。其中三者维度分别是m×1、m×n、n×1。

  • m>n:升维,将特征进行各种类型的特征组合,提高模型分辨能力
  • m

1.2.4 MLP Head和ViT-B/16模型结构图

  上面通过Transformer Encoder后输出的shape和输入的shape是保持不变的,以ViT-B/16为例,输入的是[197, 768]输出的还是[197, 768]。对于分类,我们只需要提取出[class]token生成的对应结果就行,即[197, 768]中抽取出[class]token对应的[1, 768]
  接着我们通过MLP Head得到我们最终的分类结果。MLP Head原论文中说在训练ImageNet21K时是由Linear+tanh激活函数+Linear组成。但是迁移到ImageNet1K上或者你自己的数据上时,只定义一个Linear即可。
  下面是小绿豆绘制的ViT-B/16模型结构图:(Pre-Logits就是Linear+tanh,一般迁移学习是可以不用的。)
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第8张图片

1.2.5 ViT模型的三个size

  在论文的Table1中有给出三个模型(Base/ Large/ Huge)的参数,在源码中除了有Patch Size为16x16的外还有32x32的。其中:

  • Layers:Transformer Encoder中重复堆叠Encoder Block的次数
  • Hidden Size:对应通过Embedding层后每个token的dim(向量的长度)
  • MLP size:Transformer Encoder中MLP Block第一个全连接的节点个数(是Hidden Size的四倍)
  • Heads:代表Transformer中Multi-Head Attention的heads数(多头注意力有几个头)。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第9张图片

1.3 Hybrid模型详解

  在论文4.1章节的Model Variants中有比较详细的讲到Hybrid混合模型,就是将传统CNN特征提取和Transformer进行结合。下图绘制的是以ResNet50作为特征提取器的混合模型,但这里的Resnet与之前讲的Resnet有些不同。

  1. 首先这里的ResNet50的卷积层采用的StdConv2d不是传统的Conv2d,然后将所有的BatchNorm层替换成GroupNorm层。
  2. 在原Resnet50网络中,stage1重复堆叠3次,stage2重复堆叠4次,stage3重复堆叠6次,stage4重复堆叠3次,但在这里的ResNet50中,把stage4中的3个Block移至stage3中,所以stage3中共重复堆叠9次。

如果有stage4就是下采样32倍,改为只有stage3就是下采样16倍,这样224×224的图片输出的就是14×14大小。

  通过ResNet50 Backbone进行特征提取后,得到的特征矩阵shape是[14, 14, 1024],接着再输入Patch Embedding层,注意Patch Embedding中卷积层Conv2d的kernel_size和stride都变成了1,只是用来调整channel。
  后面的部分和前面ViT中讲的完全一样,就不在赘述。
  简单说,ViT是图片经过Conv2d卷积层得到Patchs,而Hybrid是多加了一步,图片经过ResNet50 Backbone进行特征提取后,经过卷积得到Patchs。然后都是加上class token和位置向量输入Transformer Encoder,得到class token都是输出。再经过MLP得到分类结果。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第10张图片

1.4 模型效果对比

  下表是论文用来对比ViT,Resnet(和刚刚讲的一样,使用的卷积层和Norm层都进行了修改)以及Hybrid模型的效果。通过对比发现,在训练epoch较少时Hybrid优于ViT,但当epoch增大后ViT优于Hybrid。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第11张图片

1.5 PyTorch代码实现

项目代码github地址、B站代码讲解《使用pytorch搭建Vision Transformer(vit)模型》

1.5.1 PatchEmbed层

class PatchEmbed(nn.Module):
    """
    2D Image to Patch Embedding
    """
    def __init__(self, img_size=224, patch_size=16, in_c=3, embed_dim=768, norm_layer=None):
        super().__init__()
        img_size = (img_size, img_size)
        patch_size = (patch_size, patch_size)
        self.img_size = img_size
        self.patch_size = patch_size
        self.grid_size = (img_size[0] // patch_size[0], img_size[1] // patch_size[1])
        self.num_patches = self.grid_size[0] * self.grid_size[1] # 在VIT-B/16中就是16*16

        self.proj = nn.Conv2d(in_c, embed_dim, kernel_size=patch_size, stride=patch_size)
        # 默认不传入norm_layer, nn.Identity()表示不做任何操作
        self.norm = norm_layer(embed_dim) if norm_layer else nn.Identity()

    def forward(self, x):
        B, C, H, W = x.shape # x就表示传入的图片
        # 需要注意的是,VIT模型不像传统的CNN模型那样,可以更改图片的入网尺寸。
        assert H == self.img_size[0] and W == self.img_size[1], \
            f"Input image size ({H}*{W}) doesn't match model ({self.img_size[0]}*{self.img_size[1]})."

        # flatten: [B, C, H, W] -> [B, C, HW],最后两个维度拉平
        # transpose: [B, C, HW] -> [B, HW, C],后两个维度交换
        x = self.proj(x).flatten(2).transpose(1, 2)
        x = self.norm(x) # 得到 Patch Embedding
        return x

1.5.2 Attention层(实现多头注意力Multi-Head Attention)

class Attention(nn.Module):
    def __init__(self,
                 dim,   # 输入token的dim
                 num_heads=8, # 多头注意力使用几个head
                 qkv_bias=False, # 生成qkv时是否使用偏置
                 qk_scale=None,
                 attn_drop_ratio=0., # dropout概率,下同
                 proj_drop_ratio=0.):
        super(Attention, self).__init__()
        self.num_heads = num_heads
        head_dim = dim // num_heads # 每个head的维度,一般要求dim能整除num_heads
        self.scale = qk_scale or head_dim ** -0.5 # 不传入qk_scale时,self.scale=根号dk
        self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias) # 使用一个全连接层得到qkv
        self.attn_drop = nn.Dropout(attn_drop_ratio)
        self.proj = nn.Linear(dim, dim) # 多头拼接后用Wo映射,Wo就是全连接层实现
        self.proj_drop = nn.Dropout(proj_drop_ratio)

    def forward(self, x):
        # [batch_size, num_patches + 1, total_embed_dim]
        # num_patches + 1就是196+1(class token),total_embed_dim=768
        B, N, C = x.shape

        # qkv(): -> [batch_size, num_patches + 1, 3 * total_embed_dim]
        # reshape: -> [batch_size, num_patches + 1, 3, num_heads, embed_dim_per_head]
        # permute: -> [3, batch_size, num_heads, num_patches + 1, embed_dim_per_head]
        qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
        # [batch_size, num_heads, num_patches + 1, embed_dim_per_head]
        q, k, v = qkv[0], qkv[1], qkv[2]  # make torchscript happy (cannot use tensor as tuple)

        # transpose: -> [batch_size, num_heads, embed_dim_per_head, num_patches + 1]
        # @: multiply -> [batch_size, num_heads, num_patches + 1, num_patches + 1]
        attn = (q @ k.transpose(-2, -1)) * self.scale
        attn = attn.softmax(dim=-1)
        attn = self.attn_drop(attn)

        # @: multiply -> [batch_size, num_heads, num_patches + 1, embed_dim_per_head]
        # transpose: -> [batch_size, num_patches + 1, num_heads, embed_dim_per_head]
        # reshape: -> [batch_size, num_patches + 1, total_embed_dim]
        x = (attn @ v).transpose(1, 2).reshape(B, N, C)
        x = self.proj(x)
        x = self.proj_drop(x)
        return x

1.5.3 待续

1.6 PyTorch应用实例(待补充)

二、 Swin-Transformer

  • 参考:太阳花的小绿豆帖子《Swin-Transformer网络结构详解》、讲解视频、代码地址、代码讲解视频
  • 论文名称:Swin Transformer: Hierarchical Vision Transformer using Shifted Windows、官方开源代码
  • Pytorch实现代码及Swin Transformer API、Tensorflow2实现代码
  • 《Swin Transformer 论文详解及程序解读》

2.1 模型简介

  Swin transformer(Shifted Windows移动窗口)是微软研究院于2021年3月25日发表,利用transformer架构处理计算机视觉任务,在图像分割,目标检测各个领域已经霸榜(之前的VIT只能做图片分类)。比如打开其官网代码可以看到:(这排名不是卷死?)
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第12张图片
点开第一个coco测试集上的精度:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第13张图片
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第14张图片

标准的Transformer直接用到视觉领域有一些挑战,即:

  1. 多尺度问题,即图片的尺度不统一。
  2. 相比较于文本信息,图片有更大的像素分辨率,Transformer的计算复杂度是token数量的平方(每个token都要与其他token计算QK值)。如果将每个像素值算作一个token,其计算量非常大,不利于在多种机器视觉任务中的应用。
  • Vision Transformer进行WSA计算时,任何一个patch都要与其他所有的patch都进行attention计算。当patch的大小固定时,计算量与图片的大小成平方增长。
  • Swin Transformer中采用了W-MSA,只对window内部进行MSA,当图片大小增大时,计算量仅仅是呈线性增加。
  • 滑动窗口在局部不重叠的窗口中计算自注意力,并允许跨窗口连接。window self-attention大大降低了降低了计算复杂度。同时通过Shiting(移动)的操作可以使相邻的两个窗口之间进行交互,也因此上下层之间有了cross-window connection,从而变相达到了全局建模的能力。
  • 分层结构使得模型能够灵活处理不同尺度的图片,并且计算复杂度与图像大小呈线性关系。

所以最终Swin Transformer计算量比VIT更少,且在ImageNet上的效果也比VIT更好。

2.2 模型结构

  对比下Swin Transformer和之前的Vision Transformer,可以看出两点不同:

  • 层次化构建方法(Hierarchical feature maps) :Swin Transformer使用了类似卷积神经网络中的层次化构建方法,

  比如特征图尺寸中有对图像下采样4倍的,8倍的以及16倍的,这样的backbone有助于在此基础上构建目标检测,实例分割等任务。而在之前的Vision Transformer中是一开始就直接下采样16倍,且一直不变

  • W-MSA :使用窗口(Window)的形式将特征图划分成了多个不相交的区域,并且只在每个窗口(Window)内进行Multi-Head Self-Attention,大大减少计算量。

  比如在下图的4倍下采样和8倍下采样中,相对于Vision Transformer中直接对整个(Global)特征图进行Multi-Head Self-Attention,Swin Transformer只在窗口内做。这样能够减少计算量,尤其是在浅层特征图很大的时候。
  这样做虽然减少了计算量,但也会隔绝不同窗口之间的信息传递。所以在论文中作者又提出了 Shifted Windows Multi-Head Self-Attention(SW-MSA)的概念,通过此方法能够让信息在相邻的窗口中进行传递,后面会细讲。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第15张图片
  原论文中给出的关于Swin Transformer(Swin-T)网络的架构图如下:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第16张图片

  1. Patch Partition:如上图:
    • Patch Partition层会用一个4x4大小的窗口对输入图片进行分割(每4x4大小的相邻像素为一个Patch)
    • 对每个窗口都在channel方向展平(每个像素三通道,16个像素就48channel)
    • 最后通过Linear Embeding层将每个像素的channel数调整为C,并对每个channel做了一次Layer Norm。(swin-transformer有T、S、B、L等不同大小,其C的值也不同)。

  假设输入的是RGB三通道图片,那么每个patch就有4x4=16个像素,然后每个像素有R、G、B三个值所以展平后是16x3=48,所以通过Patch Partition后图像shape由 [H, W, 3]变成了 [H/4, W/4, 48]
  线性变换时由48变成C。图像shape由 [H/4, W/4, 48]变成了 [H/4, W/4, C]
  其实在源码中Patch PartitionLinear Embeding就是直接通过一个卷积层实现的,和之前Vision Transformer中讲的 Embedding层结构一模一样。(kernel size=4×4,stride=4,num_kernel=48)

  1. 通过四个Stage构建不同大小的特征图,除了Stage1中先通过一个Linear Embeding层外,剩下三个stage都是先通过一个Patch Merging层进行下采样。(2倍下采样的同时通道数翻倍)
  2. 重复堆叠Swin Transformer Block偶数次。这是因为Block其实有两种结构,两个结构是成对使用的。

  如图(b)中所示。这两种结构的不同之处仅在于一个使用了W-MSA结构,一个使用了SW-MSA结构。先使用一个W-MSA结构再使用一个SW-MSA结构。

  1. 分类网络,后面还会接上一个Layer Norm层、全局池化层以及全连接层得到最终输出。图中没有画,但源码中是这样做的。

  接下来,在分别对Patch MergingW-MSASW-MSA以及使用到的相对位置偏置(relative position bias)进行详解。关于Swin Transformer Block中的MLP结构和Vision Transformer中的结构是一样的,不再赘述。

2.3 Patch Merging

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第17张图片

  上面讲了,在每个Stage中首先要通过一个Patch Merging层进行下采样(Stage1除外)。
如上图所示,假设输入的是一个4x4大小的单通道特征图(feature map),分割窗口大小为2×2,进行的操作如下:

  1. 分割:Patch Merging会将每个2x2的相邻像素划分为一个patch,然后将每个patch中相同位置(同一颜色)像素给拼在一起,得到了4个feature map。
  2. caoncat拼接:将这四个feature map在深度方向进行concat拼接
  3. LayerNorm处理
  4. 最后通过一个全连接层对每个像素的channel进行改变,将feature map的深度由C变成C/2。

可以看出,通过Patch Merging层后,feature map的高和宽会减半,深度会翻倍(channel由1变为2,高宽由4变为2)。

2.4 W-MSA和SW-MSA

2.4.1 W-MSA

  W-MSA也就是window Multi-heads Self-attention模块。普通的Multi-heads Self-attention会对feature map中的每个像素(或称作token,patch)都要计算Self-Attention。而W-MSA模块,首先将feature map按照MxM大小划分成一个个Windows,然后单独对每个Windows内部进行Self-Attention。

目的:减少计算量(下图可以看出两种方式分别是多少计算量)
缺点:窗口之间无法进行信息交互,等于减少了感受野,无法看到全局信息
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第18张图片

具体的计算过程可以参考:太阳花的小绿豆帖子《Swin-Transformer网络结构详解》第三章

2.4.2 SW-MSA(Shifted Windows Multi-Head Self-Attention)

  与W-MSA不同的地方在于这个模块存在滑动,所以叫做shifted window。滑动距离是window_size//2,方向是向右和向下。
  滑动窗口是为了解决W-MSA计算attention时,窗口与窗口之间无法进行信息传递的问题。如下图所示,左侧是网络第L层使用的W-MSA模块,右侧是第L+1层使用SW-MSA模块。对比可以发现,窗口(Windows)发生了偏移。

  比如对于第一行第2列的2x4的窗口,它能够使第L层的第一排的两个窗口信息进行交流。再比如,第二行第二列的4x4的窗口,他能够使第L层的四个窗口信息进行交流,其他的同理。那么这就解决了不同窗口之间无法进行信息交流的问题。

在这里插入图片描述
  但是这样也有一个问题:偏移后,窗口数由原来的4个变成了9个,后面又要对每个窗口内部进行MSA,非常麻烦。为此,作者又提出而了Efficient batch computation for shifted configuration,一种更加高效的计算方法。(论文中是上图下部分图示)

2.4.3 Masked MSA

  小绿豆感觉上图不够明晰,又重新画了个。下图左侧是刚刚通过偏移窗口后得到的新窗口,右侧是为了方便大家理解,对每个窗口加上了一个标识。

  • 0对应的窗口标记为区域A
  • 3和6对应的窗口标记为区域B
  • 1和2对应的窗口标记为区域C
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第19张图片
  1. 将区域A和C移到最下方
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第20张图片
  2. 再将区域A和B移至最右侧
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第21张图片
  3. 分成4个4x4的窗口
    如下图所示,移动完后,4是一个单独的窗口;5和3合并成一个窗口;7和1合并成一个窗口;8、6、2和0合并成一个窗口。这样又和原来一样是4个4x4的窗口了,所以能够保证计算量是一样的。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第22张图片
  4. Masked MSA计算。
    上图这样划分之后,还有个问题,就是合并的窗口本身是不相邻的,比如5和3,如果直接进行MSA计算,是有问题的。我们希望是能够单独计算区域3和区域5各自区域内的MSA,论文中给的方法是Masked MSA,来隔绝不同区域的信息。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第23张图片
      如上图,区域5和区域3为例。对于该窗口内的每一个像素,都要先生成对应的query,key和value,然后与每一个像素进行attention计算。设 α 0 , 0 \alpha _{0,0} α0,0代表 q 0 q^0 q0与像素0对应的 k 0 k^0 k0进行匹配得到的attention score,同理可以得到 α 0 , 1 \alpha _{0,1} α0,1 α 0 , 15 \alpha _{0,15} α0,15
      接下来就是SoftMax操作,但是对于Masked MSA,不同区域之间的像素计算的attention score会减去100(attention score∈[0,1],减去100是一个很大的负数,经过softmax之后基本等于0了,后续加权求和结果也是0),这样等于不同区域之间的像素计算的attention被置为0,被屏蔽了。最终像素0计算的attention结果,还是和本区域5各个像素计算之后的结果。
      注意:在计算完后还要把数据给挪回到原来的位置上(例如上述的A,B,C区域)

  Efficient batch computation for shifted configuration简单说,就是通过移动合并,将9个窗口还是变为原来的4个窗口,再进行Masked MSA计算。计算量和普通的MSA一样,只是多了个mask。
  Masked MSA是为了解决合并窗口中各个窗口应该单独计算的问题。使用Masked MSA,将不同窗口元素计算的attention score-100,等价于屏蔽掉不同窗口元素的attention结果。最终达到了4个窗口同时进行MSA计算,又保证得到只在在窗口内进行计算的效果。

2.5 Relative Position Bias

  论文中还提到,使用相对位置偏置后给够带来明显的提升。(下图B就是偏置,ADE20k是图片分割数据集)
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第24张图片
  上图蓝色框是只使用W-MSA和同时使用W-MSA&SW-MSA的效果对比,后者更好。红色框是使用相对位置偏置之后的结果,效果更好。下面具体讲解什么是Relative Position Bias(假设特征图大小为2×2)

在这里插入图片描述

  1. 计算相对位置索引:比如蓝色像素,在蓝色像素使用q与所有像素k进行匹配过程中,是以蓝色像素为参考点。然后用蓝色像素的绝对位置索引与其他位置索引进行相减,就得到其他位置相对蓝色像素的相对位置索引,同理可以得到其他位置相对蓝色像素的相对位置索引矩阵(第一排四个位置矩阵)。

  2. 展平拼接:将每个相对位置索引矩阵按行展平,并拼接在一起可以得到第二排的这个4x4矩阵。

  3. 索引转换为一维:在源码中作者为了方便把二维索引给转成了一维索引。

    • 首先在原始的相对位置索引上加上M-1(M为窗口的大小,在本示例中M=2),加上之后索引中就不会有负数了。
    • 接着将所有的行标都乘上2M-1
    • 最后将行标和列标进行相加。这样即保证了相对位置关系,而且不会出现直接相加后位置重叠的问题。(0±1和-1+0结果都一样,但其实其位置不一样)
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第25张图片
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第26张图片
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第27张图片
  4. 取出相对位置偏置参数。真正使用到的可训练参数B 是保存在relative position bias table表里的,其长度是等于 ( 2 M − 1 ) × ( 2 M − 1 ) (2M-1) \times (2M-1) (2M1)×(2M1)。相对位置偏置参数B,是根据相对位置索引来查relative position bias table表得到的,如下图所示。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第28张图片

  为啥表长是 ( 2 M − 1 ) × ( 2 M − 1 ) (2M-1) \times (2M-1) (2M1)×(2M1)?考虑两个极端位置,(0,0)能取到的相对位置极值为(-1,-1),(-1,-1)能取到的极值是(1,1),即行和列都能取到(2M-1)个数。考虑到所有的排列组合,表的长度就是 ( 2 M − 1 ) × ( 2 M − 1 ) (2M-1) \times (2M-1) (2M1)×(2M1)

2.6 模型详细配置参数

模型结构和参数如下:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第29张图片

以Swin-T举例:

  • 模型一开始的Patch PartitionLinear Embeding层,其效果和Patch Merging层一样,都是进行下采样和调整channel。 concat4×4,96d,LN表示宽高都下采样4倍,调整后channel数为96,再经过一个Layer Norm层。
  • 堆叠两个Swin Transformer Block,其中:
    • win. sz. 7x7表示使用的窗口的大小(window size)
    • dim表示这个层输出的feature map的channel深度(或者说token的向量长度)
    • head表示多头注意力模块中head的个数
  • 后面以此类推,堆叠2、6、2个block。堆叠时是交替使用W-MSASW-MSA

2.7 代码讲解(待补充)

代码地址、讲解视频

三、MobileViT

论文名称:MobileViT: Light-Weight, General-Purpose, and Mobile-Friendly Vision Transformer
参考小绿豆的博文《MobileViT模型简介》
官方源码(Pytorch实现)、小绿豆的项目代码

3.1 为什么引入CNN与Transformer的混合架构

  自从2020年ViT(Vision Transformer)模型的横空出世,人们发现了Transformer架构在视觉领域的巨大潜力,视觉领域的各项任务也不断被Transformer架构模型刷新。同时其缺点也很明显,模型参数太大(比如ViT Large Patch16模型光权重就有1个多G),算力要求太高,这基本就给移动端部署Transformer模型判了死刑。
  Apple公司在2021年发表的一篇CNN与Transfomrer的混合架构模型——MobileViT:CNN的轻量和高效+Transformer的自注意力机制和全局视野。
  纯Transformer架构除了模型太重,还有一些其他的问题,比如:

  1. Transformer缺少空间归纳偏置(spatial inductive biases):
    • self-attention本身计算时是不考虑次序的,计算某个token的attention如果将其他token的顺序打乱对最终结果没有任何影响。
    • 为了解决这个问题,常见的方法是加上位置偏置(position bias)/位置编码,比如Vision Transformer中使用的绝对位置偏置,Swin Transformer中的相对位置偏置。
  2. Transformer模型迁移到其他任务(输入图像分辨率发生改变)时比较繁琐(相对CNN而言),主要原因是引入位置偏置导致的。
    • Vision Transformer的绝对位置偏置的序列长度是固定的,等于 H × W 16 × 16 \frac{H \times W}{16 \times 16} 16×16H×W。其中H、W代表输入图片的高和宽,所以只要改变输入图像的尺度就无法直接复用了。
    • 最常见的处理方法是通过插值的方式将位置偏置插值到对应图像的序列长度。但如果不对网络进行微调直接使用实际效果可能会掉点,如果每次改变输入图像尺度都要重新对位置偏置进行插值和微调,那也太麻烦了。

    比如在Imagenet上预训练好的网络(224x224),直接对位置偏置进行插值不去微调,在384x384的尺度上进行验证可能会掉点(CNN一般会涨点)。

    • Swin Transformer相对位置偏置的序列长度只和Windows大小有关,与输入图像尺度无关。但在实际使用中,一般输入图像尺度越大,Windows的尺度也会设置的大些。只要Windows尺度发生变化,相对位置偏置也要进行插值了。所以在Swin Transformer v2中就对v1的相对位置偏置进行了优化。
  3. Transformer相比CNN要更难训练
      比如Transformer需要更多的训练数据,需要迭代更多的epoch,需要更大的正则项(L2正则),需要更多的数据增强,且;对数据增强很敏感 。

      比如在MobileViT论文的引言中提到,如果将CutMix以及DeIT-style的数据增强移除,模型在Imagenet上的Acc直接掉6个点。

针对以上问题,现有的、最简单的方式就是采用CNN与Transformer的混合架构。

  • CNN能够提供空间归纳偏置所以可以摆脱位置偏置
  • 加入CNN后能够加速网络的收敛,使网络训练过程更加的稳定。

3.2 性能对比

  1. MobileViT与主流的一些Transformer模型对比
    通过下图可以看出,即使使用普通的数据增强方式,在ImageNet 1K验证集上,MobileViT也能达到更高的Acc并且参数数量更少。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第30张图片
  • basic:ResNet -style数据增强
  • advanced:basic数据增强+RandAugmentation+CutMix
  1. MobileViT与一些传统的轻量级CNN进行了对比
    如下图所示,在近似的参数数量下MobileViT的Acc要更高。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第31张图片
  2. 推理速度对比
    参数量不等于推理书速度。下表中,通过对比能够看到基于Tranaformer的模型(无论是否为混合架构)推理速度比纯CNN的模型还是要慢很多的(移动端)。作者在论文中给出解释主要还是说当前移动端对Transformer架构优化的还太少。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第32张图片

3.3 模型结构

Vision Transformer结构
  在讲MobileViT网络之前先简单回顾下Vision Transformer的网络结构。下图是MobileViT论文中绘制的Standard visual Transformer

  • 首先将输入的图片划分成一个个Patch,然后通过线性变化将每个Patch映射到一个一维向量中(视为一个个Token)
  • 接着加上位置偏置信息(可学习参数),通过一系列Transformer Block得到输出
  • 最后通过一个全连接层得到最终预测输出。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第33张图片

MobileViT结构
  下图对应的是论文中的图1(b),可以看到MobileViT主要由普通卷积,MV2MobileViT block,全局池化以及全连接层共同组成。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第34张图片

  • MV2MobiletNetV2中的Inverted Residual block,在本文4.3.1 Inverted residual block中有详细讲解。
  • 上图中标有向下箭头的MV2结构代表stride=2的情况,即需要进行下采样。
  • 下图是当stride=1时的MV2结构,有shortcut连接(输入输出size相同)
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第35张图片

3.4 MobileViT block

MobileViT block的大致结构如下:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第36张图片

  • 局部的特征建模:将特征图通过一个卷积核大小为nxn(代码中是3x3)的卷积层来完成
  • 调整通道数:通过1×1的卷积完成
  • 全局的特征建模:通过Unfold -> Transformer -> Fold结构来完成
  • 通道数调整回原始大小:通过1×1的卷积完成
  • shortcut:捷径分支与原始输入特征图沿通道方向拼接进行Concat拼接
  • 最终输出:最后再通过一个卷积核大小为nxn(代码中是3x3)的卷积层做特征融合得到输出。

  为了方便我们将Unfold -> Transformer -> Fold简写成Global representations,下面对此进行介绍。

  1. 首先对特征图划分Patch(这里为了方便忽略通道channels),图中的Patch大小为2x2
  2. 进行Self-Attention计算的时候,每个Token(图中的每个小颜色块),只和自己颜色相同的Token进行Attention,减少计算量。
  • 计算量降为原来的1/4。原始的Self-Attention计算,每个Token是需要和所有的Token进行Attention.
  • 为什么能这么做?
  1. 图像数据本身就存在大量的数据冗余,比如对于较浅层的特征图(H, W下采样倍率较低时),相邻像素间信息可能没有太大差异,如果每个Token做Attention的时候都要去看下相邻的这些像素,有些浪费算力。在分辨率较高的特征图上,增加的计算成本远大于Accuracy上的收益。
  2. 前面已经通过nxn的卷积层进行局部建模了,进行全局建模时就没必要再看这么细了
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第37张图片
  1. Unfold/Fold:只是为了将数据reshape成计算Self-Attention时所需的数据格式。
    • 普通的Self-Attention计算前,一般是直接展平H, W两个维度得到一个Token序列,即将[N, H, W, C] -> [N, H*W, C]其中N表示Batch维度
    • MobileViT blockSelf-Attention计算中,只是将颜色相同的Token进行了Attention,所以不能简单粗暴的展平H, W维度
    • Unfold:将相同颜色的Token展平在一个序列中,以便使用普通的Self-Attention来进行
    • Fold:计算完后将其折叠回原特征图
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第38张图片

3.5 Patch Size对性能的影响

  大的patch_size能够提升网络推理速度,但是会丢失一些细节信息。论文中给的图8,展示了两组不同的patch_size组合,在图像分类,目标检测以及语义分割三个任务中的性能。
下采样倍率为8,16,32的特征图所采用的patch_size大小分别为:

  • 配置A中,下采样倍率为8,16,32的特征图所采用的patch_size=[2, 2, 2]
  • 配置B中,下采样倍率为8,16,32的特征图所采用的patch_size=[8, 4, 2]
  • 对比发现,在图像分类和目标检测任务中(对语义细节要求不高的场景),配置A和配置B在Acc和mAP上没太大区别,只是配置B更快
  • 但在语义分割任务中(对语义细节要求较高的场景)配置A的效果要更好。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第39张图片

3.6 模型详细配置

  在论文中,关于MobileViT作者提出了三种不同的配置,分别是:MobileViT-S(small),MobileViT-XS(extra small)和MobileViT-XXS(extra extra small),三者的主要区别在于特征图的通道数不同。下图中的标出的Layer1~5,这里是根据源码中的部分配置信息划分的。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第40张图片
MobileViT-XXS,Layer1~5的详细配置信息如下:

layer	out_channels	mv2_exp	transformer_channels	ffn_dim	  patch_h	patch_w	  num_heads
layer1		16				2			None				None	None	None	    None
layer2		24				2			None				None	None	None	    None
layer3		48				2			64					128		2		2			4
layer4		64				2			80					160		2		2			4
layer5		80				2			96					192		2		2			4

MobileViT-XS,Layer1~5的详细配置信息如下:

layer	out_channels	mv2_exp	transformer_channels	ffn_dim	  patch_h 	patch_w 	num_heads
layer1		32				4			None				None	None	None			None
layer2		48				4			None				None	None	None			None
layer3		64				4			96					192		2		2				4
layer4		80				4			120					240		2		2				4
layer5		96				4			144					288		2		2				4

对于MobileViT-S,Layer1~5的详细配置信息如下:

layer	out_channels	mv2_exp	transformer_channels	ffn_dim	 patch_h	patch_w	num_heads
layer1		32				4			None			 None	  None		  None	  None
layer2		64				4			None			 None	  None		  None	  None
layer3		96				4			144				 288	  2			  2		  4
layer4		128				4			192				 384	  2			  2		  4
layer5		160				4			240				 480	  2			  2		  4

其中:

  • out_channels:表示该模块输出的通道数
  • mv2_exp:表示Inverted Residual Block中的expansion ratio(倍率因子)
  • transformer_channels:表示Transformer模块输入Token的序列长度(特征图通道数)
  • num_heads:表示多头自注意力机制中的head数
  • ffn_dim:表示FFN中间层Token的序列长度
  • patch_h/patch_w:表示每个patch的高度/宽度

四、MobileNet系列模型

  • 参考博文《MobileNet(v1、v2)网络详解与模型的搭建》、《轻量级神经网络MobileNet全家桶详解》
  • 模型讲解视频 《MobileNet(v1,v2)网络详解视频》、《MobileNetv3网络详解》
  • github代码地址、代码讲解《使用pytorch搭建MobileNetV2》、《使用Pytorch搭建MobileNetV3》、PyTorch API

4.1 前言

  传统的CNN网络已经普遍应用在计算机视觉领域,并且已经取得了不错的效果。但是发展到现在,模型深度越来越深,模型越来越复杂,预测和训练需要的硬件资源也逐步增多,导致无法在移动设备以及嵌入式设备上运行。
  深度学习领域内也在努力促使神经网络向小型化发展。在保证模型准确率的同时体积更小,速度更快。2016年直至现在,业内提出了SqueezeNet、ShuffleNet、NasNet、MnasNet以及MobileNet等轻量级网络模型,这些模型使移动终端、嵌入式设备运行神经网络模型成为可能。
  MobileNet在轻量级神经网络中较具代表性,特别是谷歌在2019年5月份推出了最新的MobileNetV3。在ImageNet数据集上,最新的MobileNetV3-Large的Top1准确率达到75.2%。本章将对MobileNet进行详细解析。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第41张图片
MobileNet系列模型性能对比:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第42张图片图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第43张图片

MobileNet可以在移动终端实现众多的应用,包括目标检测,目标分类,人脸属性识别和人脸识别等。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第44张图片
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第45张图片

4.2 MobileNetV1

  MobileNetV1网络类似于VGG,各个block串行连接,只不过在传统卷积层基础上加入了Depthwise Separable Convolution(深度可分卷积)。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第46张图片
  为了适配更定制化的场景,MobileNet引入了两个超参数: 宽度因子width multiplier和分辨率因子resolution multiplier,分别记为α和β:

  • α:控制卷积层卷积核个数,按比例减少/增加特征数据通道数大小,调整计算量
  • β:控制输入图像大小,仅仅影响计算量,但是不改变参数量

4.2.1 深度可分离卷积Depthwise separable convolution

  MobileNet网络基本单元是深度可分离卷积(depthwise separable convolution) ,可以大大减少运算量和参数数量,是其一大亮点。

  1. 传统卷积:每个卷积核的channel与输入特征矩阵的channel相等,即每个卷积核都会与输入特征矩阵的每一个维度进行卷积运算
  2. DW卷积 (depthwise convolution):每个卷积核的channel都是等于1的,即每个卷积核只负责输入特征矩阵的一个channel。所以有 n u m k e r n e l = c h a n n e l i n = c h a n n e l o u t num_{kernel}=channel_{in}=channel_{out} numkernel=channelin=channelout。(卷积核的个数=输入矩阵的通道数=输出矩阵的通道数)

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第47张图片

  1. 深度可分卷积 :DW卷积+PW卷积(pointwise convolution)。
    刚刚说了使用DW卷积后 n u m k e r n e l = c h a n n e l i n = c h a n n e l o u t num_{kernel}=channel_{in}=channel_{out} numkernel=channelin=channelout,如果想改变/自定义输出特征矩阵的channel,那只需要在DW卷积后接上一个PW卷积即可(普通的1×1卷积),通常DW卷积和PW卷积是放在一起使用的,合称深度可分卷积Depthwise Separable Convolution。

计算量对比

  深度可分卷积与传统的卷积相比有到底能节省多少计算量呢,下图对比了这两个卷积方式的计算量。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第48张图片
  卷积计算量≈卷积核宽高×输入channel×卷积核个数×输出矩阵宽高。假设stride=1,输入输出特征矩阵大小一样,宽高都是Df。则有:

  • Df是输入特征矩阵的宽高(这里假设宽和高相等)
  • Dk是卷积核的大小
  • M是输入特征矩阵的channel,N是输出特征矩阵的channel
  • 普通卷积计算量≈ D k × D k × M × N × D f × D f D_{k}\times D_{k}\times M \times N \times D_{f} \times D_{f} Dk×Dk×M×N×Df×Df
  • DW计算量是≈ D k × D k × M × D f × D f D_{k}\times D_{k}\times M \times D_{f} \times D_{f} Dk×Dk×M×Df×Df,PW计算量≈ M × N × D f × D f M \times N \times D_{f} \times D_{f} M×N×Df×Df
  • mobilenet网络中DW卷积都是是使用3x3大小的卷积核。所以理论上普通卷积计算量是DW+PW卷积的8到9倍。

4.2.2 MobileNetV1网络结构

MobileNetV1网络结构如下图所示:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第49张图片

  • Conv:普通卷积
  • Conv dw:DW卷积
  • s:步距
  • Filter Shape:卷积核尺寸。比如:
    • 第一层3×3×3×32表示卷积核大小是3×3,输入输出channel分别是3和32。
    • 第二层3×3×32 dw,因为卷积核channel=1,所以只有卷积核size和输出矩阵channel

右边表格是对比MobileNetV1和其它网络,以及使用不同的α、β参数时的准确率、计算量和参数量。其中:

  • α=0.75,表示卷积核个数缩减为原来的0.75倍。
  • β表示不同的输入图像尺寸

4.3 MobileNet v2

  在MobileNet v1的网络结构表中能够发现,网络的结构就像VGG一样是个直筒型的,没有残差结构。而且网络中的DW卷积很容易训练废掉,效果并没有那么理想。MobileNet v2网络是由google团队在2018年提出的,相比MobileNet V1网络,准确率更高,模型更小。
  如果说MobileNet v1网络中的亮点是DW卷积,那么在MobileNet v2中的亮点就是Inverted residual block(倒残差结构)
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第50张图片

4.3.1 Inverted residual block

  1. Inverted residual block结构如下图所示:
  • 左侧是ResNet网络中的残差结构,采用的是1x1卷积降维->3x3卷积->1x1卷积升维(两头大中间小的瓶颈结构),使用的是ReLU激活函数。
  • 右侧就是MobileNet v2中的倒残差结构。与上面相反,采用的是1x1卷积升维->3x3DW卷积->1x1卷积降维。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第51张图片
  1. 为什么要使用倒残差结构?
    原文的解释是高维信息通过ReLU激活函数后丢失的信息更少。下图所示,作者做了一系列实验:
  • 假设输入是2D矩阵(二维),channel=1
  • 使用不同matrix (矩阵T)将其变换到高维空间,再使用RELU激活函数得到输出值
  • 使用T的逆矩阵 T − 1 T^{-1} T1,将刚刚的输出还原为2D矩阵
    • output/dim=2表示矩阵T的维度为2。可以看到还原回2D后,丢失了很多信息
    • 随着T的维度不断加深,比如output/dim=30,丢失的信息越来越少
  • 结论:ReLU激活函数对低维信息造成大量损失,但是对高维信息,造成的损失较小
  1. Inverted residual block激活函数设计:
    中间使用ReLU6激活函数,最后一个1x1的卷积层使用的是线性激活函数(最后一层输入是降维后的,像刚刚讲的,不能再使用ReLU激活函数)。所以也叫Linear Bottleneck线性瓶颈结构。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第52张图片
    RELU6激活函数公式为:
    y = R E L U 6 ( x ) = m i n ( m a x ( x , 0 ) , 6 ) y=RELU6(x)=min(max(x,0),6) y=RELU6(x)=min(max(x,0),6)
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第53张图片
      可以看出,对比RELU函数,唯一的改变就是将最大值截断为6。
  2. Inverted residual block参数:
  • 第一层1x1卷积升维(BN+RELU6):输入图片高宽为h和w,channel=k。 t是升维扩展因子,即卷积核个数
  • 第二层3×3的dw卷积(BN+RELU6):输入channel=输出channel,步距=s
  • 第三层1x1卷积降维(BN):卷积核个数为 k ‘ k^` k
  • 注意:并不是每个倒残差结构都有shortcut。
    只有当stride=1且输入特征矩阵与输出特征矩阵shape相同时才有shortcut连接,比如下图stride=2 的结构就没有shortcut。因为只有当shape相同时,两个矩阵才能做加法运算。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第54张图片

4.3.2 MobileNet v2网络结构

  MobileNetV2网络模型中有共有17个Bottleneck层(每个Bottleneck包含两个pw卷积层和一个dw卷积层),一个标准卷积层(conv),两个pw conv组成,共计有54层可训练参数层。
  MobileNetV2中使用线性瓶颈和Inverted Residuals结构优化了网络,使得网络层次更深了,但是模型体积更小,速度更快了。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第55张图片

  • t:上一节讲的倒残差结构第一层的扩展倍率,将输入矩阵channel扩展t倍。
  • c:输出特征矩阵的channel,即上一节表中的 k ‘ k^` k
  • n:每个Operater模块中倒残差结构重复的次数
  • s:每个模块第一层倒残差结构的步距,后面层的步距都是1(也就是每个模块只有第一层会改变channel)
  • k:代表分类的类别数

  按照上一节讲的,只有当stride=1且输入特征矩阵与输出特征矩阵shape相同时才有shortcut连接。所以上图红色框选的模块:

  • 第一层:虽然s=1,但是输入输出channel分别是64和96,所以没有shortcut
  • 后两层:s=1,且输入输出channel都是96,size都是14×14,所以有shortcut

4.3.3 MobileNet v2性能对比

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第56张图片

  • 第一张表中MobileNet v2 (1.4)表示倍率因子α=1.4,也就是卷积核个数增加为原来的1.4倍。
  • 第二张表中,是将MobileNet和SSD联合使用进行目标检测。在CPU(自家安卓手机)上200ms检测一张图片,已经不错了。

MobileNet的提出,基本实现了在移动设备和嵌入式设备上跑深度学习模型了。

4.4 MobileNetv3

github项目地址

MobileNetv3是Google在2019年提出的,主要有三点比较重要:

  • 更新block,论文中称为bneck:引入Squeeze-and-excitation(SE)模块和 h-swish(HS)激活函数以提高模型精度
  • 使用NAS(神经架构搜索)搜索参数
  • 重新设计耗时结构:作者对搜索后的网络结构每一层进行耗时分析,针对耗时多的结构进行了进一步优化
    • 第一层普通卷积层卷积核个数由32降为16,耗时减少2ms
    • 最后一个stage去除3x3 Dconv,1x1Conv等卷积层,耗时减少7ms

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第57张图片
性能对比:

  在ImageNet数据集上,V3-Large 1.0V2 1.0的Acc分别是75.2%和72.0%,前者推理速度快了20%。(MAdds是计算量,P-1、P-2、P-3是不同手机上的推理速度。这里的1.0是上面讲的宽度因子α)
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第58张图片

4.4.1 SE模块

  SE模块首次提出是在2017年的Squeeze-and-Excitation Networks(SENet)网络结构中,在MobileNetV3中进行改进并大量使用。
  研究人员期望通过精确的建模卷积特征各个通道之间的作用关系来改善网络模型的表达能力。为了达到这个期望,提出了一种能够让网络模型对特征进行校准的机制,使得有效的权重大,无效或效果小的权重小的效果,这就是SE模块
  MobileNetV3的SE模块由一个全局平均池化层,两个全连接层组成。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第59张图片

  • Squeeze:将输入矩阵的每个channel都进行池化处理得到一维向量。向量维度=输入矩阵channel
  • Excitation:再经过两个全连接层得到每个channel的权重。
    这两步可以理解为对输入矩阵的每个channel分析出一个权重关系,重要的channel会赋予更大的权重。
    • 第一个全连接层节点个数=1/4*输入矩阵channel,激活函数为RELU
    • 第二个全连接层节点个数=输入矩阵channel,激活函数为H-sig,也就是Hard-sigmoid
  • scale:将SE模块输入矩阵与通道权重相乘,得到最终输出

下面举一个简单的例子说明:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第60张图片
  如上图所示,输入矩阵有两个channel(黄色和蓝色),池化后一维向量有两个元素[0.25,0.3]。将其经过两个Linear层处理得到两个channel的权重[0.5,0.6]。将这个权重每个元素分别和输入矩阵各个channel相乘,得到SE模块的最终输出。

4.4.2 bneck

MobileNetV3更新了block,论文中称为bneck,其改动如下:

  • 上部分是V2的倒残差结构,详情见上一节的4.3.1 Inverted residual block
  • 下部分是V3的block结构
    • 加入SE模块(乘上channel权重,类似注意力机制)
    • 更新了激活函数,在下一节会详细将。图中NL表示非线性激活函数
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第61张图片
  • ResNet中添加SE模块形成SE-ResNet网络,SE模块是在bottleneck结构之后加入的
  • MobileNetV3版本中SE模块加在了bottleneck结构的内部,在dw卷积后增加SE块,scale操作后再做pw卷积,SERadio=0.25(模块中第一个全连接层的节点个数,是输入特征矩阵channels的1/4)。
  • 使用SE模块后,MobileNetV3的参数量相比MobileNetV2多了约2M,但是MobileNetV3的精度得到了很大的提升。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第62张图片

4.4.3 swish/sigmoid替换为h-swish/h-sigmoid

  在V2中,Inverted residual block基本都是使用的RELU6激活函数。但在V3中,对其进行改进。如下图所示:

  1. 激活函数swish:可以提高Acc,但是求导、计算复杂,而且量化过程不友好(移动端一般都会对计算过程量化)
    s w i s h ( x ) = x ∗ s i g m o i d ( x ) swish(x)=x*sigmoid(x) swish(x)=xsigmoid(x)
  2. h-sigmoid激活函数:下图可见,其曲线接近于sigmoid函数。
  3. h-swish激活函数:将公式中的sigmoid激活函数用h-sigmoid激活函数替代,则
    h − s w i s h ( x ) = x ∗ R E L U 6 ( x + 3 ) 6 h-swish(x)=x*\frac{RELU6(x+3)}{6} hswish(x)=x6RELU6(x+3)
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第63张图片
      原论文中,作者说swish替换为h-swishsigmoid替换为h-sigmoid之后,推理速度得到提升,而且对量化过程比较友好。

4.4.4 重新设计耗时层结构

对耗时层结构改进了两点:

  • 第一个卷积层卷积核个数由32降为16,Acc不变,耗时减少2ms(可以看上面V1和V2的网络结构,第一个普通卷积的卷积核都是32)
  • 精简Last Stage:NAS搜索出的网络最后一层称之为Last Stage,作者觉得非常耗时,将其精简为Efficient Stage。
    精简后Acc基本不变,耗时减少7ms(占推理时间的11%)
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第64张图片

4.4.5 NAS

1. NAS简介

  V3的特别之处在于网络结构是使用基于神经架构搜索技术(NAS)学习出来的,使得V3得以将其他很多网络中的优秀特性都集于一身,而在V3之前的V1、V2版本中,网络结构则是由研究人员经过人工设计和计算得到的。本节仅介绍MobileNetV3与NAS的一些相关内容,不对NAS的技术细节展开。
  神经架构搜索(Network Architecture Search, NAS):是一种试图使用机器,自动的在指定数据集的基础上通过某种算法,找到在此数据集上效果最好的神经网络结构和超参数的方法 ,可以一定程度上解决研究人员设计一个网络的耗时的问题。NAS甚至可以发现某些人类之前未曾提出的网络结构,这可以有效的降低神经网络的使用和实现成本。
  目前市面上也已经出现了许多运用NAS技术的产品,如AutoML、OneClick.AI、Custom Vision Service、EasyDL等。在之前一些网络模型中,如NasNet、MNasNet、AmoebaNet、MobileNet,也使用了NAS技术。

2. NAS原理

  • 搜索:给定一个称为搜索空间的候选神经网络结构集合(即搜索空间包含了如:深度卷积、逐点卷积、常规卷积、卷积核、规范化、线性瓶颈、反向残差结构、SE模块、激活函数等等可作为原子的结构),用某种策略从中搜索出最优网络结构。
  • 评估:用某些指标如精度、速度来度量神经网络结构的性能优劣。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第65张图片

搜索空间,搜索策略,性能评估策略是NAS算法的核心要素。

  • 搜索空间:定义了可以搜索的神经网络结构的集合,即解的空间。
  • 搜索策略:定义了如何在搜索空间中寻找最优网络结构。
  • 性能评估策略:定义了如何评估搜索出的网络结构的性能。

对这些要素的不同实现得到了各种不同的NAS算法。

  • 常见算法:全局搜索空间、cell-based 搜索空间、factorized hierarchical search space分层搜索空间、one-shot 架构搜索等
  • 优化算法:基于强化学习的算法、基于进化算法的算法、基于代理模型的算法等。

3. MobileNetV3中的NAS

  • 使用platform-aware NAS搜索全局网络结构的优化block,也就是从搜索空间的集合中根据预定义的网络模板搜索出网络结构;
  • 使用NetAdapt算法针对block中的每一层搜索需要使用的卷积核个数。
  • 性能评估:对搜索出的网络进行性能评估。MobileNetV3是使用真实手机的cpu(pixel-1手机)运行TFLite Benchmark Tool进行性能评估。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第66张图片

4.4.6 MobileNetv3网络结构

MobileNetv3有small和large两个版本。

  • Large版本共有15个bottleneck层,一个标准卷积层,三个逐点卷积层。
  • Small版本共有12个bottleneck层,一个标准卷积层,两个逐点卷积层。

其详细网络结构如下:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第67张图片
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第68张图片

  • out:输出矩阵通道数
  • HL:非线性激活函数。HS表示h-swish,RE表示RELU激活函数
  • bneck 3×3:bneck就是左侧图结构,3×3是dw卷积核的大小
  • exp size:bneck第一个卷积层升维后的channel数。经过dw卷积核SE模块后通道数不变。最后经过pw卷积进行降维,降维后的维度就是out
  • SE:是否使用SE模块
  • NBN:最后两个卷积层不使用Batch Norm
  • 第一个bneck结构,exp size=out,即没有进行升维。所以这一层没有第一个1×1升维卷积层。其它bneck和之前讲的一样。

五、ConvNeXt

参考博文《ConvNeXt网络详解》、模型讲解视频;代码地址、代码讲解视频;PyTorch API

5.1 前言

  自从ViT(Vision Transformer)在CV领域大放异彩,越来越多的研究人员开始拥入Transformer的怀抱。回顾近一年,在CV领域发的文章绝大多数都是基于Transformer的,比如2021年ICCV 的best paper Swin Transformer,而卷积神经网络已经开始慢慢淡出舞台中央。
  2022年一月份,Facebook AI Research和UC Berkeley一起发表了一篇文章A ConvNet for the 2020s,在文章中提出了ConvNeXt纯卷积神经网络,它对标的是2021年非常火的Swin Transformer
  通过一系列实验比对,在相同的FLOPs下,ConvNeXt相比Swin Transformer拥有更快的推理速度以及更高的准确率,在ImageNet 22K上ConvNeXt-XL达到了87.8%的准确率,参看下图:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第69张图片
  上图红色框选这一栏是在A100上,每秒推理图片的数量。不仅是在ImageNet上,在coco数据集和ADE20K数据集上的效果也更好。

  阅读论文会发现,ConvNeXt使用的全部都是现有的结构和方法,没有任何结构或者方法的创新。而且源码也非常的精简,100多行代码就能搭建完成,相比Swin Transformer简直不要太简单。
  为什么现在基于Transformer架构的模型效果比卷积神经网络要好呢?论文中的作者认为可能是随着技术的不断发展,各种新的架构以及优化策略促使Transformer模型的效果更好,那么使用相同的策略去训练卷积神经网络也能达到相同的效果吗?抱着这个疑问作者就以Swin Transformer作为参考进行一系列实验。

5.2 实验设计

  作者首先利用训练vision Transformers的策略去训练原始的ResNet50模型,发现在ImageNet上的Top 1 ACC=78.8%,比原始效果要好很多,并将此结果作为后续实验的基准baseline。
  然后作者罗列了接下来实验包含哪些部分,以及每个方案对最终结果的影响(Imagenet 1K的准确率,见下图)。很明显最后得到的ConvNeXt在相同FLOPs下准确率(82%)已经超过了Swin-T(81.3%)。接下来,针对每一个实验进行解析。

ConvNeXt也有四个不同大小的版本,ConvNeXt 50对标的就是Swin-T,下图准确率也是这两者的对比数据。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第70张图片

  Our starting point is a ResNet-50 model. We first train it with similar training techniques used to train vision Transformers and obtain much improved results compared to the original ResNet-50. This will be our baseline. We then study a series of design decisions which we summarized as 1) macro design, 2) ResNeXt, 3) inverted bottleneck, 4) large kernel size, and 5) various layer-wise micro designs.

5.3 Macro design

在这个部分作者主要研究两方面:

  1. Changing stage compute ratio:

    • 在原ResNet网络中,一般conv4_x(即stage3)堆叠的block的次数是最多的。如下图中的ResNet50中stage1到stage4堆叠block的次数是(3, 4, 6, 3)比例大概是1:1:2:1
    • Swin Transformer中,比如Swin-T的比例是1:1:3:1,Swin-L的比例是1:1:9:1。很明显,在Swin Transformer中,stage3堆叠block的占比更高
    • 最后作者就将ResNet50中的堆叠次数由(3, 4, 6, 3)调整成(3, 3, 9, 3),和Swin-T拥有相似的FLOPs。进行调整后,准确率由78.8%提升到了79.4%
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第71张图片
  2. Changing stem to “Patchify”

    • 最初的卷积神经网络中,我们将下采样模块称之为stem。在ResNet中,stem是由一个卷积核大小为7x7步距为2的卷积层,以及一个步距为2的最大池化下采样共同组成,最终高和宽都下采样4倍(上图红色框)。
    • 但在Transformer模型中,下采样一般都是通过一个卷积核非常大且相邻窗口之间没有重叠的(即stride等于kernel_size)卷积层完成。比如在Swin Transformer中,采用的是一个卷积核大小为4x4步距为4的卷积层构成patchify,同样是下采样4倍。
    • 最后作者将ResNet中的stem也换成了和Swin Transformer一样的patchify。替换后准确率从79.4% 提升到79.5%,并且FLOPs也降低了一点。

5.4 ResNeXt-ify

  接下来作者借鉴了ResNeXt中的组卷积grouped convolution,而作者采用的是更激进的depthwise convolution,即group数和通道数channel相同。这样做的另一个原因是作者认为depthwise convolutionself-attention中的加权求和操作很相似。

  1. grouped convolution参考《学习笔记五:卷积神经网络原理、常见模型》3.8章节Resnext、Resnext讲解视频。
    • 组卷积简单讲,就是将输入矩阵的channel划分为g个组,然后对每个组分别进行卷积操作,最后将其在channel维度拼接,得到最终卷积结果。这样算下来,组卷积参数个数是常规卷积的1/g
    • 组卷积在不明显增加参数量级的情况下提升了模型的准确率,同时由于拓扑结构相同,超参数也减少了。
  2. depthwise convolution参考《MobileNet(v1、v2)网络详解与模型的搭建》、讲解视频。简单讲就是每个卷积核的channel=1。
  • 在传统卷积中,每个卷积核的channel与输入特征矩阵的channel相等(每个卷积核都会与输入特征矩阵的每一个维度进行卷积运算)。
    • 而在DW卷积中,每个卷积核的channel都是等于1的,即每个卷积核只负责输入特征矩阵的一个channel。故 n u m k e r n e l = c h a n n e l i n = c h a n n e l o u t num_{kernel}=channel_{in}=channel_{out} numkernel=channelin=channelout
    • 如果想改变/自定义输出特征矩阵的channel,那只需要在DW卷积后接上一个PW卷积(普通1×1卷积)即可。
    • DW卷积在准确率小幅降低的前提下,大大减少模型参数与运算量。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第72张图片
  如上图所示,ResNet和ResNeXt唯一区别就是将残差模块中间的普通卷积层替换为了组卷积层。但这个模块都是两头粗中间细的瓶颈结构(ResNet首尾两层channel=256,中间层channel=64。ResNeXt三层通道数分别是256,128,256)。

  1. 将中间3×3普通卷积层直接替换为DW卷积层后,准确率从79.5%降到78.3%,FLOPs差不多降低了一半。80.5%
  2. 增大输入特征层宽度。原先ResNet第一个stage输入特征层channel=64,而在Swin-T中是96。所以作者将最初的通道数由64调整成96,和Swin Transformer保持一致,最终准确率达到了80.5%
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第73张图片

5.5 Inverted Bottleneck

  作者认为Transformer block中的MLP模块非常像MobileNetV2中的Inverted Bottleneck模块,即两头细中间粗。所以将ResNet中采用的Bottleneck模块替换为Inverted Bottleneck模块。在较大模型上acc由81.9%提升到82.6%。

  • 下图a是ResNet中采用的Bottleneck模块,是一个两头粗中间细的瓶颈结构
  • b是MobileNetV2采用的Inverted Botleneck模块(图b的最后一个1x1的卷积层画错了,应该是384->96,后面如果作者发现后应该会修正过来)
  • c是ConvNeXt采用的是Inverted Bottleneck模块。

  关于MLP模块可以参考本文1.2.4 MLP Head,关于Inverted Bottleneck模块可以参考之前讲的MobileNetv2博文。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第74张图片

5.6 Large Kernel Sizes

  Large Kernel Sizes部分的两个改动是Moving up depthwise conv layerdepthwise conv模块上移)和Increasing the kernel size,如下图所示:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第75张图片

  1. depthwise conv模块上移。上移后,准确率下降到了79.9%,同时FLOPs也减小了。这么做是因为作者认为depthwise conv类似于Transformer中的MSA,而在transformer中,MSA模块是放在MLP模块之前的,所以这里进行效仿,将depthwise conv上移。
  2. 增大卷积核size,准确率从79.9% (3×3) 增长到 80.6% (7×7)。
    • 因为之前VGG论文中说通过堆叠多个3x3的窗口可以替代一个更大的窗口,而且现在的GPU设备针对3x3大小的卷积核做了很多的优化,会更高效,所以现在主流的卷积神经网络都是采用3x3大小的窗口。
    • 在Transformer中一般都是对全局做self-attention,比如Vision Transformer。即使是Swin Transformer也有7x7大小的窗口,所以作者将kernel size增大为7×7.
    • 当然作者也尝试了其他尺寸,包括3, 5, 7, 9, 11;发现取到7时准确率就达到了饱和。

5.7 Micro Design

  接下来作者在聚焦到一些更细小的差异,比如激活函数以及Normalization。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第76张图片

  1. 将CNN常用的激活函数ReLU替换为GELU(transformer),替换后准确率没变化。

  2. 使用更少的激活函数。在卷积神经网络中,一般会在每个卷积层或全连接后都接上一个激活函数。但在Transformer中并不是每个模块后都跟有激活函数,比如MLP中只有第一个全连接层后跟了GELU激活函数。所以作者在ConvNeXt Block中也减少激活函数的使用,如下图所示,减少后发现准确率从80.6%增长到81.3%

  3. 使用更少的Normalization。同样在Transformer中,Normalization使用的也比较少,接着作者也减少了ConvNeXt Block中的Normalization层,只保留了depthwise conv后的Normalization层。此时准确率已经达到了81.4%,已经超过了Swin-T。

  4. 将BN替换成LN,准确率小幅提升到81.5%。卷积神经网络中使用的是Batch Normalization(加速网络的收敛并减少过拟合),但在Transformer中基本都用的Layer Normalization(LN)。因为最开始Transformer是应用在NLP领域的,BN又不适用于NLP相关任务。

  5. 单独的下采样层(Separate downsampling layers),更改后准确率就提升到了82.0%。

    • ResNet网络中下采样方式并不合理

      • ResNet网络中stage2-stage4的下采样,都是通过设置主分支和右侧捷径分支的stride=2来进行下采样的。其中主分支kernel size=3×3,捷径分支kernel size=1×1。
      • 但其实这样右侧分支设置是不合理的,kernel size=1×1,stride=2则意味着1×1的格子每次移动2格,这样就丢失了3/4的信息。所以有了改进型的ResNet50-D。
      • ResNet50-D中,主分支不变,右侧分支是通过步长为2的池化层实现的。这样两边在下采样时都不会丢失信息,更加合理。
        图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第77张图片
    • 在Swin Transformer中,下采样是通过一个单独的Patch Merging实现的。

    • 作者就为ConvNext网络单独使用了一个下采样层,就是通过Laryer Norm+Conv 2×2,stride=2的卷积层构成。

5.8 ConvNeXt模型结构和不同版本的参数

  下面是小绿豆手绘的ConvNeXt模型结构图。仔细观察ConvNeXt Block会发现其中还有一个Layer Scale操作(即对每个channel的数据进行缩放,论文中并没有提到)。它将输入的特征层乘上一个可训练的参数,该参数就是一个向量,元素个数与特征层channel相同。

Layer Scale操作出自于Going deeper with image transformers. ICCV, 2021这篇文章,有兴趣的可以自行了解。

在这里插入图片描述
  对于ConvNeXt网络,作者提出了T/S/B/L四个版本,计算复杂度好和Swin Transformer中的T/S/B/L相似。其中C代表4个stage中输入的通道数,B代表每个stage重复堆叠block的次数。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第78张图片

5.9 代码讲解(待补充)

参考ConvNeXt代码地址、代码讲解视频

六、EfficientNet系列

6.1 EfficientNetV1

  • 原论文名称:EfficientNet: Rethinking Model Scaling for Convolutional Neural Networks、源码地址
  • 小绿豆实现的 pytorch代码、 tensorflow代码、代码讲解视频。博客《EfficientNet网络详解》、模型讲解视频

6.1.1 前言

  在之前的一些手工设计网络中(AlexNet,VGG,ResNet等等)经常有人问,为什么输入图像分辨率要固定为224,为什么卷积的个数要设置为这个值,为什么网络的深度设为这么深?这些问题你要问设计作者的话,估计回复就四个字——工程经验。
  而这篇论文主要是用NAS(Neural Architecture Search)技术来搜索网络的图像输入分辨率r ,网络的深度depth以及channel的宽度width三个参数的合理化配置。
  论文中提到,本文提出的EfficientNet-B7Imagenet top-1上达到了当年最高准确率84.3%,与之前准确率最高的GPipe相比,参数数量(Params)仅为其1/8.4,推理速度提升了6.1倍(看上去又快又轻量,但个人实际使用起来发现很吃显存)。下图是EfficientNet与当时主流的网络的对比(注意,参数数量少并不意味推理速度就快)。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第79张图片

6.1.2 论文思想

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第80张图片

  • 图a:baseline
  • 图b:增加网络宽度,能够获得更高细粒度的特征并且也更容易训练。但对于width很大而深度较浅的网络,往往很难学习到更深层次的特征。
  • 图c:增加网络的深度,使用更多层结构。能够得到更加丰富、复杂的特征并且能够很好的应用到其它任务中。但网络的深度过深会面临梯度消失,训练困难的问,
  • 图d:增加输入网络的分辨率,可以获得更高细粒度的特征模板。但是分辨率过高,acc增益会变少,且大幅增加计算量。
  • 图e:同时增加网络的width、网络的深度以及输入网络的分辨率来提升网络的性能(综合b、c、d)

下图虚线是分别增加width、depth、resolution后的结果,可以看到Accuracy达到80%时就趋于饱和了。而红色实线是三者同时增加,同计算量下,效果更好。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第81张图片
那么该如何同时增加width、depth和分辨率呢?

  1. 作者在论文中对整个网络的运算进行抽象:作者在论文中对整个网络的运算进行抽象:
    N ( d , w , r ) = ⊙ i = 1... s F i L i ( X ⟨ H i , W i , C i ⟩ ) N(d,w,r)=\underset{i=1...s}{\odot} {F}_i^{L_i}(X_{\left\langle{{H}_i, {W}_i, {C}_i } \right\rangle}) N(d,w,r)=i=1...sFiLi(XHi,Wi,Ci)
    其中:
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第82张图片
    论文中通过 NAS(Neural Architecture Search) 技术搜索得到的EfficientNetB0的结构,如下图所示:
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第83张图片
  2. 为了探究d , r , w 这三个因子对最终准确率的影响,则将其加入到公式中,我们可以得到抽象化后的优化问题(在指定资源限制下,其中s , t 代表限制条件),:
    其中s . t . s.t.s.t.代表限制条件:
    m a x d , w , r       A c c u r a c y ( N ( d , w , r ) ) s . t .      N ( d , w , r ) = ⊙ i = 1... s F ^ i d ⋅ L ^ i ( X ⟨ r ⋅ H ^ i ,   r ⋅ W ^ i ,   w ⋅ C ^ i ⟩ ) M e m o r y ( N ) ≤ t a r g e t _ m e m o r y            F L O P s ( N ) ≤ t a r g e t _ f l o p s          ( 2 ) \underset{d, w, r}{max} \ \ \ \ \ Accuracy(N(d, w, r)) \\ s.t. \ \ \ \ N(d,w,r)=\underset{i=1...s}{\odot} \widehat{F}_i^{d \cdot \widehat{L}_i}(X_{\left\langle{r \cdot \widehat{H}_i, \ r \cdot \widehat{W}_i, \ w \cdot \widehat{C}_i } \right\rangle}) \\ Memory(N) \leq {\rm target\_memory} \\ \ \ \ \ \ \ \ \ \ \ FLOPs(N) \leq {\rm target\_flops} \ \ \ \ \ \ \ \ (2) d,w,rmax     Accuracy(N(d,w,r))s.t.    N(d,w,r)=i=1...sF idL i(XrH i, rW i, wC i)Memory(N)target_memory          FLOPs(N)target_flops        (2)
    其中:
  • d用来缩放深度 L ^ i \widehat{L}_i L i
  • r 用来缩放分辨率即影响H ^ i H ^ i \widehat{H}_i H i W ^ i \widehat{W}_i W i
  • w就是用来缩放特征矩阵的channel即 C ^ i \widehat{C}_i C i
  • target_memory为memory限制
  • target_flops为FLOPs限制
  1. 接着作者又提出了一个混合缩放方法 compound scaling method 。在这个方法中使用了一个混合因子 ϕ \phi ϕ去统一的缩放width,depth,resolution参数,具体的计算公式如下(s.t.代表限制条件):

d e p t h : d = α ϕ w i d t h : w = β ϕ        r e s o l u t i o n : r = γ ϕ            ( 3 ) s . t .         α ⋅ β 2 ⋅ γ 2 ≈ 2 α ≥ 1 , β ≥ 1 , γ ≥ 1 depth: d={\alpha}^{\phi} \\ width: w={\beta}^{\phi} \\ \ \ \ \ \ \ resolution: r={\gamma}^{\phi} \ \ \ \ \ \ \ \ \ \ (3) \\ s.t. \ \ \ \ \ \ \ {\alpha} \cdot {\beta}^{2} \cdot {\gamma}^{2} \approx 2 \\ \alpha \geq 1, \beta \geq 1, \gamma \geq 1 depth:d=αϕwidth:w=βϕ      resolution:r=γϕ          (3)s.t.       αβ2γ22α1,β1,γ1
其中:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第84张图片
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第85张图片

6.1.3 网络详细结构

  下表为EfficientNet-B0的网络框架,网络总共分成了9个Stage(B1-B7就是在B0的基础上修改Resolution,Channels以及Layers):

  • Stage1:就是一个卷积核大小为3x3步距为2的普通卷积层(包含BN和激活函数Swish)
  • Stage2~Stage8:都是在重复堆叠MBConv结构(最后一列的Layers表示该Stage重复MBConv结构多少次)
  • Stage9:由一个普通的Conv 1×1(包含BN和激活函数Swish)、Pooling层和全连接层组成。
  • 倍率因子n:表格中每个MBConv后会跟一个数字1或6就是倍率因子n,表示MBConv中第一个1x1的卷积层会将输入特征矩阵的channels扩充为n倍。
  • k3x3或k5x5表示MBConv中Depthwise Conv所采用的卷积核大小。
  • Channels表示通过该Stage后输出特征矩阵的Channels。
  • Resolution是输入每个stage的特征图的高宽。
  • L ^ i \widehat{L}_i L i表示在该Stage中重复 F ^ i \widehat{F}_i F i的次数( F ^ i \widehat{F}_i F i表示对应Stage的运算操作)

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第86张图片

6.1.4 MBConv结构

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第87张图片
如图所示,MBConv(Mobile Conv)结构主要以下几个部分组成:

  1. Conv 1×1,stride=1:普通卷积层,作用是升维,包含BN和Swish;卷积核个数是输入特征矩阵channel的n倍。(上面提的倍率因子n,当n=1时不需要这一层)

  2. Depthwise Conv卷积,kernel size可以是3x3和5x5,也包含BN和Swish。

  3. SE模块:由一个全局平均池化,两个全连接层组成。

    • 第一个全连接层的节点个数是输入该MBConv特征矩阵channels的1/4且使用Swish激活函数。
    • 第二个全连接层的节点个数等于Depthwise Conv层输出的特征矩阵channels,且使用Sigmoid激活函数。
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第88张图片
  4. Conv 1×1,stride=1:普通卷积层,作用是降维

  5. Droupout

需要注意的是:

  • 关于shortcut连接,仅当输入MBConv结构的特征矩阵与输出的特征矩阵shape相同时才存在(代码中可通过stride==1 and inputc_channels==output_channels条件来判断)
  • 在源码实现中只有使用shortcut的时候才有Dropout层

6.1.5 EfficientNet(B0-B7)参数及性能对比

EfficientNetB0网络结构上面已经给出,其他版本的详细参数可见下表:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第89张图片

  • input_size:训练网络时输入网络的图像大小
  • width_coefficient:代表channel维度上的倍率因子,比如在 EfficientNetB0中Stage1的3x3卷积层所使用的卷积核个数是32,那么在B6中就是 32 × 1.8 = 57.6 32 \times 1.8=57.6 32×1.8=57.6,接着取整到离它最近的8的整数倍即56,其它Stage同理。
  • depth_coefficient:代表depth维度上的倍率因子(仅针对Stage2到Stage8),比如在EfficientNetB0中Stage7的L L ^ i = 4 {\widehat L}_i=4 L i=4 ,那么在B6中就是 4 × 2.6 = 10.4 4 \times 2.6=10.4 4×2.6=10.4接着向上取整即11。
  • drop_connect_rate:在MBConv结构中dropout层使用的drop_rate,在官方keras模块的实现中MBConv结构的drop_rate是从0递增到drop_connect_rate的(具体实现可以看下官方源码,注意,在源码实现中只有使用shortcut的时候才有Dropout层)。
  • 这里的Dropout层是Stochastic Depth,即会随机丢掉整个block的主分支(只剩捷径分支,相当于直接跳过了这个block)。也可以理解为减少了网络的深度。具体可参考Deep Networks with Stochastic Depth这篇文章。
  • dropout_rate是最后一个全连接层前的dropout层(在stage9的Pooling与FC之间)的dropout_rate。

最后给出原论文中关于EfficientNet与当时主流网络的性能参数对比:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第90张图片

6.2 EfficientNetV2

参考:

  • 《EfficientNetV2网络详解》、bilibil视频、项目地址
  • 《论文推荐:EfficientNetV2 - 通过NAS、Scaling和Fused-MBConv获得更小的模型和更快的训练速度》

6.2.1EfficientNetV2性能对比

  EfficientNetV2是在2021年4月份发布的,主要是做了两点改进:

  • 引入Fused-MBConv模块:将原来MBConv主分支中的expansion conv1x1和depthwise conv3x3替换成一个普通的conv3x3。替换后参数更少,训练更快。
  • 渐进式学习策略:根据训练图像的尺寸动态调节正则方法,提升了训练速度和准确率。
  1. 对比当时主流网络:
    • 紫色线是S/M/L三种尺寸的EfficientNetV2模型的准确率和推理速度
    • 红色线是S/M/L/XL四种尺寸的EfficientNetV2模型在ImageNet 21K上预训练,再在ImageNet 1K上进行微调,准确率更高。下图可以看到,其acc和推理速度比ViT-L16(21K)都更好。
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第91张图片

EfficientNetV2-M对比EfficientNetV1-B7,训练速度提升11倍,参数数量减少为1/6.8。

  1. 对比传统卷积神经网络/混合网络以及ViT网络:
    EfficientNetV2-S对标的就是EfficientNet=B5,可以发现其训练和推理速度更快。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第92张图片

  2. 对比EfficientNetV1
    EfficientNetV1中作者关注的是准确率,参数数量以及FLOPs(理论计算量小不代表推理速度快),在EfficientNetV2中作者进一步关注模型的训练和推理速度。

    • 表10 是EfficientNetV2-MEfficientNetV1-B7的各种指标对比。(准确率、参数量、理论计算量、训练和推理时间)
    • 表11 也可以看出EfficientNetV2V1在acc差不多的情况下,推理速度快很多。
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第93张图片

6.2.2 V1中存在的问题和V2的改进

作者系统性的研究了EfficientNet的训练过程,并总结出了三个问题:

  1. 训练图像的尺寸很大时,训练速度非常慢。

    • 在之前使用EfficientNet时发现当使用到B3(img_size=300)- B7(img_size=600)时基本训练不动,而且非常吃显存。
    • 通过下表可以看到,在Tesla V100上当训练的图像尺寸为380x380时,batch_size=24还能跑起来,当训练的图像尺寸为512x512时,batch_size=24时就报OOM(显存不够)了。
    • 针对这个问题一个比较好想到的办法就是降低训练图像的尺寸,这样不仅能够加快训练速度,还能使用更大的batch_size。
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第94张图片
  2. 网络浅层中使用Depthwise convolutions速度会很慢,故引入Fused-MBConv
    Fused-MBConv结构也非常简单,即将原来MBConv主分支中的expansion conv1x1和depthwise conv3x3替换成一个普通的conv3x3,如下图左侧所示。
    下表是不同stage的MBConv替换为Fused-MBConv的准确率和训练速度。作者使用NAS技术去搜索最佳组合,将浅层(stage1-3)替换为Fused-MBConv时效果最好。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第95张图片

  3. 非均匀缩放stage
      在EfficientNetV1中,每个stage的深度和宽度都是同等放大的(同等的看待每个stage)。但每个stage对网络的训练速度以及参数数量的贡献并不相同,所以直接使用同等缩放的策略并不合理。在这篇文章中,作者采用了非均匀的缩放策略来缩放模型(论文中没有给出策略,直接给出缩放后的参数)。
    图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第96张图片

6.2.3 EfficientNetV2网络框架

V1、V2框架的不同点

表4展示了作者使用NAS搜索得到的EfficientNetV2-S模型框架,相比与EfficientNetV1,主要有以下不同:

  1. 浅层使用了Fused-MBConv模块(stage1-3)
  2. 使用较小的expansion ratio,这样能够减少内存访问开销。

  expansion ratio就是上一节提到的倍率因子n,也就是下表中的MBConv4中的4,表示MBConv模块第一层会将输入通道数增大为原来的4倍。而在V1中,基本都是6。

  1. 使用更小(3x3)的kernel_size,而在V1中使用了很多5x5的kernel_size,所以V2需要堆叠更多的层结构以增加感受野。
  2. 移除了EfficientNetV1中的stage8(stride=1)。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第97张图片
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第98张图片
EfficientNetV2-S结构详情

  • Operator:在当前Stage中使用的模块

  • stride:该Stage第一个 Operator的步距,剩下的 Operator步距都是1(也就是每个模块只有第一层可能会下采样,后面层不变)

  • Channels:该Stage输出的特征矩阵的Channels

  • Layers:该Stage重复堆叠Operator的次数

  • Conv3x3:普通的3x3卷积 + 激活函数(SiLU)+ BN

  • Fused-MBConv1,k3×3:1表示expansion ratio,k表示kernel_size。

    • Fused-MBConv在论文中有SE模块,源码中没有。估计是SAN搜索后发现效果不好,删了
    • 当expansion ratio等于1时是没有expand conv的
    • 当stride=1且输入输出Channels相等时才有shortcut连接,shortcut连接时才有Dropout层
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第99张图片
    • MBConvFused-MBConv中(不包括全连接层中的dropout),Dropout层使用的是Stochastic Depth,随机丢掉整个block的主分支,只剩捷径分支,相当于直接跳过了这个block。
      图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第100张图片
  • MBConv模块和EfficientNetV1中是一样的。SE0.25表示使用了SE模块,且模块中第一个全连接层的节点个数,是输入特征矩阵channels的1/4 。(当stride=1且输入输出Channels相等时,才有shortcut连接和Stochastic Depth,详细的可以参考本文《4.1.4 MBConv结构》)
    在这里插入图片描述

6.2.4 Progressive Learning渐进学习策略

  • 动态的图像尺寸导致ACC降低:前面提到过,训练图像的尺寸对训练模型的效率有很大的影响。而如果尝试使用动态的图像尺寸(比如一开始用很小的图像尺寸,后面再增大)来加速网络的训练,但通常会导致Accuracy降低。
  • 动态的正则方法:作者猜想Acc的降低是不平衡的正则化unbalanced regularization导致的。在训练不同尺寸的图像时,应该使用动态的正则方法(之前都是使用固定的正则方法)。

  于是作者接着做了一些实验,训练过程中尝试使用不同的图像尺寸以及不同强度的数据增强。当训练的图片尺寸较小时,使用较弱的数据增强;当训练的图像尺寸较大时,使用更强的数据增强。如下表所示,当Size=128,RandAug magnitude=5时效果最好;当Size=300,RandAug magnitude=15时效果最好:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第101张图片
  基于以上实验,作者就提出了渐进式训练策略Progressive Learning。如上图所示:

  • 在训练早期(epoch = 1开始)使用较小的训练尺寸以及较弱的正则方法 weak regularization,这样网络能够快速的学习到一些简单的表达能力。
  • 接着逐渐提升图像尺寸,同时增强正则方法 。正则包括dropout rate,RandAugment magnitude以及mixup ratio。

在这里插入图片描述
训练流程的伪代码:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第102张图片
下表给出了EfficientNetV2(S,M,L)三个模型的渐进学习策略参数:
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第103张图片
  作者还在Resnet以及EfficientNetV1上进行了测试,使用了渐进式学习策略后确实能够有效提升训练速度并且能够小幅提升Accuracy。
图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第104张图片

6.2.5 配置文件

EfficientNetV2-S:在baseline的基础上采用了width倍率因子1.4, depth倍率因子1.8得到的(block里不包含stage0这个普通卷积层)。

图片分类网络ViT、MobileViT、Swin-Transformer、MobileNetV3、ConvNeXt、EfficientNetV2_第105张图片
其它模型配置参考见小绿豆的文章,这里就不写了。其它训练参数:

# (block, width, depth, train_size, eval_size, dropout, randaug, mixup, aug)

efficientnetv2_params = {
'efficientnetv2-s': # 83.9% @ 22M
(v2_s_block, 1.0, 1.0, 300, 384, 0.2, 10, 0, 'randaug'),
'efficientnetv2-m': # 85.2% @ 54M
(v2_m_block, 1.0, 1.0, 384, 480, 0.3, 15, 0.2, 'randaug'),
'efficientnetv2-l': # 85.7% @ 120M
(v2_l_block, 1.0, 1.0, 384, 480, 0.4, 20, 0.5, 'randaug'),
							}

你可能感兴趣的:(CV,计算机视觉,图片分类)