很多朋友拿到 Vision Transformer 这篇论文,第一反应是问:我是不是应该先把 Transformer 彻底搞懂再读?我的答案是:不用。这篇论文最有价值的地方,恰恰是它把 Transformer 当作一个通用工具箱,直接搬到图像上完整试了一遍,并且验证了一个在当时非常反直觉的结论:只要数据够大,通用架构也能打败专门为图像设计的卷积网络。作为一篇带我入行视觉 Transformer 的经典论文,它适合所有做深度学习、计算机视觉、甚至关心模型设计底层逻辑的人反复咀嚼。下面我重新把这篇论文读一遍,把我认为最值得抠的细节、最容易踩的坑,以及很多人在讨论它时常忽略的点一次说完。
1. 读这篇经典之前,先看清它是从什么局面里杀出来的
1.1 卷积统治视觉的年代,为什么要动 Transformer 的心思
2020 年前后,图像识别的基本盘几乎被卷积神经网络占满。卷积网络在图像分类、检测、分割上全面领先,而且当时大家的普遍共识是:卷积提出了一整套非常适合图像的结构先验,比如局部连接、权值共享、平移等变性,这些都让模型在样本量有限的时候更容易学到有用的特征。
注意力机制在那个阶段并不是没人用,但它更多是给卷积网络“打辅助”——例如在通道上做注意力、在空间上做注意力,本质上仍是卷积结构上的局部增强。真正把自注意力作为主架构的方法还停留在理论验证上,应用效果普遍不如卷积网络。
Vision Transformer 做的事情,往大了说是挑战了这个基本盘。它不再讨论“注意力该怎么塞进卷积”,而是直接把 NLP 里已经长熟的 Transformer Encoder 搬到图像上,从头到尾不用卷积。回头来看,这种“跨界移植”在深度学习历史上不算罕见,但它是第一次在超大规模图像分类任务上把验证做到这么完整,让所有人看到了通用架构的潜力。
读这篇论文之前,你需要先理解一个思想背景:卷积网络并不是“唯一会看图的模型”,它只是“很擅长利用图像先验的模型”。而 Transformer 是一个“几乎不给先验、但非常擅长学习复杂关系”的模型。前者像一台固定焦距的相机,一开始就把“看局部”写进了镜头;后者像一双没有预设视线的眼睛,靠大量见识来学会该往哪儿看。ViT 的故事,就是这双眼睛如何通过海量数据补上“空间感”的故事。
1.2 读这篇论文的正确姿势:不要只盯精度表
很多初学者读论文有个习惯,就是直奔实验表格,看到 ViT 在某些数据集上超过了卷积网络,就得出“Transformer 碾压 CNN”的结论。这个结论太危险了。
我建议拿到任何论文都先问三个问题:
- 动机是什么?论文要挑战哪个默认假设?对 ViT 来说,就是“图像任务必须依赖卷积先验”这个假设。
- 设计如何回应动机?它用 Patch Embedding 把图像变成序列,再用标准 Transformer 建模,每步都有明确意图。
- 边界在哪里?它的结论在什么数据规模下成立?在什么任务上不成立?这决定了你能否把方法用到自己的问题上。
尤其第三个问题最容易忽略。论文自己在实验部分写得非常清楚:如果数据集不够大,ViT 的表现是不如同等级别的卷积网络的。这个边界不是作者藏着掖着,而是很多读者读得太快,只记住了“反超”那一面。我自己就见过有同事直接拿着 ViT 在几万张图上做微调,然后用不过卷积网络这件事来怀疑论文有水分——其实论文里早就写了,这个场景本来就该用卷积,或者应该先做足够强的预训练。
带着这三个问题去读,你会发现 ViT 的贡献不在于“什么任务都比 CNN 强”,而在于它证明了:在数据充足的前提下,一个更通用的架构可以自行学会视觉任务所需的归纳偏置。这才是真正改变后续研究方向的点。
2. Patch 化:把图像变成一句话,是 ViT 最优雅的一步
2.1 为什么是 16×16,而不是 8×8 或 32×32
ViT 处理图像的流程并不复杂。假设输入是 224×224×3 的图片,模型先把图片切成一个个正方形小块,论文里最常用的是 16×16。这样一张图会被切成 (224/16)² = 196 个 patch,每个 patch 的原始尺寸是 16×16×3。接下来,把每个 patch 展平成 768 维的向量,再经过一个线性投影变成 Transformer 里的 token 向量。
这一步之后,一张图像就变成了长度为 196 的“句子”,每个 patch 相当于一个“词”。Transformer 内部怎么处理文本,就怎么处理这组向量。这个“把图像切成词”的设计是整个方法最核心的抽象,它让图像和文本在模型层面第一次真正共用同一套处理逻辑。
但为什么偏偏是 16×16?这不是拍脑袋定下来的,背后有很现实的计算考量。Transformer 的核心是自注意力,它对序列长度做两两交互,计算量随序列长度近似平方增长。如果改用 8×8 的 patch,同样的 224×224 图片会被切成 784 个 patch,序列长度涨到原来的四倍,自注意力计算量涨得更多,训练成本立刻爆表。如果改用 32×32,序列虽然只有 49,但每个 patch 内的空间细节被压得太碎,一些细粒度纹理和小物体信息会丢失,分类精度也会下降。
所以 16×16 是一个兼顾“序列长度”和“空间分辨率”的折中值。你可以把它类比成读文章时的断句:不会把整页纸当成一段,也不会把每个字符单独当一句话,而是按语义块切分。Patch 就是视觉里的“语义块”,切得太粗丢细节,切得太细模型撑不住。
这里还顺带解释了 ViT 一个经常被讨论的特点:它没有像卷积网络那样搞多尺度特征金字塔,因为自注意力天然是全局建模,单层就能看到全图,不需要靠堆叠多尺度卷积核来逐步扩大感受野。这是它和卷积网络在结构哲学上最大的不同。
2.2 位置编码与 CLS 标记:两个容易被低估的设计
把图像切成 patch 之后,还有一个关键问题:Transformer 的自注意力本身不关心顺序。如果直接把一堆 patch 向量丢进去,模型看到的是一个无序集合,完全不知道哪个 patch 在上面、哪个在下面。这对文本来说同样致命,词序变了语义就变了,对图像来说位置信息更是根本性的。
ViT 的做法是给每个 patch 向量加一个“可学习的位置编码”。模型会自主学会用一组向量来表示“第几行第几列”这一类位置语义。相比 NLP 中常用的固定正弦编码,可学习位置编码在图像上更灵活,因为图像是二维结构,模型可以根据数据和任务自行组织空间关系的表达。
第二个容易被低估的设计是 CLS 标记。NLP 里的 BERT 会在句子开头加一个特殊 token,ViT 也学了这个做法,在 patch 序列前面加一个额外的向量,称为 CLS 标记。整个 Transformer 前向计算完,模型直接从 CLS 标记对应的输出向量上接一个分类头,读出图像类别。
有人会问:为什么不用全局平均池化,把所有 patch 的输出取平均再分类?论文作者在实验里也做了类似对比,结论是没有显著差别,但 CLS 标记对研究者来说有它独特的价值:它相当于给模型一个“显式的全局信息汇总出口”,训练时证明这个方式收敛更稳定,在后续做对比学习、多模态对齐时也更方便。实践里,绝大多数基于 ViT 的模型也都延续了这个设计,所以“看到 CLS 就联想到分类”是读后续论文的一个基础点。
2.3 归纳偏置变弱了,换来的是更自由的感受野
卷积网络从出生就带着两个强烈的归纳偏置:局部连接和平移等变性。每一个卷积核都只看一个小邻域,同一套卷积核在图像不同位置复用。这种设计让模型在小数据集上非常高效,但也意味着它一开始就假设“图像里的特征是局部且平移不变的”,这个假设不一定对所有任务都成立。
ViT 反着来:它不预设任何空间结构。自注意力让每一个 patch 都能直接看到其他所有 patch,感受野从一开始就是全局的。浅层模型不需要像卷积那样通过层层堆叠才能把视野扩大到全图,它可以一步到位。但代价是,它不知道“相邻像素通常相关”这种常识,需要靠大量数据把这种规律自己学进网络。
论文的实验结果非常有意思:在小规模数据上,ViT 学不到好的空间结构,性能明显落后卷积网络;但在超大规模数据上,ViT 学到的结构化模式反而比卷积网络的手工偏置更灵活、更适应任务。这给了整个领域一个重要的启发:归纳偏置不是越多越好,而是要看数据规模。数据多的时候,少一点偏见、多一点自由度,往往能让模型获得更强的上限。
这也是我认为 ViT 全篇最值得反复琢磨的思想点:它不是教你“Transformer 一定比 CNN 强”,而是教你思考“当一个模型不再依赖手工先验时,需要付出多少数据成本,又能收获多少模型潜力”。
3. 实验表格里最有信息量的不是精度,而是那几张对比图
3.1 让 ViT 真正“起飞”的实验条件:数据规模由小到大
ViT 的实验部分经常被当成“精度汇报”来读,但我认为最有价值的其实是它揭示的规模效应。论文里做了非常重要的一组对照:用同一套 Transformer 结构,在不同规模的预训练数据上训练,再在下游分类任务上微调,观察结果。
在相对小规模的数据集上,ViT 是明显吃亏的,甚至可以说被打得很惨。它必须依赖很强的正则化才能不发生过拟合,即便如此,最好的结果也不如同等参数量、同等计算预算的卷积网络。原因不复杂:一个自由度很高的架构,在样本不足时就是更容易拟合噪声,而卷积网络靠先验已经把搜索空间大大缩小了。
但当预训练数据规模翻到上亿级别时,情况完全反转。大尺寸的 ViT 模型开始展现出比卷积网络更强的扩展能力:给它更多数据和更多计算量,精度几乎一路稳定上涨,肉眼很难看到天花板。卷积网络在这个规模下反而先遇到瓶颈,继续堆数据带来的收益曲线变缓。
这个观察带来的实际建议是直接可用的:如果你手头只有几十万张图片,不要硬上大 ViT。优先选择卷积网络或者带卷积先验的混合架构,这样性价比最高。只有当你拥有千万级以上的数据,或者能借助足够强的预训练模型时,基于 ViT 的架构才真正开始发光。很多人复现 ViT 失败,问题不在代码,而在数据量根本不够喂饱它。
3.2 中小数据集上为什么打不过 CNN:正则化缺口
进一步读实验细节时会发现,ViT 在小数据上表现差,很大程度上不是“注意力机制不行”,而是“正则化不够”。Transformer 的容量大、灵活度高,在小数据上非常容易把训练集背下来,验证集上自然就垮掉。
论文为了应对这个问题,几乎把所有能想到的正则化手段都上了:Dropout、权重衰减、数据增强、更大的 batch size、更长的训练步数等等。即使这样,小数据场景下它依然占不到便宜。这说明一个问题:如果你决定在自己的中小规模数据上用 Transformer,你应该把至少一半的调参精力放在正则化上,而不是疯狂增大模型。
有一个很实用的判断方法:当你发现训练集损失降得非常低、验证集损失却纹丝不动的时候,基本可以断定是过拟合。这时不要怀疑结构,先去加大 Dropout 和权重衰减,再考虑用更强数据增强。如果还不行,老老实实换回卷积或混合架构。
论文在这一点上其实给后来的研究者留了一道思考题:怎么让 Transformer 在小数据上也行得通?这个问题的答案后来由很多后续工作给出,比如更精细的训练策略、知识蒸馏、更强的数据增强,甚至自监督预训练。这些方法之所以出现,源头都是 ViT 自己坦白的“小数据短板”。
3.3 注意力可视化:先看局部再看全局
论文里放出的注意力可视化图,是很多人容易扫一眼就略过、但其实非常精彩的信息。作者把模型各层、各个注意力头关注的位置画出来,展示了模型内部是如何逐步组织视觉理解的。
观察结果大致可以归纳成两句话:浅层注意力头倾向于关注相邻位置的 patch,这有点像是自己学出来的“局部性”;深层注意力头则会跳过空间距离,去关注那些属于同一物体的语义区域,比如鸟的头部和爪子之间虽然有距离,但注意力会互相建立连接。这其实说明 Transformer 不是不懂图像结构,而是在训练中自己发现了一个事实:近处的东西往往相关,远处的东西如果是同类也应相关。只不过它是在数据里学到的,而不是被结构强加的。
如果你有条件翻出可视化原图仔细看,还会发现一些非常实用的细节:模型在面对背景和物体颜色相近的情况时,很容易注意力错乱,把背景区域和物体混淆。这就帮我们推测出 ViT 的下限来源——对纹理和颜色统计过于敏感。读完这部分之后,你应该建立一个新的习惯:看实验章节不要只看表格,图表里的失败案例和可视化往往比那几个数字更能说明模型的真正行为。
4. 复现 ViT 时最容易翻车的地方,原论文里其实写得很隐晦
4.1 学习率、warmup 和 batch size 的联动
很多团队第一次复现 ViT 时,跑出的精度离论文报告的数值总有距离,然后开始怀疑代码写错了。其实更常见的原因是训练超参数没有对齐,尤其是优化器相关的配置。
ViT 能训起来,依赖的是一套非常讲究的优化设置:大 batch、相对较高的基础学习率、很长的线性 warmup、以及适度的权重衰减。warmup 的作用是让模型在训练初期不要因为 patch 序列过度扰动而发散;大 batch 让梯度估计更稳,从而可以承受更高的学习率;权重衰减则用于缓解 Transformer 在大模型上常见的过拟合问题。这些参数不是独立的,它们互相耦合。你单独把学习率调大但没动 warmup 和 batch size,大概率直接发散。
我踩过的坑是:直接沿用训练卷积网络时惯用的小 batch、较低学习率配置,结果 ViT 训得非常慢,而且损失曲线像一条乱跳的线。后来把 batch size 提上去、学习率按 batch size 比例重新标定、warmup 步数加长之后,整个训练才恢复正常。这里想说一个通用原则:超参数是带场景的,从论文里抄配置要整套抄,最多在两边场景差异特别大时做有依据的调整,不要只挑一个数字改。
4.2 位置编码插值:改变输入分辨率时的暗坑
ViT 训练时使用的输入分辨率通常是固定的。直接把自己的数据从 224×224 送到模型里当然没问题,但很多下游任务需要更高分辨率,比如检测和分割场景经常要用到 512×512、1024×1024 这种输入。
问题出在位置编码上:位置编码是跟 patch 数量绑定的。输入分辨率变大后,patch 数量变多,原来的位置编码向量不够用了。最常见的做法是“插值”:把原来训练好的位置编码网格放大,填充到新的位置编码矩阵里。听起来简单,做起来有细节。
如果你在训练后直接改分辨率,即使做了插值,模型性能也会掉一截。原因在于,Positional Embedding 在预训练时已经和特定位置的 patch 语义纠缠在一起,插值引入的分布变化会让自注意力的相对关系产生偏移。实际项目里,如果想用更高分辨率,最好在改完分辨率之后加一个比较轻量的微调阶段,让模型重新适应插值后的位置编码。另外一个常见优化是采用相对位置编码,这样对输入尺寸的变化天然更鲁棒,这也是很多后续架构改为相对位置编码的原因之一。
4.3 从论文到代码:哪些细节是实验血泪换来的
论文正文受篇幅限制,不会把所有工程细节都写出来,但复现时这些细节往往决定成败。我根据自己的实际经验列几个特别容易翻车的点。
第一,Layer Normalization 的位置。ViT 用的是 Pre-Norm 结构,也就是先做 LayerNorm 再进子层,而不是最早 Transformer 论文里那种 Post-Norm。这个差别对训练的稳定性影响非常大。你用 Post-Norm 跑深层 Transformer,很容易出现训练后期损失震荡甚至不收敛的情况。
第二,残差连接的收尾。Transformer Block 最后一般有残差连接和 Dropout,Dropout 的落点、顺序不同,效果也会不一样。复现时不要自己改顺序,先照着验证过的实现跑通,再谈优化。
第三,混合精度训练。ViT 这种大模型不用混合精度的话,显存和训练时间会非常难看。但开启混合精度之后,偶尔会出现 loss 变成 NaN 的情况,尤其是超大 batch 的时候。处理方式一般是配合梯度裁剪和更稳健的 loss scale 策略,必要时候对特定层保持 FP32。
这些细节论文里未必逐条写明,但它们是“论文里看不到、实验里却处处见鬼”的部分。对准备复现 ViT 的朋友,我建议直接参考成熟开源的实现先跑通小实验,再对照论文重读每个模块的作用,会比从零硬写要省力得多。
5. 把 ViT 当起点,后面这些模型其实都是在补它的短板
5.1 数据效率问题:蒸馏和监督训练怎么补
ViT 被吐槽最多的一点就是“太吃数据”。中小规模应用场景里,直接用原始 ViT 并不划算。后续一系列工作基本上都在解决“如何降低 ViT 的数据门槛”,这形成了视觉 Transformer 研究的一条清晰主线。
最直接的思路是“蒸馏”:让一个已经训练好的卷积网络作为老师,把它的输出当作软标签,教小 Transformer 学习。这个策略后来被证明相当有效,能够让 Transformer 在中小规模数据上达到接近卷积网络的性能,而且训练速度还更快。原理并不复杂:卷积老师的 soft label 里包含了丰富的类间相似度信息,相当于把卷积网络多年积累的先验蒸馏进了 Transformer,弥补它初始没有归纳偏置的短板。
另一类思路是强化数据增强和正则化,让模型在同样的图片数量下看到更多有效变化。混合增强、随机擦除、更激进的裁剪策略,配合延迟较高的权重衰减,都能让 Transformer 过拟合得更慢一点。如果你现在要做一个小规模视觉任务,这些方法比单纯加大模型尺寸更值得优先尝试。
5.2 计算复杂度问题:局部注意力与金字塔结构
ViT 的全局自注意力虽然表达能力很强,但计算复杂度随 patch 数量平方增长,处理高分辨率图像时非常吃力。后续研究自然而然走向了两个方向:一是把注意力限制在局部窗口内,通过窗口划分降低复杂度;二是引入金字塔结构,在不同阶段保持不同分辨率,让模型先看全局粗略结构,再逐步细化。
这两种思路后来被很多实际部署方案采用。局部注意力让模型在计算量可控的前提下保留空间细节,金字塔结构则让不同层级的特征可以服务于检测、分割这类需要多尺度语义的任务。你会发现,这些设计在一定程度上又回归了卷积网络的一些优点,比如局部性、多尺度——只不过这次的外壳变成了 Transformer。
这对工程选型很有启发:如果你的任务是高分辨率输入,别死磕原始 ViT 的全注意力,优先选择带局部注意力或多尺度结构的变体。它们不是论文里的花架子,而是真正为复杂视觉任务设计的实用选择。
5.3 自监督复兴:掩码预训练为什么在 ViT 上特别顺
ViT 出现之后,自监督预训练也在视觉领域火了起来,尤其是“掩码图像建模”这种思路:把一部分 patch 遮盖起来,让模型根据剩下的 patch 重建被遮住的部分。这个预训练任务对 ViT 来说几乎是天然的适配,因为 ViT 本身就工作在 patch 序列上,遮盖一个 patch 就相当于文本里盖掉一个词。
这种自监督方法比监督预训练对数据量的要求低很多,也让 Transformer 在没有大量标注数据的情况下也能获得很好的初始化。从一个更长的时间维度看,ViT 的贡献不只是“用 Transformer 做图像识别”,更是把图像表示成序列这套范式推广开了。自监督、多模态对齐、跨模态理解这些后来的方向,都能在 ViT 的 patch 化设计里找到最初的影子。
我对这条延伸路线的建议是:不要只停留在读原论文,把它往后四五年的工作串起来看。你会看到同一个思想如何在不同约束下持续演化——从吃数据,到省数据;从全局注意力,到高效注意力;从单任务,到通用表示。这种脉络感,才是读一篇经典论文收获最大的地方。
我自己反复读这篇论文之后最大的体会是:读旧论文最怕带着“我已经知道结果”的心态,那样很容易错过决策现场。更值钱的做法是把结论遮住,逼自己先复现一遍作者当时做决策的依据。你会发现,每当你也有过类似念头,而论文恰好用实验验证或否定它时,你对模型设计的理解才算真正刻进脑子里。