ViT 家族的大杂烩(An Image is worth 16×16 Words)

GitHub - lucidrains/vit-pytorch: Implementation of Vision Transformer, a simple way to achieve SOTA in vision classification with only a single transformer encoder, in Pytorch

鉴于上述github主整理了如此多的模型,下面将其列表放上,并尽量整理出一个表格,由精度从低到高显示。

 

 这两张从论文中截的表可以看出RegionViT-B 与NesT-B 、Twins-SVT-L 模型的精度都达到83.8左右 在ImageNet1k数据集上。

这么多模型在Readme 震惊! 最近新出了新模型已经超过ViT

Cross ViT / 何神的MAE 屏蔽自编码神器!

慢慢上新RegionViT: Regional-to-Local Attention for Vision Transformers(83.8)

微软的SimMIM: A Simple Framework for Masked Image Modeling 会马上跟踪上去!

1、ViT模型

将CNN 结构全改成Transformer形式,输入的token 是patch 格式,就是N*N 的patch, N 小于图片的宽和高。而CNN卷积形式,由self-attention 代替。作者在实验的时候发现在小数据集上没有超越ResNet 这种优异的模型,但是当数据集大的时候,可以超越它们。利用数据打败结构!目前ViT github 代码已有 4k star  谷歌巨作。其实在Transformer 模型中,研究人员要不选择目标框的特征做Token , 要不选择 Patch 将图片分成多块做token。

GitHub - google-research/vision_transformer

 直接看结构图,应该都能看懂,利用线性将各个patch 编码成一向量 与位置编码融合输入Transformer 中。其中token序列的第一位为【cls】 token。 为了将其作为分类的标记位。其他Transformer 操作保留。 

输入的向量长度需要转换成每层的D维隐藏向量长度,且通过加和形式嵌入位置编码。

公式1 就是指的第一层最终的输入向量形式。后面的字母l 指的是层数。通过Transformer的经典操作MSA 和MLP 构成每一层的操作,最后一层的向量通过公式(4) 输入到分类器层进行图片分类等具体目标任务。0 指的就是【cls】token 的位置序号id。

作者文中指出,最终仍然选用1D 的编码,因为2D 并没有显示出更好的性能。

作者指出其实还有一种Hybrid 框架,例如,上述描述的是直接从源数据的图片直接变换输入到Transformer 。当然这种patch的获得也可以是经过几层CNN ,然后再变成一堆patch 输入到Transformer模型中。

此模型也有两个阶段,大规模数据集预训练和小数据集任务微调。两种阶段的不同在于分类器层的不同。根据具体任务变换输出层的长度。

遵从Bert 的模型大小,ViT也设计了三种尺寸大小的模型,Base Large 和Huge

 可以看出基本所有的ViT都超过了BiT-L 的ResNet 模型的识别精度 

预训练数据集的大小分析:

 从图三中可以看出,在小数据集中BiT这种ResNet 形式的网络是优于ViT。当数据集的规模变大时,ViT还是可以逆袭的。当然ViT 的模型大小也是随着数据集规模大小而逆袭。

混合模型也就是利用resnet 嵌入patch 向量后面沿用ViT模型仍然出现在小数据集效果好,在大数据逊色于ViT。 难怪,现在大训练集的patch 方式都选择直接的原始数据,而不用经过卷积层,例如最新出的跨模态模型SimVL,同样是Google 出品。

 这是可视化第一层嵌入的过滤器,和位置嵌入相似度,可以看出中间图,网络是可以学习到2D的位置编码

2、CrossViT模型

先上图

下面是上面的Cross-Attention 模块的融合方式 

本文是第一个探索ViT家族中的多尺度 双分支模型。作者指出这里一大特色就是两个尺度是如何有效的信息融合,作者使用了CLS 位的信息量进行交互评估,极大地减少了模型地交互计算量。

左边是小patch 分支,patch维度小,层数小,

右边是大patch 分支,patch维度大,层数多,

通过两个分支的交互,补充各自的信息。

作者指出ViT模型中16 的小patch 精度是32 大patch 高了6个点,但是计算量空间却极大,作者希望利用多尺度提高精度,且能获得较小的计算量。

作者的框架图是很清晰的。在进入交互层之前,这两个分支分别都融入了位置信息,只是图中没有标记出来而已。最终的图片分类任务是通过两个分支的cls token 的向量分别共同预测即可。

图3的标题其实很清晰,(a)方式所有都融合,没有什么区别性(b)只融合cls 两个,其他不变。(c)成对融合(d)就是作者的最佳融合方式。

从表6作者的实验,发现前三种效果差不多,只有最后一种精度能提高接近1个点。 

All-Attention Fusion.

拼接两个分支的token ,然后利用自注意力形式去融合信息,两端拼接后的自注意力操作。

这里应该是两个分支的token拼接通过f 函数化成token 向量一致,然后送入常见的MSA模块,多头注意力,然后将结果进行分片,两边分别通过g函数回归到原先的维度。 

Class Token Fusion.

这个计算量贼少,只是将两分支的cls 相加,其他token 不变的传到下一层即可。这里的f 和g 函数仍然是维度转换器,才能进行相加操作和返回原向量维度进行拼接patch。

Pairwise Fusion.

由于patch 大小不同两边的长度也不等。此处为了进行成对操作,采取了插值的方式,使得两分支的长度相等后,然后一一对应进行相加。

虽然想了这么多,看表6 的结果发现,效果都差不多,所以还是实践出真知,看着挺好,运行就不知道什么情况了! 

Cross-Attention Fusion.

此处简单来说就是用一个分支的cls 跟另一个分支的patch 们打交道,打完交道后再传递回自己分支的那些patch .emmmmmm, cls 就是融合了所有patch 的信息的使者呀!

 此式显示交换cls ,下面两式也非常好理解,就是将一分支的cls 作为查询向量,该cls 与另一分支拼成的patch 们作为key 和value。然后进行多头跨注意力融合。(6)式就是7式MCA的一个头的操作。

然后利用残差和形式得到更新后的cls 。 然后将其与自己分支的patch 们拼接一下。

出自作者github:https://github.com/IBM/CrossViT/blob/main/models/crossvit.py

class CrossAttention(nn.Module):
    def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
        super().__init__()
        self.num_heads = num_heads
        head_dim = dim // num_heads
        # NOTE scale factor was wrong in my original version, can set manually to be compat with prev weights
        self.scale = qk_scale or head_dim ** -0.5

        self.wq = nn.Linear(dim, dim, bias=qkv_bias)
        self.wk = nn.Linear(dim, dim, bias=qkv_bias)
        self.wv = nn.Linear(dim, dim, bias=qkv_bias)
        self.attn_drop = nn.Dropout(attn_drop)
        self.proj = nn.Linear(dim, dim)
        self.proj_drop = nn.Dropout(proj_drop)

    def forward(self, x):

        B, N, C = x.shape
        q = self.wq(x[:, 0:1, ...]).reshape(B, 1, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3)  # B1C -> B1H(C/H) -> BH1(C/H)
        k = self.wk(x).reshape(B, N, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3)  # BNC -> BNH(C/H) -> BHN(C/H)
        v = self.wv(x).reshape(B, N, self.num_heads, C // self.num_heads).permute(0, 2, 1, 3)  # BNC -> BNH(C/H) -> BHN(C/H)

        attn = (q @ k.transpose(-2, -1)) * self.scale  # BH1(C/H) @ BH(C/H)N -> BH1N
        attn = attn.softmax(dim=-1)
        attn = self.attn_drop(attn)

        x = (attn @ v).transpose(1, 2).reshape(B, 1, C)   # (BH1N @ BHN(C/H)) -> BH1(C/H) -> B1H(C/H) -> B1C
        x = self.proj(x)
        x = self.proj_drop(x)
        return x


class CrossAttentionBlock(nn.Module):

    def __init__(self, dim, num_heads, mlp_ratio=4., qkv_bias=False, qk_scale=None, drop=0., attn_drop=0.,
                 drop_path=0., act_layer=nn.GELU, norm_layer=nn.LayerNorm, has_mlp=True):
        super().__init__()
        self.norm1 = norm_layer(dim)
        self.attn = CrossAttention(
            dim, num_heads=num_heads, qkv_bias=qkv_bias, qk_scale=qk_scale, attn_drop=attn_drop, proj_drop=drop)
        # NOTE: drop path for stochastic depth, we shall see if this is better than dropout here
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()
        self.has_mlp = has_mlp
        if has_mlp:
            self.norm2 = norm_layer(dim)
            mlp_hidden_dim = int(dim * mlp_ratio)
            self.mlp = Mlp(in_features=dim, hidden_features=mlp_hidden_dim, act_layer=act_layer, drop=drop)

    def forward(self, x):
        x = x[:, 0:1, ...] + self.drop_path(self.attn(self.norm1(x)))
        if self.has_mlp:
            x = x + self.drop_path(self.mlp(self.norm2(x)))

        return x

3、RegionViT模型 

思想:将图片分成多个不重叠的大块,每个大块里面又可以分细小块,然后大块先自注意力得到全局信息,然后将更新后的大块信息与自己所属于的小块信息交流,就可以让小块拥有全局信息。这样相比于ViT 每个小块都要与全图所有小块交流 大大提高了效率,减少了很多计算量。(感觉这个想法还是很容易想到的)

下面是主要的思想图 

(a)图为最原始ViT。 ( b)PVT 采用了金字塔形式,随着层数的升高,增加patch 的大小,(c)本模型,在PVT基础上,利用高层的大patch 与其内部的小patch 进行局部交流,减少运算,大patch 进行整图运算,大patch集合了最广的全局信息,通过局部交流让小patch 也能关注到全局信息。

下面是RegionViT 的整体架构图,官网的代码还没有放出来! 

在分类任务中,region 分支的平均后输入到分类器层,目标检测用到所有的token 因为都提供了位置信息。

下面是具体的区域与所对应的局部小块如何交互的示意图

4、Masked Autoencoders Are Scalable Vision Learners

何神的作品MAE

 先上效果图吧

屏蔽了75%的像素,中间是重建出来的,右边是原图。感觉像去噪自动编码器的工作 

哎呀,复制不了到知乎,所以分两部分吧。MAE其他部分看知乎。

ViT家族大杂烩(部分代码移植csdn博客) - 知乎

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值