第 13 讲 · 视觉-语言模型(VLM)· Vision-Language Models

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

课程源码 ZIP ↓

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

本篇目录

对应 Maps to:CMU 10-423 / 10-623 / 10-723 Generative AI(Spring 2026;Matt Gormley、Aran Nayebi),Lecture 13 · Fri 27-Feb · Vision-language models(slides:lecture13-vlm;部分 slides 注明取自 Henry Chai)。 阅读材料:Radford et al. (2021), Learning Transferable Visual Models From Natural Language Supervision(CLIP);Zhai et al. (2023), Sigmoid Loss for Language Image Pre-Training(SigLIP);Beyer et al. (2024), PaliGemma;Bai et al. (2023), Qwen-VL;van den Oord et al. (2017), VQ-VAE;Liu et al. (2024), World Model on Million-Length Video and Language with RingAttention(LWM)。 依据说明:本讲按原课第 13 讲公开的 slides 展开:文生图模型 vs VLM;VLM 的常见任务(视觉推理、视觉定位、视觉问答、看图说话);VLM 的总体结构与两种图像编码器;CLIP 的结构、“错误但直观”的目标与正确目标、两个条件分布、零样本分类;SigLIP;只有文字解码器的 VLM(PaliGemma、Qwen-VL 的分阶段冻结、Qwen-VL 与 Llama 3.2 Vision 的评测、图像分辨率);为什么要整数 token;VQ-VAE(复习:码本、直通估计、三项损失);CLIP vs VQ-VAE;能同时输出文字和图像的 VLM(LWM、Gemini、Qwen2.5-Omni / Qwen3-Omni)。所有实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture13/(4 个脚本 + 1 个模块;01 第一次约 3 分钟(训练并缓存三个 CLIP),04 第一次约 3 分钟,03 约 1.5 分钟,02 约 1 分钟) 预计阅读时间:3 小时(含运行代码)


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

0.1 学习目标 Learning goals

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

  1. 说出 VLM 的常见任务和总体结构:图像和文字都变成向量(或整数),交给一个只有解码器的 Transformer。
  2. 写出 CLIP 的目标函数,解释为什么”直观”的线性目标会失败、两个 softmax 方向各是什么;用 CLIP 做零样本分类,并说明提示集成为什么有用。
  3. 说明 SigLIP 把 softmax 换成 sigmoid 的动机(分布式训练的通信)。
  4. 描述 PaliGemma / LLaVA 式的 VLM:线性投影、图像 token 的个数、分阶段冻结;说出”灾难性遗忘”在 VLM 训练里怎样出现、怎样缓解。
  5. 比较两种图像编码器(CLIP 的连续嵌入 vs VQ-VAE 的离散 token)各自适合什么;描述”任意到任意”的模型。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 5 讲:ViT;第 9 讲:VQ-VAE(码本、直通估计)交叉注意力式的 VLM(第 14 讲讲交叉注意力;Flamingo、Llama 3.2 Vision)
第 11 讲:指令微调、农场聊天助手Q-Former(第 15 讲)
第 12 讲:带描述的形状世界、迷你 Parti视频、音频(第 24、25 讲)

0.3 本讲地图 Map

§1  VLM:任务与总体结构
§2  图像编码器之一:CLIP;SigLIP                                 ← 代码 01、02
§3  只有文字解码器的 VLM:PaliGemma、Qwen-VL                       ← 代码 03
§4  图像编码器之二:VQ-VAE;能输出图像的 VLM                        ← 代码 04
§5–9  小结、误区、练习、延伸阅读、下一讲

本讲的实验都在第 12 讲的带描述的形状世界里:每张 28×28 的图有形状、大小、上下、左右 4 个属性(32 种组合),描述有 4 种说法(“a big circle at the top left”、“a circle , big , top left”……)。和第 12 讲一样,训练时都去掉了 4 种属性组合,用来测组合泛化。


1. VLM:任务与总体结构 · What VLMs do

slides 先把上一讲和这一讲对比:

  • 之前(文生图):改造图像的生成模型,用自然语言引导它的输出——输出仍是图像。
  • 今天(VLM):改造文字的生成模型,让它能和图像(以及文字)这样的输入交互——输出(通常)仍是文字。

VLM 常见的评测任务(slides):

  • 视觉推理:给一张图(或一对图),判断一句关于它的自然语言陈述是真是假(例如 NLVR2);
  • 视觉定位(grounding):给一段自然语言描述,在图里找到对应的物体;
  • 视觉问答(VQA):对一张(或几张)图,回答任意的、可能开放式的问题;
  • 看图说话(captioning):为图像内容生成自然语言描述。

总体结构(slides,取自 Hugging Face 的 VLM 博客):把图像和文字输入都转成嵌入向量,交给一个只有解码器的 Transformer,做下一个(文字)token 的预测。两种常见的图像编码器:

  1. VQ-VAE 编码器 + 一个嵌入层,把离散的 token 变成稠密向量(§4);
  2. CLIP 编码器,用对比学习的预训练目标直接学一个嵌入向量(§2)。

2. CLIP 与 SigLIP

2.1 结构

slides:文字编码器是(比如)一个只有编码器的 Transformer,图像编码器是(比如)一个类似 ResNet 的 CNN 或 ViT;两者各自线性投影到同样维度的向量——多模态嵌入空间。一个小批量有 N 对(图 IiI_i,描述 TiT_i),两个编码器同时预训练,让配对的图和描述的余弦相似度最大、其余所有组合的余弦相似度最小。

vlm_lab.CLIP:图像编码器是第 5 讲结构的小 ViT(49 个 4×4 的块),文字编码器是 2 层的非因果 Transformer(对非 <pad> 的位置取平均),各接一个线性投影到 32 维,再归一化成单位向量;温度 τ 可学习,从 0.07 出发(和原论文一样)。

2.2 一个”错误(但直观)“的目标

slides 先给了一个直观的目标:

max⁡ ∑i=1NIi⊤Ti − ∑i=1N∑j≠iIi⊤Tj.\max\ \sum_{i=1}^N I_i^\top T_i\ -\ \sum_{i=1}^N\sum_{j\ne i} I_i^\top T_j .

为什么是错的?代码 01 训练了一遍(1500 步,每批 128 对):

目标检索:4 个属性全对形状大小上下左右配对 / 不配对的余弦
正确的目标(CLIP)0.9300.9800.9770.9820.982+0.91 / +0.09
SigLIP0.8580.9570.9300.9790.976+0.60 / −0.12
“错误但直观”的目标0.0370.2660.5060.4660.502−1.00 / −1.00

(“检索”:每张测试图在 32 种描述里挑最相似的一句,4 个属性全对才算对;瞎猜 1/32 ≈ 0.031。)

“错误”的目标完全失败了,而且失败得很彻底:不同图之间的平均余弦 +1.00,不同描述之间也是 +1.00——所有图挤成一个点、所有描述挤到它的正对面。原因:目标对相似度是线性的;第二项 ∑j≠iIi⊤Tj≈Ii⊤(NTˉ)\sum_{j\ne i}I_i^\top T_j \approx I_i^\top(N\bar T),几乎就是”每张图和所有描述的平均方向的相似度”。N 很大时,第二项远远压过第一项,最省事的解就是把图推到”平均描述”的反方向——而这不需要区分谁配谁。

2.3 正确的目标:两个条件分布

slides 的正确目标:

max⁡ ∑i=1N[log⁡exp⁡(Ii⊤Ti/τ)∑j=1Nexp⁡(Ii⊤Tj/τ)+log⁡exp⁡(Ii⊤Ti/τ)∑j=1Nexp⁡(Ij⊤Ti/τ)].\max\ \sum_{i=1}^N \Bigg[\log\frac{\exp(I_i^\top T_i/\tau)}{\sum_{j=1}^N\exp(I_i^\top T_j/\tau)} + \log\frac{\exp(I_i^\top T_i/\tau)}{\sum_{j=1}^N\exp(I_j^\top T_i/\tau)}\Bigg].

它可以解释成两个条件分布(slides):

  1. 图 → 文:pIT(i 配 j∣Ii,T1,…,TN)=exp⁡(Ii⊤Tj/τ)∑kexp⁡(Ii⊤Tk/τ)p_{IT}(i\text{ 配 }j \mid I_i, T_1, \ldots, T_N) = \frac{\exp(I_i^\top T_j/\tau)}{\sum_k\exp(I_i^\top T_k/\tau)}——对相似度矩阵的一行做 softmax;
  2. 文 → 图:pTI(i 配 j∣Ti,I1,…,IN)p_{TI}(i\text{ 配 }j \mid T_i, I_1, \ldots, I_N)——对一列做 softmax。

双向对比损失最大化”正确配对”在两个分布下的对数似然。softmax 的好处:已经分开的对,梯度自动变小;力气都花在”分不清的那几对”上。温度 τ 越小,分布越”尖”——我们的 CLIP 学到的 τ 是 0.050。

代码 01 第 2 部分挑了 4 对,其中前两张图的描述一模一样:

p_IT(每一行)           T1     T2     T3     T4
图 1(small square …)  0.500  0.500  0.000  0.000
图 2(small square …)  0.500  0.500  0.000  0.000
图 3                    0.000  0.000  1.000  0.000
图 4                    0.000  0.000  0.000  1.000

模型把概率平分给两句相同的描述,但训练时只有对角线上那个算”正确答案”——批里的重复被当成了负样本(假负样本)。真实的 CLIP 数据集有几亿对,一个批里撞上同一句描述的机会小得多。

2.4 零样本分类

slides:在 N 个类别标签里,挑概率最高的那个:

y^=arg⁡max⁡i pIT(1 配 i∣I1,T1,…,TN)=arg⁡max⁡i exp⁡(I1⊤Ti/τ)∑jexp⁡(I1⊤Tj/τ),\hat y = \arg\max_i\ p_{IT}(1 \text{ 配 } i \mid I_1, T_1, \ldots, T_N) = \arg\max_i\ \frac{\exp(I_1^\top T_i/\tau)}{\sum_j\exp(I_1^\top T_j/\tau)},

其中 TiT_i 是第 i 个类别的文字描述。不训练任何分类器,只靠”类别的文字描述”。

代码 01 第 3 部分用它给 1000 张测试图分形状:

给每种形状的文字提示形状分类准确率
一句完整描述(“a small ___ at the top left”)0.849
只写形状(“a ___”),训练时从没见过这种短句0.879
提示集成:每种形状 32 句描述(8 种其他属性 × 4 种说法)的嵌入取平均0.950
(对照)线性探针:用 1000 张有标签的图训练0.978

一句完整描述把”小、左上”也带了进去,对大的、在别处的图打分偏低,反而不如只写形状;把所有说法、所有其他属性平均掉,只剩”形状”这个共同点,效果最好。这就是 CLIP 论文的提示集成(prompt ensembling):把几十个”A photo of a {label}.”式的模板取平均。零样本已经接近有监督的线性探针。

组合泛化(第 4 部分):训练时没见过的 4 种组合,CLIP 检索 4 个属性全对 0.921 / 0.818 / 0.829 / 0.815(133 张图合起来 0.850;见过的组合 0.930)——它学到的基本是一个个属性,能重新组合。不过真实的 CLIP 常被批评”像一袋单词”(Yuksekgonul et al., 2023):分不清”马骑宇航员”和”宇航员骑马”——我们的描述里没有这种关系。

2.5 SigLIP

slides:

SigLIP:max⁡ ∑i=1N∑j=1Nlog⁡11+exp⁡(yij(−t Ii⊤Tj−b)),yij={+1i=j−1否则\text{SigLIP:}\quad \max\ \sum_{i=1}^N\sum_{j=1}^N \log\frac{1}{1 + \exp\big(y_{ij}(-t\,I_i^\top T_j - b)\big)},\qquad y_{ij} = \begin{cases}+1 & i = j\\ -1 & \text{否则}\end{cases}

t=exp⁡(t′)t = \exp(t') 和 bb 可学习。动机:CLIP 的目标在批量小到一台机器放得下时没问题,但要把那个矩阵分散到很多机器上就会产生通信开销;SigLIP 把 softmax 换成 sigmoid,部分解决了这个问题。

代码 02 把 512 对分到 4 台”设备”上(每台 128 对),分块算损失(float64):

损失整批一起算分块算差分块时要交换什么
SigLIP76.27355276.2735520每次只需要别的设备的一块文字嵌入,按环传一圈
CLIP(精确)4.5400314.5400319e-16每一行、每一列的 softmax 分母要合并所有设备的部分和
CLIP(只用本机的负样本)4.5400313.2120591.3不交换,但变成了另一个目标:负样本从 511 个减到 127 个

SigLIP 每一对的损失只看这一对,所以可以在每台设备上只放一个 128×128 的小块;CLIP 要精确,就得在每一行、每一列上合并所有设备的部分分母(all-gather / all-reduce,第 17 讲)。

批大小(第 2 部分,各 1500 步):CLIP 0.930 → 0.681,SigLIP 0.858 → 0.544(批 128 → 16)。SigLIP 论文报告”小批量时 sigmoid 更好”——在我们这里没有出现,SigLIP 在两种批大小下都不如 CLIP,小批量时掉得还更多。真实的 CLIP 用 32768 的批,SigLIP 的主要卖点是在那个规模下省通信、省内存。


3. 只有文字解码器的 VLM · VLMs with text-only decoders

3.1 slides 里的模型

  • PaliGemma:图像编码器是 SigLIP,语言模型是 Gemma(2B,Gemini 的开源对应)。一个线性投影把图像嵌入变成和词嵌入同一个高维空间里的向量;语言模型要自己弄清楚怎样利用这些图像嵌入,让正确回答的似然最大。数据集 D={(x(i),z(i),y(i))}\mathcal D = \{(x^{(i)}, z^{(i)}, y^{(i)})\}:图像 x、文字前缀 z、回答 y。
  • Qwen-VL:训练时冻结一部分参数(对应预训练好的子模型)很常见。Qwen-VL 的做法:(1) 先冻结语言模型,学习和词空间对齐的图像嵌入;(2) 再全部解冻训练一阵;(3) 最后只冻结 ViT 图像编码器。
  • 评测:正如 LLM 用一堆文本基准评测理解和生成能力,VLM 用一堆图文基准评测它对多模态数据的理解和回答(slides 列了 Qwen-VL 和 Llama 3.2 Vision 的结果表)。
  • 图像分辨率:Qwen-VL(第一版)要求固定大小的输入——每张图缩放到 448×448,再转成固定长度的 256 个嵌入,配合绝对位置编码;Qwen2-VL 支持动态分辨率:ViT 仍按 28×28 的块工作,所以尺寸缩放到 28 的倍数,支持的范围是 56×56 到约 3584×3584,并把 ViT 的位置编码换成 2D-RoPE(第 4 讲 RoPE 的二维版)。

3.2 我们的 VLM(代码 03)

把三样已有的东西拼起来:

  • 图像编码器:01 训练的 CLIP 的图像编码器(冻结);
  • 语言模型:第 11 讲的农场聊天助手(扩充词表,加上 circle、top、yes 这些词);
  • 投影:一个线性层(64 → 64),把图像特征变成语言模型的输入向量,插在 <user> 后面:
<s> <user> [图像 token ×k] what shape is it ? <assistant> circle </s>

5 种问题:什么形状、大还是小、在哪里(“top left”)、是不是某种形状(yes / no)、描述这张图(整句)。图像 token 的个数:1 个(CLIP 的汇总向量)或 16 个(7×7 的块特征平均池化成 4×4)。两个阶段(各 1500 步):

  • A:Transformer 各层冻结,只训练投影层和词表的两端(词嵌入、输出层)。为什么要放开词表两端:我们新加了 circle、top、yes 这些词,冻结的输出层永远给它们打 0 分,模型就不可能说出来——我们第一版只训练投影层,所有问题都是 0 分(见 README)。真实的 VLM(LLaVA 第一阶段只训练投影层)用的语言模型本来就认识这些词。
  • B:全部解冻(图像编码器一直冻结)。

结果(500 张测试图,回答要逐词完全正确;最后一列是第 11 讲的 9 种农场任务):

做法什么形状大还是小在哪里是不是某种形状描述这张图原来的农场任务
第 11 讲的聊天助手(还不是 VLM)—————0.981
不给图像(语言模型全部训练)0.2240.5140.2620.5540.0240.104
1 个图像 token:A0.9560.9260.9620.8740.8580.074
1 个图像 token:A → B0.9560.9460.9540.9740.8600.000
16 个图像 token:A0.9060.8760.9120.5460.7700.193
16 个图像 token:A → B0.9200.9160.9520.9140.8100.000
16 个图像 token:A → B,混入纯文本数据0.9160.9120.9260.9160.7760.989

阶段 A 换 3 个随机种子(投影层的初始化 + 训练时抽到的数据;代码 03 第 2 部分):

阶段 A种子 0(上表)种子 1种子 2
1 个图像 token:“什么形状”0.9560.9480.954
1 个图像 token:“是不是某种形状”0.8740.9600.948
16 个图像 token:“什么形状”0.9060.9120.898
16 个图像 token:“是不是某种形状”0.5460.5540.862
  • 不给图像的基线告诉我们语言模型靠先验能答对多少(什么形状 0.224,瞎猜 0.25)——超出它的部分,都是从图像里读出来的。
  • 阶段 A:Transformer 各层一个没动,“说出图里是什么”已经很好(1 个图像 token 时什么形状 0.956、描述 0.858),换种子也几乎不变(什么形状 0.948–0.956)——这一步把图像嵌入对齐到了词空间。“是不是某种形状”则很不稳定:1 个图像 token 时 0.874–0.960,16 个时 0.546–0.862(瞎猜 0.5)。它要把问题里的形状和图里的形状放在一起比较;冻结的 Transformer 没学过这种比较,只能靠投影层和词表两端去”凑”,凑不凑得出来要看初始化和抽到的数据(我们修好随机种子之前的一次运行,CLIP 的初始化不同,1 个图像 token 时只有 0.446,见 README)。阶段 B 解冻以后是 0.974 / 0.914。这就是 Qwen-VL “先冻结、再解冻”的道理:先对齐,再让语言模型学会使用。
  • 1 个还是 16 个图像 token:1 个反而略好。CLIP 的汇总向量本来就是为了和整句描述对齐而训练的,已经包含了形状、大小、位置;在这个简单的世界里,更细的块特征没有带来更多信息,反而让序列更长。真实的 VLM 要在”细节”和”上下文长度”之间取舍(Qwen-VL 的 256 个 token、Qwen2-VL 的动态分辨率)。
  • 灾难性遗忘:阶段 A 之后农场任务就掉到 0.074 / 0.193——Transformer 各层没动,但输出层只在图像问答的答案上训练过,学会了压低农场词的分数;阶段 B 之后 0.000,原来的能力被完全覆盖。每一步混入一批纯文本的农场指令数据,农场任务保住了 0.989,图像问答五种问题平均只比不混入时低 0.013(代价是每一步多算一批纯文本)。真实的 VLM 训练总要混入纯文本数据,原因就在这里。(修好随机种子之前的那次运行里,混入纯文本后”是不是某种形状”退回了 0.552——和阶段 A 一样,这一列对随机性很敏感。)

4. VQ-VAE 与能输出图像的 VLM · VLMs with text and image decoders

4.1 为什么要整数 token

slides:另一种总体结构是把图像和文字输入都转成整数,交给一个只有解码器的 Transformer,做下一个(文字或图像)token 的预测。图像这一侧用 VQ-VAE(或 VQGAN)编码器,后面接一个嵌入层把离散 token 变成稠密向量。第 12 讲的 Parti 就是这样给图像分词的(ViT-VQGAN)。

4.2 VQ-VAE(复习,第 9 讲)

slides 的要点:

  • 嵌入空间由 K 个 D 维的隐向量 {e1,…,eK}\{e_1, \ldots, e_K\} 组成(训练中学习),编号 1..K 就是固定码本里的”图像 token”;
  • 编码器(比如类似 ResNet 的 CNN)把图像映射成一组 D 维向量 ze(x)z_e(x);
  • 每个编码器输出映射到最近的码本向量:zq(x)=ekz_q(x) = e_k,k=arg⁡min⁡j∥ze(x)−ej∥2k = \arg\min_j\lVert z_e(x) - e_j\rVert^2;解码器从离散的表示重建原图;
  • argmin 怎么求梯度?直通估计:把对 zq(x)z_q(x) 的梯度当作对 ze(x)z_e(x) 的梯度的估计——两者越近,估计越好;
  • 目标函数(三项):−log⁡p(x∣zq(x))+∥sg[ze(x)]−e∥2+β∥ze(x)−sg[e]∥2-\log p(x\mid z_q(x)) + \lVert\text{sg}[z_e(x)] - e\rVert^2 + \beta\lVert z_e(x) - \text{sg}[e]\rVert^2——第一项是重建误差;第二项把码本向量拉向映射到它的编码器输出;第三项让编码器的输出靠近码本向量(“承诺”),别让编码器过拟合训练数据。sg 是停止梯度。
  • 结果(van den Oord et al.):128×128×3 的 ImageNet 图压缩成 32×32×1(K = 512),重建质量接近原图;slides 引用”比特数减少到原来的 1/42.6”。

4.3 CLIP vs VQ-VAE

slides:

  • 用 VQ-VAE 编码器(或任何向量量化的图像模型)的 VLM 能生成图像——只要在图像码本的 token 上定义损失;
  • CLIP 不把图像嵌入离散化,所以基于 CLIP 的 VLM 不能(自然地)在图像上定义损失,只能输出文字;
  • 但 CLIP 的嵌入比离散的 VQ-VAE 编码更有表达力,在一些场景下表现更好。

4.4 能同时读图和画图的 VLM

slides 的例子:

  • Large World Model(LWM):一个同时处理离散文字 token 和离散图像 token 的 Transformer LM。关键:预训练好图像分词器 / 反分词器(VQGAN);数据里的图像都可以提前转成离散表示;然后像训练任何其他 LM 一样训练;测试时只要看到一串图像 token,就把它们还原成图像(slides 的例子:“这只狗几岁?给我一张图,画出它年龄的概率分布和你的最佳猜测”)。
  • Gemini:多种模态交错的输入、文字和图像交错的输出。
  • Qwen2.5-Omni / Qwen3-Omni(“任意到任意”):输入文字(119 种语言)、图像、音频(40 分钟以上的录音)、视频;输出文字(含”思考”模式)和语音(10 种语言)。

4.5 我们的”任意到任意”(代码 04)

一个 GPT(82 万参数),词表 = 描述的词 + 64 个图像 token(第 9 讲的 VQ-VAE)+ 一个分隔符,训练数据两种序列各一半:

看图说话:  <s> <img> #1 #4 #45 … (49 个图像 token) <txt> a big square at the top right
按描述画图:<s> a big square at the top right <img> #1 #4 #45 …
方向形状大小上下左右4 个全对十字
看图说话(贪心生成 7 个词)0.9050.9250.9850.9850.8120.87
按描述画图(形状拟合读回属性)0.7150.8650.9550.9550.5750.11
  • 同一个模型、同一套参数,两个方向都会。对 Transformer 来说,图像 token 和词没有区别,“任意到任意”只是训练数据里两种顺序都有。第 12 讲同样大小、只做”按描述画图”的迷你 Parti 是 0.637——同样的容量和训练步数分给两件事,每件事就少分到一些。
  • 十字:看图说话时说对 0.87,按描述画图时只画对 0.11。VQ-VAE 的编码器分得清十字(看图说话说得对),只是解码器画不出好看的十字——离散 token 用来”理解”够了,用来”生成”却受限于反分词器。
  • 没见过的组合(测试集里 47 张):看图说话 4 个全对只有 0.60(见过的组合 0.812),而 01 的 CLIP 在这些组合上检索得好得多(0.85)。逐词生成整句描述时,模型更容易套用训练时见过的搭配。
  • 和 03 基于 CLIP 的 VLM 比:“描述这张图”0.860(1 个图像 token、全部解冻)vs 这里的 0.812——CLIP 的连续嵌入理解得更好一些,符合 slides 的说法;VQ 这条路的好处是能输出图像。

5. 小结 · Summary

  1. VLM 把图像和文字都变成向量(或整数 token),交给一个只有解码器的 Transformer。图像编码器有两种:CLIP(连续,理解更好,只能输出文字)和 VQ-VAE / VQGAN(离散,能输出图像)。
  2. CLIP 用双向的对比损失(两个 softmax 方向)对齐图像和文字;“直观”的线性目标会让所有嵌入塌缩。CLIP 可以做零样本分类,提示的写法很重要,提示集成最好。
  3. SigLIP 把 softmax 换成逐对的 sigmoid,损失可以精确地分块计算,省掉了分布式训练里的归一化通信;在我们的小实验里它并没有更准。
  4. PaliGemma / LLaVA 式的 VLM:线性投影把图像特征接进语言模型。先冻结语言模型做对齐,再解冻学会使用;需要”比较”的问题必须改动语言模型本身。只在图像数据上训练会让语言模型忘掉原来的本事,混入纯文本数据可以保住。
  5. 把图像也变成整数 token,同一个 Transformer 就能既读图又画图;生成能力的上限是反分词器。

6. 常见误区 · Common pitfalls

  • “对比学习就是让配对的近、不配对的远。” 目标的形式很关键:线性的版本会塌缩(§2.2),softmax 的交叉熵才行。
  • “零样本分类只要写类别名。” 提示的写法会改变结果;把多种写法平均(提示集成)通常最好。
  • “SigLIP 比 CLIP 准。” 它的主要好处是分布式训练时省通信、省内存;准不准取决于设定(我们的实验里它更差)。
  • “冻结语言模型就不会遗忘。” 只要输出层被改了,原来的能力就可能受损(§3.2 阶段 A)。
  • “图像 token 越多越好。” 信息已经在少数几个 token 里时,更多 token 只是更长的序列。
  • “VQ token 画不出十字,说明模型认不出十字。” 编码器认得出(看图说话 0.87),是解码器画不出。

7. 练习 · Exercises

练习 1(错误的目标)。 设所有图的嵌入都等于 uu、所有描述的嵌入都等于 −u-u(单位向量)。算出 §2.2 那个”直观”目标的值,并和”每对完美匹配、不同对正交”的嵌入比较。N 很大时哪个更大?

参考答案

塌缩解:第一项 ∑iu⊤(−u)=−N\sum_i u^\top(-u) = -N,第二项 ∑i∑j≠iu⊤(−u)=−N(N−1)\sum_i\sum_{j\ne i}u^\top(-u) = -N(N-1),目标 =−N+N(N−1)=N(N−2)= -N + N(N-1) = N(N-2)。完美匹配、不同对正交(需要 N≤N \le 维数):第一项 NN,第二项 0,目标 NN。N > 3 时塌缩解更大——“直观”目标奖励的是把图和”平均描述”推开,而不是区分配对。

练习 2(两个方向)。 为什么 CLIP 要两个方向(图 → 文、文 → 图)都算交叉熵?如果只算图 → 文,可能出现什么问题?

参考答案

只算图 → 文时,每张图只要求”它的描述比其他描述更像它”;一句描述可以同时很像好几张图而不受惩罚(比如一句很”通用”的描述得分都高)。加上文 → 图,每句描述也要求”它的图比其他图更像它”,两边都被约束,嵌入更对称、检索两个方向都好用。

练习 3(零样本分类的提示)。 01 号脚本里”一句完整描述”(a small ___ at the top left)只有 0.849,而”只写形状”有 0.879。解释原因,再解释为什么提示集成能到 0.950。

参考答案

一句完整描述的嵌入同时编码了”small""top left”,和一张”大的、在右下”的图相似度偏低;四种形状的提示都带着同样的”小、左上”,于是对大的、在别处的图,形状的差别被这部分不匹配”稀释”了。只写形状没有这些额外信息(虽然训练时没见过这种短句)。提示集成把 8 种其他属性 × 4 种说法的描述平均:其他属性的影响相互抵消,只剩”形状”这个共同方向。

练习 4(SigLIP 的分块)。 写出 SigLIP 的损失在 M 台设备、每台 b 对时的分块计算:设备 k 需要哪些数据?峰值内存是多少(以相似度矩阵的元素个数计)?CLIP 精确计算时,每台设备至少要和别人交换什么?

参考答案

设备 k 持有自己的 b 张图的嵌入,文字嵌入按环一块一块传过来;每块算一个 b×b 的相似度矩阵和它的 sigmoid 损失,累加。峰值内存 b2b^2 个元素(不是 b×Mbb\times Mb)。CLIP 的每一行要对全部 MbMb 列做 softmax:至少要交换每一行在各块上的 log-sum-exp(部分分母),或者直接把所有文字嵌入 all-gather 到每台设备(Mb×dMb\times d 个数);列方向同理。

练习 5(分阶段冻结)。 03 号脚本的阶段 A 冻结了 Transformer,“什么形状”换种子一直在 0.9 以上,“是不是某种形状”却在 0.546 和 0.960 之间大起大落。为什么”什么形状”稳定、“是不是”不稳定?给出一个只改投影层就能答对”是不是”的设计(提示:问题能不能也变成图像那一侧的输入?)。

参考答案

“什么形状”只需要把图像特征映射到对应的词:投影层把圆的特征投到”circle”这个词附近,冻结的语言模型照着”复读”就行。“是不是”要比较问题里的词和图像内容,再输出 yes / no——这是一个新的计算,冻结的 Transformer 没学过;投影层和词表两端有时能”凑”出一个可行的解(让图像 token 和问题里的形状词在注意力里对上),有时凑不出来,所以随种子大起大落。一个只改投影的设计:让投影层看到问题(比如投影层输入 = 图像特征和问题里形状词的嵌入),直接输出一个”匹配 / 不匹配”的向量,把比较放到投影层里做——这其实就是第 15 讲 Q-Former 的思路:让图像那一侧的模块”看着问题”去提取信息。

练习 6(遗忘)。 阶段 A 只改了词嵌入和输出层,农场任务却从 0.981 掉到 0.074。这和第 10 讲 §8.3 的遗忘有什么相同之处?

参考答案

都是”新数据没覆盖的地方,模型的行为被意外改变”。这里输出层在图像问答上只见过 circle、top、yes 这些答案,交叉熵把其他所有词(包括农场词)的分数都往下压——没有任何数据告诉它”农场词在农场问题里仍然要高”。第 10 讲的方言模型同样把方言的局部规则推广到了原来的语言上。缓解办法也一样:让训练数据覆盖原来的场景(混入纯文本数据),或者少改参数。

练习 7(任意到任意)。 04 号脚本里,十字”看图说话说得对、按描述画图画不对”。用 VQ-VAE 的编码器、码本、解码器三部分解释。如果把 VQ-VAE 换成 06 号(第 12 讲)的 KL 自编码器,还能做”按描述画图”吗?要改什么?

参考答案

编码器把十字映射到的那串码本编号,和其他形状的编号不同(所以 GPT 能从编号认出”这是十字”);但码本里没有足够细的向量来表示十字的细横竖,解码器从这串编号重建出来的图不像十字(形状拟合读不出来)。KL 自编码器的潜变量是连续的,不能直接当作”下一个 token”让 GPT 用交叉熵生成;要么在连续潜变量上换成扩散(第 12 讲的潜空间扩散),要么把它量化成离散 token(回到 VQ)。这正是”CLIP / 连续嵌入适合理解、离散 token 适合生成”的另一面。

8. 延伸阅读 · Further reading

  • 对比学习:Radford et al. (2021), CLIP;Jia et al. (2021), ALIGN;Zhai et al. (2023), SigLIP;Yuksekgonul et al. (2023), When and Why Vision-Language Models Behave like Bags-of-Words。
  • 只有文字解码器的 VLM:Alayrac et al. (2022), Flamingo(交叉注意力);Liu et al. (2023), LLaVA(线性投影 + 视觉指令微调);Bai et al. (2023), Qwen-VL;Wang et al. (2024), Qwen2-VL(动态分辨率、2D-RoPE);Beyer et al. (2024), PaliGemma。
  • 离散图像 token 与任意到任意:van den Oord et al. (2017), VQ-VAE;Esser et al. (2021), VQGAN;Team Chameleon (2024), Chameleon;Liu et al. (2024), LWM;Gemini Team (2023);Xu et al. (2025), Qwen2.5-Omni。
  • 评测:Suhr et al. (2019), NLVR2;Antol et al. (2015), VQA。

9. 下一讲预告 · Next lecture

第 14 讲回到文生图,把第 12 讲留下的几个零件补上:文字到底怎样”注入”扩散模型——交叉注意力(查询来自图像,键和值来自文字);无分类器引导怎样用一个强度 w 在”听话”和”多样”之间取舍;扩散 Transformer(DiT)怎样用 Transformer 替换 U-Net;以及 Prompt-to-Prompt:只改提示里的一个词,怎样只改图里对应的那一部分。

← 返回课程目录