English: English
第十四章:多模态——超越文本¶
"Once you tokenize it, it's text. The question is just what counts as 'it'."
第一章我们说 LLM 只做一件事:预测下一个 token。本章把这个论点推向极致:只要能把它变成 token,LLM 就能处理它——图像、音频、视频、3D 模型、蛋白质序列,原则上都一样。
这就是多模态模型的核心思路。它不是"在 LLM 上又装了一个图像模块",而是把图像(或音频、视频)转换成 token 序列,喂进同一个 transformer。一旦你接受这个视角,多模态就不再神秘——它是文本 LLM 的自然延伸。
本章核心论点:
- 多模态本质就是 tokenize 的扩展——图像变成视觉 token,音频变成音频 token
- CLIP 是一切的基础——它教会模型"图像和文本可以共享一个语义空间"
- 生成图像/音频的方式根本不同——主流路径是 diffusion,不是 next-token prediction
- Omni model 是趋势——一个模型理解和生成所有模态
读完本章,你会理解 GPT-4o 的"看图能力"、Sora 的视频生成、Whisper 的语音识别、Suno 的音乐生成——它们看似不同,背后是同一套思路的不同实现。
14.1 把图像变成 token:Vision Transformer¶
文本 token 化的回顾¶
第一章里我们已经知道:tokenizer 把文本切成离散单元,每个单元映射到一个向量(embedding)。
这个向量序列就是 transformer 的输入。
图像怎么变成 token?¶
最直接的想法:把图像也切成"块",每块当一个 token。这正是 Vision Transformer (ViT) 的做法(Dosovitskiy et al., 2020, An Image is Worth 16x16 Words)。
flowchart LR
Img["原图<br>224×224×3"] --> Patch["切成 16×16 的块<br>共 14×14 = 196 块"]
Patch --> Flat["每块拉平<br>16×16×3 = 768 维"]
Flat --> Proj["线性投影<br>到 d 维 embedding"]
Proj --> Tok["196 个图像 token"]
Tok --> Trans["送进 Transformer"]
style Tok fill:#c8e6c9
具体步骤:
- 切块(patch):把 224×224 的图片切成 14×14 = 196 个小块,每块 16×16 像素
- 拉平 + 投影:每个块 16×16×3 = 768 维,过一个线性层投到 transformer 的 hidden dim
- 加位置编码:让模型知道每个 patch 在原图哪里(图像 patch 没有"自然顺序")
- 送进 transformer:和文本 token 一样处理
核心洞察:ViT 不需要任何"图像专用"的网络结构(不需要 CNN、不需要卷积)。它把图像当成"二维的 token 序列",让 transformer 自己学怎么理解。
实践证明:当数据足够多时,ViT 在图像任务上能超过经典 CNN。而且——这是关键——它和文本 transformer 是同一种架构。
Vision-Language Model:把图文 token 拼在一起¶
一旦图像也是 token 了,VLM(Vision-Language Model)的设计就显而易见:
输入: [图像 token1, ..., 图像 token196, 文本 token1, ..., 文本 tokenN]
↓
同一个 Transformer
↓
输出: 文本 token (生成回答)
flowchart LR
Img["图片"] --> ViT["视觉编码器<br>(ViT)"] --> ImgTok["图像 token"]
Txt["问题文本"] --> TT["文本 tokenizer"] --> TxtTok["文本 token"]
ImgTok --> Concat["拼接"]
TxtTok --> Concat
Concat --> LLM["统一 Transformer"]
LLM --> Out["回答(文本)"]
style Concat fill:#fff9c4
style LLM fill:#c8e6c9
GPT-4V、Claude 3、Gemini、LLaVA 都是这种结构的变体。差异在于:
- 视觉编码器用什么(ViT、CLIP 的 vision tower、自研编码器)
- 怎么把图像 token 投影到 LLM 的 embedding 空间(线性层、MLP、cross-attention)
- 训练数据多少图文对、什么质量
但核心思路就是"图像变 token,拼到文本前面"。当你看到 Claude 能"看图回答",背后做的就是这件事。
14.2 CLIP:图文对齐的基石¶
一个简单到震撼的训练目标¶
2021 年 OpenAI 发表的 CLIP(Learning Transferable Visual Models From Natural Language Supervision)改变了多模态。它的训练目标简单到不可思议:
给一批图文对(image, caption),让"匹配的对"在 embedding 空间里靠近,"不匹配的对"远离。
flowchart LR
subgraph 训练["训练目标"]
I["图像编码器"] --> Vi["图像 vec"]
T["文本编码器"] --> Vt["文本 vec"]
Vi --> S["相似度"]
Vt --> S
S --> Loss["匹配的对 → 大<br>不匹配的对 → 小"]
end
style Loss fill:#c8e6c9
具体形式(contrastive loss):
# 一批 N 个图文对
images, captions = batch # 各 N 个
# 编码
image_embs = vision_encoder(images) # N × d
text_embs = text_encoder(captions) # N × d
# 归一化
image_embs = normalize(image_embs)
text_embs = normalize(text_embs)
# 相似度矩阵 N × N
sim = image_embs @ text_embs.T # 第 [i,j] 项 = 第 i 张图和第 j 个 caption 的相似度
# 对角线元素是匹配对,应该大;其他元素应该小
# 用对称的 cross-entropy loss
labels = arange(N) # 第 i 张图应该匹配第 i 个 caption
loss = (cross_entropy(sim, labels) + cross_entropy(sim.T, labels)) / 2
这个目标产生了什么? 一个共享的语义空间:图像和文本被映射到同一个向量空间,里面"a dog running on the beach" 这句话的 embedding 和实际"狗在海滩跑步"的图片 embedding 距离很近。
为什么这是"基石"¶
CLIP 的影响远超图像分类:
应用 1:零样本图像分类
不需要训练分类器,只需要把候选标签变成文本:
labels = ["a photo of a cat", "a photo of a dog", "a photo of a car"]
text_embs = clip.encode_text(labels)
img_emb = clip.encode_image(test_image)
predicted_label = labels[argmax(img_emb @ text_embs.T)]
CLIP 把"分类问题"变成了"文本检索问题"。
应用 2:图像生成的"评分函数"
Diffusion model 怎么知道"生成的图像是否符合 prompt"?用 CLIP:把生成的图像和 prompt 各自编码,看相似度。这是 DALL-E、Stable Diffusion 早期的核心机制。
应用 3:VLM 的视觉编码器
很多 VLM 直接用 CLIP 的 vision tower 作为图像编码器。因为 CLIP 已经学到了"图像里的概念"——和文本对齐过的,这正是 VLM 需要的。
应用 4:检索(image search、text-to-image search)
把所有图像和查询文本都编码到同一个空间,向量检索就能跨模态。Pinterest、Google 图像搜索、电商的"以图搜图"都用类似机制。
共享语义空间的直觉¶
flowchart TD
subgraph Space["共享语义空间"]
Cat1["🐱 cat photo"]
CatT["'a cat'"]
Dog1["🐕 dog photo"]
DogT["'a dog'"]
Car1["🚗 car photo"]
CarT["'a car'"]
Cat1 -.- CatT
Dog1 -.- DogT
Car1 -.- CarT
end
CLIP 训练完后,"图片 embedding" 和"对应文字描述 embedding" 不是简单地相似——它们几乎重合。这意味着:在这个空间里,模态的边界被消解了。"cat" 这个概念,不管是用图片还是文字表达,对应的位置是同一个。
所有现代多模态模型都在用这个洞察。
14.3 图像生成:为什么不是 next-token?¶
一个看似自然的想法¶
既然图像可以变成 token 序列,那生成图像不就和生成文本一样吗?让 LLM 一个 token 一个 token 地预测,最后把 token 序列还原成图像。
这条路确实有人走(DALL-E 1、Parti),但目前主流的图像生成不是这样。原因要从图像的特殊性说起。
图像 token 的特殊性¶
文本 token 有几个性质:
- 离散:只有有限个 vocab
- 顺序明确:从左到右
- 每个 token 信息量大:一个 token = 一个词
图像 token 不太一样:
- 可以是离散的(用 VQ-VAE 量化)也可以是连续的
- 顺序是任意约定的(光栅扫描、Z-curve...)
- 每个 token 信息量小:一个 patch 只有几个像素,离开周围 patch 没多少意义
更要命的是:图像的依赖结构是二维的、全局的。一个像素和它上下左右的所有像素都强相关;一个图像的左上角和右下角也常常存在长程依赖(比如对称性)。
自回归地从左上扫到右下,会破坏这种二维全局结构——前面生成的内容固定后,后面生成的没法回头修。
Diffusion:从噪声里"显影"¶
主流的图像生成走的是另一条路:diffusion。
flowchart LR
subgraph 训练["训练(前向)"]
I0["原图"] -->|加噪| I1["稍微噪声"] -->|加噪| I2["更多噪声"] -->|加噪| IN["纯噪声"]
end
subgraph 生成["生成(反向)"]
N["纯噪声"] -->|去噪| GN["稍微清晰"] -->|去噪| G2["更清晰"] -->|去噪| G0["最终图像"]
end
style I0 fill:#c8e6c9
style G0 fill:#c8e6c9
style IN fill:#ffcdd2
style N fill:#ffcdd2
直觉解释:
- 训练时:拿干净的图像,逐步加噪声,训练一个网络学会"看到 t 步的噪声图,预测 t-1 步的图"
- 生成时:从纯噪声开始,反复调用这个网络,逐步去噪,最终得到清晰图像
整个生成过程是全局-到-全局的:每一步去噪都看完整张图、修改完整张图。这天然适合图像的二维全局结构。
text-to-image 的实现就是把文本 prompt 编码(用 CLIP 或类似模型),作为去噪网络的条件输入:
def text_to_image(prompt, n_steps=50):
text_emb = clip.encode_text(prompt)
image = random_noise()
for t in reversed(range(n_steps)):
image = denoiser(image, t, condition=text_emb)
return image
DiT:把 Transformer 用进 Diffusion¶
早期的 diffusion 用 U-Net 做去噪网络。最近的趋势是用 Transformer,称为 DiT (Diffusion Transformer)(Peebles & Xie, 2022, Scalable Diffusion Models with Transformers)。
DiT 的好处:
- 和 LLM 用同样的架构 → 能吃 transformer 的所有 scaling 经验
- 支持 attention → 长程依赖处理得更好
- 可以扩展到视频(在时间维度上加 attention)
OpenAI 的 Sora、Stability AI 的 Stable Diffusion 3、Google 的 Imagen 3 都用了 DiT 架构。
关键趋势:架构上,文本生成(autoregressive transformer)和图像生成(diffusion transformer)正在收敛——都是 transformer,差别在训练目标。
Autoregressive 图像生成的回归¶
最近也有"复活"自回归图像生成的工作(如 LlamaGen、Anthropic 的某些实验、Google 的 Parti 后续)。它们用更聪明的 tokenize 方法(VQ-VAE 的改进),让 next-token prediction 在图像上效果接近 diffusion。
哪条路最终胜出还在博弈中。但工程上你今天最常打交道的,仍然是 diffusion。
14.4 音频:听与说¶
听:Whisper¶
OpenAI 的 Whisper(2022, Robust Speech Recognition via Large-Scale Weak Supervision)是开源 ASR (Automatic Speech Recognition) 的事实标准。它的设计也很 transformer:
flowchart LR
Audio["音频<br>(波形)"] --> Spec["梅尔频谱<br>(2D 特征图)"]
Spec --> Enc["Encoder<br>(Transformer)"]
Enc --> Hid["音频表示"]
Hid --> Dec["Decoder<br>(Transformer)"]
Dec --> Text["文本"]
style Hid fill:#c8e6c9
关键点:
- 输入不是原始波形,而是梅尔频谱图(mel-spectrogram)——一种把音频变成"频率随时间变化"的 2D 表示
- 频谱图被切成时间块,每块当一个 token(类似 ViT 的 patch)
- Encoder-Decoder 架构(少见——大部分现代 LLM 是 decoder-only),decoder 输出文本 token
Whisper 的训练数据:从互联网爬的 68 万小时多语言音频 + 字幕。规模驱动了它的鲁棒性——它能处理各种口音、背景噪声、专业术语。
说:TTS 的两种思路¶
Text-to-Speech (TTS) 的目标反过来:文本 → 音频。
思路 1:tokenize 音频,然后 next-token prediction
代表作:Tortoise TTS、Bark、Meta 的 Voicebox、Anthropic 的某些实验。
# 用一个 audio tokenizer(如 EnCodec、SoundStream)把音频切成离散 token
audio_tokens = audio_tokenizer.encode(reference_voice)
# 训练一个 LLM 学习: text → audio_tokens
prompt = f"<text>{input_text}</text>"
generated_audio_tokens = llm.generate(prompt)
# 解码回波形
audio = audio_tokenizer.decode(generated_audio_tokens)
思路 2:直接生成声学特征 + vocoder
代表:Tacotron、FastSpeech 系列。
第一种思路更现代、更接近"统一架构"的方向;第二种更传统但工程成熟。
近期的 GPT-4o voice、Gemini Live 走的是更激进的路线:端到端音频对话——音频输入 → LLM 直接处理 → 音频输出,中间没有"文本"中转。这避免了"文本中转损失情感、节奏、停顿"的问题。
14.5 视频:最贵的模态¶
视频可以理解为"图像 + 时间维度"。Tokenize 的思路是 3D patches:
flowchart LR
Vid["视频<br>(T 帧 × H × W × 3)"] --> P3D["3D patches<br>(t × h × w 的小立方块)"]
P3D --> Tok["视频 token<br>(数量 = T/t × H/h × W/w)"]
style Tok fill:#fff9c4
数量爆炸的问题:一个 5 秒、24fps、1024×1024 的视频,按 8×16×16 的 patch 切,token 数量是:
一个 1 分钟的视频就是百万 token 级别。这是为什么视频生成(Sora、Veo、Kling、Runway)极度昂贵——每一秒视频都是巨大的 attention 计算。
Sora 的核心思路¶
OpenAI 的 Sora(2024)应用了 DiT + 3D patches + 大规模训练:
- 统一表示:图像、视频都被表示成"时空 patch"序列(图像 = 单帧的退化情形)
- DiT 架构:在时空 patch 上做 diffusion
- VAE 压缩:先把视频压缩到一个 latent space(节省计算),diffusion 在 latent 里做
- 海量训练数据:网页视频 + 合成(其他模型生成的)字幕
flowchart LR
V["视频"] --> VAE_E["VAE encoder<br>(压缩)"]
VAE_E --> Lat["Latent 时空 patches"]
Lat --> DiT["DiT diffusion"]
Cap["文本 caption"] --> DiT
DiT --> LatGen["生成的 latent"]
LatGen --> VAE_D["VAE decoder<br>(还原)"]
VAE_D --> Out["生成视频"]
目前视频生成的工程现实:
- 几秒视频生成需要数十秒到几分钟
- 高分辨率成本极高(一段高清视频生成可能花几美元 API 成本)
- 物理一致性还是挑战(液体、布料、人脸长时间一致性)
- 长视频(>1 分钟)质量退化明显
视频是"最贵的模态、最大的机会"——市场需求极大(影视、广告、教育、游戏),但技术尚未成熟到大规模应用。
14.6 Omni Models:一个模型理解一切¶
趋势¶
2024 年开始的趋势:单一模型同时处理所有模态——不是"文本模型 + 视觉模型 + 音频模型"组合,而是从训练阶段就把所有模态混在一起。
代表:GPT-4o(OpenAI)、Gemini(Google)、Claude(Anthropic 的视觉支持)、Llama 3.2 vision、Qwen-VL 系列。
为什么 omni 是趋势¶
好处 1:模态间知识迁移
如果模型同时学过"猫的图片"、"猫的描述文字"、"猫叫的录音",它对"猫"这个概念的理解会比单模态模型深。
好处 2:跨模态任务变得自然
"听一段音频,看一张相关图片,写一段文字总结" —— omni 模型可以一次完成,不需要中间转换。
好处 3:更少的模型,更简单的部署
一个模型、一套权重、一个 API 就能搞定多模态需求。
Omni 模型的架构¶
flowchart LR
Img["图像"] --> ImgTok["图像 tokenizer<br>(ViT patches)"]
Aud["音频"] --> AudTok["音频 tokenizer<br>(频谱 patches 或 codec)"]
Vid["视频"] --> VidTok["视频 tokenizer<br>(3D patches)"]
Txt["文本"] --> TxtTok["BPE tokenizer"]
ImgTok --> Mix["统一的 token 序列"]
AudTok --> Mix
VidTok --> Mix
TxtTok --> Mix
Mix --> Trans["统一 Transformer"]
Trans --> OutTxt["文本输出"]
Trans --> OutAud["音频输出"]
Trans --> OutImg["图像输出(可选)"]
style Mix fill:#c8e6c9
style Trans fill:#c8e6c9
各模态共享:
- 同一个 transformer
- 同一套 attention
- 同一个 hidden dim
差异只在两端:
- 输入端:每种模态有自己的 tokenizer
- 输出端:根据任务选择 decoder(文本 token、音频 token、图像 latent)
工程上意味着什么¶
对于应用开发者:
1. 你不需要拼模型了
以前要做"看图回答",要么用商业 API(GPT-4V),要么自己拼 BLIP/CLIP + LLM。现在用 Claude / Gemini / GPT-4o 一个 API 就能搞定。
2. 多模态 prompt 是新技能
# 例如 Anthropic API
response = client.messages.create(
model="claude-opus-4-7",
messages=[{
"role": "user",
"content": [
{"type": "image", "source": {...}}, # 图片
{"type": "image", "source": {...}}, # 另一张图
{"type": "text", "text": "对比这两张图的差异"},
]
}]
)
第九章讨论的所有 prompt 工程原则都适用——只是 prompt 现在是多模态的。
3. 评估也要多模态
第十二章的 eval 框架要扩展。比如 VLM 的 eval 通常包括:
- VQA(Visual Question Answering)准确率
- 图像描述质量(BLEU、CIDEr、人评)
- OCR 准确率(看图认字)
- 图表理解
- 多图推理
14.7 多模态系统的工程现实¶
把这一章落到实践,几个值得知道的事:
1. 模态成本不一样¶
| 模态 | 1 个 token 的成本(粗略) |
|---|---|
| 文本 | 1x |
| 图像(每张约 1000 tokens) | 1000x |
| 视频(每分钟约 10 万 tokens) | 100000x |
| 音频(每分钟约 1500 tokens) | 1500x |
视频处理是文本的几个数量级。设计系统时这个成本结构必须放进决策。
2. 多模态延迟分布¶
视频/音频生成通常是异步的(生成时间长,用户必须等)。这影响产品形态:
- 文本聊天 → 实时
- 图像生成 → 几秒等待
- 视频生成 → 任务式,发邮件通知
3. 多模态模型的失败模式¶
VLM 有自己独特的失败模式(除了文本 LLM 已有的):
- OCR 不准:看图认字仍然不可靠(尤其是手写、倾斜、低分辨率)
- 数数不准:图里有几个人?模型经常算错
- 空间关系混乱:"左边的杯子" vs "右边的杯子" 经常分不清
- 看图编故事:被问到图中没有的东西时会编造(multimodal hallucination)
- 看不到细节:图像被压缩成有限的 token,细节丢失
不要假设"看图 = 像人一样看图"。多模态模型有自己的 token 化导致的盲区——和第六章讲的"strawberry 数 r"是同一类问题。
4. 安全和隐私的新维度¶
- 用户上传图片可能包含 PII(脸、身份证、地址)
- 生成的图像可能侵权(训练数据里的画家风格)
- 深度伪造、虚假视频
- 跨模态的 prompt injection(图片里嵌入"忽略上述指令"的文字)
多模态扩大了攻击面。设计系统时要考虑。
14.8 一个反直觉的思考:模态会不会消失?¶
最后一节留个开放思考:
当模型足够强大时,"模态"这个概念可能本身就是一个工程方便的分类,而不是模型内部的真实区分。
人脑不会把"看花的图像"和"花"这个词分成两个独立系统——它们指向同一个概念表征。我们今天给模型分"视觉编码器、文本编码器、音频编码器",更多是工程上的便利(已有的预训练模型可以拼装),而不是模型本身需要这种分割。
未来的 omni 模型可能:
- 没有"视觉编码器"和"文本编码器"——所有输入用同一个统一的 tokenizer
- 没有"图像生成 head"和"文本生成 head"——所有输出用同一个统一的 decoder
- 模态成为一个任意属性("输出 4K 视频"和"输出 100 字总结"是同样的指令)
这条路在研究上已经在走(如 Meta 的 Chameleon、Google 的 Pathways、Anthropic 的多模态实验)。
如果这一步走通,第一章的论点会变得更彻底:LLM 真的就只做一件事——预测下一个 token。只不过 token 的含义被推到了极致。
总结¶
| 问题 | 答案 |
|---|---|
| 多模态的核心思路 | 把所有模态变成 token,喂进同一个 transformer |
| 图像怎么变 token | ViT:切成 patches,每个 patch 是一个 token |
| CLIP 的贡献 | 教会模型"图像和文本可以共享一个语义空间" |
| 为什么图像生成不用 next-token | 图像的二维全局依赖结构不适合自回归;diffusion 更自然 |
| Sora/视频生成的核心 | DiT + 3D 时空 patches + VAE 压缩 |
| 音频识别(Whisper)的设计 | 频谱图 → patches → encoder-decoder transformer |
| Omni model 是什么 | 一个模型同时理解和生成所有模态 |
| 工程现实 | 模态成本差几个数量级,失败模式各有不同 |
下一章是最后一章:站到当下,看 LLM 的未来——scaling 会撞墙吗?工程师这个角色会变成什么?
延伸阅读¶
- Dosovitskiy et al., 2020: An Image is Worth 16x16 Words (ViT) — Vision Transformer 开山作
- Radford et al., 2021: Learning Transferable Visual Models from Natural Language Supervision (CLIP) — 图文对齐基石
- Ho et al., 2020: Denoising Diffusion Probabilistic Models — Diffusion 的核心论文
- Peebles & Xie, 2022: Scalable Diffusion Models with Transformers (DiT) — DiT 架构
- Radford et al., 2022: Whisper — 大规模弱监督语音识别
- OpenAI, 2024: Video generation models as world simulators (Sora technical report) — Sora 技术报告
- Liu et al., 2023: Visual Instruction Tuning (LLaVA) — 开源 VLM 的代表
- Team Chameleon (Meta), 2024: Mixed-Modal Early-Fusion Foundation Models — 早期融合的统一模型