我最早看到 ViT 论文的时候,标题就让我觉得离谱:「一张图值 16×16 个词」。图片和词怎么能一样?CNN 花了二十多年才把卷积、池化、平移不变性打磨成图像识别的标配,你现在告诉我,直接把图片撕成碎片,当作一维序列扔进 Transformer,然后它就赢了?这就像你把一本漫画书剪成小纸片,打乱顺序,然后让一个从来没读过漫画的人去猜主角是谁——听起来像个笑话。

但谷歌那帮人不但做了,还做成了。更让我崩溃的是,当我仔细读完整篇论文,发现这个思路 简单到不需要任何图像领域的先验知识,纯粹靠 Transformer 的全局注意力硬刚。今天这篇文章,我就来拆解一下 ViT 到底是怎么把图片变成“文字”的,以及为什么这种看似暴力的方法,最终能反超精心设计的 CNN。
把图片拆成 Token,总共分几步?
你平时用 ChatGPT 处理文字,它看到的是一串 token 序列,每个 token 是一个向量。ViT 的起点就是:能不能把一张图片也变成一串向量? 答案是可以,而且步骤异常直接。
- 切块:把一张 224×224 像素的图片,切成一个个 16×16 的小方块(patch)。一共切出 (224/16)×(224/16) = 14×14 = 196 个 patch。每个 patch 就是一张小图,里面 16×16×3 = 768 个像素值。
- 拉平:把每个 16×16×3 的小块拉成一个长度为 768 的一维向量。这 196 个向量,就是 ViT 眼中的“单词”。
- 投影:用一个可训练的线性层(全连接层,也叫 E 矩阵),把 768 维向量压缩到模型固定的维度 D(比如 768 或 1024)。这一步类似于 NLP 里把单词 ID 映射成词嵌入向量。
- 加位置编码:Transformer 本身没有顺序概念,所以必须告诉模型每个 patch 原来在图片里的位置。ViT 用的是一组可学习的 1D 位置编码,直接加到每个 patch 的嵌入向量上。注意,这里不是 2D 的,就是简单的 1, 2, 3, …, 196,模型自己会学会“第 27 个 patch 大概在中间偏左”这种空间关系。
- 插一个 CLS token:在序列最前面加一个特殊的、可学习的 [CLS] token,它的嵌入向量也是随机初始化的。这个 token 在 Transformer 编码器最后一层的输出,会被拿去接一个分类头,用来做图像分类。你可以把它想象成“整个图片的摘要”——模型在训练过程中,会把所有有用的信息都会汇聚到这个 token 里。
- 喂进 Transformer:把这 197 个向量(1 个 CLS + 196 个 patch)组成的序列,直接扔进标准 Transformer 编码器。接下来的事情就和 NLP 一模一样了:多头自注意力让每个 patch 都能和所有其他 patch 交互,前馈网络做非线性变换。
整个过程一点卷积都没有,一点池化都没有,甚至连图像特有的操作都没有。它就是一套纯文本 Transformer 的流水线,只不过把“词”换成了“图块”。
为什么这么“蠢”的方法能工作?
这可能是你最困惑的地方。CNN 有两大法宝:局部连接(每个神经元只看一小块区域)和 平移不变性(同一个卷积核滑过整张图,学到的是空间无关的特征)。这两点让 CNN 天然适合处理图像,哪怕数据量不大也能学到不错的特征。而 ViT 的自注意力是全局的,第一层就让每个 patch 和所有其他 patch 算注意力,完全没有“距离越近关系越重要”的先验。按道理,这种模型在小数据集上应该严重过拟合,完全学不到东西。
事实也确实如此。论文里有一个非常直观的实验:在 ImageNet-1k(120 万张图)上训练,ViT 的性能不如同等规模的 ResNet。但一旦把数据集换成更大的 ImageNet-21k(1400 万张)或谷歌自己的 JFT-300M(3 亿张),ViT 就反超了,而且 数据量越大,优势越明显。这说明什么?
ViT 的“弱”就弱在没有先验,所以它需要海量数据来弥补没有卷积偏置的缺陷。但当数据足够多时,没有先验反而成了优势——模型不会被卷积的局部性束缚,可以自由地学习长距离依赖。比如区分一只鸟的种类,可能需要同时看鸟喙的形状和翅膀末端的颜色,两者相距很远,CNN 要靠很多层才能把感受野扩大到全局,而 ViT 从第一层起就能直接关联任意两个 patch。这种全局视野,让 ViT 在复杂、精细的分类任务上更容易学到高层次的特征。
我自己的认知转变也发生在这里。我以前一直觉得,CNN 的归纳偏置是上帝给视觉模型的礼物,没有它根本不行。但 ViT 用事实告诉我:当数据量足够大时,你不需要教模型“应该怎么学”,它自己会找到最优的学习方式。这就像你教小孩画画,如果你只给他看 10 张猫的图片,你得告诉他“猫有尖耳朵、长胡须”;但如果你给他看 100 万张猫的图片,他自然自己就总结出规律了,不需要你替他归纳。
一张表看清 CNN 和 ViT 的根本区别
| CNN (ResNet) | ViT | |
|---|---|---|
| 核心操作 | 局部卷积 + 池化 | 全局自注意力 |
| 归纳偏置 | 局部性、平移不变性 | 几乎没有(仅 patch 切分) |
| 感受野 | 从局部逐渐扩大 | 第一层就是全局 |
| 数据需求 | 中等(ImageNet-1k 即可) | 大(ImageNet-21k/JFT-300M 起步) |
| 计算效率 | 每个卷积核独立,但需要深层堆叠 | 自注意力 O(n²),但训练时可以用更少的层数达到同等精度 |
| 可解释性 | 特征图可视化直观 | 注意力图可直接看 patch 间关系 |
这张表其实藏着一个重要的信息:ViT 并不是在所有场景下都更好。如果数据量不够,CNN 依旧是王者。但如果你有海量数据,ViT 的训练效率更高——论文里提到,ViT 在同等计算量下,精度比 ResNet 更高,而且训练时间更短(因为可以用更少的层数)。
两个你可能想问的问题
ViT 的位置编码为什么不用 2D?
论文里试过 2D 位置编码,也试过相对位置编码,但发现效果和 1D 差不多,甚至 1D 更简单。所以就直接用了最简单的可学习 1D 向量。这其实反直觉——你可能会觉得“第 3 行第 5 列”这种 2D 信息应该更精确。但实验表明,模型从 1D 序号里就能隐式学会 2D 空间关系,因为图片的 patch 是按从左到右、从上到下顺序排列的,模型自己就能推断出相邻 patch 在空间上也是相邻的。这再次印证了 ViT 的暴力美学:能用数据学出来,就别手工设计。
ViT 能处理任意尺寸的图片吗?
理论上可以,因为 patch 大小是固定的,图片尺寸变了,patch 的数量就变,序列长度也就变了。但位置编码是预训练时学好的,长度固定。如果输入图片的分辨率变了,patch 数量变了,位置编码就不能直接用了。常见的做法是用双线性插值把预训练的位置编码缩放成新的长度,然后微调整个模型。这种灵活性让 ViT 可以轻松迁移到不同分辨率的任务上,比 CNN 改输入尺寸要方便得多。
我踩过的坑:ViT 真的不需要数据增强吗?
我一开始天真地以为,既然 ViT 没有先验,那就应该用超强的数据增强来弥补。结果我发现,论文里用的数据增强其实和 CNN 差不多:随机裁剪、随机水平翻转、颜色抖动,还加了一个叫 Mixup 的增强策略。但关键不是增强的种类,而是预训练的数据集规模。在没有 JFT-300M 这种级别数据的情况下,单纯靠增强在 ImageNet-1k 上训练 ViT,效果还是不如 ResNet。所以,别被“暴力美学”这个词骗了,它暴力的是数据需求,不是训练技巧。
ViT 现在的边界在哪里?
到今天,ViT 已经演化出了多个变体(Swin Transformer、DeiT 等),但核心思想没变:把图像序列化,用 Transformer 提取全局特征。它最大的贡献是 统一了 NLP 和 CV 的模型架构,让多模态模型(比如 CLIP、GPT-4V)的实现变得理所当然——既然图片和文字都能用同一个 Transformer 处理,那把它们拼在一起训练就毫无违和感了。
但 ViT 的局限性也依然存在:第一,它仍然需要海量标注数据,或者用自监督预训练(如 MAE)来缓解;第二,自注意力的 O(n²) 复杂度让高分辨率图像处理很吃力,虽然 Swin 等用窗口注意力缓解了,但终究不是完全全局的;第三,对于需要精细定位的密集预测任务(如语义分割),纯 ViT 不如 CNN 直观,一般要结合特征金字塔或卷积头。
所以,如果有人问你“ViT 和 CNN 谁更好”,别急着站队。正确的回答是:取决于你有多少数据,以及你要做什么任务。数据少、需要精细定位,CNN 依旧强悍;数据多、需要全局理解,ViT 是更优选择。而未来,两者大概率会合流,比如 ConvNeXt 就是证明——那是另一个故事了。
参考来源:ViT 原始论文、Google AI Blog 介绍、Swin Transformer 论文。
原创文章,作者:guanweilu,如若转载,请注明出处:https://guanweilu.cn/article/184.html