精华内容
下载资源
问答
  • 这个工作本着尽可能少修改的原则,将原版的Transformer开箱即用地迁移到分类任务上面。并且作者认为没有必要总是依赖于CNN,只用Transformer也能够在分类任务中表现很好,尤其是在使用大规模训练集的时候。同时,在...

    在这里插入图片描述

    An Image is Worth 16x16 Words:Transformers for Image Recognition at Scale

    代码:https://github.com/google-research/vision_transformer


    1、ViT原理分析:

    这个工作本着尽可能少修改的原则,将原版的Transformer开箱即用地迁移到分类任务上面。并且作者认为没有必要总是依赖于CNN,只用Transformer也能够在分类任务中表现很好,尤其是在使用大规模训练集的时候。同时,在大规模数据集上预训练好的模型,在迁移到中等数据集或小数据集的分类任务上以后,也能取得比CNN更优的性能。下面看具体的方法:

    这个工作首先把 xH×W×Cx\in H \times W \times C 的图像,变成一个 xpN×(P2C)x_p \in N \times (P^2 \cdot C) 的sequence of flattened 2D patches。它可以看做是一系列的展平的2D块的序列,这个序列中一共有 N=HW/P2N =HW/P^2 个展平的2D块,每个块的维度是 (P2×C)(P^2\times C) 。其中 PP 是块大小, CC 是channel数。

    注意作者做这步变化的意图:
    根据之前的讲解,Transformer希望输入一个二维的矩阵 (N,D)(N,D) ,其中 NN 是sequence的长度,DD 是sequence的每个向量的维度,常用256。所以这里也要设法把 H×W×CH\times W \times C 的三维图片转化成 (N,D)(N,D) 的二维输入。

    所以有: H×W×CN×(P2C)H \times W \times C \to N \times (P^2 \cdot C),where N=HW/P2N=HW/P^2

    其中,NN 是Transformer输入的sequence的长度。

    代码是:

    x = rearrange(img, 'b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1=p, p2=p)
    

    具体是采用了einops库实现,具体可以参考这篇博客。

    科技猛兽:PyTorch 70.einops:优雅地操作张量维度:https://zhuanlan.zhihu.com/p/342675997

    现在得到的向量维度是:xpN×(P2×C)x_p \in N \times (P^2 \times C) ,要转化成 (N,D)(N,D) 的二维输入,我们还需要做一步叫做Patch Embedding的步骤。


    Patch Embedding

    方法是对每个向量都做一个线性变换(即全连接层),压缩后的维度为DD ,这里我们称其为 Patch Embedding。

    z0=[xclass;xp1E;xp2E;....;xpnE]+Epos(1)z_0 = [\color{green}x_{class}; \color{back} x_p^1E; x_p^2E; .... ; x_p^nE]+ E_{pos} \tag1

    这个全连接层就是上式(5.1)中的 E\color{red}E ,它的输入维度大小是 (P2C)(P^2 \cdot C) ,输出维度大小是 DD

    # 将3072变成dim,假设是1024
    self.patch_to_embedding = nn.Linear(patch_dim, dim)
    x = self.patch_to_embedding(x)
    

    注意这里的绿色字体 xclass\color{green}x_{class} ,假设切成9个块,但是最终到Transfomer输入是10个向量,这是人为增加的一个向量。


    为什么要追加这个向量?

    如果没有这个向量,假设 N=9N=9 个向量输入Transformer Encoder,输出9个编码向量,然后呢?对于分类任务而言,我应该取哪个输出向量进行后续分类呢?
    不知道。干脆就再来一个向量 xclass(vector,dim=D)\color{green}x_{class}(vector ,dim =D) ,这个向量是可学习的嵌入向量,它和那9个向量一并输入Transfomer Encoder,输出1+9个编码向量。然后就用第0个编码向量,即 xclass\color{green}x_{class} 的输出进行分类预测即可。

    这么做的原因可以理解为:ViT其实只用到了Transformer的Encoder,而并没有用到Decoder,而 xclass\color{green}x_{class} 的作用有点类似于解码器中的 QueryQuery 的作用,相对应的 Key,ValueKey, Value 就是其他9个编码向量的输出。xclass\color{green}x_{class} 是一个可学习的嵌入向量,它的意义说通俗一点为:寻找其他9个输入向量对应的 imageimage 的类别。

    代码为:

    # dim=1024
    self.cls_token = nn.Parameter(torch.randn(1, 1, dim))
    
    # forward前向代码
    # 变成(b,64,1024)
    cls_tokens = repeat(self.cls_token, '() n d -> b n d', b=b)
    # 跟前面的分块进行concat
    # 额外追加token,变成b,65,1024
    x = torch.cat((cls_tokens, x), dim=1)
    

    Positional Encoding

    按照Transformer的位置编码的习惯,这个工作也使用了位置编码。引入了一个 Positional encoding Epos\color{violet}E_{pos}来加入序列的位置信息,同样在这里也引入了pos_embedding,是用一个可训练的变量。

    z0=[xclass;xp1E;xp2E;....;xpnE]+Eposz_0 = [x_{class}; x_p^1E; x_p^2E; .... ; x_p^nE]+ \color{violet}E_{pos}

    没有采用原版Transformer的 sincossincos 编码,而是直接设置为可学习的Positional Encoding,效果差不多。对训练好的pos_embedding进行可视化,如下图所示。
    我们发现,位置越接近,往往具有更相似的位置编码。此外,出现了行列结构;同一行/列中的patch具有相似的位置编码。

    在这里插入图片描述

    # num_patches=64,dim=1024,+1是因为多了一个cls开启解码标志
    self.pos_embedding = nn.Parameter(torch.randn(1, num_patches + 1, dim))
    

    Transformer Encoder的前向过程

    z0=[xclass;xp1E;xp2E;....;xpnE]+Epos,ERP2×C×D,EposR(N+1)×D(2)z_0 = [x_{class}; x_p^1E; x_p^2E; .... ; x_p^nE]+ E_{pos}, \qquad \qquad E\in \mathbb{R}^{P^2 \times C\times D}, E_{pos} \in \mathbb{R}^{(N+1)\times D} \tag2

    z=MSA(LN(z1))+z1,=1...L(3){z}'_\ell = \color{violet}MSA(LN(z_{\ell-1}))+z_{\ell-1}, \qquad \qquad \color{back}\ell=1...L \qquad \qquad \qquad \tag3

    z=MLP(LN(z))+zell,=1...L(4)z_{\ell} = \color{blue}MLP(LN({z}'_\ell))+{z}'_{ell}, \qquad \qquad \color{back} \ell=1...L \qquad \qquad \quad \tag4

    y=LN(z0)(5)y = LN(z^0_{\ell}) \qquad\qquad\qquad \tag5

    • 其中,第1个式子为上面讲到的Patch Embedding和Positional Encoding的过程。
    • 第2个式子为Transformer Encoder的 MultiheadSelfAttention,AddandNorm\color{violet}Multi-head \quad Self-Attention, Add and Norm 的过程,重复 LL 次。
    • 第3个式子为Transformer Encoder的 FeedForwardnetwork,AddandNorm\color{blue}Feed Forward network, AddandNorm 的过程,重复 LL 次。

    作者采用的是没有任何改动的transformer。

    最后是一个 MLPMLPClassficationHeadClassfication \quad Head ,整个的结构只有这些,如下图所示,为了方便读者的理解,我把变量的维度变化过程标注在了图中。

    在这里插入图片描述


    训练方法:

    先在大数据集上预训练,再迁移到小数据集上面。做法是把ViT的 predictionhead\color{violet}prediction-head 去掉,换成一个 D×KD \times KFeedForwardLayer\color{violet}FeedForwardLayer 。其中 KK 为对应数据集的类别数。

    当输入的图片是更大的shape时,patch size PP 保持不变,则 N=HW/P2N=HW/P^2 会增大。

    ViT可以处理任意 NN 的输入,但是Positional Encoding是按照预训练的输入图片的尺寸设计的,所以输入图片变大之后,Positional Encoding需要根据它们在原始图像中的位置做2D插值。


    最后,展示下ViT的动态过程:

    ViT的动态过程

    在这里插入图片描述


    Experiments:

    预训练模型使用到的数据集有:

    • ILSVRC-2012 ImageNet dataset:1000 classes
    • ImageNet-21k:21k classes
    • JFT:18k High Resolution Images

    将预训练迁移到的数据集有:

    • CIFAR-10/100
    • Oxford-IIIT Pets
    • Oxford Flowers-102
    • VTAB

    作者设计了3种不同答小的ViT模型,它们分别是:

    DModel Layers Hidden size MLP size Heads Params
    ViT-Base 12 768 3072 12 86M
    ViT-Large 24 1024 4096 16 307M
    ViT-Huge 32 1280 5120 16 632M

    ViT-L/16代表ViT-Large + 16 patch size


    评价指标 Metrics :

    结果都是下游数据集上经过finetune之后的Accuracy,记录的是在各自数据集上finetune后的性能。


    实验1:性能对比

    实验结果如下图所示,整体模型还是挺大的,而经过大数据集的预训练后,性能也超过了当前CNN的一些SOTA结果。对比的CNN模型主要是:

    2020年ECCV的Big Transfer (BiT)模型,它使用大的ResNet进行有监督转移学习。

    2020年CVPR的Noisy Student模型,这是一个在ImageNet和JFT300M上使用半监督学习进行训练的大型高效网络,去掉了标签。

    All models were trained on TPUv3 hardware。

    在这里插入图片描述

    在JFT-300M上预先训练的较小的ViT-L/16模型在所有任务上都优于BiT-L(在同一数据集上预先训练的),同时训练所需的计算资源要少得多。 更大的模型ViT-H/14进一步提高了性能,特别是在更具挑战性的数据集上——ImageNet, CIFAR-100和VTAB数据集。 与现有技术相比,该模型预训练所需的计算量仍然要少得多。

    下图为VTAB数据集在Natural, Specialized, 和Structured子任务与CNN模型相比的性能,ViT模型仍然可以取得最优。

    在这里插入图片描述


    实验2:ViT对预训练数据的要求
    ViT对于预训练数据的规模要求到底有多苛刻?

    作者分别在下面这几个数据集上进行预训练:ImageNet, ImageNet-21k, 和JFT-300M。

    结果如下图所示:

    在这里插入图片描述

    我们发现: 当在最小数据集ImageNet上进行预训练时,尽管进行了大量的正则化等操作,但ViT-大模型的性能不如ViT-Base模型

    但是有了稍微大一点的ImageNet-21k预训练,它们的表现也差不多

    只有到了JFT 300M,我们才能看到更大的ViT模型全部优势。 图3还显示了不同大小的BiT模型跨越的性能区域。BiT CNNs在ImageNet上的表现优于ViT(尽管进行了正则化优化),但在更大的数据集上,ViT超过了所有的模型,取得了SOTA。

    作者还进行了一个实验: 在9M、30M和90M的随机子集以及完整的JFT300M数据集上训练模型,结果如下图所示。 ViT在较小数据集上的计算成本比ResNet高, ViT-B/32比ResNet50稍快;它在9M子集上表现更差, 但在90M+子集上表现更好。ResNet152x2和ViT-L/16也是如此。这个结果强化了一种直觉,即:

    残差对于较小的数据集是有用的,但是对于较大的数据集,像attention一样学习相关性就足够了,甚至是更好的选择。

    在这里插入图片描述


    实验3:ViT的注意力机制Attention

    作者还给了注意力观察得到的图片块, Self-attention使得ViT能够整合整个图像中的信息,甚至是最底层的信息。作者欲探究网络在多大程度上利用了这种能力。

    具体来说,我们根据注意力权重计算图像空间中整合信息的平均距离,如下图所示。

    在这里插入图片描述

    注意这里我们只使用了attention,而没有使用CNN,所以这里的attention distance相当于CNN的receptive field的大小。
    作者发现:在最底层, 有些head也已经注意到了图像的大部分,说明模型已经可以globally地整合信息了,说明它们负责global信息的整合。其他的head 只注意到图像的一小部分,说明它们负责local信息的整合。Attention Distance随深度的增加而增加。

    整合局部信息的attention head在混合模型(有CNN存在)时,效果并不好,说明它可能与CNN的底层卷积有着类似的功能。

    作者给出了attention的可视化,注意到了适合分类的位置:

    在这里插入图片描述


    ViT代码解读:

    使用:

    import torch
    from vit_pytorch import ViT
    
    v = ViT(
        image_size = 256,
        patch_size = 32,
        num_classes = 1000,
        dim = 1024,
        depth = 6,
        heads = 16,
        mlp_dim = 2048,
        dropout = 0.1,
        emb_dropout = 0.1
    )
    
    img = torch.randn(1, 3, 256, 256)
    mask = torch.ones(1, 8, 8).bool() # optional mask, designating which patch to attend to
    
    preds = v(img, mask = mask) # (1, 1000)
    
    • 传入参数的意义: image_size:输入图片大小。
    • patch_size:论文中 patch size: 图片 的大小。
    • num_classes:数据集类别数。
    • dim:Transformer的隐变量的维度。
    • depth:Transformer的Encoder,Decoder的Layer数。
    • heads:Multi-head Attention
    • layer的head数。
    • mlp_dim:MLP层的hidden dim。
    • dropout:Dropout rate。
    • emb_dropout:Embedding dropout rate。

    定义残差,Feed Forward Layer 等:

    class Residual(nn.Module):
        def __init__(self, fn):
            super().__init__()
            self.fn = fn
        def forward(self, x, **kwargs):
            return self.fn(x, **kwargs) + x
    
    class PreNorm(nn.Module):
        def __init__(self, dim, fn):
            super().__init__()
            self.norm = nn.LayerNorm(dim)
            self.fn = fn
        def forward(self, x, **kwargs):
            return self.fn(self.norm(x), **kwargs)
    
    class FeedForward(nn.Module):
        def __init__(self, dim, hidden_dim, dropout = 0.):
            super().__init__()
            self.net = nn.Sequential(
                nn.Linear(dim, hidden_dim),
                nn.GELU(),
                nn.Dropout(dropout),
                nn.Linear(hidden_dim, dim),
                nn.Dropout(dropout)
            )
        def forward(self, x):
            return self.net(x)
    
    

    Attention和Transformer,注释已标注在代码中:

    class Attention(nn.Module):
        def __init__(self, dim, heads = 8, dim_head = 64, dropout = 0.):
            super().__init__()
            inner_dim = dim_head *  heads
            self.heads = heads
            self.scale = dim ** -0.5
    
            self.to_qkv = nn.Linear(dim, inner_dim * 3, bias = False)
            self.to_out = nn.Sequential(
                nn.Linear(inner_dim, dim),
                nn.Dropout(dropout)
            )
    
        def forward(self, x, mask = None):
    		# b, 65, 1024, heads = 8
            b, n, _, h = *x.shape, self.heads
    
    		# self.to_qkv(x): b, 65, 64*8*3
    		# qkv: b, 65, 64*8
            qkv = self.to_qkv(x).chunk(3, dim = -1)
    
    		# b, 65, 64, 8
            q, k, v = map(lambda t: rearrange(t, 'b n (h d) -> b h n d', h = h), qkv)
    
    		# dots:b, 65, 64, 64
            dots = torch.einsum('bhid,bhjd->bhij', q, k) * self.scale
            mask_value = -torch.finfo(dots.dtype).max
    
            if mask is not None:
                mask = F.pad(mask.flatten(1), (1, 0), value = True)
                assert mask.shape[-1] == dots.shape[-1], 'mask has incorrect dimensions'
                mask = mask[:, None, :] * mask[:, :, None]
                dots.masked_fill_(~mask, mask_value)
                del mask
    
    		# attn:b, 65, 64, 64
            attn = dots.softmax(dim=-1)
    
    		# 使用einsum表示矩阵乘法:
    		# out:b, 65, 64, 8
            out = torch.einsum('bhij,bhjd->bhid', attn, v)
    
    		# out:b, 64, 65*8
            out = rearrange(out, 'b h n d -> b n (h d)')
    
    		# out:b, 64, 1024
            out =  self.to_out(out)
            return out
    
    class Transformer(nn.Module):
        def __init__(self, dim, depth, heads, dim_head, mlp_dim, dropout):
            super().__init__()
            self.layers = nn.ModuleList([])
            for _ in range(depth):
                self.layers.append(nn.ModuleList([
                    Residual(PreNorm(dim, Attention(dim, heads = heads, dim_head = dim_head, dropout = dropout))),
                    Residual(PreNorm(dim, FeedForward(dim, mlp_dim, dropout = dropout)))
                ]))
        def forward(self, x, mask = None):
            for attn, ff in self.layers:
                x = attn(x, mask = mask)
                x = ff(x)
            return x
    

    ViT整体:

    class ViT(nn.Module):
        def __init__(self, *, image_size, patch_size, num_classes, dim, depth, heads, mlp_dim, pool = 'cls', channels = 3, dim_head = 64, dropout = 0., emb_dropout = 0.):
            super().__init__()
            assert image_size % patch_size == 0, 'Image dimensions must be divisible by the patch size.'
            num_patches = (image_size // patch_size) ** 2
            patch_dim = channels * patch_size ** 2
            assert num_patches > MIN_NUM_PATCHES, f'your number of patches ({num_patches}) is way too small for attention to be effective (at least 16). Try decreasing your patch size'
            assert pool in {'cls', 'mean'}, 'pool type must be either cls (cls token) or mean (mean pooling)'
    
            self.patch_size = patch_size
    
            self.pos_embedding = nn.Parameter(torch.randn(1, num_patches + 1, dim))
            self.patch_to_embedding = nn.Linear(patch_dim, dim)
            self.cls_token = nn.Parameter(torch.randn(1, 1, dim))
            self.dropout = nn.Dropout(emb_dropout)
    
            self.transformer = Transformer(dim, depth, heads, dim_head, mlp_dim, dropout)
    
            self.pool = pool
            self.to_latent = nn.Identity()
    
            self.mlp_head = nn.Sequential(
                nn.LayerNorm(dim),
                nn.Linear(dim, num_classes)
            )
    
        def forward(self, img, mask = None):
            p = self.patch_size
    
    		# 图片分块
            x = rearrange(img, 'b c (h p1) (w p2) -> b (h w) (p1 p2 c)', p1 = p, p2 = p)
    
    		# 降维(b,N,d)
            x = self.patch_to_embedding(x)
            b, n, _ = x.shape
    
    		# 多一个可学习的x_class,与输入concat在一起,一起输入Transformer的Encoder。(b,1,d)
            cls_tokens = repeat(self.cls_token, '() n d -> b n d', b = b)
            x = torch.cat((cls_tokens, x), dim=1)
    
    		# Positional Encoding:(b,N+1,d)
            x += self.pos_embedding[:, :(n + 1)]
            x = self.dropout(x)
    
    		# Transformer的输入维度x的shape是:(b,N+1,d)
            x = self.transformer(x, mask)
    
    		# (b,1,d)
            x = x.mean(dim = 1) if self.pool == 'mean' else x[:, 0]
    
            x = self.to_latent(x)
            return self.mlp_head(x)	# (b,1,num_class)
    
    展开全文
  • Transformer

    2021-03-26 11:24:15
    Transformer 作为 NLP 领域的大杀器,目前已经在 CV 领域逐渐展露锋芒,大有替代 CNN 的趋势,在图像分类,视频处理,low/high level 的视觉任务都有相应的 transformer 刷榜。 下表是transformer截至目前在视觉领域...

    在这里插入图片描述
    一、背景
    Transformer 作为 NLP 领域的大杀器,目前已经在 CV 领域逐渐展露锋芒,大有替代 CNN 的趋势,在图像分类,视频处理,low/high level 的视觉任务都有相应的 transformer 刷榜。
    下表是transformer截至目前在视觉领域的应用。
    在这里插入图片描述
    transformer 在CV中的应用可以分为四类,分别是classification, high-level vision, low-level vision 和video processing.(在这里解释一下什么是high-level vision,和low-level vision ,低级视觉关注的是类似从视网膜这类图像中提取图像的特性。高级视觉主要关注的是知觉组织的日常功能。详细解释看文章末尾的注释)
    Classification 顾名思义就是分类任务,High-level vision 作者定义为:“对图像中所见内容的解释和使用”,包括目标检测、分割等。Low-level vision 定义为“为图像提取描述信息”,典型应用包括超分,图像去噪,风格迁移等。
    二、算法原理
    在这里插入图片描述
    1.结构
    transformer是采用encoder-decoder架构。
    encoder层是6层encoder堆叠在一起的,decoder是6层decoder堆叠在一起。一个encoder是由Self-Attention(自注意力机制层)和Feed Forward(前向神经网络层)组成,而decoder比encoder多了一层Encoder-Decoder Attention,该层目的是接收encoder层的结果。值得注意的是,decoder与encoder的Self-Attention并不完全相同,decoder采用的是Masked Self-Attention(掩码自注意力)。
    2.算法流程
    encoder层
    1)每个特征向量(feture embedding)➕ 对应的位置向量(positional embedding)= 编码器的输入向量x
    2)输入向量通过多头自注意力机制(Multi-Head Attention)得到的向量与输入向量进行残差连接与归一化(Add & Normalize)
    3)将归一化得到的每个特征的向量继续做前向神经网络(Feed Forward)
    4)最后再进行一次残差连接与归一化(Add & Normalize)
    此时一层encoder层结束,将得到的结果向量当成输入向量继续传给第二层的encoder,依次传递计算,直到6层encoder计算结束,将最后结果向量保留,之后会传给decoder层计算。
    decoder层
    1)encoder的输出向量(feture embedding)➕ 随机向量(object queris)=decoder输入向量x
    2)输入向量x同样经过多头自注意力机制(Multi-Head Attention)处理和残差连接与归一化
    3)这一步的Encoder-Decoder Attention,其中q、k是来自于encoder层的结果,而v是本身上一层的结果
    4)接下来几步和上面encoder的步骤是一样的,最后得到结果向量,作为decoder第二层的输入向量。然后依次进行以上步骤,直到6层decoder全部计算结束。
    transformer的整个运行过程,其主要核心就是Self-Attention机制,而其在encoder层和decoder层又是不同实现的。其主要原因是encoder层是相当于学习到输入图像的特征信息,所以需要将不同位置的特征都包含进来计算,而decoder层相当于进行预测分类,因而只需要关注局部信息,而将其他区域的特征都盖住。
    Multi-Head Attention(多头注意力机制)
    作用:多层注意力层进行一系列的矩阵运算把特征拆分成多个维度并行输出,它的作用主要是允许模型在不同位置共同关注着来自不同表示子空间的信息。让模型捕捉更多的信息,将特征变得更丰富些,提升Transformer的建模能力。
    运算过程:一个输入向量x乘以不同的权重系数得到多组q、k、v,x与q、k、v之间进行矩阵运算从而得到多个z,将多个z拼接成一个大矩阵,乘以权重矩阵wo,得到最后的结果向量z。(查询向量q、键向量k、值向量v)
    Feed Forward Neural Network(前馈神经网络
    Feed Forward Neural Network(前馈神经网络)包含两层,第一层是ReLU激活函数,第二层是一个线性激活函数
    Add & Normalize(残差连接&归一化)层
    残差连接就是将输入向量加上输出向量后传给下一层。
    例如:假设一个输入向量x,经过一个网络结构,得到输出向量f(x),即:x->f(x),这时加上残差连接,相当于在输出向量中加入输入向量,输出结构变为f(x)+x。作用:避免了梯度消失的问题,因为对x求偏导时,总会有一个常数项1。因此,Add & Normalize层的实质是,输出向量经过残差连接与输入向量相加然后通过LayerNorm进行归一化,将最后结果传给下一层。
    3.详解
    1)Self-Attention Layer
    自注意力机制先将一个 embedding 转化为三个向量,query,key 和 value (q、k、v ),三者的维度都与原始 embedding 一致。所有的 embedding 放在一起组成三个大矩阵Q,K,V ,然后注意力机制计算过程如下
    1)计算不同输入向量的得分 S=Q乘以K^T
    2)为了梯度的稳定性将得分进行归一化Sn=S/[(dk)^1/2]
    3) 将归一化后的得分转化为概率P=softmax(Sn)
    4)最后得到加权的矩阵 Z=V乘以P
    这整个过程可以被统一为一个简单的函数:
    在这里插入图片描述
    第 1 步计算两个不同向量之间的分数,这个分数用来确定我们在当前位置编码对其他位置特征的注意程度。步骤 2 标准化得分,使其具有更稳定的梯度,以便更好地训练;步骤 3 将得分转换为概率。最后,将每个值向量乘以概率的总和,概率越大的向量将被下面几层更多地关注。
    2)encoder-decoder attention layer
    encoder-decoder attention layer 其实和自注意力机制非常类似,不同之处在于,key,value 矩阵K,V是从 encoder 那里继承来的,Q是从上一层继承来的。
    数学定义为:
    在这里插入图片描述
    pos 表示 token 在 sequence 中的位置,例如第一个 token 就是 0。
    i和2i+1表示了 Positional Encoding 的维度.
    3)Multi-Head Attention layer
    Multi-Head Attention layer是为了提高模型的表达能力。在上面 single-head 的模型中,我们最终得到的 embedding 融合了其他各个位置,但是他很有可能被本身 dominate(自身对自身的 attention 一般很大),而且我们不能确保随机初始化后不断学习得到 Q、K、V这些矩阵带来的 attention 一定对。因此 multi-head 可以看作是一种 ensemble,我们现在有多组矩阵 ,他们将同一个输入 embedding 映射到不同的表达空间以此来提高模型的表达能力。不过此时 query,key,value 的维度不再与原始 embedding 一致,而是变为d(medel)/h ,因此每个 head 经过 self-attention 将 word 映射为d(medel)/h维的embedding,将这些 embedding 连接在一起就变为原始维度。
    数学定义如下:
    在这里插入图片描述
    在这里插入图片描述
    这就是基本的 Multihead Attention 单元,对于 encoder 来说就是利用这些基本单元叠加,其中 key, query, value 均来自前一层 encoder 的输出,即 encoder 的每个位置都可以注意到之前一层 encoder 的所有位置。
    对于 decoder 来讲,我们注意到有两个与 encoder 不同的地方,一个是第一级的 Masked Multi-head,另一个是第二级的 Multi-Head Attention 不仅接受来自前一级的输出,还要接收 encoder 的输出,下面分别解释一下是什么原理。
    第一级 decoder 的 key, query, value 均来自前一层 decoder 的输出,但加入了 Mask 操作,即我们只能attend到前面已经翻译过的输出的词语,因为翻译过程我们当前还并不知道下一个输出词语,这是我们之后才会推测到的。
    而第二级 decoder 也被称作 encoder-decoder attention layer,即它的 query 来自于之前一级的 decoder 层的输出,但其 key 和 value 来自于 encoder 的输出,这使得 decoder 的每一个位置都可以 attend 到输入序列的每一个位置。
    总结一下,k 和 v 的来源总是相同的,q 在 encoder 及第一级 decoder 中与 k,v 来源相同,在 encoder-decoder attention layer 中与 k,v 来源不同。
    4.Other Parts in Transformer
    Residual in the encoder and decoder:在上面的结构图中可以看到,每个 encoder,decoder 模块都是会有一个残差连接+ layerNorm 的。
    在这里插入图片描述
    具体而言就是:
    在这里插入图片描述
    Feed-forward neural network:这个模块不是简单的 FCN,而是两层 FCN 加一个非线性的激活函数,即
    在这里插入图片描述
    Final layer in decoder:解码器的最后一层旨在将向量转为一个字。这是通过一个线性层和一个 softmax 层来实现的。线性层将向量投影到一个dword维的logit向量中,其中dword是词汇表中的单词数。然后,使用 softmax 层将 logits 向量转换为概率。
    5.总结
    大多数用于计算机视觉任务的 Transformer 都使用原编码器模块。总之,它可以被视为一种不同于 CNN 和递归神经网络 RNN 的新型特征选择器。与只关注局部特征的 CNN 相比,transformer 能够捕捉到长距离特征,这意味着 transformer 可以很容易地获得全局信息。
    与 RNN 的隐态计算顺序相比较,Transformer 的自注意层和全连接层的输出可并行计算,且速度快。因此,进一步研究 Transformer 在自然语言处理和计算机视觉领域的应用具有重要意义。
    三、Transformer在CV领域的应用
    图像作为一种高维、噪声大、冗余度高的形态,被认为是生成建模的难点,这也是为什么过了好几年,transformer 才应用到视觉领域。比较初始的应用是在 Visual Transformer 一文中,作者使用 CNN 提取 low-level 的特征,然后将这些特征输 入Visual Transformer(VT)。
    在 VT 中,作者设计了一个 tokenizer 将各个 pixel 分成少量的 visual tokens,每个 token 代表了图像中的某些语义信息。然后使用 transformer 来建模 token 之间的关系。最后输出的 tokens 直接被用来做分类或者处理一下恢复成特征图用于实例分割。
    在 CV 中使用 transformer,目前来看主要的两个问题,以及下列文章的核心区别在于:

    • 得到 Token 的方式
    • 训练的方式
    • 评估 representation 的方式
      只要得到 token,我们就能像 NLP 一样使用 transformer;有训练目标我们就能 train 我们的 model;有评估方式我们才知道自己的 model 好还是坏。(token其实说的更通俗点可以叫暗号,在一些数据传输之前,要先进行暗号的核对,不同的暗号被授权不同的数据操作。)
      1)Token:iGPT 使用一种比较暴力的方式得到 token,原始图像(322 )进行预处理,将其调整为低分辨率,并将其重塑为一维序列(从左到右,从上到小)。接着把每个像素相当于一个 word,即对每个 pixel,我们采用nn.Embedding(num_vocab, embed_dim)提取每个像素 embedding。至此图片数据已经完全转化为了 transformer 的输入形式。
      2)Pretrain:iGPT 有两种预训练方式:1)像自编码器一样进行逐像素预测;2)像 Bert 一样 mask 一部分 pixel 然后预测。其实第一种方式的实现与 bert 也很类似,就是预测第 i个 pixel 的时候,mask 掉 i+1 之后的所有 pixel。
      3)Evaluation:两种评估方式:1)fine-tune:增加了一个小的分类头,用于优化分类目标并 adapt 所有权重;2)Linear-probe:将 pretraining 的模型视作特征提取器,增加一个分类头,只训练这个分类头。第二种方式的直觉在于“一个好的特征应该能够区分不同的类”,除此之外,fine-tune 效果好有可能是因为架构很适合下游任务,但是 linear-probe 只取决于特征质量。
      四、在目标检测中的应用(High-level Vision)
      基于 transformer 的目标检测可以分为两类,也即下图的 (a)(b):

      Transformer-based set prediction for detection. DETR 是这类工作的先驱,其将目标检测视为集合预测问题,去掉了目标检测种很多手工的组件像 NMS,anchor generation 等。
      Token:CNN 将图像 downsample 为Z0 ,然后将Z0 的空间维度压缩为一维,造成一个序列 。这个 token 的获取方式挺有意思,空间维度塌缩。当然也要加上位置编码。
      Train:如何将 object detection 转化为 set prediction 然后进行训练,这是一个非常有意思的问题。作者使用了 object queries,这实际上是另一组可学习的 positional embedding,其功能类似于 anchor。之后每个 query 经过 decoder 后算一个 bbox 和 class prob。
      Evaluation:目标检测传统的评估方式。
      在这里插入图片描述
      DETR 也大方地承认了他的缺点:训练周期长,对小物体检测效果差。
      Transformer-based backbone for detection.与 DETR 不同,ViT-FRCNN [3] 将 ViT 与传统的检测框架融合,直接使用 transformer 的 encoder 作为 backbone 提取特征,与 ViT 处理图像的方式一致,但是输出的 patch feature 重新调整为一个图像的特征图送入传统检测模型。
      在这里插入图片描述
      总结一下,目前 transformer 已经在很多视觉应用中展现出了强大的实力。使用 transformer 最重要的两个问题是如何得到输入的 embedding(妥善处理position embedding),模型的训练与评估。
      目前还有很多非常有价值的课题值得我们探索,例如,对于最终的性能,像 CNN 或 PointNet 这样的特征提取模块是必要的吗?如何让 visual transformer 受益于像 BERT 或 GPT-3 在 NLP 社区做的大规模的预训练数据。是否有可能预先训练单个 transformer 模型,并通过几次微调来针对不同的下游任务进行微调?

    参考资料:
    1)Transformer讲解以及在CV领域的应用
    https://blog.csdn.net/qq_40585800/article/details/112427990
    2)视觉Transformer最新综述
    视觉算法
    3)视觉Transformer综述
    https://blog.csdn.net/KANG157/article/details/111771262
    4)综述论文
    https://arxiv.org/pdf/2012.12556.pdf
    5)图解Transformer
    https://zhuanlan.zhihu.com/p/94998435
    注释
    1. Low-level feature和High level feature
    1)Low-level feature: 通常是指图像中的一些小的细节信息,例如边缘(edge),角(corner),颜色(color),像素(pixeles), 梯度(gradients)等,这些信息可以通过滤波器、SIFT或HOG获取;
    2)High level feature:是建立在low level feature之上的,可以用于图像中目标或物体形状的识别和检测,具有更丰富的语义信息。
    通常卷积神经网络中都会使用这两种类型的features,卷积神经网络的前几层学习low level feature,后几层学习的是high level feature,区别于high-level vision,和low-level vision。

    展开全文
  • 1. ImageNet-1K的图像分类Swin Transformer: Hierarchical Vision Transformer using Shifted Windows一元@炼丹笔记最近朋友和我聊Swin Transformer,说霸榜了各大CV任务的榜单,一搜,发现该文章才出来不到两周,...

    1. ImageNet-1K的图像分类

    Swin Transformer: Hierarchical Vision Transformer using Shifted Windows

    v2-071e132c7353c2be34deb925be1bf617_b.jpg
    一元@炼丹笔记

    最近朋友和我聊Swin Transformer,说霸榜了各大CV任务的榜单,一搜,发现该文章才出来不到两周,赶紧趁热赶学习一波!

    v2-3d0e0202a55922700ba2ab425be0ebee_b.jpg

    之前计算机视觉相关的任务主要被CNN所统治。

    • 从AlexNet及其在ImageNet图像分类挑战方面的革命性表现,CNN架构已经通过更大的规模,更广泛的连接,以及更复杂的卷积形式而逐渐壮大。

    自然语言处理(NLP)中网络体系结构的演变走了一条不同的道路,今天流行的体系结构取而代之的是Transformer。

    • Transformer是为序列建模和转换任务而设计的,因为它关注数据中的长期依赖性建模。它在语言领域的巨大成功促使研究人员研究它对计算机视觉的适应性,最近它在某些任务上显示了不错的结果,特别是图像分类和联合视觉语言建模。

    本文重点探讨将Transformer从NLP转移到CV的策略。我们先看二者的不同:

    • scale。与作为语言Transformer中处理的基本元素的单词标记不同,视觉元素在scale上可能有很大的差异,这是一个在目标检测等任务中受到关注的问题。在现有基于Transformer的模型中,tokens都是固定比例的,这种属性不适合这些应用。
    • 图像中像素的分辨率比文本段落中的单词高得多。

    在本篇文章中,作者提出了一种新的视觉Transformer,称为Swin Transformer,它可以作为计算机视觉的通用backbone。将Transformer从语言转到视觉的过程中所面临的挑战来自于两个领域之间的差异,例如视觉实体的规模变化很大,图像中的像素与文本中的单词相比分辨率很高。为了解决这些差异,本文提出了一个层次化的Transformer,其表示是用移位窗口计算的。

    移位窗口方案通过将self-attention计算限制在非重叠的局部窗口上,同时允许跨窗口连接,从而提高了效率。这种分层结构具有在不同尺度下建模的灵活性,并且相对于图像大小具有线性计算复杂性。Swin-Transformer的这些特性使其能够兼容广泛的视觉任务,包括:

    • 图像分类ImageNet-1K上的准确率为86.4 top-1;
    • 密集预测任务,如目标检测(COCO test dev上的58.7 box AP和51.1 mask AP);
    • 语义分割(ADE20K val上的535 mIoU)。

    它的效果超过了之前的最佳水平,COCO上的box-AP和mask-AP分别为+2.7和+2.6,ADE20K上的mask-AP和+3.2 mIOU,显示了基于Transformer的模型作为视觉支柱的潜力。

    存在许多视觉任务,如语义分割,需要在像素级进行dense的预测,这对于高分辨率图像上的Transformer来说是很困难的,因为它self-attention的计算复杂度是图像大小的二次方。

    为了克服这些问题,我们提出了一种通用的Transformer backbone,称为Swin-Transformer,它构造了层次化的特征映射,并且计算复杂度与图像大小成线性关系。

    v2-6a277c62069094b514d919710e1a44e7_b.jpg

    如上图所示,Swin-Transformer通过从小尺寸的面片(用灰色表示)开始,逐渐合并更深层次的Transformer层中的相邻面片来构造层次表示。有了这些分层特征映射,Swin-Transformer模型可以方便地利用高级技术进行dense预测,如特征金字塔网络(FPN)或U-Net。线性计算复杂度是通过在分割图像的非重叠窗口(红色轮廓)内局部计算自我注意来实现的。每个窗口中的面片数是固定的,因此复杂度与图像大小成线性关系。这些优点使得Swin-Transformer适合作为各种视觉任务的通用主干,与以前基于Transformer的体系结构形成对比,后者产生单一分辨率的特征图,并且具有二次复杂性。

    Swin Transformer的一个关键设计元素是它在连续的self-attention之间的窗口分区的移动,如下图所示。

    v2-5ba06aee6cc193535850a0bb718f0245_b.jpg

    移动的窗口桥接了前一层的窗口,提供了它们之间的连接,显著增强了建模能力。这种策略对于真实世界的延迟也是有效的:一个窗口中的所有query patches都共享相同的key set,这有助于硬件中的内存访问。

    相比之下,早期的基于滑动窗口的self-attention方法由于不同query像素的key集合不同,在一般硬件上的延迟较低。实验结果表明,所提出的shifted window方法比传统方法具有更低的延迟。

    所提出的Swin Transformer在图像分类、目标检测和语义分割等识别任务上取得了很好的效果。在这三个任务上,它的延迟时间与ViT/DeiT和ResNe(X)t模型相似,显著优于ViT/DeiT和ResNe(X)t模型。

    v2-5c1f7e32d31b4cf1fc2e163fc3905dac_b.jpg

    v2-c92f09d891adc9e3d8a8673ebd0b272a_b.jpg

    Stage1

    • 首先通过像ViT一样的分片模块将输入的RGB图像分片成不重叠的patch。每个patch被视为一个“token”,其特征被设置为原始像素RGB值的串联。
    在我们的实现中,我们使用了4×4的面片大小,因此每个面片的特征维数为4×4×3=48。在这个原始值特征上应用一个线性嵌入层,将其投影到任意维(表示为C)。

    变化过的self-attention(Swin Transformer blocks)被应用到这些patch token上。Transformer block保留了token的个数()并且使用了线性的Embedding。

    Stage2

    为了生成一个层次化的表示,当网络变得更深,token的数量会通过patches合并层而减少。第一块拼接层连接了每组2×2相邻的patch的特征,并在维级联特征上应用线性层。

    这将token的数量减少了2×2=4的倍数(分辨率的2×降采样),并且输出维度设置为2C。之后应用Swin Transformer block进行特征变换,分辨率保持在。

    Stage3&4

    将该过程重复两次,输出分辨率分别为和。这些阶段共同产生一个层次表示,具有与典型卷积网络相同的特征图分辨率,例如VGG和ResNet。因此,所提出的架构可以方便地取代现有方法中的主干网来执行各种视觉任务。

    v2-3f18668f067ecc04a9fd70bb5b8db3e1_b.jpg

    Swin Transformer是将Transformer模块中的标准multi-head self-attention(MSA)模块替换为基于移动窗口,其它层保持不变。Swin Transformer由一个基于移位窗口的MSA模块组成,然后是一个介于GELU非线性之间的2层MLP。在每个MSA模块和每个MLP之前应用LayerNorm(LN)层,在每个模块之后应用剩余连接。

    v2-780656e823b6dc15aff4d0da252abeb1_b.jpg

    标准Transformer体系结构及其对图像分类的自适应都进行global self-attention,其中计算了一个token和所有其他token之间的关系。全局计算导致token数量的二次复杂度,这使得它不适用于许多需要大量令牌进行密集预测或表示高分辨率图像的视觉问题。

    1. Self-attention in non-overlapped windows

    v2-5e920babd887440de789a2c2462fbc62_b.jpg

    2. Shifted window partitioning in successive blocks

    基于窗口的自self-attention模块缺乏跨窗口的连接,这限制了它的建模能力。为了在保持非重叠窗口计算效率的同时引入跨窗口连接,我们提出了一种移位窗口划分方法,该方法在连续的Swin Transformer块中交替使用两种划分配置。

    如上图所示,第一个模块使用了一个从左上角像素开始的规则窗口划分策略,第一个模块采用将8×8 特征map平均划分为2×2个4×4(M=4)的窗口。然后,下一模块采用从上一层的窗口配置偏移的窗口配置,通过将窗口从规则分区的窗口置换像素。利用移位窗口划分方法,连续的swin transformer块被计算为:

    v2-5ba06aee6cc193535850a0bb718f0245_b.jpg
    • W-MSA:使用regular窗口分区配置的基于window的multi-head self-attention
    • SW-MSA:使用移动的窗口分区配置的基于window的multi-head self-attention

    移位窗口分割方法引入了前一层相邻非重叠窗口之间的连接,被发现在图像分类、目标检测和语义分割上是非常有效的。

    v2-ba8ca99ef451401fd1da5e202f43edab_b.jpg

    在计算self-attention,此处我们引入一个相对位置bias:

    v2-49910c632a5f5901d9843040d0cdb24f_b.jpg

    我们观察到与没有这个偏差项或使用绝对位置嵌入的对应项相比有显著的改进。如[19]中所述,进一步向输入中添加绝对位置嵌入会略微降低性能,因此在我们的实现中不采用这种方法。

    在预训练中学习到的相对位置偏差也可以用来初始化模型,通过bi-cubic插值对不同窗口大小的模型进行微调。

    v2-c5870996eecefda50578a96fbac2a6b2_b.jpg

    我们建立了与ViTB/DeiT-B相似计算复杂度的模型Swin-B,并介绍了Swin-T、Swin-S和Swin-L,它们分别是模型大小和计算复杂度的0.25倍、0.5倍和2倍。

    v2-046ba937da8268e0eddbcaed96c706e6_b.jpg

    v2-f0d23bcb9f13eaa987f4e29d83e2d0d6_b.jpg

    1. ImageNet-1K的图像分类

    v2-2b2eae068d444e3dc1d1eda98e1e896b_b.jpg
    • 与最先进的ConvNets(RegNet和EfficientNet)相比,Swin Transformer有更好一点的速度精度trade-off。
    • 虽然RegNet和EfficientNet是通过彻底的架构搜索获得的,但所提出的Swin Transformer是从标准Transformer改编而来的,具有很强的潜力。
    • 对于Swin-B,ImageNet22K预训练比ImageNet-1K从头开始的培训带来了**1.8%∼1.9%**的收益;
    • 与之前ImageNet-22K预训练的最佳结果相比,我们的模型实现了显著更好的速度-精度折衷:Swin-B获得86.0%的top-1精度,比ViT高2.0%,具有相似的推理吞吐量(84.7 vs.85.9 images/秒)和略低的FLOPs(47.0G vs.55.4G)。更大的Swin-L模型达到86.4%的top-1精度,略好于Swin-B模型。

    2. COCO的目标检测


    v2-602bdbf823f75a515a833447fb42bb5f_b.jpg
    • 与ResNet-50相比,Swin-T框架带来了+3.4∼4.2 box的AP增益,具有略大的模型大小、FLOPS和延迟;
    • Swin-Transformer可以拿到51.9 box-AP和45.0 mask-AP的高检测精度,与ResNeXt101-64x4d相比,可以获得+3.6 box-AP和+3.3mask-AP的显著增益,ResNeXt101-64x4d具有相似的模型大小、触发器和延迟
    • 在使用改进的HTC框架的52.3 box AP和46.0 mask AP的较高基线上,Swin-Transformer的增益也较高,分别为+4.1 box AP和+3.1 mask AP;
    • 使用级联Mask R-CNN框架的DeiT-S的性能。Swin-T的结果是+2.5 box-AP和+2.3mask-AP高于DeiT-S,模型尺寸相似(86M对80M),推理速度显著提高(15.3fps对10.4fps);
    • 我们的最佳模型在COCO test dev上实现了58.7 box AP和51.1 mask AP,超过了之前的最佳结果+2.7 box AP和+2.6 mask AP(DetectoRS)。

    3. ADE20K的语义分割

    v2-fc9f3ca94d420cd8cdafb6e7301b7791_b.jpg
    • 在计算成本相似的情况下,Swin-S比DeiT-S高出5.3 mIoU(49.3比44.0)。
    • 比ResNet-101高出4.4mIoU,比ResNeSt-101高出2.4 mIoU。我们的带有ImageNet-22K预训练的Swin-L模型在val集上实现了53.5 mIoU,超过了以前最好的模型+3.2mIoU.

    4. 解耦实验

    v2-2f7bce82bf672ee588941c09e62b1ae5_b.jpg
    • 在ImageNet-1K、COCO和ADE20K上,采用移位窗口划分的Swin-T比采用单一窗口划分的Swin-T在每个阶段的精度都高出+1.1%top-1、+2.8 box AP/+2.2 mask AP和+2.8 mIoU。
    • 具有相对位置偏差的Swin-T在ImageNet-1K上产生+1.2%/+0.8%的top-1精度;在COCO上+1.3/+1.5 box AP和+1.1/+1.3 mask AP;以及+2.3/+2.9 mIoU在ADE20K上分别与那些没有位置编码和绝对位置嵌入的相关,
    • 相对位置偏差的有效性。同时也注意到,虽然绝对位置嵌入的加入提高了图像分类的准确率(+0.4%),但它不利于目标检测和语义分割;

    v2-0cc845ed0b4a240c092059cf7523c620_b.jpg
    • 我们的cyclic实现比单纯的填充更具硬件效率,特别是对于更深层的阶段。总的来说,它可以为Swin-T、Swin-S和Swin-B带来13%、18%和18%的加速;
    • 构建在移动窗口上的Swin-Transformer架构分别比构建在滑动窗口上的Swin-T、Swin-S和Swin-B快4.1/1.5、4.0/1.5和3.6/1.5倍;
    • 与Performer相比,Performer是速度最快的Transformer体系结构之一,我们的基于shifted window的self-attention计算和整体Swin-Transformer体系结构稍快,同时与使用Swin-T的ImageNet-1K上的Performer相比,提升了+2.3%的top-1精度。

    v2-f590e1abcaa1947ec3bf0057ae3325cc_b.jpg

    本文提出了一种新的视觉Transformer Swin-Transformer,它产生了一种层次化的特征表示,其计算复杂度与输入图像的大小成线性关系。Swin-Transformer在COCO目标检测和ADE20K语义分割方面达到了最先进的性能,显著超过了

    以前的最佳方法。我们希望Swin-Transformer在各种视觉问题上的强大性能将促进视觉和语言信号的统一建模。

    作为Swin-Transformer的一个关键元素,基于移位窗口的自我注意被证明是解决视觉问题的有效方法,我们也期待着研究它在自然语言处理中的应用。

    霸榜各大CV任务榜单,Swin Transformer横空出世!

    展开全文
  • 分类 图像价值16x16字:用于图像识别的变压器[VIT] [ICLR 2021] [] [] DeiT:数据高效的图像变压器[arxiv2021] [] [] 侦测 DETR:使用变压器进行端到端对象检测[ECCV2020] [] [] 可变形DETR:用于端到端对象检测的...
  • 自从ViT之后,关于vision transformer的研究呈井喷式爆发,从思路上分主要沿着两大个方向,一是提升ViT在图像分类的效果;二就是将ViT应用在其它图像任务中,比如分割和检测任务上,这里介绍的**PVT(Pyramid Vision...

    自从ViT之后,关于vision transformer的研究呈井喷式爆发,从思路上分主要沿着两大个方向,一是提升ViT在图像分类的效果;二就是将ViT应用在其它图像任务中,比如分割和检测任务上,这里介绍的**PVT(Pyramid Vision Transformer)**就属于后者。PVT相比ViT引入了和CNN类似的金字塔结构,使得PVT像CNN那样作为backbone应用在dense prediction任务(分割和检测等)。

    在这里插入图片描述

    CNN结构常用的是一种金字塔架构,如上图所示,CNN网络一般可以划分为不同的stage,在每个stage开始时,特征图的长和宽均减半,而特征维度(channel)扩宽2倍。这主要有两个方面的考虑,一是采用stride=2的卷积或者池化层对特征降维可以增大感受野,另外也可以减少计算量,但同时空间上的损失用channel维度的增加来弥补。但是ViT本身就是全局感受野,所以ViT就比较简单直接了,直接将输入图像tokens化后就不断堆积相同的transformer encoders,这应用在图像分类上是没有太大的问题。但是如果应用在密集任务上,会遇到问题:一是分割和检测往往需要较大的分辨率输入,当输入图像增大时,ViT的计算量会急剧上升;二是ViT直接采用较大patchs进行token化,如采用16x16大小那么得到的粗粒度特征,对密集任务来说损失较大。这正是PVT想要解决的问题,PVT采用和CNN类似的架构,将网络分成不同的stages,每个stage相比之前的stage特征图的维度是减半的,这意味着tokens数量减少4倍,具体结构如下:

    在这里插入图片描述

    每个stage的输入都是一个维度Hi×Wi×CiH_i\times W_i \times C_i的3-D特征图,对于第1个stage,输入就是RGB图像,对于其它stage可以将tokens重新reshape成3-D特征图。在每个stage开始,首先像ViT一样对输入图像进行token化,即进行patch embedding,patch大小均采用2x2大小(第1个stage的patch大小是4x4),这意味着该stage最终得到的特征图维度是减半的,tokens数量对应减少4倍。PVT共4个stage,这和ResNet类似,4个stage得到的特征图相比原图大小分别是1/4,1/8,1/16和1/32。由于不同的stage的tokens数量不一样,所以每个stage采用不同的position embeddings,在patch embed之后加上各自的position embedding,当输入图像大小变化时,position embeddings也可以通过插值来自适应。

    不同的stage的tokens数量不同,越靠前的stage的patchs数量越多,我们知道self-attention的计算量与sequence的长度NN的平方成正比,如果PVT和ViT一样,所有的transformer encoders均采用相同的参数,那么计算量肯定是无法承受的。PVT为了减少计算量,不同的stages采用的网络参数是不同的。PVT不同系列的网络参数设置如下所示,这里PP为patch的size,CC为特征维度大小,NN为MHA(multi-head attention)的heads数量,EE为FFN的扩展系数,transformer中默认为4。

    在这里插入图片描述

    可以见到随着stage,特征的维度是逐渐增加的,比如stage1的特征维度只有64,而stage4的特征维度为512,这种设置和常规的CNN网络设置是类似的,所以前面stage的patchs数量虽然大,但是特征维度小,所以计算量也不是太大。不同体量的PVT其差异主要体现在各个stage的transformer encoder的数量差异。

    PVT为了进一步减少计算量,将常规的multi-head attention (MHA)用spatial-reduction attention (SRA)来替换。SRA的核心是减少attention层的key和value对的数量,常规的MHA在attention层计算时key和value对的数量为sequence的长度,但是SRA将其降低为原来的1/R21/R^2。SRA的具体结构如下所示:

    在这里插入图片描述

    在实现上,首先将维度为HW×CH W \times C的patch embeddings通过
    reshape变换到维度为H×W×CH \times W \times C的3-D特征图,然后均分大小为R×RR\times R的patchs,每个patchs通过线性变换将得到维度为HWR2×C\frac{H W}{R^2} \times C的patch embeddings(这里实现上其实和patch emb操作类似,等价于一个卷积操作),最后应用一个layer norm层,这样就可以大大降低K和V的数量。具体实现代码如下:

    class Attention(nn.Module):
        def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0., sr_ratio=1):
            super().__init__()
            assert dim % num_heads == 0, f"dim {dim} should be divided by num_heads {num_heads}."
    
            self.dim = dim
            self.num_heads = num_heads
            head_dim = dim // num_heads
            self.scale = qk_scale or head_dim ** -0.5
    
            self.q = nn.Linear(dim, dim, bias=qkv_bias)
            self.kv = nn.Linear(dim, dim * 2, bias=qkv_bias)
            self.attn_drop = nn.Dropout(attn_drop)
            self.proj = nn.Linear(dim, dim)
            self.proj_drop = nn.Dropout(proj_drop)
    
            self.sr_ratio = sr_ratio
            # 实现上这里等价于一个卷积层
            if sr_ratio > 1:
                self.sr = nn.Conv2d(dim, dim, kernel_size=sr_ratio, stride=sr_ratio)
                self.norm = nn.LayerNorm(dim)
    
        def forward(self, x, H, W):
            B, N, C = x.shape
            q = self.q(x).reshape(B, N, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3)
    
            if self.sr_ratio > 1:
                x_ = x.permute(0, 2, 1).reshape(B, C, H, W)
                x_ = self.sr(x_).reshape(B, C, -1).permute(0, 2, 1) # 这里x_.shape = (B, N/R^2, C)
                x_ = self.norm(x_)
                kv = self.kv(x_).reshape(B, -1, 2, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
            else:
                kv = self.kv(x).reshape(B, -1, 2, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
            k, v = kv[0], kv[1]
    
            attn = (q @ k.transpose(-2, -1)) * self.scale
            attn = attn.softmax(dim=-1)
            attn = self.attn_drop(attn)
    
            x = (attn @ v).transpose(1, 2).reshape(B, N, C)
            x = self.proj(x)
            x = self.proj_drop(x)
    
            return x
    

    从PVT的网络设置上,前面的stage的RR取较大的值,比如stage1的R=8R=8,说明这里直接将Q和V的数量直接减为原来的1/64,这个就大大降低计算量了。

    PVT具体到图像分类任务上,和ViT一样也通过引入一个class token来实现最后的分类,不过PVT是在最后的一个stage才引入:

        def forward_features(self, x):
            B = x.shape[0]
    
            # stage 1
            x, (H, W) = self.patch_embed1(x)
            x = x + self.pos_embed1
            x = self.pos_drop1(x)
            for blk in self.block1:
                x = blk(x, H, W)
            x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()
    
            # stage 2
            x, (H, W) = self.patch_embed2(x)
            x = x + self.pos_embed2
            x = self.pos_drop2(x)
            for blk in self.block2:
                x = blk(x, H, W)
            x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()
    
            # stage 3
            x, (H, W) = self.patch_embed3(x)
            x = x + self.pos_embed3
            x = self.pos_drop3(x)
            for blk in self.block3:
                x = blk(x, H, W)
            x = x.reshape(B, H, W, -1).permute(0, 3, 1, 2).contiguous()
    
            # stage 4
            x, (H, W) = self.patch_embed4(x)
            cls_tokens = self.cls_token.expand(B, -1, -1) # 引入class token
            x = torch.cat((cls_tokens, x), dim=1)
            x = x + self.pos_embed4
            x = self.pos_drop4(x)
            for blk in self.block4:
                x = blk(x, H, W)
    
            x = self.norm(x)
    
            return x[:, 0]
    

    具体到分类任务上,PVT在ImageNet上的Top-1 Acc其实是和ViT差不多的。其实PVT最重要的应用是作为dense任务如分割和检测的backbone,一方面PVT通过一些巧妙的设计使得对于分辨率较大的输入图像,其模型计算量不像ViT那么大,论文中比较了ViT-Small/16 ,ViT-Small,PVT-Small和ResNet50四种网络在不同的输入scale下的GFLOPs,可以看到PVT相比ViT要好不少,当输入scale=640时,PVT-Small和ResNet50的计算量是类似的,但是如果到更大的scale,PVT的增长速度就远超过ResNet50了。

    ![image.png-54.4kB][5]

    PVT的另外一个相比ViT的优势就是其可以输出不同scale的特征图,这对于分割和检测都是非常重要的。因为目前大部分的分割和检测模型都是采用FPN结构,而PVT这个特性可以使其作为替代CNN的backbone而无缝对接分割和检测的heads。论文中做了大量的关于检测,语义分割以及实例分割的实验,可以看到PVT在dense任务的优势。比如,在更少的推理时间内,基于PVT-Small的RetinaNet比基于R50的RetinaNet在COCO上的AP值更高(38.7 vs. 36.3),虽然继续增加scale可以提升效果,但是就需要额外的推理时间:

    在这里插入图片描述

    所以虽然PVT可以解决一部分问题,但是如果输入图像分辨率特别大,可能基于CNN的方案还是最优的。另外旷视最新的一篇论文YOLOF指出其实ResNet一个C5特征加上一些增大感受野的模块就可以在检测上实现类似的效果,这不得不让人思考多尺度特征是不是必须的,而且transformer encoder本身就是全局感受野的。近期Intel提出的DPT直接在ViT模型的基础上通过Reassembles operation来得到不同scale的特征图以用于dense任务,并在ADE20K语义分割数据集上达到新的SOTA(mIoU 49.02)。而在近日,微软提出的Swin Transformer和PVT的网络架构和很类似,但其性能在各个检测和分割数据集上效果达到SOTA(在ADE20K语义分割数据集mIoU 53.5),其核心提出了一种shifted window方法来减少self-attention的计算量。

    相信未来会有更好的work!期待!

    参考

    1. Pyramid Vision Transformer: A Versatile Backbone for Dense Prediction without Convolutions
    2. whai362/PVT
    3. 大白话Pyramid Vision Transformer
    4. You Only Look One-level Feature
    5. Swin Transformer: Hierarchical Vision Transformer using Shifted Windows
    6. Vision Transformers for Dense Prediction
    展开全文
  • 基于双向transformer编码器及卷积操作的增强语义关系分类,段希,张茹,最近,经过预训练的BERT模型在许多NLP任务中都取得了非常成功的效果。关系分类不同于其他任务,因为它依赖于句子和两个目标实体的�
  • 介绍Transformer的发明最近取代了自然语言处理的世界。transformers是完全无视传统的基于序列的网络。RNN是用于基于序列的任务(如文本生成,文本分类等)的最初武器。但是,...
  • 文本分类不是生成式的任务,因此只使用Transformer的编码部分(Encoder)进行特征提取。如果不熟悉Transformer模型的原理请移步。 网络结构 代码实现 自注意力模型: class TextSlfAttnNet(nn.Module): ''' 自...
  • 文章目录Pyramid Vision Transformer: A Versatile Backbone for Dense Prediction without Convolutions前言与ViT和CNN的比较下游任务分类检测分割其他的一些细节链接 原始文档:https://www.yuque.com/lart/paper
  • 点蓝色字关注“机器学习算法工程师”设为星标,干货直达!自从ViT之后,关于vision transformer的研究呈井喷式爆发,从思路上分主要沿着两大个方向,一是提升ViT在图像分类的效...
  • 第一个是手工进行的特征提取和分类,第二个使用深度神经网络。 在我们的论文中,我们还提出了用于年龄估计的视觉转换器。 它是最早提出用于面部任务的视觉转换器之一,因此没有预训练的模型。 但是,我们仍然设法在...
  • 2.bert是一个预训练语言模型,bert是一个考虑上下文(双向)的模型,为了适配多任务下的迁移学习,BERT设计了更通用的输入层和输出层,学习阶段如下: 本次NLP训练营有些遗憾,特别是对知识的理解。 ...
  • 深度学习模型完成文本分类任务,首先对文本进行embedding表示,再利用深度模型自动获取特征表达能力,去掉繁杂的人工特征工程,实现端到端的文本分类。文本分类模型训练过程文本分类模型预测过程...
  • Transformer在视觉领域的应用前言在机器翻译, NLP领域, 基于attention机制的transformer模型取得了很好的结果, 目前有许多工作把Transformer用到CV领域, 实现端到端的目标检测和图片分类。 在这篇博客中, 我们...
  • Graph Transformer Networks与...图神经网络(GNNs)已被广泛应用于图形的表示学习,并在节点分类和链路预测等任务中取得了最先进的性能。然而,大多数现有的神经网络被设计来学习固定和同构图上的节点表示。当学习由各
  • Transformer的原理

    千次阅读 2019-05-29 00:33:59
    这是第10个任务,本次任务主要是一下几个方面: Transformer的原理 BERT的原理 利用预训练的BERT模型将句子转换为句向量,进行文本分类1 Transformer原理 和大多数seq2seq模型一样,transformer的结构也是由...
  • 承接前两篇笔记邓文涛:NLP中文文本分类任务的笔记(一)​zhuanlan.zhihu.com邓文涛:NLP中文文本分类任务的笔记(二)​zhuanlan.zhihu.com这篇主要想讲一讲对transformer和BERT框架的一些个人理解。关于细节一些...
  • Learning Texture Transformer Network for Image Super-Resolution, CVPR2020Paper:https://arxiv.org/abs/2006.04139​arxiv.org最近可以看到很多transformer迁移到CV各个任务的工作(分类、检测、分割......
  • 详解DETR和Transformer

    2020-12-14 11:13:35
    在机器翻译, NLP领域, 基于attention机制的transformer模型取得了很好的结果, 目前有许多工作把Transformer用到CV领域, 实现端到端的目标检测和图片分类。 在这篇博客中, 我们会从Attention机制开始回顾, 之后...
  • 该模型在分类、检测等多个任务上屠榜! 文章标题:Swin Transformer: Hierarchical Vision Transformer using Shifted Windows 论文地址:https://arxiv.org/abs/2103.14030 代码地址:Swin Transformer 1 概述  ...
  • A Survey on Visual Transformer

    千次阅读 2020-12-24 11:00:05
    本文将视觉Transformer模型根据不同的任务进行分类(如检测、分类、视频等),并分析了这些方法的优缺点! 注:文末附**【Transformer】**学习交流群 A Survey on Visual Transformer 作者单位:华为诺亚, 北京...
  • Video Transformer Network阅读笔记 Abstract VTN, a transformer-based framework for video recognition. 抛弃3D ConvNets,引入了一种通过关注...基于transformer在许多任务上的应用,CNN的优势不在[8, 2, 27, 31]

空空如也

空空如也

1 2 3 4 5 ... 12
收藏数 228
精华内容 91
热门标签
关键字:

transformer分类任务