一、简介

 1. Vision Transformer(ViT)是一种基于Transformer架构的深度学习模型,它将Transformer模型从自然语言处理(NLP)领域成功扩展到计算机视觉(CV)领域。

 2. Vision Transformer由Google Brain团队在2020年提出,该模型挑战了卷积神经网络(CNN)在视觉任务中的主导地位,证明了Transformer架构不仅在处理序列数据(如文本)方面非常有效,在处理图像数据时也能取得卓越性能。

 3. Vision Transformer的核心思想是将输入的图像视为一个序列化的输入,通过自注意力机制来处理图像中的像素关系。具体而言,ViT首先将输入图像划分为多个固定大小的图像块(Patches),然后对每个图像块进行线性映射(Flattening + Linear Projection),将其转换成一个向量。这些向量连同一个特殊的分类Token一起作为Transformer的输入序列。这样,图像就被转换成了一个序列数据,从而可以直接应用自注意力机制进行特征提取。

二、模型结构

2.1 整体架构

 ViT模型如下架构图所示,其中主要有三个部分组成:(1) Linear Projection of Flattened Patches(Embedding层,将子图映射为向量);(2) Transformer Encoder(编码层,对输入的信息进行计算学习);(3) MLP Head(用于分类的层结构)。

在这里插入图片描述

在这里插入图片描述

2.2 Linear Projection of Flattened Patches

 1. Linear Projection of Flattened Patches(平铺块的线性投影)是ViT模型架构中的一个重要组成部分。这个过程主要涉及到将输入的图像数据转换为Transformer模型能够处理的一维向量序列。

 2. 作用与目的:
 (1)图像数据转换:由于标准的Transformer模型接收的是一维的嵌入序列,而图像数据是三维的(高度H、宽度W、通道数C),因此需要通过线性投影将图像数据转换为Transformer能够处理的格式。
 (2)信息提取:通过平铺和线性投影,图像被划分为多个小块(Patches),每个小块被转换为一个一维向量,这些向量包含了图像中的局部信息。

 3. 具体步骤:
 (1)图像划分:将输入图像按照预定的尺寸(如16x16)划分为多个小块(Patches)。以ViT-B/16为例,如果输入图像的大小为224x224,则会被划分为(224/16)x(224/16)=196个小块。

 (2)平铺操作:将每个小块展平(Flatten)为一维向量。

 (3)线性投影:使用一个线性层(通常是卷积层)将每个展平后的小块映射到一个更高维的向量空间中。这个线性层的作用是将每个小块的特征进行抽象和整合,以便后续的自注意力机制能够处理。以ViT-B/16为例,线性投影层通常使用一个卷积核大小为16x16、步距为16、卷积核个数为768的卷积来实现。这个卷积操作会生成一个形状为[14, 14, 768]的特征图(由于步距为16,所以高度和宽度都减少了),然后将其展平为[196, 768]的形状,即196个长度为768的向量(后面都直接称为token)。

在这里插入图片描述

 (4)添加特殊Token和位置编码:在所有向量序列的开头添加一个特殊的class Token(分类Token),用于后续的图像分类任务。这个Token是一个可训练的参数,与其他向量具有相同的维度。给每个向量添加一个位置编码(Position Embedding),以保留它们在图像中的位置信息。位置编码通常是可学习的,并且与向量的维度相同。

 4. 图像分块代码块:

class PatchEmbed(nn.Module):
    def __init__(self, input_shape = [224,224], patch_size = 16, in_channels = 3, num_features = 768, norm_layer = None, flatten = True):
        super().__init__()
        # num_patch就是可以划分多少个图像块,14*14的patch = 196
        self.num_patch = (input_shape[0] // patch_size) * (input_shape[1] // patch_size) 
        self.flatten = flatten
 
        self.proj = nn.Conv2d(in_channels, num_features, kernel_size=patch_size, stride=patch_size)
        self.norm = norm_layer(num_features) if norm_layer else nn.Identity()
 
    def forward(self, x):
        # proj就是对输入图像进行卷积分块
        x = self.proj(x) 
        if self.flatten:
            x = x.flatten(2).transpose(1, 2)
        x = self.norm(x)
        return x

 每个图像块都是经过一次特征提取的,可以对其中的一个图像块可视化一下看看:

在这里插入图片描述

# class token的定义
self.cls_token      = nn.Parameter(torch.zeros(1, 1, num_features))
# position embedding定义
self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, num_features))

在这里插入图片描述

在这里插入图片描述

2.3 Transformer Encoder

Transformer Encoder是属于Transformer中的内容,具体请看:深度学习(6)—Transformer

 Encoder结构如下图所示,左侧为实际结构,右侧为论文中结构,省去了Dropout/DropPath层。
在这里插入图片描述

 MLP Block结构如下图所示,由全连接+激活函数+Dropout组成:

在这里插入图片描述

 经过多层Transformer Encoder处理后,最开始添加的分类Token的特征向量被提取出来,该向量包含了关于整个图像的综合信息。
 在Vision Transformer中,通常会在Transformer编码器的输出之后添加一个多层感知机(MLP)用于最终的任务输出,如在图像分类任务中预测类别。

2.4 MLP Head

 1. 在经过Transformer Encoder时,输入的shape和输出的shape保持不变。在论文中,以ViT-B/16为例,输入的是[197, 768]输出的还是[197, 768]。在Transformer Encoder后还有一个Layer Norm,结构图中并没有给出,如下图所示:
在这里插入图片描述

 2. MLP Head通过一系列的全连接层(Fully Connected Layers)和激活函数来将Transformer Encoder输出的表示向量进一步处理,以生成对应于不同类别的概率分布。

 3. 这里我们只是需要Transformer Encoder中的分类信息,所以我们只需要提取出class token生成的对应结果就行,即[197, 768]中抽取出class token对应的[1, 768],因为self-attention计算全局信息的特征,这个class token其中已经融合了其他token的信息。接着我们通过MLP Head得到我们最终的分类结果。

三、ViT模型搭建参数

 1. 为了方便大家理解,我自己根据源代码画了张更详细的图(以ViT-B/16为例):

在这里插入图片描述

 2. 在论文中有给出三个模型(Base/ Large/ Huge)的参数,在源码中除了有Patch Size为16x16的外还有32x32的。其中:
 (1)Layers是Transformer Encoder中重复堆叠Encoder Block的次数。
 (2)Hidden Size是对应通过Embedding层后每个token的dim(向量的长度)。
 (3)MLP size是Transformer Encoder中MLP Block第一个全连接的节点个数(是Hidden Size的四倍)。
 (4)Heads代表Transformer中Multi-Head Attention的heads数。
 (5)Params代表参数的个数。

ModelPatch SizeLayersHidden Size DMLP sizeHeadsParams
ViT-Base16x161276830721286M
ViT-Large16x16241024409616307M
ViT-Huge14x14321280512016632M

四、思考题

 为什么Vision Transformer比CNN效果好?
 (1)Vision Transformer采用了Transformer架构中的自注意力机制,这种机制能够捕获图像中任意两个像素或图像块之间的依赖关系,而不仅仅是局部信息。相比之下,CNN虽然能够提取局部特征,但在处理全局依赖关系时可能存在局限。
 (2)ViT通过将图像分割成一系列小块(patches)并作为序列处理,使得每个patch在模型中的表示都能够考虑到整个图像的信息,从而具有全局感受野。而CNN的感受野大小受限于卷积核的大小和网络的深度。

GitHub 加速计划 / vi / vision
15.84 K
6.89 K
下载
pytorch/vision: 一个基于 PyTorch 的计算机视觉库,提供了各种计算机视觉算法和工具,适合用于实现计算机视觉应用程序。
最近提交(Master分支:1 个月前 )
6d7851bd 4 天前
7eb09df3 Co-authored-by: Nicolas Hug <nh.nicolas.hug@gmail.com> 4 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐