上一章《语义分割》卡在 CNN 一路丢位置,这一章接住它:2020 年,有人做了一件很荒唐的事——把图片切成小方块排成一队, 当成一句话喂给 Transformer。中小数据上它输给 CNN,数据量够大(3 亿张,JFT-300M)时才全面反超。
Transformer 吃的是"一串向量"。图片是二维网格。ViT 的桥梁只有一步: 切成固定大小的方块,拉平,各做一个线性投影(拿一张权重表,把一块像素乘成一组新数),再当成词向量(一块图像内容对应的一串数)排成序列。
先补半句,不然下面每一节都悬空:Transformer 在这串向量上做的事,是让每个方块都去看所有别的方块, 按「跟我有多相关」给它们打分,再按分数把别人的信息混到自己身上。好处是它第一层就能看到全图; 代价是方块两两都要比一次——方块数变成 n,就要比 n² 次(这就是后文反复出现的 O(n²),第 6 节会真的算它)。 细节在后面的《注意力》和《Transformer》两章。
互动 · 亲手切一次图
这是个纯粹的权衡。方块越小,序列越长、计算量按平方增长;
方块越大,序列越短,但每个方块里的信息越杂(一个 32×32 的块可能同时包含眼睛和耳朵)。
224×224 的图,切 16×16 → 196 个
直接把方块序列丢给 Transformer 是不行的——Transformer 什么都不假设, 而图像里有些东西是必须告诉它的。
互动 · 拆开 ViT 的输入序列
| 零件 | 干什么 | 为什么必需 |
|---|---|---|
| ① Patch |
把 16×16×3 的方块线性投影成 768 维向量 | Transformer 只能处理向量序列 |
| ② |
给每个方块加一个可学习的位置向量 | 没有它,方块序列就是无序集合—— 把图片的方块打乱,模型看到的是同一张图(原理见后面《位置编码与长上下文》) |
| ③ [CLS] token | 在序列最前面插入一个可学习的向量,用它最后一层的输出做分类 | 让"整张图的摘要"有一个固定的位置。也可以用全局平均池化(每一维对全部方块取平均)代替,两种做法效果接近 |
互动 ·
上面那张表里写着「把 16×16×3 的方块线性投影成 768 维向量」。 这句话只有三个动作。下面这张图把它一步一步算出来——每一步乘都是真的 (权重是为演示造的,公式卡里会说明这一点)。
互动 · 切块 → 拉平 → 乘 E,得到一个新向量(768 个数)
整个 ViT-Base(ViT 的一个标准尺寸)有 86M 参数,而 16×16 时「把图片变成序列」这一步只占
768 × 768 ≈ 0.59M——绝大部分在后面的 12 层 Transformer 里。
这也是为什么换分辨率、换方块大小只影响这一层:序列一长,第 1 节说的那种两两打分就开始变贵,
而这里几乎不花什么钱。
这是 ViT 论文最重要的发现,也是最容易被忽略的一点: 在 ImageNet-1k 这个量级上(100 多万张),原版 ViT 的配方还训不好;到 JFT-300M(3 亿张)就全面反超。 后来的 DeiT 证明,中间的差距主要是训练配方问题(强增强与正则,外加用 CNN 蒸馏),不全是数据量问题——这部分第 4 节会讲。 两句话都对,说的是两种配方:原版配方要海量数据;换上强增强、正则和蒸馏,ImageNet 这个量级也能训好。
互动 · 数据量决定谁赢
数据少时,CNN 靠现成的先验赢;数据够多时,ViT 把先验从数据里自己学出来,反超。 这一章剩下的每一个零件、每一条代价,都是为这句话服务的。
CNN 的卷积核里带着几条现成的先验:
局部性(相邻像素相关)、平移等变(配合池化后近似不变,猫挪个位置还是猫)、层次性。
这些先验让它在数据少时非常高效——不用学就知道这些规律。
ViT 什么都不假设。它得从数据里自己发现"相邻像素是相关的"这件事。
数据少时它学不到,所以输;但数据足够多时,"不带偏见"反而成了优势——
它可以学到卷积结构根本表达不了的模式。
CNN 像一个被老师手把手教过的学生:上来就知道"要从局部看、要认形状",
所以用少量练习题就能考及格。
ViT 像一个完全没受过训练的人:题少的时候一塌糊涂;
但当题目多到几亿道时,他自己悟出的规律反而比老师教的更全面。
这个类比管到「学什么」为止:ViT 不是真的「悟」,它是把统计规律一步步编进参数里(本章的 ViT-Base 约 8600 万;更大的 ViT-L / H 才到几亿);题不够时,这些参数学不出稳定的规律。
| 方法 | 解决的问题 | 做法 |
|---|---|---|
| DeiT 2020 |
ViT 要 3 亿张图才能训,太贵了 | 强增强与正则 + 知识蒸馏:先把训练配方(数据增强、正则)调到位, 再让一个训练好的 CNN 当"老师"、用输出指导 ViT。在 ImageNet 上就能训出可用的 ViT |
| Swin 2021 |
ViT 全程用同一分辨率,做检测/分割时不够用 | 层次化 + 滑窗 |
| MAE(掩码 2021 |
标注数据贵,但无标注图片到处都是 | |
| CLIP 2021 |
固定类别数的分类不够灵活 | 图文对比学习(把配对的图文拉近、不配对的推远):用 4 亿对"图片-文字"对齐两个 |
标准 ViT 是"一把尺子量到底":196 个 token 从头到尾不变,每个都看全部。
做分类还行,但做分割时你需要多尺度特征(大物体看小图、小物体看大图,CNN 里用 FPN 做这件事)。
Swin 改了两件事:
① 层次化——每隔几层把相邻方块合并(2×2 拼成 1 个),分辨率逐层减半,通道数翻倍;
② 滑窗注意力——注意力只在局部窗口内计算,复杂度从 O(n²) 降到 O(n)。
窗口还会在层间"错位"(shifted window),让不同窗口之间也能通信。
互动 · 上面那句话的账单:滑窗注意力到底省了多少
互动 · MAE 为什么敢遮掉 75% 的方块
| 维度 | CNN | ViT |
|---|---|---|
| 归纳偏置 | 强(局部性、平移等变) | 几乎没有 |
| 数据需求 | 小数据也能训(万级) | 需要大数据(百万~亿级),或靠 |
| 计算复杂度 | O(n),和像素数线性相关 | O(n²),高分辨率图很贵 |
| 全局关系建模 | 要靠堆很多层( |
第一层就能看到全图 |
| 数据足够时 | 会饱和 | 上限更高 |
| 今天的状态 | 移动端、边缘设备、小数据领域仍然首选 | 大规模 |
如果你的数据是几万张量级:用 CNN 或者用
如果你的数据是百万级或者可以用大规模预训练模型:ViT 系列通常更好。
临界点来自论文的图 4:900 万张的 JFT 子集 ViT 明显输,9000 万张以上就反超。这也和开头对上了——等到几亿张的 JFT-300M,就是全面反超。
| 问题 | 说明 |
|---|---|
| ① 高分辨率太贵 | O(n²) 的注意力。图片分辨率翻倍,token 数变 4 倍,计算量变 16 倍。 这是 ViT 处理视频、医学大图时的核心瓶颈 |
| ② |
可学习的 |
| ③ 缺多尺度结构 | 标准 ViT 只有单一分辨率,做检测/分割时不如 CNN 顺手(Swin 修了,但那基本是"把 CNN 结构搬回来") |
互动 · 把第 ① 条真的算一遍:分辨率一动,账单涨多快
ViT 本身作为"图像分类器"已经不太重要了。它真正的历史地位是:
让图像也可以用和语言完全一样的 Transformer 处理。
这直接导致了两件事:
① 多模态模型成为可能——图像 token 和文字 token 放进同一个序列,
就得到了能看图的 LLM(阶段 4);
② "一个架构统治一切"——文本、图像、音频、视频,最后都变成了"切成 token 喂进 Transformer"。
这一章是全站对“先验知识”这四个字最清楚的一次实验:同一条结论,换个数据量就翻面。
一张图带走:这两条线,数据少时 CNN 在上面,数据多时翻过来
回到第 2 节那张「拆开 ViT 的输入序列」。先把「
那一下你看到的就是“先验被拿掉了”:CNN 永远不会发生这件事—— 它的滑动窗口天生就知道哪块挨着哪块,不需要人告诉它。 ViT 把这份“知道”退回去了,换成“从数据里学”,而换取它的价钱就是几亿张图。
| 暗线 | 这一章的回答 |
|---|---|
| A 信息流动 | 图片 (H, W, 3) → 切块 + 线性投影 → 序列 (N+1, D)(224×224、patch 16 →
197×768)→ Transformer 内部形状全程不变 → 取 [CLS] 那个向量过一层线性分类头(每个类别得一个分数)→ 分数最高的那类。 和 CNN 最本质的形状差异:CNN 是“空间越来越小、通道越来越多”, ViT 是“长度和宽度从头到尾不动”——所以它没有天然的多尺度结构, 这就是 Swin 要把它改回层次形状的原因 |
| B 什么被牺牲了 | 三样东西:数据效率(同样的精度要高一个数量级以上的样本)、
可扩展性(注意力开销按方块数的平方涨,高分辨率下尤其贵)、
|
| C 参数账本 | ViT-Base:图像块投影 + 12 层(注意力 + MLP)≈ 86M 参数,
而其中“把图片变成序列”的那一层只有 16×16×3×768 ≈ 0.6M——
这一步几乎是免费的,绝大部分参数在 Transformer 里面。 算力的账才是重点:token 数 197、维度 768 时,注意力里“两两打分”那一步要做 197×197×768 ≈ 3000 万次乘加;乘上 2(打完分还要用同一张表乘 V)和 12 层, 就是第 6 节那笔 7.15 亿次乘加。ViT-B/16 在 224×224 下整体约 17.6 GFLOPs(十亿次乘加)。把分辨率提到 512×512,token 数从 197 涨到 1025(×5.2), 注意力那部分就涨到 约 27 倍(两两打分随方块数的平方涨)。 这就是它处理大图、视频时真正的瓶颈 |
| D 跑在什么上 | 低分辨率时算得动却算不满,分辨率一高就变成“搬数据”的瓶颈——而且它比 CNN 更难喂饱。 ViT 的计算几乎全是矩阵乘法,这是 GPU 最擅长的形状; 但注意力要先算一张 n×n 的打分表(197×197,12 组同时算), 分辨率一高,时间主要花在把这张中间结果搬来搬去。 所以高效方案分成两条路:Swin 的滑窗注意力干脆不算这么大一张表; FlashAttention 是一种不把整张打分表存下来的算法。 完整的账在 《硬件与算力账本》 |
| E 它假设了什么 | 假设位置信息可以靠“加一个可学习的向量”得到,而不是靠结构保证。
这条假设有个很具体的代价:训练分辨率之外的分辨率表现会掉——
因为那些位置上的向量从来没被学过。 还假设一个小方块里的像素结构可以被一层线性投影压掉而不丢关键信息。 patch 很小时(8×8)这个近似很安全,patch 很大时(32×32)就真的丢了东西 (回看第 1 节那个切块滑块) |
| F 违背了哪个直觉 | 两条。 ① “天生知道该看哪儿”的模型竟然输了。CNN 手里握着几条现成的先验(局部性、平移等变), ViT 什么都没有,最初在 ImageNet 上确实打不过 ResNet。 ② “先验是优势”这句话在数据足够多时会翻转:到几亿张图量级, 不带偏置反而学到更多——先验只在样本稀缺时才值钱 |
它接住了上一章的什么:《语义分割》最后一行说, U-Net 那种“先降后升”的局部结构受限,完整的答案在《ViT》。
它给后面留了什么:ViT 真正的遗产是 图像和语言用同一个序列、同一个 Transformer。 把两串 token 放进一个模型,就得到了能看图的 LLM(更后面《多模态模型》); 它不靠标注,下一章《自监督与对比学习》接着讲。
ViT = 把图片切成方块,当成一句话喂给 Transformer,再加
它一个卷积都没用,因此也没有 CNN 的归纳偏置——
代价是需要海量数据才能训起来,好处是数据够多时上限更高。
DeiT(强增强与正则 + 蒸馏)让它能在 ImageNet 上训,Swin(层次化 + 滑窗)让它能做检测分割,
MAE(自监督)让它不需要标注,CLIP(图文对比)让它能零样本分类。
它最终的价值不在分类,而在让图像和语言进入了同一个架构——这是多模态模型的地基。
上面讲的都是「够用」的版本。想往下挖,这里有三个入口—— 它们不是必修内容,是给想再往前走一步的读者准备的。