Skip to content
Published on

Vision Transformer(ViT)论文深度解析:一张图像相当于16x16个单词

分享
Authors

1. 论文概述

《An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale》是2020年10月由Google Research的Alexey Dosovitskiy、Lucas Beyer、Alexander Kolesnikov等人发表、并在ICLR 2021正式收录的论文。该论文证明了在NLP领域取得压倒性成功的Transformer架构,几乎无需修改,即可直接应用于Computer Vision的图像分类任务。

核心思想简单得惊人:将图像分割成固定大小的patch,把每个patch当作NLP中的token来处理,输入标准的Transformer Encoder。论文标题本身就直观地说明了这一点——一张图像由16x16大小的单词组成

结果具有颠覆性。在JFT-300M这一大规模数据集上预训练的ViT-H/14模型,在ImageNet上达到了88.55% top-1 accuracy,超越了现有基于CNN的SOTA(State-of-the-Art)模型BiT(Big Transfer)与Noisy Student。更重要的是,达到这一结果所需的训练成本远低于现有方法这一点。

这篇论文在Computer Vision领域引发了一场范式转移(paradigm shift)。ViT之后,DeiT、Swin Transformer、BEiT、MAE、DINO等无数后续研究相继涌现,「Vision Transformer」这一全新研究领域由此诞生。


2. 背景:CNN主导的Computer Vision时代

2.1 Convolutional Neural Network的黄金时代

2012年AlexNet在ImageNet Challenge夺冠之后,CNN事实上成为了Computer Vision领域唯一的架构。从VGGNet(2014)、GoogLeNet/Inception(2014)、ResNet(2015)、DenseNet(2017)到EfficientNet(2019),这一脉络都共享Convolution运算作为核心。

CNN之所以能在Vision任务中取得成功,根本原因在于两种Inductive Bias(归纳偏置)。

第一,Locality(局部性)。 Convolution Filter只处理输入的局部区域,这在架构层面内置了「图像中相邻像素具有强相关性」这一事实。

第二,Translation Equivariance(平移等变性)。 由于相同的filter被共享应用于图像的所有位置,无论物体位于图像中的什么位置,都能提取相同的特征。

得益于这两种偏置,CNN即使用相对较少的数据也能有效学习视觉模式。

2.2 NLP中的Transformer革命

2017年《Attention Is All You Need》论文发表后,NLP领域发生了彻底的变革。从BERT(2018)、GPT-2(2019)、T5(2019)到GPT-3(2020),基于Transformer的模型几乎横扫了所有NLP基准测试。

Transformer的核心优势如下:

  • 通过Self-Attention实现Global Receptive Field:序列内任意两个位置之间都可以直接交互
  • 出色的并行处理能力:与RNN不同,可以同时处理序列中的所有位置
  • 卓越的可扩展性(Scalability):模型规模和数据量增加时,性能会持续提升,呈现出Scaling Law

2.3 将Transformer应用于Vision的早期尝试

在ViT之前,也有一些将Attention机制引入Vision的尝试,代表性的包括:

  • Non-local Neural Networks(Wang et al., 2018):在CNN内部插入Self-Attention模块,以捕捉Long-range Dependency
  • Stand-Alone Self-Attention(Ramachandran et al., 2019):用Local Self-Attention替代Convolution
  • DETR(Carion et al., 2020):在Object Detection中使用Transformer Decoder

不过,这些方法要么将CNN与Attention进行混合(hybrid),要么使用了特殊设计的Attention。ViT的创新之处在于,没有做出这样的折中,而是将标准Transformer以最小的修改直接应用于Vision


3. 核心思想:将图像转换为patch序列

3.1 为什么不能把图像直接输入Transformer

标准Transformer接收1D token序列作为输入。假设把图像按像素逐个输入Transformer:224x224分辨率的图像有50,176个像素。Self-Attention的计算复杂度相对于序列长度 NNO(N2)O(N^2),因此对50,176个token做Self-Attention大约需要25亿次运算,这在现实中是不可行的。

3.2 通过分割patch缩短序列长度

ViT的解法既优雅又直观:将图像分割为固定大小的patch,把每个patch当作一个token处理。

将224x224的图像分割为16x16大小的patch,patch数量如下:

N=H×WP2=224×22416×16=196N = \frac{H \times W}{P^2} = \frac{224 \times 224}{16 \times 16} = 196

不再需要处理50,176个像素,只需处理196个patch token。Self-Attention的复杂度为 1962=38,416196^2 = 38,416,相比像素级别减少了约65,000倍

这一转换的核心前提是:一个16x16的patch可以作为与NLP中的一个单词(word)等价的语义单位来发挥作用。 正如自然语言是由单词这种离散token组成的序列一样,图像也可以表示为由patch这种视觉token组成的序列。

3.3 与NLP的对应关系

NLPVision(ViT)
句子(Sentence)图像(Image)
单词(Word/Token)图像patch(Patch)
词汇(Vocabulary)可能的patch模式空间
Token EmbeddingPatch Embedding (Linear Projection)
Position EmbeddingPosition Embedding (1D Learnable)
[CLS] Token[CLS] Token
Transformer EncoderTransformer Encoder(相同)

这一对应关系几乎可以说就是ViT的全部。将NLP Transformer中已验证的结构照搬过来,且只做了最小的改动,这正是ViT的本质。


4. 架构详细分析

4.1 整体流程概览

ViT的整体处理过程如下:

  1. 将输入图像分割为固定大小的patch
  2. 将每个patch展平(flatten)为1D向量
  3. 通过Linear Projection将patch向量转换为D维Embedding
  4. 在序列开头添加可学习的[CLS] token
  5. 加上Position Embedding以注入位置信息
  6. 输入标准Transformer Encoder
  7. 用[CLS] token的最终输出进行分类
输入图像 (224x224x3)
     |
     v
patch分割 (196个16x16x3的patch)
     |
     v
Flatten (196768维向量)
     |
     v
Linear Projection (196D维Embedding)
     |
     v
[CLS] Token Prepend (197D维向量)
     |
     v
加上Position Embedding (197D维向量)
     |
     v
Transformer Encoder (L个block)
     |
     v
提取[CLS] Token输出
     |
     v
Classification Head (MLP) → 类别预测

4.2 Patch Embedding:将图像转为token

4.2.1 patch分割与展平

输入图像 xRH×W×C\mathbf{x} \in \mathbb{R}^{H \times W \times C} 被分割为 P×PP \times P 大小的patch。每个patch被展平为 xpiRP2C\mathbf{x}_p^i \in \mathbb{R}^{P^2 \cdot C}

例如,将224x224x3(RGB)的图像分割为16x16的patch时:

  • patch数量:N=2242/162=196N = 224^2 / 16^2 = 196
  • 每个patch展平后的向量维度:P2C=16×16×3=768P^2 \cdot C = 16 \times 16 \times 3 = 768

4.2.2 Linear Projection

对展平后的每个patch向量,应用可学习的Linear Projection ER(P2C)×D\mathbf{E} \in \mathbb{R}^{(P^2 \cdot C) \times D},将其映射到D维Embedding空间。

z0i=xpiE,i=1,2,,N\mathbf{z}_0^i = \mathbf{x}_p^i \mathbf{E}, \quad i = 1, 2, \ldots, N

这里的 DD 是Transformer的Hidden Dimension。对ViT-Base而言 D=768D = 768,因此这里的Linear Projection是一个768x768的矩阵。

有趣的是,这个Linear Projection实际上等价于stride与patch size相同的Convolution运算。也就是说,它在数学上与Conv2d(in_channels=3, out_channels=D, kernel_size=P, stride=P)完全相同。实际实现中这种方式效率更高,因此通常采用Convolution来实现。

4.3 [CLS] Token与Classification Head

4.3.1 [CLS] Token

这是借用自BERT的概念:在patch Embedding序列的最前面,添加一个可学习的特殊token z00=xclass\mathbf{z}_0^0 = \mathbf{x}_{\text{class}}

z0=[xclass;z01;z02;;z0N]\mathbf{z}_0 = [\mathbf{x}_{\text{class}}; \, \mathbf{z}_0^1; \, \mathbf{z}_0^2; \, \ldots; \, \mathbf{z}_0^N]

这个[CLS] token通过Transformer的Self-Attention与所有patch token交互,从而学习到整张图像的全局表示(global representation)。Transformer Encoder最后一层中,这个[CLS] token的输出 zL0\mathbf{z}_L^0 被用作代表整张图像的向量。

4.3.2 Classification Head

在预训练(pre-training)阶段,会在[CLS] token输出后接一个带有1个Hidden Layer的MLP Head。在微调(fine-tuning)阶段,则只使用一个Linear Layer。

y^=Linear(LN(zL0))\hat{y} = \text{Linear}(\text{LN}(\mathbf{z}_L^0))

论文中也实验了用patch token的Global Average Pooling(GAP)代替[CLS] token的方法,报告称其性能与[CLS] token相近。之所以将[CLS] token作为默认选择,是为了与NLP Transformer保持一致性。

4.4 Position Embedding:注入位置信息

4.4.1 为什么需要Position Embedding

Self-Attention本质上是顺序不变(permutation invariant)的:即便打乱输入token的顺序,输出也只会被同样地重新排列。但在图像中,patch的空间位置是重要信息——图像左上角的patch和右下角的patch具有不同的空间意义。

4.4.2 1D Learnable Position Embedding

ViT使用可学习的1D Position Embedding EposR(N+1)×D\mathbf{E}_{pos} \in \mathbb{R}^{(N+1) \times D},其中 N+1N+1 是包含[CLS] token在内的整个序列长度。

z0=[xclass;xp1E;xp2E;;xpNE]+Epos\mathbf{z}_0 = [\mathbf{x}_{\text{class}}; \, \mathbf{x}_p^1\mathbf{E}; \, \mathbf{x}_p^2\mathbf{E}; \, \ldots; \, \mathbf{x}_p^N\mathbf{E}] + \mathbf{E}_{pos}

论文中比较了2D Position Embedding(分别编码patch的行/列位置)的实验,发现1D与2D Position Embedding之间没有显著的性能差异。这说明ViT可以从1D Position Embedding中自行学习到2D空间结构。

实际将学习到的Position Embedding可视化后(论文Figure 7)可以看到,空间上相近的patch的Position Embedding呈现出较高的余弦相似度,行与列的结构也自然地显现出来。这是一个令人印象深刻的结果,表明模型从数据中自动学习到了2D位置关系。

4.5 Transformer Encoder

4.5.1 结构

ViT直接使用标准的Transformer Encoder。每个block的结构如下:

z=MSA(LN(z1))+z1,=1,,L\mathbf{z}_\ell' = \text{MSA}(\text{LN}(\mathbf{z}_{\ell-1})) + \mathbf{z}_{\ell-1}, \quad \ell = 1, \ldots, L z=MLP(LN(z))+z,=1,,L\mathbf{z}_\ell = \text{MLP}(\text{LN}(\mathbf{z}_\ell')) + \mathbf{z}_\ell', \quad \ell = 1, \ldots, L

其中:

  • LN:Layer Normalization(Pre-norm方式,与原始Transformer的Post-norm不同)
  • MSA:Multi-head Self-Attention
  • MLP:Feed-Forward Network
  • Residual Connection:将输入加到每个子block的输出上

ViT与原始Transformer的不同之处在于采用了Pre-norm。在原始的《Attention Is All You Need》中,Layer Normalization应用在Sub-layer输出之后(Post-norm),而ViT则应用在Sub-layer输入之前(Pre-norm)。已知Pre-norm具有更高的训练稳定性。

4.5.2 Multi-head Self-Attention (MSA)

MSA将输入分割为 hh 个Head,各自独立执行Self-Attention后再合并。

MSA(z)=[head1;head2;;headh]WO\text{MSA}(\mathbf{z}) = [\text{head}_1; \, \text{head}_2; \, \ldots; \, \text{head}_h] \mathbf{W}^O headi=Attention(zWiQ,zWiK,zWiV)\text{head}_i = \text{Attention}(\mathbf{z}\mathbf{W}_i^Q, \, \mathbf{z}\mathbf{W}_i^K, \, \mathbf{z}\mathbf{W}_i^V) Attention(Q,K,V)=softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V

每个Head的维度为 dk=D/hd_k = D / h。在ViT-Base中,D=768D = 768h=12h = 12,因此 dk=64d_k = 64

4.5.3 MLP(Feed-Forward Network)

MLP由两个Linear Layer和GELU激活函数组成。

MLP(z)=GELU(zW1+b1)W2+b2\text{MLP}(\mathbf{z}) = \text{GELU}(\mathbf{z}\mathbf{W}_1 + \mathbf{b}_1)\mathbf{W}_2 + \mathbf{b}_2

Hidden Dimension通常设置为Embedding Dimension DD 的4倍(4D4D)。ViT-Base的情况下为 768×4=3072768 \times 4 = 3072

之所以用GELU(Gaussian Error Linear Unit)代替原始Transformer使用的ReLU,是沿用了BERT的设计。


5. 数学分析:从patch到预测

将整个过程用数学方式整理如下。

5.1 输入处理

给定图像 xRH×W×C\mathbf{x} \in \mathbb{R}^{H \times W \times C}

Step 1. patch分割与展平:

[xp1,xp2,,xpN],xpiRP2C,N=HWP2[\mathbf{x}_p^1, \mathbf{x}_p^2, \ldots, \mathbf{x}_p^N], \quad \mathbf{x}_p^i \in \mathbb{R}^{P^2 C}, \quad N = \frac{HW}{P^2}

Step 2. Patch Embedding + [CLS] Token + Position Embedding:

z0=[xclass;xp1E;;xpNE]+Epos\mathbf{z}_0 = [\mathbf{x}_{\text{class}}; \, \mathbf{x}_p^1\mathbf{E}; \, \ldots; \, \mathbf{x}_p^N\mathbf{E}] + \mathbf{E}_{pos}

其中 ER(P2C)×D\mathbf{E} \in \mathbb{R}^{(P^2 C) \times D}EposR(N+1)×D\mathbf{E}_{pos} \in \mathbb{R}^{(N+1) \times D}

5.2 Transformer Encoder

Step 3. 重复 LL 个Transformer block:

z=MSA(LN(z1))+z1\mathbf{z}_\ell' = \text{MSA}(\text{LN}(\mathbf{z}_{\ell-1})) + \mathbf{z}_{\ell-1} z=MLP(LN(z))+z\mathbf{z}_\ell = \text{MLP}(\text{LN}(\mathbf{z}_\ell')) + \mathbf{z}_\ell'

5.3 输出

Step 4. 用[CLS] token输出进行分类:

y=LN(zL0)\mathbf{y} = \text{LN}(\mathbf{z}_L^0) y^=Softmax(yWhead+bhead)\hat{y} = \text{Softmax}(\mathbf{y}\mathbf{W}_{\text{head}} + \mathbf{b}_{\text{head}})

5.4 计算复杂度分析

对于序列长度 NN、Embedding维度 DD,主要运算的复杂度如下。

运算复杂度
Patch EmbeddingO(NP2CD)O(N \cdot P^2C \cdot D)
Self-Attention(生成QKV)O(ND2)O(N \cdot D^2)
Self-Attention(计算Attention)O(N2D)O(N^2 \cdot D)
MLPO(ND2)O(N \cdot D^2)
整个Transformer BlockO(N2D+ND2)O(N^2 \cdot D + N \cdot D^2)

序列长度 NN 对应的 O(N2)O(N^2) 复杂度,是限制ViT分辨率可扩展性的核心瓶颈。这也是后来Swin Transformer等引入Windowed Attention的动机。


6. 模型变体:ViT-Base、Large、Huge

ViT沿用了BERT的设计惯例,定义了三种规模的模型。模型名称斜杠后的数字表示patch大小(例如ViT-B/16表示使用16x16的patch)。

项目ViT-Base (ViT-B)ViT-Large (ViT-L)ViT-Huge (ViT-H)
Layers (LL)122432
Hidden Dim (DD)76810241280
MLP Dim307240965120
Attention Heads (hh)121616
Parameters~86M~307M~632M
Head Dim (dk=D/hd_k = D/h)646480

6.1 按patch大小划分的变体

即便架构相同,patch大小不同也会导致性能与计算量出现较大差异。

模型patch大小序列长度 (224x224)序列长度 (384x384)
ViT-B/3232x3249144
ViT-B/1616x16196576
ViT-L/1616x16196576
ViT-H/1414x14256784

patch越小,越能捕捉细粒度(fine-grained)的视觉信息,但序列长度增加会使计算成本以 O(N2)O(N^2) 急剧上升。ViT-H/14的14x14 patch产生的序列长度,约是ViT-B/32的32x32 patch的27倍

6.2 Hybrid模型

论文中也实验了结合CNN与Transformer的Hybrid模型:用ResNet的中间Feature Map代替patch Embedding。例如,将ResNet-50 stage 4的输出(14x14 Feature Map)当作1x1的patch输入Transformer。

z0i=ResNet_feature_map(i)Ehybrid+Eposi\mathbf{z}_0^i = \text{ResNet\_feature\_map}_{(i)} \mathbf{E}_{\text{hybrid}} + \mathbf{E}_{pos}^i

实验结果显示,当预训练数据较少时,Hybrid模型优于纯ViT;但当数据规模足够大时,纯ViT便追上了Hybrid模型。


7. 训练策略

7.1 预训练(Pre-training)

ViT的训练策略沿用了NLP中「预训练+微调」的范式。

数据集:

  • ImageNet-1K:约130万张图像,1,000个类别
  • ImageNet-21K:约1,400万张图像,21,843个类别
  • JFT-300M:Google内部数据集,约3亿张图像,18,291个类别

预训练设置:

  • Optimizer:Adam(β1=0.9\beta_1 = 0.9β2=0.999\beta_2 = 0.999
  • Batch Size:4,096
  • Weight Decay:0.1
  • Linear Learning Rate Warmup + Cosine Decay
  • 分辨率:224x224

论文的核心发现之一是:预训练数据的规模对ViT的性能起决定性作用。仅用ImageNet-1K时不敌CNN,但在JFT-300M规模下则超越了CNN。

7.2 微调(Fine-tuning)

微调时会移除预训练好的Classification Head,附加一个适配目标任务的新Linear Layer。

高分辨率微调的核心技巧:

在比预训练(224x224)更高的分辨率(384x384或512x512)下微调,可以提升性能。但分辨率变化会导致patch数量(序列长度)发生变化,因此预训练好的Position Embedding无法直接沿用。

为解决这一问题,需要应用2D插值(Interpolation)。先将预训练好的Position Embedding还原为原始的2D网格形式,再按照新的分辨率通过Bicubic Interpolation调整大小。

示例:224x224预训练(14x14网格)→ 384x384微调(24x24网格)

预训练Position Embedding (14x14 = 196)
     |
     v
重构为2D网格 (14 x 14)
     |
     v
Bicubic Interpolation  (24 x 24)
     |
     v
重新展平为1D (24x24 = 576)

这种Position Embedding插值方法,此后几乎被所有Vision Transformer采纳为标准技巧。

7.3 训练成本

模型预训练数据TPUv3-core-days
ViT-B/16JFT-300M未提供
ViT-L/16JFT-300M未提供
ViT-H/14JFT-300M2,500
BiT-L (ResNet152x4)JFT-300M9,900
Noisy Student (EfficientNet-L2)JFT-300M + ImageNet12,300

ViT-H/14所需的训练成本,约为BiT-L的1/4、Noisy Student的1/5,却取得了更高的性能。这体现了Transformer出色的扩展效率。


8. 实验结果

8.1 主要基准测试结果

论文Table 2中报告的核心结果整理如下。

模型Pre-trainImageNetImageNet-ReaLCIFAR-10CIFAR-100Oxford PetsOxford Flowers
ViT-H/14JFT-300M88.5590.7299.5094.5597.5699.68
ViT-L/16JFT-300M87.7690.5499.4293.9097.3299.74
ViT-L/16ImageNet-21K85.3088.6299.1593.2594.6799.61
BiT-L (ResNet152x4)JFT-300M87.5490.5499.3793.5196.6299.63
Noisy StudentJFT-300M88.490.55----

8.2 VTAB基准测试

VTAB(Visual Task Adaptation Benchmark)将19种多样化的Vision任务划分为Natural、Specialized、Structured三个类别。每个任务仅使用1,000个训练样本来评估模型的泛化能力。

模型NaturalSpecializedStructured整体
ViT-H/14 (JFT)79.3984.2369.2777.63
ViT-L/16 (JFT)76.2883.3664.7274.78
BiT-L (JFT)76.2984.9266.5175.90

ViT-H/14在Natural和Structured类别中表现最佳,在Specialized类别中则与BiT-L基本持平。整体VTAB得分77.63,在当时是最高纪录。

8.3 预训练数据规模与性能的关系

论文中最重要的实验之一,是分析了性能随预训练数据规模变化的情况(Figure 3、4)。

预训练数据ViT-L/16 ImageNet AccBiT-L ImageNet Acc胜者
ImageNet-1K (~1.3M)~76.5% (scratch)~80% (scratch)BiT (CNN)
ImageNet-21K (~14M)85.30%84.02%ViT
JFT-300M (~303M)87.76%87.54%ViT

这一结果展现了明确的规律:

  • 小规模数据:CNN的Inductive Bias(Locality、Translation Equivariance)发挥有利作用,CNN获胜
  • 大规模数据:Transformer直接从数据中学习到这些模式,超越CNN

9. 核心发现与洞察

9.1 Inductive Bias的双刃剑

CNN的Inductive Bias——Locality与Translation Equivariance——在小规模数据下起到了有效的正则化(regularization)作用,因为它能引导模型即便用少量数据也能学到正确的特征。

但当数据足够多时,这种Inductive Bias反而成为限制模型表达能力的枷锁。Transformer无需任何特殊的结构假设,就能通过Self-Attention从数据中学习到包括Locality和Translation Equivariance在内的更通用、更灵活的模式

这再次印证了AI领域一条古老的教训:只要有足够的数据,更通用(less biased)的模型就会超越更特化(more biased)的模型。

9.2 Attention Map可视化

9.2.1 Position Embedding相似度

将学习到的Position Embedding的余弦相似度可视化后(论文Figure 7左侧)可以看到,每个patch位置的Embedding与空间上相近的patch之间呈现出较高的相似度。进一步地,处于同一行或同一列的patch之间,也呈现出明显的相似度规律。

这表明,尽管只使用了1D Position Embedding,模型依然自动学习到了2D空间结构

9.2.2 Attention Distance

论文Figure 7右侧分析了每个Transformer层中,各Attention Head的平均Attention Distance。Attention Distance是指用Attention Weight加权后,Query-Key patch之间的平均像素距离。

核心发现:

  • 底层(Lower Layers):部分Head关注相邻patch,部分Head关注较远的patch——与CNN早期层类似的Local模式与Global模式并存
  • 高层(Higher Layers):大部分Head将注意力分散到更广的范围——实现Global信息的整合

这表明,ViT从第一层开始就能利用Global信息,这一点与CNN有根本性的不同。在CNN中,Receptive Field要随着层数加深才逐渐扩大,而ViT从第一层起就能对整张图像进行Attention。

9.3 Representation质量分析

在Linear Probing(仅在冻结的Feature上训练Linear Classifier)实验中,ViT的性能相对低于CNN,但在Fine-tuning中却取得了更高的性能。这说明ViT学习到的是不同类型的Feature表示——ViT的Feature可能蕴含着通过Fine-tuning才能被激活的更丰富的信息。


10. PyTorch核心实现

用PyTorch实现ViT的核心结构如下。这里尽量忠实地还原了论文的实现,同时也照顾了可读性。

10.1 Patch Embedding

import torch
import torch.nn as nn


class PatchEmbedding(nn.Module):
    """将图像分割为patch,并通过Linear Projection做Embedding。"""

    def __init__(
        self,
        img_size: int = 224,
        patch_size: int = 16,
        in_channels: int = 3,
        embed_dim: int = 768,
    ):
        super().__init__()
        self.img_size = img_size
        self.patch_size = patch_size
        self.num_patches = (img_size // patch_size) ** 2

        # 使用Conv2d实现Patch Embedding
        # 将stride设为patch_size,即与Linear Projection等价
        self.projection = nn.Conv2d(
            in_channels,
            embed_dim,
            kernel_size=patch_size,
            stride=patch_size,
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        # x: (B, C, H, W)
        # projection output: (B, embed_dim, H/P, W/P)
        x = self.projection(x)
        # flatten spatial dims and transpose: (B, num_patches, embed_dim)
        x = x.flatten(2).transpose(1, 2)
        return x

10.2 Multi-head Self-Attention

class MultiHeadSelfAttention(nn.Module):
    """Multi-Head Self-Attention模块。"""

    def __init__(self, embed_dim: int = 768, num_heads: int = 12, dropout: float = 0.0):
        super().__init__()
        self.num_heads = num_heads
        self.head_dim = embed_dim // num_heads
        self.scale = self.head_dim ** -0.5  # 1/sqrt(d_k)

        # 一次性生成Q, K, V
        self.qkv = nn.Linear(embed_dim, embed_dim * 3)
        self.proj = nn.Linear(embed_dim, embed_dim)
        self.attn_dropout = nn.Dropout(dropout)
        self.proj_dropout = nn.Dropout(dropout)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        B, N, D = x.shape

        # 生成QKV: (B, N, 3*D) -> (B, N, 3, num_heads, head_dim)
        qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, self.head_dim)
        qkv = qkv.permute(2, 0, 3, 1, 4)  # (3, B, num_heads, N, head_dim)
        q, k, v = qkv.unbind(0)  # 各为 (B, num_heads, N, head_dim)

        # Scaled Dot-Product Attention
        attn = (q @ k.transpose(-2, -1)) * self.scale  # (B, num_heads, N, N)
        attn = attn.softmax(dim=-1)
        attn = self.attn_dropout(attn)

        # 与Value做加权求和
        x = (attn @ v).transpose(1, 2).reshape(B, N, D)  # (B, N, D)
        x = self.proj(x)
        x = self.proj_dropout(x)
        return x

10.3 Transformer Encoder Block

class TransformerBlock(nn.Module):
    """ViT Transformer Encoder Block (Pre-norm)。"""

    def __init__(
        self,
        embed_dim: int = 768,
        num_heads: int = 12,
        mlp_ratio: float = 4.0,
        dropout: float = 0.0,
    ):
        super().__init__()
        self.norm1 = nn.LayerNorm(embed_dim)
        self.attn = MultiHeadSelfAttention(embed_dim, num_heads, dropout)
        self.norm2 = nn.LayerNorm(embed_dim)
        self.mlp = nn.Sequential(
            nn.Linear(embed_dim, int(embed_dim * mlp_ratio)),
            nn.GELU(),
            nn.Dropout(dropout),
            nn.Linear(int(embed_dim * mlp_ratio), embed_dim),
            nn.Dropout(dropout),
        )

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        # Pre-norm + MSA + Residual
        x = x + self.attn(self.norm1(x))
        # Pre-norm + MLP + Residual
        x = x + self.mlp(self.norm2(x))
        return x

10.4 完整ViT模型

class VisionTransformer(nn.Module):
    """Vision Transformer (ViT) 完整模型。"""

    def __init__(
        self,
        img_size: int = 224,
        patch_size: int = 16,
        in_channels: int = 3,
        num_classes: int = 1000,
        embed_dim: int = 768,
        depth: int = 12,
        num_heads: int = 12,
        mlp_ratio: float = 4.0,
        dropout: float = 0.0,
    ):
        super().__init__()
        self.patch_embed = PatchEmbedding(img_size, patch_size, in_channels, embed_dim)
        num_patches = self.patch_embed.num_patches

        # 可学习的[CLS] Token
        self.cls_token = nn.Parameter(torch.zeros(1, 1, embed_dim))
        # 可学习的Position Embedding ([CLS] + patches)
        self.pos_embed = nn.Parameter(torch.zeros(1, num_patches + 1, embed_dim))
        self.pos_dropout = nn.Dropout(dropout)

        # Transformer Encoder
        self.blocks = nn.Sequential(
            *[
                TransformerBlock(embed_dim, num_heads, mlp_ratio, dropout)
                for _ in range(depth)
            ]
        )
        self.norm = nn.LayerNorm(embed_dim)

        # Classification Head
        self.head = nn.Linear(embed_dim, num_classes)

        # 初始化
        nn.init.trunc_normal_(self.pos_embed, std=0.02)
        nn.init.trunc_normal_(self.cls_token, std=0.02)
        self.apply(self._init_weights)

    def _init_weights(self, m: nn.Module):
        if isinstance(m, nn.Linear):
            nn.init.trunc_normal_(m.weight, std=0.02)
            if m.bias is not None:
                nn.init.zeros_(m.bias)
        elif isinstance(m, nn.LayerNorm):
            nn.init.ones_(m.weight)
            nn.init.zeros_(m.bias)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        B = x.shape[0]

        # Step 1: Patch Embedding
        x = self.patch_embed(x)  # (B, num_patches, embed_dim)

        # Step 2: [CLS] Token Prepend
        cls_tokens = self.cls_token.expand(B, -1, -1)  # (B, 1, embed_dim)
        x = torch.cat([cls_tokens, x], dim=1)  # (B, num_patches + 1, embed_dim)

        # Step 3: Position Embedding
        x = x + self.pos_embed
        x = self.pos_dropout(x)

        # Step 4: Transformer Encoder
        x = self.blocks(x)
        x = self.norm(x)

        # Step 5: 用[CLS] Token进行分类
        cls_output = x[:, 0]  # (B, embed_dim)
        logits = self.head(cls_output)  # (B, num_classes)
        return logits


# 生成各模型变体的函数
def vit_base_patch16_224(**kwargs):
    return VisionTransformer(
        img_size=224, patch_size=16, embed_dim=768,
        depth=12, num_heads=12, **kwargs,
    )

def vit_large_patch16_224(**kwargs):
    return VisionTransformer(
        img_size=224, patch_size=16, embed_dim=1024,
        depth=24, num_heads=16, **kwargs,
    )

def vit_huge_patch14_224(**kwargs):
    return VisionTransformer(
        img_size=224, patch_size=14, embed_dim=1280,
        depth=32, num_heads=16, **kwargs,
    )

10.5 使用示例

# 创建ViT-Base/16模型
model = vit_base_patch16_224(num_classes=1000)

# 查看参数量
total_params = sum(p.numel() for p in model.parameters())
print(f"Total parameters: {total_params:,}")
# 输出: Total parameters: 86,567,656

# 推理
dummy_input = torch.randn(1, 3, 224, 224)
output = model(dummy_input)
print(f"Output shape: {output.shape}")
# 输出: Output shape: torch.Size([1, 1000])

11. 后续研究全面梳理

ViT成为了Vision Transformer这一庞大研究浪潮的起点。以下按时间顺序整理其后出现的主要后续研究。

11.1 DeiT: Data-efficient Image Transformers (2020.12)

论文:《Training data-efficient image transformers & distillation through attention》(Touvron et al., Facebook AI)

核心贡献:克服了ViT最大的局限——对大规模数据的依赖——提出了仅用ImageNet-1K就能有效训练ViT的方法。

主要技巧:

  • Knowledge Distillation Token:在[CLS] token之外额外添加一个Distillation Token,从而有效传递Teacher模型(CNN)的知识
  • Hard Distillation:使用Teacher的Hard Label(argmax预测)来训练Student
  • 有趣的是,CNN Teacher比Transformer Teacher更有效——CNN的Inductive Bias通过Distillation被传递给了Transformer

结果:

  • DeiT-B:在ImageNet-1K上取得83.1% top-1 accuracy(未使用外部数据)
  • DeiT-B distilled:85.2%(使用RegNetY-16GF Teacher)
  • 未使用任何外部数据,就超越了ViT-B/16 JFT-300M pre-trained的84.15%

11.2 Swin Transformer (2021.03)

论文:《Swin Transformer: Hierarchical Vision Transformer using Shifted Windows》(Liu et al., Microsoft Research)

核心贡献:同时解决了ViT的两个根本性局限——O(N2)O(N^2) 复杂度与Single-scale Feature。

主要技巧:

  • Window-based Self-Attention:将图像分割为固定大小的窗口(7x7 patch),仅在窗口内部执行Self-Attention,使复杂度从 O(N2)O(N^2) 降至 O(N)O(N)(相对于图像尺寸呈线性)
  • Shifted Window:在连续的层之间移动窗口位置,使窗口之间可以交换信息
  • Hierarchical Feature Map:随着层数加深,通过合并patch(Patch Merging)将分辨率减半、通道数翻倍,提供类似CNN Feature Pyramid的multi-scale feature

结果:

  • Swin-L:在ImageNet-1K上取得87.3% top-1 accuracy(经ImageNet-22K预训练)
  • COCO Object Detection:58.7 box AP51.1 mask AP
  • ADE20K Semantic Segmentation:53.5 mIoU

Swin Transformer成为了比ViT更通用的Backbone,广泛用于Object Detection、Semantic Segmentation等Dense Prediction任务

11.3 BEiT: BERT Pre-Training of Image Transformers (2021.06)

论文:《BEiT: BERT Pre-Training of Image Transformers》(Bao et al., Microsoft Research)

核心贡献:首次将NLP中BERT风格的Masked Language Modeling成功应用于Vision。

主要技巧:

  • Masked Image Modeling (MIM):遮蔽(mask)图像patch的一部分(约40%),预测被遮蔽patch的Visual Token
  • Visual Tokenizer:使用dVAE(discrete Variational Autoencoder)将图像转换为离散的Visual Token——相当于NLP中的词汇(vocabulary)
  • 两种视角(View):原始图像patch(输入)与Visual Token(预测目标)

结果:

  • BEiT-B:在ImageNet-1K上取得83.2%(Self-supervised pre-training + Fine-tuning)
  • BEiT-L:在ImageNet-1K上取得86.3%(仅使用ImageNet-1K数据)
  • 相较DeiT-B的81.8%提升了+1.4%(相同的Base模型规模)

11.4 MAE: Masked Autoencoders (2021.11)

论文:《Masked Autoencoders Are Scalable Vision Learners》(He et al., Facebook AI Research)

核心贡献:将Self-supervised Vision Pre-training的效率与可扩展性发挥到极致,提出了简单却强大的预训练框架。

主要技巧:

  • 高遮蔽比例:遮蔽输入patch的75%——远高于NLP(15%),原因在于图像具有更高的信息冗余度
  • 非对称Encoder-Decoder:Encoder只处理未被遮蔽的patch(全部的25%)以最大化效率,再用轻量的Decoder重建被遮蔽的像素
  • 像素级重建:与BEiT不同,不使用Visual Tokenizer,而是直接重建被遮蔽patch的原始像素值

结果:

  • MAE(ViT-H):在ImageNet-1K上取得87.8%(仅使用ImageNet-1K数据)
  • 训练效率:由于Encoder仅处理全部patch的25%,训练时间缩短3倍以上
  • 远优于不做预训练、直接从头训练ViT的效果

11.5 DINO / DINOv2 (2021.04 / 2023.04)

DINO论文:《Emerging Properties in Self-Supervised Vision Transformers》(Caron et al., Facebook AI Research)

DINOv2论文:《DINOv2: Learning Robust Visual Features without Supervision》(Oquab et al., Meta AI)

DINO核心技巧:

  • Self-Distillation:Teacher与Student拥有完全相同的网络结构,Teacher是Student的Exponential Moving Average(EMA)
  • Multi-crop策略:交替输入Global View(完整图像)与Local View(较小的裁剪区域)
  • 发现:Self-supervised ViT的Self-Attention Map无需显式训练,就能获得Object Segmentation能力

DINOv2核心技巧:

  • 自动构建大规模Curated Dataset(LVD-142M)的流水线
  • 先训练一个1B参数的Teacher模型,再通过Knowledge Distillation蒸馏到较小的Student模型
  • 不使用文本、不使用标签,学习通用的视觉表示(Universal Visual Feature)

结果:

  • DINO(ViT-B):在ImageNet Linear Probing上取得80.1%
  • DINOv2:在大多数基准测试中超越OpenCLIP的通用Visual Feature

11.6 EVA / EVA-02 (2022 / 2023)

EVA论文:《EVA: Exploring the Limits of Masked Visual Representation Learning at Scale》(Fang et al., BAAI)

EVA-02论文:《EVA-02: A Visual Representation for Neon Genesis》(Fang et al., BAAI)

核心技巧:

  • Masked Image Modeling + 以CLIP Feature作为重建目标
  • 学习Language-aligned Visual Feature,在Vision-Language任务中也表现出色
  • 提出了高效训练大规模ViT的技巧

结果:

  • EVA(ViT-g):在ImageNet上取得89.6%(336x336)
  • EVA-02:以304M参数在ImageNet上取得90.0%(仅使用公开数据)
  • EVA-02-CLIP:Zero-shot ImageNet 80.4%(参数量仅为此前最佳CLIP的1/6)

11.7 ConvNeXt:CNN的反击 (2022.01)

论文:《A ConvNet for the 2020s》(Liu et al., Facebook AI Research / UC Berkeley)

核心贡献:证明了把Transformer的设计原则系统性地应用于纯CNN之后,CNN也能取得与Transformer相当的性能。这是对「CNN真的逊色吗?」这一问题的有力反驳。

应用于ResNet的Transformer设计要素:

  1. Macro Design:调整Stage Ratio(ResNet的3:4:6:3 → Swin-T的1:1:3:1)
  2. 将Stem替换为Patchify(4x4 Conv, stride 4)
  3. ResNeXt-style Grouped Convolution → Depthwise Convolution
  4. Inverted Bottleneck(MobileNetV2风格)
  5. 7x7 Large Kernel(对应Swin Transformer的7x7 Window)
  6. BN → LayerNorm、ReLU → GELU等激活/归一化方式的调整

结果:

  • ConvNeXt-B:在ImageNet-1K上取得85.1%(较Swin-B的84.5%提升+0.6%,推理速度快12.5%)
  • ConvNeXt-L:经ImageNet-22K预训练后取得87.8%
  • 不仅性能,处理量(throughput)也与Swin Transformer相当或更优

12. ViT vs CNN vs Hybrid对比

12.1 综合对比表

特性CNN(ResNet系列)ViT(纯Transformer)Hybrid(CNN + Transformer)
Inductive Bias强(Locality、Translation Equivariance)几乎没有中等(部分借用自CNN)
小规模数据性能优秀较差优秀
大规模数据性能良好最佳非常好
计算复杂度(相对分辨率)O(N)O(N)O(N2)O(N^2)O(N)O(N2)O(N) \sim O(N^2)
Multi-scale Feature天然具备(Feature Pyramid)缺乏(Single-scale)多样
Global Receptive Field需堆叠多层才能获得从第一层起即可获得CNN之后可获得
Dense Prediction适用性低(需要后处理)中~高
训练效率(按FLOPs计的性能)良好大规模下最佳良好
实现与优化成熟度非常高快速走向成熟中等
代表模型ResNet、EfficientNet、ConvNeXtViT、DeiT、BEiTSwin Transformer、CoAtNet

12.2 各任务推荐架构(截至2026年)

任务推荐架构依据
Image Classification(大规模)ViT + MAE/DINO pre-training在大规模数据下性能最佳
Image Classification(小规模)DeiT(Distillation)或ConvNeXt数据效率高
Object DetectionSwin Transformer + FPN系列必须具备Multi-scale Feature
Semantic SegmentationSwin / SegFormer / DINOv2适合Dense Prediction
Vision-LanguageViT + CLIP-style pre-training具备Language-aligned Feature
Edge/Mobile部署EfficientNet / MobileViT需要轻量化
Self-supervised Pre-trainingMAE / DINOv2无需标签、可扩展性强

13. Computer Vision的未来:Foundation Models

13.1 Vision Foundation Model的出现

ViT所引发的这场范式转移,最终催生了Vision Foundation Model。正如NLP领域中GPT-3、GPT-4这类Foundation Model用单一模型处理各种任务一样,Vision领域也正朝着同样的方向发展。

主要的Vision Foundation Models:

  • SAM(Segment Anything Model):基于ViT-H,用单一模型处理各类Segmentation
  • DINOv2:Self-supervised ViT,通用Visual Feature Extractor
  • CLIP/SigLIP:Vision-Language对齐,支持Zero-shot Classification与Retrieval
  • Florence/Intern:大规模多任务Vision-Language模型

13.2 未来的研究方向

效率提升:

  • 通过FlashAttention、Linear Attention等方法克服 O(N2)O(N^2) 瓶颈
  • 通过Token Pruning/Merging去除不必要的patch
  • 通过Knowledge Distillation生成轻量模型

训练范式:

  • Self-supervised Pre-training的普及(MAE、DINO系列)
  • Vision-Language Alignment(CLIP系列)
  • 基于强化学习的视觉决策(VLM + RL)

架构创新:

  • Mamba / State Space Model在Vision中的应用(Vision Mamba、VMamba)
  • 利用Mixture of Experts(MoE)实现高效扩展
  • 持续研究融合CNN与Transformer优点的Hybrid架构

13.3 ViT的历史意义

ViT留下的最重要的教训是架构的通用性(universality)。单一架构(Transformer)能够应用于文本、图像、语音、视频、代码等所有模态,这在AI历史上是极为特殊的事件。

在ViT之前,NLP与Vision拥有完全不同的架构生态。ViT之后,Transformer真正成为了通用架构(Universal Architecture),这正是如今多模态Foundation Model(GPT-4V、Gemini、Claude等)得以实现的技术基础。

「An Image is Worth 16x16 Words」——这个标题不仅仅是一个比喻,而是一句深刻的宣言:Vision与Language可以在同一个框架内实现统一


14. References

  1. Dosovitskiy, A., Beyer, L., Kolesnikov, A., Weissenborn, D., Zhai, X., Unterthiner, T., ... & Houlsby, N. (2020). An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale. ICLR 2021. arXiv:2010.11929

  2. Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., ... & Polosukhin, I. (2017). Attention Is All You Need. NeurIPS 2017. arXiv:1706.03762

  3. Touvron, H., Cord, M., Douze, M., Massa, F., Sablayrolles, A., & Jegou, H. (2021). Training data-efficient image transformers & distillation through attention (DeiT). ICML 2021. arXiv:2012.12877

  4. Liu, Z., Lin, Y., Cao, Y., Hu, H., Wei, Y., Zhang, Z., ... & Guo, B. (2021). Swin Transformer: Hierarchical Vision Transformer using Shifted Windows. ICCV 2021. arXiv:2103.14030

  5. Bao, H., Dong, L., Piao, S., & Wei, F. (2021). BEiT: BERT Pre-Training of Image Transformers. ICLR 2022. arXiv:2106.08254

  6. He, K., Chen, X., Xie, S., Li, Y., Dollar, P., & Girshick, R. (2022). Masked Autoencoders Are Scalable Vision Learners (MAE). CVPR 2022. arXiv:2111.06377

  7. Caron, M., Touvron, H., Misra, I., Jegou, H., Mairal, J., Bojanowski, P., & Joulin, A. (2021). Emerging Properties in Self-Supervised Vision Transformers (DINO). ICCV 2021. arXiv:2104.14294

  8. Oquab, M., Darcet, T., Moutakanni, T., Vo, H., Szafraniec, M., Khalidov, V., ... & Bojanowski, P. (2023). DINOv2: Learning Robust Visual Features without Supervision. arXiv:2304.07193

  9. Fang, Y., Wang, W., Xie, B., Sun, Q., Wu, L., Wang, X., ... & Cao, Y. (2023). EVA: Exploring the Limits of Masked Visual Representation Learning at Scale. CVPR 2023. arXiv:2211.07636

  10. Fang, Y., Sun, Q., Wang, X., Huang, T., Wang, X., & Cao, Y. (2023). EVA-02: A Visual Representation for Neon Genesis. arXiv:2303.11331

  11. Liu, Z., Mao, H., Wu, C. Y., Feichtenhofer, C., Darrell, T., & Xie, S. (2022). A ConvNet for the 2020s (ConvNeXt). CVPR 2022. arXiv:2201.03545

  12. Devlin, J., Chang, M. W., Lee, K., & Toutanova, K. (2018). BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding. NAACL 2019. arXiv:1810.04805

  13. He, K., Zhang, X., Ren, S., & Sun, J. (2016). Deep Residual Learning for Image Recognition (ResNet). CVPR 2016. arXiv:1512.03385

  14. Kolesnikov, A., Beyer, L., Zhai, X., Puigcerver, J., Yung, J., Gelly, S., & Houlsby, N. (2020). Big Transfer (BiT): General Visual Representation Learning. ECCV 2020. arXiv:1912.11370

  15. Radford, A., Kim, J. W., Hallacy, C., Ramesh, A., Goh, G., Agarwal, S., ... & Sutskever, I. (2021). Learning Transferable Visual Models From Natural Language Supervision (CLIP). ICML 2021. arXiv:2103.00020

  16. Kirillov, A., Mintun, E., Ravi, N., Mao, H., Rolland, C., Gustafson, L., ... & Girshick, R. (2023). Segment Anything (SAM). ICCV 2023. arXiv:2304.02643