从网格到一句「图块」组成的句子
在这架学习阶梯的前面,你已经掌握了两个重要思想。在计算机视觉里,卷积神经网络靠在像素网格上滑动小小的滤波器来读图,一条边一条边、一块区域一块区域地堆叠出特征。在语言相关的几阶里,Transformer通过自注意力让每个词都去看其它所有词,从而读懂一句话。视觉 Transformer 提出了一个看似简单的问题:如果我们像喂一句话那样,把一张图像喂给 Transformer,会怎么样?
问题在于,Transformer 想要的是一小串词元(token),可是一张 224×224 的图像就有超过 15 万个像素——多得无法让每个像素都去关注其它所有像素。诀窍是把图像切成由小方块组成的网格,每个方块叫一个图块(patch),比如各 16×16 像素。这样一张 224×224 的图像就变成整齐的 14×14 网格,只有 196 个图块。每个图块被展平成一个向量,再经过一个小小的线性层,变成一个嵌入向量——正是 Transformer 爱吃的那种稠密向量。一个图块,就这样变成了一个「词」。
走进视觉 Transformer 内部
视觉 Transformer(ViT)把这些零件组装起来,方式应该会让你想起语言那一侧的做法。首先,每个图块嵌入都会加上一个位置编码——一个可学习的向量,告诉网络「这是第 5 个图块,在第 1 行、第 5 列」——好让网络找回它在做成列表时丢掉的布局。然后整串序列流过一摞标准的 Transformer 块,每一块先做多头自注意力,再接一个小小的前馈网络。
正是在这里,ViT 与卷积网络分道扬镳。CNN 在它早期的层里只会把邻近的像素组合起来;要经过很多层堆叠,某个滤波器的感受野才够宽,才能把图像的一个角和它的中心联系起来。自注意力没有这种限制。在最最开始的那一块里,覆盖狗耳朵的图块就可以直接去关注覆盖狗尾巴的图块,无论它们隔得多远。从第一层起,整张图就已经「尽收眼底」。
为了给整张图给出一个单一的答案——比如一个类别标签——ViT 又从语言模型那里借来一招:它在最前面额外加上一个可学习的词元,常叫做 [CLS] 词元,它不属于任何图块。随着注意力运转,这个词元会从所有真实图块那里汇聚信息,它最终的向量被送进一个小小的分类头。它就是一个专职的记录员,唯一的任务就是把这张图总结出来。
patches = split_image(img, patch=16) # 196 patches of 16x16 tokens = linear_project(flatten(patches))# each patch -> embedding vector tokens = [CLS] + tokens # prepend the summary token tokens = tokens + positional_encoding # add back the 'where' z = transformer_blocks(tokens) # attention all the way down label = classifier_head(z[CLS]) # read the answer off [CLS]
为什么 CNN 没有就此退场
把卷积宣布为「已死」很诱人,但诚实的故事要有意思得多。CNN 在搭建时就内置了很强的归纳偏置:它假设邻近的像素彼此相关(局部性),也假设一只猫无论出现在画面哪个位置都还是一只猫(平移等变性)。这些假设是礼物——它们让 CNN 能从规模不大的数据集里学到东西。ViT 几乎不做这些假设;注意力把所有图块都看作同样可以相互连接。这份自由,恰恰就是它在小数据上的弱点。
2020 年最初那篇 ViT 论文把这一点讲得毫不客气。在 ImageNet(约一百万张图像)上从零训练时,ViT 实际上输给了规模相当的 ResNet。只有当它先在一个大得多、含数亿张图像的数据集上做预训练、再在较小的目标任务上微调之后,它才反超。数据足够多时,Transformer 会自己学到 CNN 被白白赠予的那种局部性,然后继续往前跑。这个教训在本领域反复出现:一个灵活的模型加上海量数据,能够击败精心手工设计的先验,但前提是越过某个规模阈值。
CLIP:教图像和文字共享同一个空间
一旦图像和文字都以词元序列的形式存在,一种诱人的可能性就打开了:能不能让一个模型同时理解两者?CLIP(对比式语言—图像预训练,2021)就是这个突破性的答案。它用两个编码器——一个图像编码器(通常是 ViT)和一个文本编码器(一个 Transformer)——并训练它们把一张图和它的配文放到同一个共享嵌入空间里的同一个位置上。不需要任何人工标注的类别;监督信号是免费来的,来自从网上抓取的数亿对「图像—配文」。
训练目标是对比学习,它的想法美在简单。取一批,比如 256 对「图像—配文」。把每张图和每段配文都编码成向量。现在把全部 256×256 种可能的图文组合摆给模型看,并告诉它:那 256 对真实配对应该得高分(把它们拉到一起),而所有错配的组合应该得低分(把它们推开)。它从不去学一份固定的标签清单。它学到的是一种丰富得多的本领:判断任意一段配文与任意一张图有多匹配。
回报是惊人的:CLIP 能对它从未被明确训练过的类别做零样本图像分类。要问「这是不是一张柯基的照片?」,你只需把文字「一张柯基的照片」和其它几个候选句子都编码,再把图像编码,然后挑出在共享空间里离这张图最近的那句配文。你可以在测试时只靠写新句子就发明出新类别——不必重新训练,不需要带标签的样本。
它解锁了什么——以及它真正做不到什么
CLIP 的图文共享空间,最后悄悄成了许多现代 AI 之下的地基。它是许多多模态模型内部的那座桥,让模型能描述一张照片或回答关于它的问题;而它的文本编码器,正是让文生图系统能用一句文字提示来引导图像生成的关键——这正是下一篇关于扩散模型的指南的主题。把图块当作词元,给我们的不只是一个新的分类器;它让视觉和文字拥有了一种共同的语言。
现在说说诚实的局限。CLIP 会识别,但不会定位。它会乐呵呵地告诉你图里有个消防栓,但靠它自己,画不出一个框把消防栓框起来——那仍然需要专门的检测方法。它在数数上也弱得出人意料(在它眼里「三只猫」常常和「两只猫」差不多),在细致的空间关系上同样如此(「盘子左边的杯子」)。而且,因为它的训练配文是从开放网络上抓来的,CLIP 也吸收了网络的偏见与盲点——它了解的是互联网选择去拍摄、去配文的那个视觉世界,而不是世界本来的样子。
还有一件事要摆正分寸。「零样本」听起来像魔法,但它只对那些在那数亿条训练配文里某处被充分呈现过的概念才奏效。去问 CLIP 一种罕见的医学病症,或一个它从未见过被描述的小众工业零件,魔法就蒸发了。模型并不是在从第一性原理出发对全新类别进行推理;它是在检索、重组它在某种弥散意义上「已经见过」的模式。这确确实实很强大——也确确实实不等于「理解」。