ViT 详解:如何把一张图变成一段 token 序列

前言 本站的《Transformer 详解》讲了如何用注意力机制处理文本:把句子切分成 token,让任意两个位置直接交互。本文回答一个相关的问题:同一套机制,能不能用来处理图像? 答案是能,这个架构就是 ViT(Vision Transformer,视觉 Transformer),由 Google 在 2020 年提出。它的核心思路是:把图像切成固定大小的小块(Patch),每块展平成一个向量,再把这些向量按顺序组成序列输入 Transformer。像素是连续矩阵,文本是离散符号,两者结构原本不同;这一步变形把图像转换成了 Transformer 能够处理的序列形式。 ViT 是本站 VLM 专栏的基础:《CLIP 详解》的视觉编码器是 ViT,《LLaVA 详解》复用的也是它。理解了 ViT,就能理解这两篇文章中的图像特征是如何产生的。 阅读前提:已经读过本站《Transformer 详解》(理解自注意力、多头、位置编码),并会写基础的 PyTorch 代码。本文会与 CNN 做对比,但不要求你已经精通 CNN。 为什么视觉需要 Transformer CNN 的归纳偏置 在 ViT 之前,视觉任务的标准做法是 CNN(卷积神经网络)。CNN 有两个内在的设计假设: 局部性(Locality):CNN认为图上相邻的像素一定是有关系的,因此它让一个固定大小的 3*3 卷积核在图片上滑动,每个输出位置只"看"周围的一小片区域。要利用远处的信息,只能逐层堆叠卷积,逐步扩大感受野。 平移等变性(Translation Equivariance):同一个卷积核在整张图上共享权重,物体平移后,对应的特征也随之平移。也就是说,一个物体无论出现在一张图片中的哪一个地方,其特征都是一样的。 这两个假设统称归纳偏置(Inductive Bias),即用先验知识规定模型理解图像的方式。优点是数据效率高,用 ImageNet 规模的数据就能训练出不错的模型;缺点是这些先验限制了模型的表达能力:局部性意味着远距离信息只能通过加深网络来间接获取,而且这些先验并非在所有任务中都成立。 ViT 的选择:去掉归纳偏置 ViT 采取相反的思路:几乎完全去掉 CNN 的归纳偏置,只保留 Transformer 结构。图像被切成 patch 后,任意两个 patch 之间可以直接交互(自注意力),远距离依赖不再是问题;平移等变性也不再由结构保证,需要模型从数据中自行学习。 这种设计的代价是数据需求:归纳偏置越少,需要的数据就越多。ViT 论文的对比实验直接说明了这一点(详见"训练"一节):在 ImageNet(128 万张图)上从头训练时,ViT 的表现与同规模的 ResNet 相当;在更大的数据集(ImageNet-21k、JFT-300M)上预训练后,ViT 超过最强的 CNN 基线,而且数据规模越大,优势越明显。 ...

📅 August 13, 2026 · 🔄 更新于 2026-08-16 · ⏱️ 49 min · 📝 约 7455 字 · 👁️ — 次阅读

Transformer 详解:从注意力机制到代码实战

前言 Transformer 是目前深度学习中最重要的一类架构。从 GPT、BERT 这类大语言模型,到 ViT 这类视觉模型,近几年绝大多数突破背后都有它的身影。可以说,理解 Transformer 是读懂当代 AI 的必修课。 本文假设你已经读过本站的《正向传播与反向传播:神经网络到底如何学习》,理解"网络是一串函数复合、训练时误差沿链式法则反向流动"这两条主线。我们会沿用同样的思路拆解 Transformer:信息如何向前流动,梯度如何向后流动。 本文会从"为什么需要 Attention"讲起,逐步推导公式,最后用一个从零手写的迷你 Transformer(PyTorch)把代码落地。涉及 softmax 的数学细节——梯度、数值稳定性、为什么注意力要除以 $\sqrt{d_k}$——会链接到本站 ai-math 专栏的配套文章,避免在这里打断主线。 为什么要 Transformer RNN 的局限 在 Transformer 之前,处理序列(文本、语音等)的主流架构是 RNN(循环神经网络)。RNN 像一条传送带,按顺序逐个处理 token,把之前看到的信息压缩在一个隐藏状态里。这个设计有三个天然的瓶颈: 无法并行:第 $t$ 步的计算依赖第 $t-1$ 步的隐藏状态,只能从左到右依次计算,GPU 的大规模并行能力完全用不上。 长距离依赖困难:信息每传一步都要经过一次变换,距离越远衰减越明显。处理长文本时,开头的词往往"传不到"结尾。 信息瓶颈:所有历史都被压缩进一个固定大小的隐藏向量,容量有限。 Transformer 的思路 Transformer 的做法截然不同:一次看完整条序列。它不再按顺序传递状态,而是让序列中的任意两个位置直接交互。 先解释一个词:token(词元,我实在不喜欢它的官方中译) 是文本被切分后的基本单位,可以是一个词、一个字符或一个子词片段。比如"我吃了一个红苹果"可以切成 6 个 token:我 / 吃 / 了 / 一个 / 红 / 苹果。 flowchart LR subgraph RNN["RNN:信息一站一站传"] direction LR r1["第 1 个"] --> r2["第 2 个"] r2 --> r3["第 3 个"] r3 --> r4["第 4 个"] end subgraph ATTN["Transformer:任意两个直接对话"] direction LR a1["第 1 个"] --- a2["第 2 个"] a1 --- a3["第 3 个"] a1 --- a4["第 4 个"] a2 --- a3 a2 --- a4 a3 --- a4 end 上图为两种架构的token之间的交互示意: 从图论的角度来说,RNN 是一个 有向路径图,包含 $n$ 个节点(代表隐状态 $h_t$)和 $n-1$ 条有向边($h_{t-1} \to h_t$);而 Transformer 是一个 完全图,包含 $n$ 个节点和 $\frac{n(n-1)}{2}$ 条无向边(每两个 token 之间都有一条边)。 ...

📅 August 3, 2026 · 🔄 更新于 2026-08-06 · ⏱️ 48 min · 📝 约 7268 字 · 👁️ — 次阅读
Comments