第 5 讲 · 计算机视觉:CNN、仅编码器 Transformer 与 ViT · CNNs, Encoder-only Transformers & Vision Transformers

Generative AI · Lecture 05。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:CMU 10-423 / 10-623 / 10-723 Generative AI(Spring 2026;Aran Nayebi、Matt Gormley),Lecture 5 · Wed 28-Jan · Computer Vision: CNNs / Encoder-only Transformers / Vision Transformers。 阅读材料:Goodfellow, Bengio & Courville, Deep Learning 第 9.1–9.3 节(卷积);Devlin et al. (2019), BERT;Dosovitskiy et al. (2021), An Image is Worth 16x16 Words(ViT)。 依据说明:本讲以原课第 5 讲公开的 slides(lecture5-cnn-vit.pdf)为主线:回顾现代 Transformer;卷积层(把卷积核当参数学)、二维卷积、填充、步长与下采样、CNN 的训练、各层的前向与反向(ReLU、softmax、全连接、多通道卷积、最大池化)、CNN 架构(LeNet-5、AlexNet、深度的革命)、核大小的选择、神经科学起源;计算机视觉的任务谱系;仅编码器的 Transformer 与 BERT 的掩码语言模型、[CLS] 微调;ViT。slides 引用的论文数字尽量核对过原文。“形状世界”数据集和全部实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture05/(5 个脚本 + 3 个模块;需要 PyTorch CPU 版,02 还需要 torchvision(只构造模型、不下载权重);01、02 几秒,03–05 各约 1 分钟) 预计阅读时间:4 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲,你应该能够:

  1. 手算二维卷积;说明填充、步长、多通道怎样决定输出的形状和参数量;推导卷积层和最大池化的反向传播。
  2. 解释 CNN 的归纳偏置(局部连接、权重共享、平移等变、池化带来的近似不变性),以及它们在数据少时的价值。
  3. 计算感受野,解释为什么 VGG 全用 3×3 卷积;概括 LeNet → AlexNet → VGG → ResNet 的演进以及参数和计算分布在哪里。
  4. 说出计算机视觉的主要任务,并区分分类与结构化预测。
  5. 解释仅编码器的 Transformer 为什么不是自回归语言模型、怎样用掩码语言模型训练它、怎样用 [CLS] 做分类。
  6. 描述 ViT 怎样把图像变成 token 序列;用实验说明”ViT 需要更多数据”、数据增强的作用,以及一维位置嵌入能学到多少二维结构。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 1 讲:反向传播、模块化的自动微分生成式图像模型:GAN、扩散、VAE(第 6–9 讲)
第 2 讲:注意力、Transformer 块、因果掩码、残差连接视觉-语言模型、CLIP(第 13 讲)
第 4 讲:预训练与微调扩散 Transformer(第 14 讲)

0.3 本讲地图 Map

§1  回顾:RoPE、GQA、滑动窗口
§2  卷积神经网络:卷积层、填充、步长、多通道、训练、各层的反向传播、平移等变    ← 代码 01
§3  CNN 架构:LeNet、AlexNet、深度的革命;核大小;感受野与神经科学起源         ← 代码 02
§4  计算机视觉的任务
§5  仅编码器的 Transformer:BERT 与掩码语言模型                              ← 代码 05
§6  Vision Transformer;形状世界上的 MLP / CNN / ViT                         ← 代码 03、04
§7–11  小结、误区、练习、延伸阅读、下一讲

0.4 本讲的玩具图像:形状世界

图像模型需要图像数据,而这门课的代码约定不下载数据集。shapes_world.py 自己”画”图:每张图是 28×28 的灰度图(和 MNIST 一样大),上面有一个圆、正方形、三角形或十字,位置、大小、旋转角度随机,再加一点噪声。像素亮度由”到形状边界的有符号距离”经过 sigmoid 得到,所以边缘是平滑的。和农场语言一样,每张图的生成参数都记录下来——这让受控实验成为可能(比如只在左半边放形状来训练,§6.4)。之后的图像讲次(GAN、扩散、VAE)也会用它。


1. 回顾:现代 Transformer · Recap

slides 开头总结了第 4 讲的三个技术:

  • RoPE:一种相对位置编码;对注意力层的根本性改动;把每个二维小块旋转一定的角度。
  • GQA:Transformer 的计算和内存都很密集;GQA 复用一部分键/值头,但保持查询头的个数;减少计算和内存。
  • 滑动窗口注意力:改变注意力掩码,让每个 token 只看左边固定个数的 token;把注意力的计算从平方降到线性。

这一讲换一个模态:图像。


2. 卷积神经网络 · Convolutional neural networks

2.1 另一种决策函数

slides 回到机器学习的配方(第 3 讲 §1.2):给定数据,选择决策函数 y^=hθ(x)\hat y = h_\theta(x) 和损失函数,用 SGD 训练。卷积神经网络(CNN)提供了另一种形式的决策函数。

2.2 卷积层:把卷积核当成参数

slides 的关键想法:把卷积矩阵当作参数,然后学习它们。

二维卷积的基本做法:

  • 取一个小的权重矩阵 FF(叫卷积核,kernel,或卷积矩阵);
  • 把它在图像上滑动,在每个位置计算 FF 和对应区域的”内积”(相似度),用结果替换这个区域中心的像素。

关键点:不同的卷积提取图像中不同类型的低层”特征”;要得到不同的特征,只需要改变 FF 的权重。

slides 的例子(1 个输入通道、1 个输出通道、2×2 的核):

y11=α11x11+α12x12+α21x21+α22x22+α0,y12=α11x12+α12x13+α21x22+α22x23+α0,…y_{11} = \alpha_{11}x_{11} + \alpha_{12}x_{12} + \alpha_{21}x_{21} + \alpha_{22}x_{22} + \alpha_0,\qquad y_{12} = \alpha_{11}x_{12} + \alpha_{12}x_{13} + \alpha_{21}x_{22} + \alpha_{22}x_{23} + \alpha_0,\quad\dots

3×3 的输入、2×2 的核、不补零、步长 1,输出是 2×2。01_convolution.py 第 1 部分用循环实现和 F.conv2d 对照,结果完全相同。(严格地说,这在数学上叫互相关;数学上的”卷积”还要把核翻转 180°。因为核是学出来的,翻不翻无所谓,深度学习库都直接算互相关并称之为卷积。)

slides 还给了一个 7×7 的”字母图”和它的卷积结果(5×5)。01 第 2 部分在 512 个 0/1 的 3×3 核里逐个试,发现只有一个能得到 slides 的结果:

F=(000011010)F = \begin{pmatrix} 0 & 0 & 0 \\ 0 & 1 & 1 \\ 0 & 1 & 0 \end{pmatrix}

它数的是”这个像素、右边、下边”三个位置里有几个 1,所以在笔画的左上角拐角处输出最大(3)——一个”拐角检测器”。

2.3 填充

slides:“如果你想让卷积后的图像保持原来的大小,可以在输入的四周补零。“输出大小的公式(01 第 3 部分逐个核对):

Hout=⌊H+2p−Ks⌋+1H_\text{out} = \left\lfloor \frac{H + 2p - K}{s} \right\rfloor + 1

不补零时每做一次卷积,图就缩小 K−1K - 1 圈;补 ⌊K/2⌋\lfloor K/2 \rfloor 圈零(KK 为奇数)可以保持大小。slides 的”恒等卷积”(只有中心是 1 的 3×3 核)加一圈零填充,输出和输入完全相同。

2.4 步长与下采样

slides:步长决定卷积每次移动几个像素;取平均的下采样是卷积的一个特例,权重固定为均匀分布。01 第 3 部分把 6×6 的图用”2×2、权重 1/4、步长 2”的卷积下采样,得到

(0.750.750.250.750.2500.2500)\begin{pmatrix} 0.75 & 0.75 & 0.25 \\ 0.75 & 0.25 & 0 \\ 0.25 & 0 & 0 \end{pmatrix}

和 F.avg_pool2d 完全相同。CNN 也可以把下采样的权重学出来。AlexNet 第一层用 11×11 的核、步长 4,把 224 一下子缩到 55。

2.5 多通道:彩色图像与 3D 卷积

彩色图像每个像素有 3 个数(R、G、B),卷积核也必须是三维的:slides 的例子是 3×64×64 的输入、3×5×5 的核、(补零后)输出 1×64×64。要提取 CoutC_\text{out} 种特征,就用 CoutC_\text{out} 个核,第 jj 个输出通道来自第 jj 个核。slides 写出的一般公式(步长 ss):

yh′,w′(c′)=β(c′)+∑c=1C∑m=1K∑n=1Kxh′s+m, w′s+n(c)⋅αm,n(c′,c)y^{(c')}_{h',w'} = \beta^{(c')} + \sum_{c=1}^{C} \sum_{m=1}^{K} \sum_{n=1}^{K} x^{(c)}_{h's+m,\ w's+n} \cdot \alpha^{(c',c)}_{m,n}

01 第 4 部分的形状和参数账:

输入卷积核输出参数量前向 FLOPs
3×64×641 个 3×5×51×64×64760.61M
3×64×6416 个 3×5×516×64×641,2169.83M
64×56×56128 个 64×3×3128×56×5673,856462.42M

参数量 =Cout(CinK2+1)= C_\text{out}(C_\text{in}K^2 + 1),只和核的大小、通道数有关,和图像大小无关——同一个核在所有位置上共享(权重共享)。计算量却和图像大小成正比:最后一行只有 7.4 万个参数,一次前向要 4.6 亿次浮点运算。

2.6 训练 CNN

slides:“现在 CNN 是一个决策函数了,怎样计算梯度?当然是反向传播!“一个简单的 CNN:

z(1)=conv(x,α), z(2)=maxpool(z(1)), z(3)=conv(z(2),β), z(4)=relu(z(3)), z(5)=linear(z(4),W), y=softmax(z(5))z^{(1)} = \mathrm{conv}(x, \alpha),\ z^{(2)} = \mathrm{maxpool}(z^{(1)}),\ z^{(3)} = \mathrm{conv}(z^{(2)}, \beta),\ z^{(4)} = \mathrm{relu}(z^{(3)}),\ z^{(5)} = \mathrm{linear}(z^{(4)}, W),\ y = \mathrm{softmax}(z^{(5)})

用第 1 讲的 SGD:采样一个样本,前向算 J(θ)=ℓ(y,y∗)J(\theta) = \ell(y, y^*),反向算 ∇θJ\nabla_\theta J,更新 θ←θ−η∇θJ\theta \leftarrow \theta - \eta \nabla_\theta J。只要每一层都有 forward() 和 backward(),自动微分就能完成剩下的事(第 1 讲 §5.6)。

2.7 各层的前向与反向

slides 逐层写出了前向和反向:

  • ReLU:前向 y=max⁡(0,x)y = \max(0, x) 逐元素;反向 ∂J/∂xj=∂J/∂yj⋅1[xj>0]\partial J/\partial x_j = \partial J/\partial y_j \cdot \mathbb{1}[x_j > 0](在 0 处取一个次导数)。
  • Softmax:∂yi/∂xj=yi(1−yi)\partial y_i/\partial x_j = y_i(1 - y_i)(i=ji = j),−yiyj-y_iy_j(i≠ji \ne j)。
  • 全连接层(3D 输入):先把 C×H×WC \times H \times W 的张量拉平成向量,再做普通的线性层。
  • 卷积层:slides 给出 ∂J∂αm,n(c′,c)=∑h′,w′∂J∂yh′,w′(c′)⋅xh′s+m, w′s+n(c)\dfrac{\partial J}{\partial \alpha^{(c',c)}_{m,n}} = \sum_{h',w'} \dfrac{\partial J}{\partial y^{(c')}_{h',w'}} \cdot x^{(c)}_{h's+m,\ w's+n},∂J∂β(c′)=∑h′,w′∂J∂yh′,w′(c′)\dfrac{\partial J}{\partial \beta^{(c')}} = \sum_{h',w'} \dfrac{\partial J}{\partial y^{(c')}_{h',w'}}。
  • 最大池化:前向 yij=max⁡y_{ij} = \max 窗口;max⁡\max 不可导但次可导,存在一组导数,SGD 任选一个就行:梯度只流向每个窗口里最大的那个输入。

01 第 5 部分把 slides 的卷积反向公式写成循环,和自动微分对比:∂J/∂α\partial J/\partial \alpha 差 8.9×10−168.9 \times 10^{-16},∂J/∂β\partial J/\partial \beta 差 0。最大池化(2×2、步长 2)的梯度只出现在每个窗口的最大值位置上。注意 ∂J/∂α\partial J/\partial\alpha 本身就是”上游梯度”和”输入窗口”的相关:反向传播也是一种卷积。

2.8 平移等变与归纳偏置

01 第 6 部分:把一小块图案整体平移 (5, 6) 个像素,比较”先平移再计算”和”先计算再平移”:

层两种顺序的 max|差|参数量
卷积(4 个 3×3 的核)036
全连接(256 → 256)0.2965,536

卷积是平移等变的:图案移到哪里,响应就跟着移到哪里,因为同一个核在每个位置做同样的计算。再加上池化(尤其是全局平均池化),就得到近似的平移不变。这就是 CNN 的归纳偏置:它预先假设”局部的像素一起看”、“同一个图案出现在哪里都是同一个东西”。§6 的实验会检验这个假设在数据少时有多值钱。

(01 第 7 部分还演示了 GPU 上怎样实际计算卷积:把每个输入窗口拉直成一列——im2col——卷积就变成了一次矩阵乘法 (Cout×CinK2)⋅(CinK2×位置数)(C_\text{out} \times C_\text{in}K^2) \cdot (C_\text{in}K^2 \times \text{位置数}),结果和 F.conv2d 完全相同。所以 前置讲 P3 的 roofline 分析同样适用于 CNN。)


3. CNN 架构 · CNN architectures

3.1 典型的层与 LeNet-5

slides:CNN 的典型层有卷积层、最大池化层、全连接层、ReLU(或其他非线性)、softmax,它们可以排成任意深的结构。LeNet-5(LeCun et al., 1998)是最早的经典:两组”卷积 + 池化”,再接三个全连接层,输入 32×32 的灰度手写数字(练习 2 追踪它的形状)。

3.2 AlexNet

slides 引用的 AlexNet(Krizhevsky, Sutskever & Hinton, 2012):在 ILSVRC-2012 比赛上 top-5 错误率 15.3%;5 个卷积层(有的带最大池化)+ 3 个全连接层 + 1000 类 softmax;分在两块 GPU 上训练(两块 GPU 只在某些层之间通信)。论文的两个细节(slides 截取了原文):

  • 网络有 6000 万个参数,1000 类、每个样本只提供约 10 比特的约束,不足以学这么多参数而不过拟合;
  • 数据增强:随机截取 224×224 的块并水平翻转,把训练集”扩大了 2048 倍”(练习 10);另外对 RGB 通道做基于 PCA 的颜色扰动。

3.3 深度的革命

slides 引用 Kaiming He 的图:AlexNet 8 层(ILSVRC 2012)→ VGG 19 层(2014)→ ResNet 152 层(2015)。02_cnn_architectures.py 第 3 部分在 PyTorch 的 “meta” 设备上构造了这些模型(只推算形状、不做计算),统计参数和乘加次数(224×224 输入;LeNet-5 是 32×32):

模型卷积 + 全连接层数参数量全连接层的参数占比乘加次数卷积层的计算占比
LeNet-5(1998)50.06M96%0.00G86%
AlexNet(2012)861.10M96%0.71G92%
VGG-16(2014)16138.36M89%15.47G99%
VGG-19(2014)19143.67M86%19.63G99%
ResNet-18(2015)1811.69M4%1.81G100%
ResNet-50(2015)5025.56M8%4.09G100%
ResNet-152(2015)15260.19M3%11.51G100%
  • 参数在全连接层,计算在卷积层:AlexNet 96% 的参数在最后三个全连接层,92% 的计算却在卷积层——卷积层参数少(权重共享)、计算多(每个位置都要算)。
  • VGG 把深度加到 16–19 层,计算量涨了 20 多倍。
  • ResNet-152 有 152 层,参数却不到 VGG-16 的一半:它用 1×1 卷积先压缩通道(瓶颈结构),最后用全局平均池化代替巨大的全连接层。能训练这么深的网络,靠的是第 2 讲 §4.4 的残差连接。

3.4 卷积核选多大?

slides 的问题:“卷积层的核大小怎么选?“小核只能看到图像很小的一部分,但算得快;大核能看到更多,但以速度为代价。02 第 1 部分(64 通道、56×56 的特征图):

结构感受野参数量乘加次数非线性层数
1 个 5×55×5102,400321M1
2 个 3×35×573,728231M2
1 个 7×77×7200,704629M1
3 个 3×37×7110,592347M3

叠三个 3×3 和一个 7×7 的感受野相同,参数少 45%,中间还多了两次非线性。这是 VGG(Simonyan & Zisserman, 2015)全用 3×3 卷积的理由。

3.5 感受野与神经科学起源

slides 引用 Hubel & Wiesel 在 1960 年代对猫视觉皮层的研究:给麻醉的猫看屏幕上移动的光条,发现有些神经元只在光条竖直(而不是水平)时放电。这种选择性对应的视野区域叫感受野;CNN 的感受野就是比如 3×3 的像素区域。CNN 的操作乍看很随意,其实受到了这些研究的启发。

层层叠加后,感受野不断扩大(公式:RFℓ=RFℓ−1+(kℓ−1)Jℓ−1\mathrm{RF}_\ell = \mathrm{RF}_{\ell-1} + (k_\ell - 1) J_{\ell-1},JJ 是相邻输出在输入上的间隔,每经过一个步长为 ss 的层乘以 ss)。02 第 2 部分算了 VGG-16:13 个卷积层之后,最后一个位置的感受野是 196×196,已经接近整张 224×224 的图。浅层”看”边和角,深层”看”复杂的图案——和第 4 讲 §6.3 滑动窗口注意力的”多层叠加后能看多远”是同一个计算。

slides 的 CNN 小结:CNN 被用于计算机视觉的方方面面,赢过很多模式识别比赛;能在不同的抽象层次上学到可解释的特征;通常由卷积层、池化层、非线性和全连接层组成。


4. 计算机视觉的任务 · Common tasks in computer vision

slides 列出了八种常见任务:

任务输入 → 输出
图像分类一张图 → 一个标签(多分类问题)
分类 + 定位一张图 → 一个标签和一个边界框 (x,y,h,w)(x, y, h, w)
人体姿态估计一张人的图 → 若干关键点(左手、右手、左肘……)的位置(多元回归)
语义分割一张图 → 每个像素一个标签(像素标签之间强相关,不只是逐像素分类)
目标检测一张图 → 每个物体一个边界框和标签 (x,y,w,h,l)(x, y, w, h, l)(例:R-CNN)
实例分割像语义分割,但要区分同一类的不同个体(person-1、person-2)
图像描述一张图 → 一句描述它的话(早期方法:深度 CNN / Transformer 编码图像 + 类 RNN 的语言模型生成句子)
图像生成(第 6–9、12、14 讲)

slides 特别指出:这些任务大多是结构化预测问题,而不只是分类——输出是一组相互关联的变量(边界框、像素标签、词序列)。医学图像分析里也有对应的每一种任务。


5. 仅编码器的 Transformer · Encoder-only Transformers (BERT)

5.1 从解码器到编码器

slides 先回顾自回归语言模型的定义:

p(x1:T)=∏t=1Tp(xt∣x1,…,xt−1)p(x_{1:T}) = \prod_{t=1}^{T} p(x_t \mid x_1, \dots, x_{t-1})

仅解码器的 Transformer(也叫 Transformer 语言模型,GPT)每一层由因果注意力、前馈网络、层归一化、残差连接组成;每个隐藏向量只回头看前一层里当前和之前时间步的隐藏向量。

然后 slides 在第 2 讲那张”很多箭头”的矩阵版注意力图上问:

  • 我们总是需要所有这些箭头吗?——不!(语言模型需要因果掩码。)
  • 我们有时候需要所有这些箭头吗?——是的!

去掉因果掩码,每个 token 都能看左右两边所有的 token——这就不再是自回归语言模型了(第 tt 个位置的输出已经看到了第 tt 个词本身和它后面的词,不能拿来”预测下一个词”)。这就是仅编码器的 Transformer:每一层由非因果注意力、前馈网络、层归一化、残差连接组成,每个隐藏向量看前一层所有时间步的隐藏向量。第 2 讲 lm_models.Block 的 causal=False 就是它。

“好,那怎样训练这种东西?”

5.2 BERT:掩码语言模型

BERT(Devlin et al., 2019)让这种结构和它的预训练方式流行起来。slides 的描述:

  • 不再”根据前面的词预测下一个词”;
  • 而是遮住一个(或几个)词,根据剩下的词预测被遮住的词——掩码语言模型(masked language model, MLM)。

slides 的例子([CLS] 是放在开头的特殊记号):

[CLS] [MASK] cat sat: J=log⁡p(w1∣w2,w3);[CLS] [MASK] cat [MASK]: J=log⁡p(w1,w3∣w2)\text{[CLS] [MASK] cat sat}:\ J = \log p(w_1 \mid w_2, w_3);\qquad \text{[CLS] [MASK] cat [MASK]}:\ J = \log p(w_1, w_3 \mid w_2)

BERT 实际的遮盖规则:在所有词里随机选 15% 作为要预测的位置;被选中的位置 80% 换成 [MASK]、10% 换成一个随机的词、10% 保持不变。为什么不全换成 [MASK]?因为微调和使用时输入里没有 [MASK],如果被预测的位置总是 [MASK],模型可能只学会”在 [MASK] 处干活”(05_bert_mlm.py 的 mask_tokens 照此实现)。

5.3 [CLS] 与有监督微调

slides:“怎样为一个分类任务微调这个模型?“——用特殊记号 [CLS] 位置的嵌入预测类别标签,微调整个模型让它擅长这种分类。slides 的结语:“虽然它不是一个生成式语言模型,但可以非常有效地用作判别器。”

[CLS] 本身没有内容,但在每一层都能看到整句话;微调时它被逼着把”整句的摘要”放进自己的表示里。

5.4 实验:农场语言上的 BERT

05_bert_mlm.py 在第 1 讲的农场语言(2 万句)上训练了一个小 BERT(2 层、4 头、d=64d = 64,掩码语言模型,6 个 epoch),和第 2 讲的 GPT 比较。

填空:遮住主语,谁能猜出来?输入 “[CLS] the [MASK] near the cats eats corn in the field .”,在 16 种主语形式(8 种动物 × 单复数)里猜。因为我们知道真实分布,还能用贝叶斯公式算出理论上最好能猜对多少:把 16 种主语一个个代入,用真实概率归一化成后验。

干扰名词数 kkGPT(只看左边)BERT(看两边)贝叶斯最优BERT 猜对单复数
00.0700.6600.7951.000
10.0500.6600.7701.000
30.0550.7050.7951.000
  • GPT 在主语的位置只看得到 “<s> the”,只能按先验猜,准确率约 1/16。
  • BERT 能看到右边的动词(决定单复数)、宾语和时间短语(各种动物的习性):单复数全对,具体动物猜对约 2/3。
  • 贝叶斯最优也不是 1:吃同样东西、出现在同样时间的动物(比如都在夜里吃老鼠的猫和猫头鹰)本来就分不清。BERT 离这个上限还有一段距离,但远远超过只看左边的模型。

**语法判断:主谓一致对不对?**一半句子的动词换成相反的单复数,判断”一致 / 不一致”(测试集 500 句):

标注样本数做法测试准确率
0(零样本)GPT:比较原句和”动词换了单复数”的句子的概率1.000
0(零样本)BERT:遮住动词,比较两种形式的概率1.000
64BERT(预训练)+ [CLS] 微调0.616
64GPT(预训练)+ 最后一个 token 微调0.491
64编码器(从零训练)+ [CLS]0.500
256BERT(预训练)+ [CLS] 微调0.987
256GPT(预训练)+ 最后一个 token 微调0.683
256编码器(从零训练)+ [CLS]0.559
  • 零样本时两个预训练模型都全对:判断”哪个版本更像真话”正是语言模型训练时学会的事,只要换成它熟悉的问法(比较概率)。
  • 换成”接一个分类头”的问法,就需要标注数据来学怎样读出答案。256 个样本时 BERT 达到 0.987,GPT 只有 0.683。判断一致性要同时比较主语和动词:BERT 的 [CLS] 在每一层都能同时看到两者;GPT 的最后一个 token 是句号,预训练时它在这里只需要预测 </s>,并不需要记住前面有没有语法错误。BERT 论文里,同等大小的 BERT-base 在 GLUE 句子理解基准上明显超过 GPT-1,作者给出的主要原因正是双向的上下文。
  • 从零训练的编码器在这么少的数据上学不会(第 4 讲 §2.8 的结论在编码器上同样成立)。

BERT 式模型不能从左到右逐个生成文字,但至今仍是很多分类、检索、打分任务(以及第 13 讲 CLIP 的文本编码器)的主力。


6. Vision Transformer · ViT

6.1 模型

slides 对 ViT(Dosovitskiy et al., 2021)的描述:

  • 模型几乎和 BERT 一样;
  • 输入不是词,而是 P×PP \times P 的像素块,P∈{14,16,32}P \in \{14, 16, 32\},块之间不重叠;
  • 每个块被线性地嵌入成一个 1024 维的向量;
  • 一维的位置嵌入;
  • 预训练:在大型有标注数据集(ImageNet-21K、JFT-300M)上做图像分类——和 CNN 一样的设置;
  • 微调:在小数据集(如 CIFAR-100)上学一个新的分类头。

和 BERT 一样,ViT 在块序列前面加一个可学习的 [CLS] 向量,用它最后一层的输出接 MLP 头做分类。一张 224×224 的图、P=16P = 16,就是 14×14=19614 \times 14 = 196 个块(加 [CLS] 共 197 个 token),每个块拉直后是 16×16×3=76816 \times 16 \times 3 = 768 维(练习 6)。

vision_models.ViT 是一个迷你版:28×28 的图切成 4×4 的块(49 个),嵌入成 64 维,2 层、4 头、可学习的一维位置嵌入,约 10.5 万个参数。它直接复用了第 2 讲的 Transformer 块(causal=False)。

6.2 实验一:数据量与归纳偏置

03_cnn_mlp_vit.py 在形状世界的四分类上(随机猜 0.25),用 256、1024、8192 张训练图比较三种模型,每个训练 1000 步、每步 64 张图:

训练图数MLP(11.8 万参数)小 CNN(1.4 万参数)小 ViT(10.5 万参数)
2560.3880.9580.601
10240.6230.9890.874
81920.9110.9820.885
  • 只有 256 张图时,参数最少的 CNN 就有 0.958,ViT 0.601、MLP 0.388。三者的训练损失都很低,但 MLP 和 ViT 是在背训练集。CNN 的结构里已经写进了”图像的知识”:局部的像素一起看(卷积核)、同一个图案在哪里都一样(权重共享)、位置不重要(池化)。
  • 数据多了,MLP 和 ViT 都追上来不少(MLP 0.388 → 0.911,ViT 0.601 → 0.885),但在 1000 步的训练预算下仍不如 CNN。8192 张图时 ViT 的训练损失还有 0.290:它还没训练够——数据多了,也需要相应更多的计算。
  • ViT 论文的结论正是这样:在 ImageNet 这种”中等”规模的数据上,ViT 不如同等大小的 ResNet;在 1400 万(ImageNet-21k)到 3 亿张图(JFT-300M)上、用大量计算预训练之后才反超(slides:ViT 的成功在很大程度上归功于更大的预训练数据集)。我们的玩具规模只能看到”差距随数据缩小”的前半段。

归纳偏置是一把双刃剑:数据少时它是帮助,数据足够多时它可能成为限制。第 13–14 讲的视觉-语言模型、扩散 Transformer 都选择了 ViT 式的”少假设、多数据”。

6.3 实验二:平移泛化与数据增强

04_translation_and_vit.py:只在左半边有形状的 2048 张图上训练,分别在左半边、右半边测试:

模型数据增强测试:左半边测试:右半边
MLP无0.8660.307
MLP随机平移 ±8 像素0.8020.774
小 CNN无0.9900.978
小 CNN随机平移 ±8 像素0.9640.924
小 ViT无0.9630.866
小 ViT随机平移 ±8 像素0.9420.935
  • MLP 学到的是”哪些像素亮”,形状换了位置,亮的就是另一批像素,右半边几乎完全失败。
  • CNN 不需要任何帮助:平移不变是写在结构里的。
  • ViT 介于两者之间:块嵌入对所有块共享(这部分和卷积一样平移等变),但位置嵌入是每个位置单独学的,右半边的位置在训练中从没和形状一起出现过。
  • 数据增强把”形状可以在任何位置”直接写进训练数据:ViT 的右半边准确率变成 0.935、MLP 变成 0.774。没有归纳偏置的模型,可以用数据(真实的或增强出来的)来补——这正是 AlexNet 的做法。CNN 加了增强反而略差:它本来就不需要,而 torch.roll 的平移会把靠边的形状从另一侧”绕”回来、切成两半。增强不是免费的,要和任务的不变性匹配。

6.4 一维的位置嵌入,学到了二维的结构吗?

slides 的问题:“ViT 怎样从一维的位置嵌入里学到二维的位置信息?“ViT 的位置嵌入只是 49 个编号各自对应一个向量,模型并不知道编号 3 和编号 10 在图上是上下相邻的。

04 第 3 部分计算了训练好的 ViT(8192 张图)各块位置嵌入之间的余弦相似度:

  • 能看到一些二维结构:中间块(第 3 行第 3 列)和它上下左右 4 个邻居的平均相似度 +0.463,和其余块只有 +0.014——其中上下两个邻居在一维编号里相隔 7。
  • 但整体上相关很弱:相似度和二维距离的相关系数 +0.119,只比和一维编号之差的 +0.057 略强。
  • 另一个明显的模式是四个角彼此很像(+0.629):形状的中心离边界至少 r+1r + 1 个像素,角上几乎永远是背景,模型把它们编码成同一类”不重要的位置”。位置嵌入学到的是”这个位置在这个任务里意味着什么”,不一定是几何坐标。

ViT 论文(图 7)在大数据上训练后看到了清楚的行、列结构——答案是”从数据里学出来的”:相邻的块看到的内容高度相关,用相似的位置嵌入对完成任务有利;所以他们发现手工设计二维位置编码没有带来明显的好处。我们的小模型、短训练、简单任务只学出了一部分。

6.5 注意力头看多远?

04 第 4 部分计算了每个头”按注意力加权的平均距离”:8 个头都在 12.3–14.2 像素,接近均匀注意力的 14.4——这个小 ViT 几乎没有学出”只看附近”的局部头(一个可能的原因是区分四种形状只需要整体轮廓;我们没有进一步验证)。ViT 论文在大数据上发现低层同时存在局部和全局的头。和 CNN 对比:CNN 的第一层只能看 3×3 的邻域,要叠很多层才能看到整张图;ViT 从第一层起就可以看整张图,看多远由数据和任务决定。

6.6 时间线

slides 最后画了一条语言建模的时间线:n-gram(2000 年代之前)→ RNN 语言模型(2010 年前后)→ Transformer(2017)→ GPT、BERT(2018)→ GPT-2(2019)→ GPT-3(2020)……视觉这边,CNN(LeNet、AlexNet、VGG、ResNet)之后,2021 年的 ViT 把同一个 Transformer 带进了图像,为之后的多模态模型(第 13–15 讲)铺平了道路:图像块和文字 token 可以放进同一个序列。


7. 小结 · Summary

  1. 卷积层把一个小的核在图像上滑动、做内积;核是要学的参数。填充控制边界、步长控制下采样,输出大小 ⌊(H+2p−K)/s⌋+1\lfloor (H + 2p - K)/s \rfloor + 1;多通道时核是三维的,参数量 Cout(CinK2+1)C_\text{out}(C_\text{in}K^2 + 1) 和图像大小无关。反向传播也是一种卷积;最大池化的梯度只流向最大值。
  2. CNN 的归纳偏置:局部连接、权重共享、平移等变(加池化得到近似不变)。在形状世界上,256 张图时 CNN 0.958、ViT 0.601、MLP 0.388;只在左半边训练时,CNN 在右半边仍有 0.978,MLP 只有 0.307。
  3. 架构:LeNet → AlexNet(6000 万参数、数据增强、两块 GPU)→ VGG(全用 3×3:同样的感受野、更少的参数、更多的非线性)→ ResNet(残差连接、瓶颈、全局池化,152 层只有 6000 万参数)。参数多在全连接层,计算多在卷积层;感受野随深度增长。
  4. 计算机视觉的任务大多是结构化预测:分类、定位、姿态、语义 / 实例分割、检测、描述、生成。
  5. 仅编码器的 Transformer 去掉因果掩码,每个位置看两边,不再是自回归语言模型;用掩码语言模型(遮住 15%,80/10/10)预训练,用 [CLS] 微调做分类。它是很好的判别器:在需要同时比较两个位置的句子判断上,比同等大小的 GPT 学得快得多。
  6. ViT 几乎就是 BERT:把图像切成 P×PP \times P 的块当作 token,加 [CLS] 和一维位置嵌入。归纳偏置少,所以需要更多数据(或数据增强);位置嵌入的二维结构是从数据里学出来的。

8. 常见误区 · Common pitfalls

  1. “深度学习里的卷积就是数学上的卷积。” 实际算的是互相关(不翻转核);因为核是学出来的,两者等价。
  2. “卷积层的参数量和图像大小有关。” 无关(权重共享);计算量才和图像大小成正比。
  3. “CNN 的参数主要在卷积层。” 经典 CNN(AlexNet、VGG)的参数主要在全连接层,计算主要在卷积层。
  4. “大卷积核看得更远,所以更好。” 叠几个 3×3 能得到同样的感受野,参数更少、非线性更多。
  5. “最大池化不可导,所以不能反向传播。” 它是次可导的,梯度流向最大值的位置。
  6. “BERT 也是语言模型,可以用来生成文字。” 它不定义 p(xt∣x<t)p(x_t \mid x_{<t}),不能从左到右生成;它是一个很好的判别器和表示学习器。
  7. “[CLS] 的表示天生就是句子的摘要。” 它是在微调(或特定的预训练目标)中被训练成摘要的;不经训练直接拿来用效果有限。
  8. “ViT 比 CNN 好。” 取决于数据量和计算量:数据少时 CNN 的归纳偏置是巨大的优势。
  9. “ViT 的位置嵌入是二维的。” 原始 ViT 用的是一维的可学习嵌入;二维结构(如果有)是学出来的。
  10. “数据增强总是有益的。” 增强要和任务的不变性匹配;对已经有这种不变性的模型,不合适的增强(如会切断形状的循环平移)反而有害。

9. 练习 · Exercises

练习 1(手算卷积)。 输入 (120013210)\begin{pmatrix}1&2&0\\0&1&3\\2&1&0\end{pmatrix},核 (100−1)\begin{pmatrix}1&0\\0&-1\end{pmatrix},无偏置、不补零、步长 1。求输出。

参考答案

y11=1⋅1+2⋅0+0⋅0+1⋅(−1)=0y_{11} = 1 \cdot 1 + 2 \cdot 0 + 0 \cdot 0 + 1 \cdot (-1) = 0;y12=2−3=−1y_{12} = 2 - 3 = -1;y21=0−1=−1y_{21} = 0 - 1 = -1;y22=1−0=1y_{22} = 1 - 0 = 1。输出 (0−1−11)\begin{pmatrix}0 & -1\\-1 & 1\end{pmatrix}。这个核计算的是”左上减右下”——一个对角方向的边缘检测器。

练习 2(追踪 LeNet-5 的形状)。 输入 1×32×32;conv 5×5(6 个核)→ 2×2 平均池化 → conv 5×5(16 个核)→ 2×2 平均池化 → 拉平 → 全连接。每一步之后的形状是什么?第一个全连接层的输入维度是多少?

参考答案

6×28×28 → 6×14×14 → 16×10×10 → 16×5×5 → 400。第一个全连接层是 400 → 120(02 的 LeNet5 正是这样定义的,全部参数 61,706 个,其中 96% 在全连接层)。

练习 3(参数量)。 ResNet 的第一层:3 个输入通道、64 个 7×7 的核。带偏置和不带偏置时各有多少参数?

参考答案

带偏置:64×(3×49+1)=9,47264 \times (3 \times 49 + 1) = 9{,}472;不带偏置:64×3×49=9,40864 \times 3 \times 49 = 9{,}408(ResNet 的卷积层后面接批归一化,偏置是多余的,所以不带)。

练习 4(感受野)。 依次是:3×3 卷积(步长 1)、3×3 卷积(步长 1)、2×2 池化(步长 2)、3×3 卷积(步长 1)。最后一层一个位置的感受野多大?

参考答案

RF:1 → 3 → 5 → 6(池化:+1×1,之后间隔变成 2)→ 10(+2×2)。所以是 10×10。(用 02 的 receptive_fields 函数可以核对。)

练习 5(最大池化的反向)。 输入 (4127035122011633)\begin{pmatrix}4&1&2&7\\0&3&5&1\\2&2&0&1\\1&6&3&3\end{pmatrix},2×2 池化、步长 2。上游梯度是 (1234)\begin{pmatrix}1&2\\3&4\end{pmatrix}。求输出和对输入的梯度。右下角的窗口里有两个 3,梯度给谁?

参考答案

输出 (4763)\begin{pmatrix}4&7\\6&3\end{pmatrix}。梯度只出现在每个窗口的最大值处:(1,1)(1,1) 得 1,(1,4)(1,4) 得 2,(4,2)(4,2) 得 3;右下窗口两个 3 并列,PyTorch 取扫描顺序中的第一个 (4,3)(4,3),得 4,其余位置为 0。(这就是”任选一个次梯度”。)

练习 6(ViT 的 token 数)。 224×224 的彩色图,块大小 PP = 14、16、32 时,各有多少个 token(含 [CLS])?每个块拉直后多少维?自注意力的分数矩阵大小怎样随 PP 变化?

参考答案

P=14P = 14:162+1=25716^2 + 1 = 257 个 token,每块 588 维;P=16P = 16:197 个,768 维;P=32P = 32:50 个,3072 维。分数矩阵是 token 数的平方:块越小,序列越长,注意力的代价按 (224/P)4(224/P)^4 增长——这就是 ViT 选 16×16 而不是逐像素的原因(逐像素就是 50,176 个 token)。

练习 7(BERT 的遮盖)。 一句话 20 个词。按 BERT 的规则,期望有多少个位置要预测?其中期望多少个被换成 [MASK]、多少个换成随机词、多少个保持不变?

参考答案

20×15%=320 \times 15\% = 3 个;其中 [MASK] 2.4 个、随机词 0.3 个、不变 0.3 个。(在 05_bert_mlm.py 里,被选中的位置由随机数决定,所以每句实际个数不同。)

练习 8(为什么 BERT 不能直接生成)。 用 BERT 的掩码语言模型,能不能写出一句话的概率 p(x1,…,xT)p(x_1, \dots, x_T)?如果把所有 p(xt∣x−t)p(x_t \mid x_{-t}) 乘起来,得到的是概率吗?

参考答案

不能直接写出。BERT 给出的是”其余位置都已知时,某个位置的条件分布” p(xt∣x−t)p(x_t \mid x_{-t})。把它们乘起来(所谓伪对数似然)一般不是一个合法的联合分布——这些条件分布可能彼此不相容,乘积在所有句子上也不保证加起来是 1。自回归模型用链式法则 ∏tp(xt∣x<t)\prod_t p(x_t \mid x_{<t}),每一项都只依赖前面,乘积天然是联合分布(第 1 讲 §2.4)。

练习 9(平移等变的证明)。 一维卷积 yi=∑mwmxi+my_i = \sum_m w_m x_{i+m}。把输入平移 δ\delta:xi′=xi−δx'_i = x_{i-\delta}。证明 yi′=yi−δy'_i = y_{i-\delta}(忽略边界)。全连接层 yi=∑jWijxjy_i = \sum_j W_{ij} x_j 一般为什么不满足?

参考答案

yi′=∑mwmxi+m′=∑mwmxi+m−δ=yi−δy'_i = \sum_m w_m x'_{i+m} = \sum_m w_m x_{i+m-\delta} = y_{i-\delta}。关键是 wmw_m 只依赖相对偏移 mm,不依赖位置 ii(权重共享)。全连接层的 WijW_{ij} 对每一对 (i,j)(i, j) 都不同,只有当 WijW_{ij} 只依赖 j−ij - i 时(即它本身就是一个卷积)才满足。

练习 10(AlexNet 的”2048 倍”)。 AlexNet 从 256×256 的图里随机截取 224×224 的块,并以 50% 的概率水平翻转。不同的截取位置和翻转一共有多少种组合?

参考答案

截取的左上角在每个方向有 256−224=32256 - 224 = 32 种位置(论文的计数方式),共 322=102432^2 = 1024 种,再乘 2(翻转)= 2048。当然这些样本高度相关,不等于真的多了 2048 倍的独立数据——论文自己也这样说。

练习 11(VGG-16 的全连接层)。 VGG-16 最后一个池化层输出 512×7×7,后面是 4096、4096、1000 三个全连接层(带偏置)。求这三层的参数量,以及占全模型 138,357,544 个参数的比例。

参考答案

25088×4096+4096=102,764,54425088 \times 4096 + 4096 = 102{,}764{,}544;4096×4096+4096=16,781,3124096 \times 4096 + 4096 = 16{,}781{,}312;4096×1000+1000=4,097,0004096 \times 1000 + 1000 = 4{,}097{,}000;合计 123,642,856,占 89%(和 02 的输出一致)。第一个全连接层一个就占了全模型的 74%。


10. 延伸阅读 · Further reading

  • CNN 经典:LeCun et al. (1998), Gradient-Based Learning Applied to Document Recognition(LeNet-5);Krizhevsky, Sutskever & Hinton (2012)(AlexNet);Simonyan & Zisserman (2015)(VGG);He et al. (2016)(ResNet)。
  • 神经科学起源:Hubel & Wiesel (1962), Receptive fields, binocular interaction and functional architecture in the cat’s visual cortex;Fukushima (1980), Neocognitron。
  • 讲解:CS231N(Stanford)的卷积网络笔记(slides 的 3D 卷积动画就来自那里);Dumoulin & Visin (2016), A guide to convolution arithmetic for deep learning(填充、步长、转置卷积的图解)。
  • BERT 及其后续:Devlin et al. (2019);Liu et al. (2019), RoBERTa;Clark et al. (2020), ELECTRA(“替换检测”代替掩码预测)。
  • ViT 及其后续:Dosovitskiy et al. (2021);Touvron et al. (2021), DeiT(在 ImageNet-1k 上用数据增强和蒸馏训练 ViT);He et al. (2022), Masked Autoencoders(把 BERT 的掩码预训练用到图像上)。
  • 归纳偏置与数据:d’Ascoli et al. (2021), ConViT;Raghu et al. (2021), Do Vision Transformers See Like Convolutional Neural Networks?。

11. 下一讲预告 · Next lecture

到目前为止,我们的图像模型都是判别式的:给一张图,输出一个标签。第 6 讲开始讲生成图像:

  • 生成对抗网络(GAN):一个生成器和一个判别器互相博弈;本讲的 CNN 会被用作判别器,它的”反向”版本(转置卷积)用作生成器;
  • 概率图模型:怎样用有向图表示变量之间的依赖,为第 7–9 讲的扩散模型和 VAE 打下概率基础。

我们会在形状世界上训练第一个能”画”形状的生成模型。

← 返回课程目录