第 17 讲:多模态模型 —— 让语言模型看见图片

Language Modeling from Scratch · Lecture 17。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

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

本篇目录

对应:Stanford CS336 Spring 2026 Lecture 17(Multimodal models,Percy Liang 的可执行讲义 lecture_17.py)。 配套代码:code/lecture17/ 预计阅读时间:2.5 小时 硬件说明:全部在 CPU 上运行,图片是程序生成的 32×32 小图。01、04 号脚本几秒钟;02 号约半分钟;03、05 号约 2~3 分钟。


0. 本讲导航

0.1 学完本讲,你应该能够

  1. 说清把图片、视频送进 Transformer 的基本思路:一切都要变成 token。
  2. 解释 ViT 的切块、CLIP 的预处理,以及它们为什么会丢掉细节;说出 AnyRes 和动态分辨率的做法。
  3. 推导 CLIP 的对比损失和 SigLIP 的 sigmoid 损失,说出两者的区别和各自的好处。
  4. 描述 LLaVA 的模板(视觉编码器 + 投影层 + 语言模型)和两阶段训练,以及 LLaVA-OneVision、Qwen-VL 系列的演进。
  5. 解释 M-RoPE 和它的交错改进,以及多模态训练中损失怎样平衡。
  6. 说出 Chameleon”全离散 token”路线的优雅之处和代价。

0.2 先修知识

知识点用在哪里最低要求
第 1 讲第 1 节分词:把文字变成 token
第 3 讲第 2、5 节Transformer、注意力、RoPE、QK-Norm、z-loss
第 15 讲第 4 节SFT、只对回答计算损失
softmax 交叉熵、sigmoid第 3 节分类损失

0.3 本讲地图

第1节 目标:全模态模型;一切都要变成 token
第2节 图片怎样变成 token:切块、缩放裁剪、高分辨率     ← 01 号文件
第3节 编码图片:CLIP 与 SigLIP                          ← 02 号文件
第4节 把图片接进语言模型:LLaVA、Qwen-VL 系列           ← 03 号文件
第5节 图片 token 的位置:M-RoPE;损失的平衡             ← 04 号文件
第6节 走向全模态:Chameleon 与离散图片 token            ← 05 号文件
第7节 小结

1. 目标:全模态模型

到目前为止,我们的语言模型都是”文字进、文字出”。可世界是多模态的:图片、视频、声音、文档、界面截图……终极目标是一个全模态(omni)模型:

  • 输入任意组合的模态(理解);
  • 输出任意组合的模态(生成)。

我们今天的处境:

  • Transformer 非常好用,所以我们想用它;
  • Transformer “说”的是 token(离散的或连续的),一个 token 大致代表一个”语义单元”的信息;
  • 所以,必须把一切都变成 token。我们对文字做过同样的事(第 1 讲的分词);对非文字的模态,这更有挑战。

两个问题:

  1. 怎样输入非文字的数据(例如理解图片)?
  2. 怎样输出非文字的数据(例如生成声音、图片)?

本讲的大部分篇幅回答第 1 个问题,最后用 Chameleon 讨论第 2 个。

我们的玩具世界(shapes.py):32×32 的彩色小图,黑色背景上有一个图形——5 种颜色 × 4 种形状(圆、正方形、三角形、十字)× 2 种大小 × 4 个位置 = 160 种组合。每张图配一句说明文字,而且像网络上的图片说明一样不完整:每个属性只有 60% 的概率被提到(“a red shape on the left”、“a big circle”)。还可以用一个 3×5 像素的小字体在图上写数字,用来演示”细节”有多容易丢失。


2. 图片怎样变成 token

2.1 切块:Vision Transformer

ViT(Dosovitskiy et al. 2020)的答案出奇地简单:把图片切成 P×P 的小块,每块展平成一个向量,经过一个线性层(“块嵌入”)——这就是一个图片 token。再加上位置信息,送进 Transformer。

  • CLIP 最好的模型 ViT-L/14@336px:336×336 的图片,14×14 的块 → 24×24 = 576 个 token,每个块 3×14×14 = 588 个数;
  • 块越小,token 越多(注意力的计算量 ∝ token 数的平方),每个 token 看到的细节越少;
  • 块嵌入层本身很小(588 × 1024 ≈ 60 万个参数),贵的是后面的 Transformer。

和文字 Transformer 的一个区别:图片的块之间没有”先后”,所以视觉编码器用双向注意力(不加因果掩码)。

2.2 CLIP 的预处理:缩放 + 中心裁剪

图片的分辨率五花八门(任意的宽 × 高)。CLIP 的做法:用双三次插值把短边缩放到 336 像素,再从中间裁出 336×336(它的代码 clip.py 里就是这样写的)。01_images_to_tokens.py 演示 2:

原图尺寸保留的面积
336×336100%
640×48075%
1920×108056%
3000×100033%

长宽比越悬殊,两边被裁掉得越多——全景照片、长截图、文档都会丢掉大块内容。另一个问题是缩小:在 128×128 的图上写 “2025”(笔画 2 像素宽),缩小到 32×32 后,笔画只剩半个像素宽,变成一团模糊的灰色。CLIP 的训练目标以图片分类为导向,不太需要这种细节;但对 OCR、读图表、看文档来说,这是致命的。保留高分辨率是后来的模型花大力气解决的问题(第 4 节)。


3. 编码图片:CLIP 与 SigLIP

3.1 CLIP

背景:计算机视觉模型过去在人工标注的图片上训练(ImageNet:120 万张图,1000 个类别)。能不能利用网上多得多的”(图片, 说明文字)“对?

方法(Radford et al. 2021,对比学习):

  1. 取一批 (图片, 文字) 对(CLIP 用 32768 对);
  2. 分别编码每张图片和每段文字,归一化成长度为 1 的向量;
  3. 对每张图片:它自己的文字应该比这批里所有其他文字都更相似(一个 N 选 1 的分类);
  4. 对每段文字:它自己的图片应该比所有其他图片都更相似;两个方向的交叉熵取平均。

logitsij=s⋅⟨I^i,T^j⟩,L=12[CE(logits,对角线)+CE(logits⊤,对角线)]\text{logits}_{ij} = s \cdot \langle \hat{I}_i, \hat{T}_j \rangle, \quad \mathcal{L} = \tfrac{1}{2}\big[\mathrm{CE}(\text{logits}, \text{对角线}) + \mathrm{CE}(\text{logits}^\top, \text{对角线})\big]

s 是一个可学习的温度(初始 1/0.07,上限 100)。

数据:用 50 万个搜索词去搜,每个词最多约 2 万对,一共训练了 4 亿对(数据没有公开)。OpenCLIP 用 LAION-5B 复现了 CLIP——有趣的是,LAION 本身是用 CLIP 过滤出来的。

编码器:图片编码器试了 ResNet-50 和 ViT(ResNet 版用”注意力池化”:以全局平均的激活为 query 做一次注意力),最好的是 ViT-L/14@336px;文字编码器是一个 GPT-2 式的 Transformer(6300 万参数,12 层),编码 [BOS] … [EOS],取最高一层 [EOS] 位置的输出。

头条结果:在 ImageNet 上,零样本的 CLIP 超过了在 120 万张 ImageNet 图片上训练的 ResNet-50。零样本分类的做法:把每个类别名写成一句话(“a photo of a {类别}”),编码所有这些句子,看图片和哪句最像。

消融:另一种做法是”从图片直接预测文字”(生成说明)。它的计算效率比 CLIP 式的”排序”低得多——判断”这句话和这张图是不是一对”,比”逐字写出这句话”容易得多。

小结:图片的编码抓住了(带噪声的)文字所给出的语义;设计上以图片分类为导向(不太精细);技术上需要很大的批次,并且要对整批做 softmax。

3.2 SigLIP

SigLIP(Zhai et al. 2023)改了目标:

  • CLIP:对 (文字, 图片) 与所有 (文字, 另一张图片) 做多分类;
  • SigLIP:对每一个 (文字, 图片) 组合做二分类——配对的是正例,其余是负例: L=−1N∑i,jlog⁡σ(zij (t⋅⟨I^i,T^j⟩+b)),zij=±1\mathcal{L} = -\frac{1}{N}\sum_{i,j} \log \sigma\big(z_{ij}\,(t \cdot \langle \hat{I}_i, \hat{T}_j\rangle + b)\big), \quad z_{ij} = \pm 1 偏置 b 初始化为 -10(N×N 个组合里只有 N 个正例,一开始”都判为不配对”更合理),t 初始化为 10。

数据:WebLI——从网上抓取的数十亿对 (图片, 文字),用自动 OCR 提取图中的文字,只保留质量最高的 10%,支持 100 种语言。

效率:CLIP 用 256 块 TPUv3 训练了 10 天;SigLIP 用 32 块 TPUv4 训练了 5 天——快得多。因为不需要对整批做 softmax,批次大小和损失解耦了,分布式训练时通信也更少。

批次大小:批次小于约 1.6 万时 SigLIP 比 CLIP 好;可以一路加到 100 万,但 3.2 万左右就够了。

3.3 在玩具世界里训练 CLIP 和 SigLIP

02_clip_siglip.py:迷你 ViT(16 个 8×8 的块,2 层)+ 词袋文字编码器,训练 300 步。评估是零样本分类:把 160 种可能的描述都编码,给每张测试图片挑最相似的一句(瞎猜的”四项全对”率只有 1/160 ≈ 0.6%)。训练时故意排除了 3 种”颜色 + 形状”组合(黄色三角形、绿色十字、紫色圆),测试模型能否”举一反三”。

损失批次见过的组合:颜色 / 形状 / 大小 / 位置 / 全对没见过的组合:全对
CLIP16100% / 94% / 100% / 99% / 93%55%
CLIP256100% / 100% / 100% / 100% / 100%100%
SigLIP1698% / 85% / 100% / 82% / 73%79%
SigLIP256100% / 100% / 100% / 100% / 100%100%
  • 模型从没被告知”这是一张红色的图”,它只知道”这张图和这句话是一对”。颜色、形状、位置这些概念,都是从”哪些图和哪些词经常一起出现”里学出来的——即使每句说明文字只提到一部分属性;
  • 批次 256 时,连没见过的组合都认得出来:模型把”黄色”和”三角形”学成了独立的概念,可以组合;
  • 注意这张表的一个”不公平”:都训练 300 步,批次 256 看到的样本是批次 16 的 16 倍。在这个玩具任务上,小批次时 SigLIP 并没有比 CLIP 好(和论文的结论不一致)——论文的结论来自几十亿对数据、上万的批次,玩具实验说明不了那个规模下的事。

4. 把图片接进语言模型

4.1 LLaVA:此后几乎所有开源 VLM 的模板

LLaVA(Large Language and Vision Assistant,Liu et al. 2023):

  • 视觉编码器:CLIP(ViT-L/14);
  • 文字解码器:Vicuna(在 ShareGPT 对话上微调的 LLaMA);
  • 连接方式:一个线性投影 W,把视觉编码器的网格特征(每个块一个)映射到语言模型的词嵌入空间,当作一串”图片 token”放在文字前面(Flamingo 的交叉注意力、BLIP-2 的 Q-Former 更复杂)。

数据:MS COCO 的图片有边界框标注和众包写的说明。把说明和检测到的物体(文字形式)交给 GPT-4(纯文字的),让它生成关于这张图的问题和对话,再和原图配对——得到 15.8 万条指令数据。

训练:

  • 阶段 1(对齐):冻结视觉编码器和语言模型,只训练 W;
  • 阶段 2(微调):冻结视觉编码器,训练 W 和语言模型。

03_llava.py 在玩具世界里走一遍:语言模型先只在文字上预训练(学会”说话”);视觉编码器用 02 号文件训练的 CLIP;然后阶段 1(看图写完整的说明)和阶段 2(看图回答”what color is the shape?”之类的问题)。它还对比了跳过阶段 1、阶段 2 冻结语言模型、以及”不给图片”时的准确率。运行时请留意:

  • “不给图片”时的准确率应该接近瞎猜(颜色 20%、形状 25%、大小 50%、位置 25%)——模型确实在”看图”回答,而不是靠语言模型的先验去猜;
  • 阶段 2 只训练回答问题之后,模型”看图写说明”的能力可能退化——这就是真实的指令数据要尽量多样的原因;
  • 跳过阶段 1、或冻结语言模型,在这个小任务上差别可能不大;LLaVA 论文在真实数据上发现两个阶段都有帮助。

(这个脚本我只做了冒烟测试,具体数字以你运行的结果为准。)

4.2 LLaVA-OneVision

LLaVA 系列的最新版本(在 LLaVA-1.5、LLaVA-NeXT 之后),能处理多张图片和视频:

  • 视觉编码器:SigLIP(取最后一层 Transformer 之前和之后的网格特征);文字解码器:Qwen-2 72B;投影层:两层 MLP;
  • 保留高分辨率很重要(例如 OCR)。CLIP 缩放裁剪到 336×336 会丢信息。解决办法是 LLaVA-1.5 引入的 AnyRes:把图片切成 a×b 个和视觉编码器分辨率一样大的格子,分别编码再拼起来(再加一张缩小的全图);如果原图分辨率太高、token 太多,就用双线性插值减少;
  • 三种输入(单张图、多张图、视频)的原则是让它们产生差不多长度的 token:单张图用更高的分辨率,多张图每张用基础分辨率,视频每帧用更低的分辨率;
  • 数据:质量胜于数量;训练:从易到难;
  • 模态之间的迁移:在单图数据上学的图表理解推广到了多图;单图的 OCR + 多图的关系推理推广到了操作图形界面的智能体;单图上的”视觉提示”(在图上画圈)推广到了视频。
  • 总结:标准的 VLM 模板(视觉编码器 + 投影层 + 语言模型);大部分工作都花在数据整理上(大量合成的、针对具体任务的数据);开源(公开了权重和数据)。

01_images_to_tokens.py 演示 3 算了算 token 数:

图片尺寸CLIP-336AnyRes(格子 + 全图)Qwen2-VL
224×2245761×1 + 全图 = 115266
640×4805762×2 + 全图 = 2880393
1920×10805762×4 + 全图 = 51841298

4.3 Qwen-VL 系列

Qwen-VL(2023):

  • 视觉编码器:OpenCLIP 的 ViT-bigC(14×14 的块);
  • 适配器:一层交叉注意力,带二维位置编码,把图片特征压缩成固定的 256 个 token;
  • 特殊 token:<img>、<box>、<ref>(用于定位、指代);
  • 训练三个阶段:(1) 大规模、低质量的数据,冻结语言模型,训练视觉编码器和适配器;(2) 更高质量、针对任务的数据,提高分辨率,训练所有参数;(3) 指令数据,冻结视觉编码器,训练适配器和语言模型。

Qwen2-VL(2024):

  • 更大的 ViT(6.75 亿参数),从 DFN 的视觉编码器初始化,语言模型从 Qwen2 初始化;
  • 动态分辨率:按原图的分辨率切 14×14 的块,每 2×2 个相邻的块合并成一个 token——224×224 的图 → 8×8 = 64 个 token,加上开始、结束两个特殊 token 共 66 个;
  • 视频:每秒取 2 帧,最多 16384 个 token(01 号文件算出:448×448 时最长约 64 秒);
  • 多模态旋转位置编码(M-RoPE,第 5 节);
  • 训练阶段和 Qwen-VL 类似;能力很多(文档理解、多语言 OCR、视频、智能体……)。

Qwen3-VL(2025):

  • 语言模型:Qwen3(稠密和 MoE,最大 235B-A22B),支持 256K 长上下文;
  • 视觉编码器:SigLIP-2(结构同 SigLIP);
  • 交错 M-RoPE:把时间、宽、高三个方向交错分配到高频和低频([t w h t w h …] 而不是 [t t t … w w w … h h h …]);
  • 视频的显式时间戳:作为单独的文字 token(例如 “<3.5 seconds>”),而不是只放在位置编码里;
  • 按样本长度的平方根归一化的逐 token 损失:平衡文字和多模态数据(视频样本很长,不能让它主导训练);
  • 适配器:DeepStack——把视觉特征注入语言模型的多层(跨层融合),而不只是输入层;
  • 预训练 4 个阶段:先训练适配器,再在 8K、32K、256K 的上下文长度上训练所有参数;后训练:长思维链的 SFT、知识蒸馏、强化学习。
  • 总结:最先进的效果;大量的数据工作,但细节不多;一些不起眼但可能很重要的架构改进;规模化。

5. 图片 token 的位置:M-RoPE;损失的平衡

5.1 M-RoPE

第 3 讲的 RoPE 给每个 token 一个一维位置,注意力分数只取决于相对位置。把图片块按行展开成一维序列,“正下方的块”就隔了一整行,模型要费力才能学到二维的邻近关系。

Qwen2-VL 的 M-RoPE:每个 token 的位置变成三个数 (t, h, w)。04_mrope.py 演示 1(“Describe this” + 一张 2×3 的图 + “It is red”):

tokenthw
Describe000
this111
图[0,0]222
图[0,2]224
图[1,1]233
It555
  • 文字 token 的三个数相同(退化成普通 RoPE);
  • 图片的所有块共用 t,h、w 是行、列(加上起始偏移);
  • 图片之后的文字从”目前用过的最大编号 + 1”开始:一张 2×3 的图只”占用”3 个位置。

实现上,把每个注意力头的维度对分成三组,分别用 t、h、w 去旋转。演示 2 验证:三对 (Δt, Δh, Δw) 相同的 token,无论整体平移到哪里,注意力分数都完全相同——M-RoPE 只”看”三维的相对位置。

5.2 交错的频率分配

RoPE 的每一对维度有自己的频率:高频的转得快,对相邻位置的差别敏感;低频的转得慢,对远距离敏感。演示 3(每个头 24 对维度):

分配方式方向最高频率最低频率
分块(Qwen2-VL)t1.00006.8e-02
h0.04643.2e-03
w0.00221.5e-04
交错(Qwen3-VL)t1.00003.2e-04
h0.68132.2e-04
w0.46421.5e-04

分块分配时,t 只有高频(长视频里远距离的时间关系难以表达),w 只有低频(列方向上相邻的块很难区分);交错分配让每个方向都拥有从高到低的完整频率范围。

5.3 长短悬殊的样本怎样平衡损失

演示 4:4 个样本的长度分别是 60(纯文字问答)、400(单图问答)、1500(多图)、8000(视频)个 token,每个样本在总梯度里占的比重:

样本按 token 平均按样本平均√长度归一化
纯文字问答(60)0.6%25%5.0%
单图问答(400)4.0%25%12.8%
多图(1500)15.1%25%24.8%
视频(8000)80.3%25%57.4%

按 token 平均,视频独占 80% 的梯度;按样本平均,文字 token 的权重是视频 token 的 100 多倍;Qwen3-VL 的平方根归一化折中。这和第 16 讲 GRPO”按回答长度平均”的偏差是同一类问题:长短不一的序列,损失怎样合起来,会系统性地改变模型学到的东西。


6. 走向全模态:Chameleon

6.1 离散的图片 token

到目前为止,VLM 都是把图片编码(CLIP、SigLIP)后注入语言模型。缺点:不能生成图片(还得另接一个扩散模型)。

Chameleon(Meta 2024):把一切都映射成离散 token。优点:可以用统一的方式理解和生成图片——一个自回归模型从头到尾只做一件事:预测下一个 token,不管它是字还是图的一块。

视觉编码器的关键区别:要映射成离散 token(这样才能生成)。做法是 VQ-VAE(向量量化变分自编码器,van den Oord et al. 2017):把图片映射到一本离散的”码本”,再解码回图片,最小化重建误差。Chameleon 把 512×512 的图片编码成 1024 个 token(码本大小 8192),并训练了一个新的 BPE 分词器(文字和图片 token 共用词表)。

训练:

  • 阶段 1(占 80%):大规模无监督数据——2.9 万亿文字 token、1.5 万亿”文字 / 图片” token、4000 亿图文交错的 token;
  • 阶段 2(占 20%):一半是阶段 1 的数据,一半是高质量数据。

训练稳定性:文字 token 熵低(分布很”尖”),图片 token 熵高(分布很”平”),混在一起训练导致范数增长、logit 漂移。修正:QK-Norm 和 z-loss(第 3 讲的稳定性技巧)。

小结:优雅(只是对离散 token 做自回归建模);但效果不如同期的方法(离散化丢失信息——想想 OCR);多模态混合训练很棘手。

6.2 在玩具世界里:码本与”看说明画图”

05_vq_tokens.py 用最简单的向量量化:在大量 4×4 的图片块上做 k-means,得到 K 个”代表块”作为码本;每张 32×32 的图 = 64 个 token(每个块换成最近的码本编号);解码就是查表。演示 1:

码本大小 K每个 token 的比特数形状图的重建误差写了数字的图:数字区域的误差
830.01170.2296
3250.00720.2393
12870.00520.2156
51290.00330.1985

码本越大,形状图的重建越准;但数字区域的误差几乎不随码本变大而下降:码本是在没有写字的图片上学的,里面根本没有”白色笔画”的块,笔画只能被换成最接近的彩色块。教训:图片 tokenizer 学的是训练数据里常见的”零件”——训练数据里文字少,它就不擅长编码文字;而且即使有,一个块里既有笔画又有背景,离散化也会把细节”平均”掉。

演示 2 把 31 个字符、1 个 <图片开始> 和 128 个图片 token 放进同一个词表,训练一个 3 层的 Transformer:序列 = 完整的说明文字 + <图片开始> + 64 个图片 token。训练后给它一句 “a big red circle on the left”,它会一个 token 一个 token 地”画”出一张图(用字符画显示)。模型从来不知道”图片”是什么——对它来说,图片 token 和字符一样,只是词表里的一些编号。同一个模型、同一个”预测下一个 token”的目标,把文字放在前面就是画图,把图片放在前面就是看图。(这部分我只做了冒烟测试,画得像不像,以你运行的结果为准。)


7. 小结

  1. 前沿模型被期待是多模态的(原生多模态、全模态);
  2. 根本的挑战:怎样编码非文字的模态?——切块(ViT)、缩放裁剪(CLIP)、AnyRes、动态分辨率;
  3. 理解和生成可能需要不同的东西:理解要语义(CLIP 式的连续表示很合适),生成要更细的细节(离散 token 会丢信息);
  4. 平衡图片、视频(信息密度低、token 多)和文字,才能训练稳定——损失归一化、数据配比、QK-Norm / z-loss;
  5. 当前的主流:连续的编码器 + Transformer 理解;扩散模型负责生成。
  6. 大部分工作在数据上:LLaVA 用 GPT-4 合成指令数据,OneVision 强调”质量胜于数量”,Qwen-VL 系列的数据细节很少公开。

8. 与作业的关系

CS336 没有专门的多模态作业。本讲的代码可以看作第 3 讲(Transformer)、第 15 讲(SFT)在多模态上的延伸:03_llava.py 里的”只对回答计算损失”和第 15 讲的 SFT 完全相同,只是在文字前面多了一串图片 token。


9. 练习

练习 1(token 数):一张 1024×768 的图片,(a) 用 ViT-L/14@336 的 CLIP 处理,有多少个 token?被裁掉了多少面积?(b) 用 Qwen2-VL 的动态分辨率(14×14 的块、2×2 合并、不超过像素上限)呢?

参考答案

(a) 固定 576 个 token。短边 768 → 336,长边 1024 → 448,从中间裁出 336×336,保留 336/448 = 75% 的面积,裁掉 25%。(b) 1024 和 768 取整到 28 的倍数:1036(37 × 28)和 756(27 × 28),token 数 37 × 27 = 999,加 2 个特殊 token 共 1001(在像素上限之内)。

练习 2(CLIP 与 SigLIP 的损失):批次为 N 时,CLIP 的相似度矩阵有多少个元素参与 softmax?SigLIP 把每个元素当成独立的二分类,这对分布式训练有什么好处?

参考答案

N×N 个。CLIP 每一行(每张图)要对 N 个文字做 softmax,归一化需要整批的所有文字向量——分布式训练时每块卡都要拿到全部 N 个向量(all-gather),而且大批次的 N×N 矩阵很大。SigLIP 每个元素的损失独立,可以分块计算:每块卡先算自己的正例和本地负例,再依次和其他卡交换文字向量块(SigLIP 论文的”分块”实现),不需要一次存下整个 N×N 矩阵,也不需要全局的 softmax 归一化。

练习 3(零样本分类):为什么 CLIP 能做零样本分类?如果一个类别名在网上很少和对应的图片一起出现(例如一种罕见的鸟),会怎样?

参考答案

CLIP 学到的是”图片和文字的共同空间”:把类别名写成一句话编码,和图片比相似度,就等于”问这张图更像哪句话”。它的能力来自训练数据中图文共现的统计:罕见概念(少见的鸟、专业术语、图中的文字)在网络数据里出现得少,学得就差;而且 CLIP 以分类为导向,对计数、空间关系、组合(“红色的圆和蓝色的方块”与反过来)也不敏感。

练习 4(LLaVA 的两个阶段):阶段 1 为什么要冻结语言模型、只训练投影层?如果一开始就同时训练投影层和语言模型,可能出什么问题?

参考答案

一开始投影层是随机的,图片 token 对语言模型来说是一串”噪声”。如果同时训练语言模型,它可能为了适应这些噪声输入而破坏已有的语言能力(灾难性遗忘),或者学会忽略图片 token。先只训练投影层,让它学会把图片特征”翻译”成语言模型已经理解的空间,再一起微调,更稳定、更省数据。

练习 5(M-RoPE):一段 4 秒的视频,每秒取 2 帧、每两帧合并,每组帧是 3×3 个 token,前面有 5 个文字 token。按 Qwen2-VL 的规则,视频 token 的 t 取哪些值?视频之后的第一个文字 token 的位置编号是多少?

参考答案

8 帧合并成 4 组。文字占位置 04,视频从 5 开始:第 k 组(k = 03)的 t = 5 + k,h = 5 + 行,w = 5 + 列(行、列 0~2)。用过的最大编号:t 最大 8,h、w 最大 7 → 8。所以下一个文字 token 的位置是 9。

练习 6(离散 vs 连续):Chameleon 的码本大小是 8192,每张 512×512 的图 1024 个 token。每张图最多能携带多少比特的信息?和原图(每像素 24 比特)比,压缩了多少倍?这解释了什么现象?

参考答案

每个 token log2(8192) = 13 比特,1024 × 13 = 13312 比特 ≈ 1.6 KB。原图 512 × 512 × 24 ≈ 630 万比特,压缩约 470 倍。这么激进的压缩必然丢掉大量细节——图中的小字、细纹理首当其冲,所以离散 token 的模型在 OCR 等任务上吃亏(05 号文件的演示 1)。

练习 7(动手): (a) 在 02_clip_siglip.py 中,把批次 16 的训练步数改成 4800(和批次 256 训练 300 步看到的样本数相同),再比较 CLIP 和 SigLIP。 (b) 在 03_llava.py 中,把投影层换成两层 MLP,比较 VQA 准确率。 (c) 在 05_vq_tokens.py 中,把写了数字的图片也加进 k-means 的训练数据,数字区域的误差会怎样?


10. 延伸阅读

  • CS336 Spring 2026 Lecture 17(stanford-cs336/lectures 中的 lecture_17.py)。
  • 编码图片:Dosovitskiy et al.,An Image is Worth 16x16 Words(2020,ViT);Radford et al.,Learning Transferable Visual Models From Natural Language Supervision(2021,CLIP);Cherti et al.(2022,OpenCLIP 的规模定律);Zhai et al.,Sigmoid Loss for Language Image Pre-Training(2023,SigLIP);Tschannen et al.(2025,SigLIP 2)。
  • 视觉语言模型:Liu et al.,Visual Instruction Tuning(2023,LLaVA);Liu et al.,Improved Baselines with Visual Instruction Tuning(2023,LLaVA-1.5);Li et al.,LLaVA-OneVision(2024);Bai et al.,Qwen-VL(2023);Wang et al.,Qwen2-VL(2024);Qwen Team,Qwen3-VL Technical Report(2025);Meng et al.(2024,DeepStack)。
  • 离散 token 与全模态:van den Oord et al.,Neural Discrete Representation Learning(2017,VQ-VAE);Chameleon Team,Chameleon: Mixed-Modal Early-Fusion Foundation Models(2024)。

11. 下一讲预告

课程的主体到这里就结束了(原课最后两讲是嘉宾讲座)。最后一讲是我们自己加的全流程实战:把前面所有的部件串起来,从零训练一个小模型——

  • 准备数据(生成一个语料库,或者用你自己的文本),训练 BPE 分词器,把数据编码成 uint16 的二进制文件;
  • 选择模型配置,估算参数量、FLOPs、显存和训练时间;
  • 训练:学习率预热 + 余弦衰减、梯度裁剪、定期评估、保存与恢复检查点、记录日志;在 CPU、Apple MPS、NVIDIA GPU 上都能跑;
  • 生成与评估:采样、验证集损失、每字节比特数、与简单基线比较。
← 返回课程目录