ViT:把图像切成词之后,Transformer 如何进入计算机视觉
本文是一篇原创中文论文解读,主要参考 D2L《Dive into Deep Learning》1.0.3 章节 Transformers for Vision,解读 Alexey Dosovitskiy 等人的经典论文 An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale。D2L 书籍文本与图示采用 Creative Commons Attribution-ShareAlike 4.0 International License;本文复用的 D2L 图示已在本地备份并转换为 PNG,用于说明模型结构与实验现象。原论文图片未转载。
在 Transformer 刚提出时,它解决的是机器翻译里的序列建模问题;几年之后,GPT、BERT、T5 等模型把它推成了自然语言处理的主干。但在计算机视觉里,长期占据中心的是 CNN:卷积天然带有局部连接、平移等变性和权值共享,这些归纳偏置非常适合图像。
Vision Transformer,也就是 ViT,真正有意思的地方不在于"给图像加了注意力",而在于它提出了一个很直接的问题:如果不把卷积当作视觉建模的默认答案,只把图像切成一串 patch token,再交给标准 Transformer encoder,会发生什么?
答案后来被证明足够改变视觉模型设计路线:在数据和模型规模足够大时,ViT 能展现出比传统卷积网络更强的可扩展性;但在小数据集上,它也会暴露缺少视觉先验的问题。这种"更通用,但更吃数据"的性格,正是理解 ViT 的关键。
从"像素网格"到"视觉词序列"
ViT 的第一步非常朴素:把一张图像切成固定大小的小块。
假设输入图像高为 h h h,宽为 w w w,通道数为 c c c,每个 patch 的边长是 p p p。那么图像会被拆成
m = h w p 2 m = \frac{hw}{p^2} m=p2hw
个 patch;每个 patch 展平后是一个长度为 c p 2 cp^2 cp2 的向量。
这一步把二维图像问题变成了序列问题:每个 patch 类似 NLP 里的一个 token。接下来,ViT 对每个 patch 做线性投影,得到统一维度的 patch embedding。由于 Transformer 本身不知道 token 的空间位置,还需要加入可学习的位置嵌入。
从实现角度看,D2L 的解释很干净:patch 切分加线性投影可以等价地写成一次卷积,卷积核大小等于 patch size,stride 也等于 patch size。也就是说,ViT 并不是完全没有卷积算子;它可以用卷积高效完成 patch embedding,但后续的主干不再依赖卷积层堆叠。

<cls> token:让整张图有一个可读出的表示
如果每个 patch 都会输出一个向量,那么分类头到底该看哪一个?
ViT 采用了和 BERT 类似的做法:在 patch 序列前面加一个特殊的 <cls> token。这个 token 不对应图像中的某个局部区域,而是作为全局汇聚位置存在。经过多层自注意力之后,<cls> token 可以和所有 patch 交互,它的最终表示被送入分类头,预测图像类别。
这件事的直觉是:CNN 通常靠池化或全局平均池化把空间特征汇总起来;ViT 则让一个专门的 token 通过注意力机制主动读取所有 patch 信息。
当然,这不是唯一选择。很多后续模型也尝试过直接平均所有 patch token,再送入分类头。二者的差异可以理解为:<cls> token 是"学习一个汇聚查询",平均池化是"固定地汇总所有局部表示"。
Encoder Block:几乎就是标准 Transformer,只是改成 Pre-Norm
D2L 章节强调,ViT 的主体并没有发明一个全新的视觉模块。每个 ViT block 仍由两部分组成:
- 多头自注意力:让不同 patch 之间建立全局依赖。
- MLP:对每个 token 的表示做非线性变换。
每一部分外面都有残差连接。和早期 Transformer 常见的 Post-Norm 不同,ViT 采用了 Pre-Norm:先 LayerNorm,再进入 attention 或 MLP,输出后再和残差相加。
可以把一个 ViT block 简化写成:
text
Y = X + MultiHeadAttention(LayerNorm(X))
Z = Y + MLP(LayerNorm(Y))
其中 MLP 通常使用 GELU 激活,并在全连接层之后加 dropout。GELU 比 ReLU 更平滑,在 Transformer 系列模型中很常见。
这段结构说明了 ViT 为什么容易和 NLP Transformer 技术栈共享经验:注意力、残差、LayerNorm、MLP、位置嵌入这些核心积木基本一致。视觉侧真正变化的是输入表示方式:token 不再是词,而是图像 patch。
Patch 大小控制了序列长度,也控制了计算代价
Transformer 的自注意力复杂度与序列长度平方相关。图像越大、patch 越小,token 数越多,计算量增长越明显。
如果图像大小是 224 × 224 224 \times 224 224×224,patch size 为 16 × 16 16 \times 16 16×16,则 patch 数是:
224 × 224 16 2 = 196 \frac{224 \times 224}{16^2} = 196 162224×224=196
加上一个 <cls> token,序列长度就是 197。这个长度对 Transformer 还算可控。
但如果把 patch size 减到 8 × 8 8 \times 8 8×8,patch 数会变成 784,注意力矩阵规模约扩大到原来的 16 倍。这也是 ViT 系模型后来会发展出 Swin Transformer 这类层次化、窗口注意力结构的重要原因:视觉任务常常需要高分辨率,直接全局 self-attention 并不总是经济。
ViT 为什么在大数据上更强,在小数据上不一定赢
ViT 论文和 D2L 章节都指向同一个核心判断:Transformer 在视觉上的优势主要来自可扩展性,而不是小数据场景下的天然优势。
CNN 有很强的视觉归纳偏置。卷积核天然关注局部邻域,同一个卷积核在不同位置共享参数,因此模型从一开始就"相信"局部纹理和平移结构是重要的。这个先验非常有效,尤其是在数据不够大时。
ViT 的先验弱得多。它把图像变成一串 patch,再让注意力自己学习哪些 patch 之间应该交互。这给了模型更大的表达空间,也意味着它需要更多数据去学会那些 CNN 预先写进结构里的规律。
D2L 在 Fashion-MNIST 上的演示也符合这个现象:小规模 ViT 能训练起来,但并不会自然压过 ResNet。

真正改变局面的是大规模预训练。ViT 原论文报告,在更大的模型和更大的数据集上训练时,ViT 的可扩展性开始显现,并能显著超过 ResNet。D2L 也特别提醒:在约 3 亿图像级别的数据上,ViT 才展示出很强的规模收益。
这就是 ViT 和 CNN 的根本分歧:CNN 更像把视觉结构先写进网络,ViT 则把结构学习更多交给数据和优化。
一个最小实现应该抓住哪些变量
如果用 PyTorch 写一个教学版 ViT,最小闭环大致包括这些对象:
python
class PatchEmbedding(nn.Module):
def __init__(self, img_size=96, patch_size=16, num_hiddens=512):
super().__init__()
self.num_patches = (img_size // patch_size) ** 2
self.proj = nn.Conv2d(
in_channels=3,
out_channels=num_hiddens,
kernel_size=patch_size,
stride=patch_size,
)
def forward(self, x):
x = self.proj(x)
return x.flatten(2).transpose(1, 2)
上面这段代码背后的形状变化比代码本身更重要:
text
(B, C, H, W)
-> Conv2d(kernel=P, stride=P)
-> (B, D, H/P, W/P)
-> flatten + transpose
-> (B, N, D)
其中 B 是 batch size,D 是隐藏维度,N 是 patch 数。后续只需要拼上一个可学习的 cls_token,加上位置嵌入,然后送进若干个 Transformer encoder block。
分类头也很简单:
text
logits = Linear(LayerNorm(encoded_cls_token))
这份最小实现不追求复现大模型效果,但能帮助我们看清 ViT 的骨架:图像 patch 化,序列建模,全局注意力,读出分类 token。
ViT 的影响:视觉主干从"卷积优先"走向"Token 优先"
ViT 之后,计算机视觉出现了几条很清晰的延伸路线。
第一条是数据效率。DeiT 证明,通过更强的数据增强、蒸馏和训练策略,ViT 不一定非要依赖极端规模的数据才能在 ImageNet 上工作得很好。
第二条是结构效率。Swin Transformer 用窗口注意力和 shifted window 降低高分辨率图像上的注意力开销,同时重新引入局部性和层次结构,让 Transformer 更适合检测、分割等密集预测任务。
第三条是多模态统一。图像可以变成 patch token,文本可以变成 word/subword token,音频也可以被切成时间-频率 token。这让 Transformer 成为跨模态建模的共同语言,也为 CLIP、Flamingo、GPT-4V 这类视觉语言模型铺平了道路。
所以 ViT 的历史意义并不只是"把 Transformer 用到图片上"。它更像一次范式切换:视觉模型不再必须从卷积出发,而可以从 token、注意力和规模化训练出发。
读 ViT 时最容易误解的三件事
第一,不要把 ViT 理解成"完全否定 CNN"。ViT 的成功说明弱先验模型在大规模数据下很强,但 CNN 的局部性、层次性仍然非常有价值,许多现代视觉 Transformer 又把这些先验以窗口、金字塔、混合 stem 等形式加了回来。
第二,不要只看架构图而忽略训练规模。小数据上从零训练 ViT,常常得不到论文级结论;预训练数据、正则化、增强策略和优化细节都很关键。
第三,不要把 patch token 当成语义对象。一个 patch 并不等同于一个"词",它只是固定区域的像素集合。ViT 之所以能得到高级语义,是多层注意力和 MLP 逐步组织表示的结果,而不是 patch 天生就有语义。
小结
ViT 的核心思想可以压缩成一句话:把图像切成 patch,把 patch 当作 token,用标准 Transformer encoder 学习全局表示。
这句话看似简单,背后却改变了视觉网络设计的重心。CNN 通过结构先验高效建模局部视觉模式;ViT 则用更通用的 token 序列建模方式换取更强的规模化潜力。它在小数据上不一定占优,在大数据和大模型条件下却打开了新的上限。
从今天回看,ViT 已经不是孤立论文,而是现代视觉大模型、多模态模型和通用感知系统的基础拼图之一。理解 ViT,就是理解 Transformer 如何从语言走向视觉,也是在理解"模型架构"和"数据规模"之间那场仍在继续的交换。
参考来源与授权说明
- D2L《Dive into Deep Learning》1.0.3:Transformers for Vision,作者 Aston Zhang、Zachary C. Lipton、Mu Li、Alexander J. Smola。页面 HTTP Last-Modified:2023-08-18。D2L README License Summary 说明书籍内容采用 Creative Commons Attribution-ShareAlike 4.0 International License,示例与参考代码采用 modified MIT license。
- ViT 原论文:Alexey Dosovitskiy 等,An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale,arXiv:2010.11929,2020-10-22,ICLR 2021。
- Google Research 官方代码仓库:google-research/vision_transformer,用于补充了解 ViT/MLP-Mixer 代码与预训练模型发布情况。
- 相关后续工作:DeiT(Touvron et al., 2021)与 Swin Transformer(Liu et al., 2021),用于说明 ViT 后续的数据效率与结构效率路线。