第 17 讲:对齐 —— 多模态

目录 · ← l16 · appendix →

第 17 讲:对齐 —— 多模态

日期:5 月 27 日(周三,Spring 2026) | 讲师:Percy Liang | 材料:lecture_17.py(第 18–19 讲为客座讲座:Daniel Selsam、Dan Fu,无公开材料)

概览

世界是多模态的;终极目标是全能模型(omni model)——能输入与输出任意模态组合。由于 Transformer “只会说 token”,一切都要被转换成 token。本讲覆盖如何输入非文本数据(CLIP/SigLIP 对比学习编码器、ViT)、如何把图像编码注入 LLM(LLaVA 及其后继、Qwen-VL 1/2/3),以及迈向生成的一步——Chameleon 的”全离散(VQ-VAE)token”方案,以及混合文本/图像自回归建模的训练稳定性挑战。

核心概念与定义

  • 两个问题:(1) 如何输入非文本数据(理解图像/音频/视频);(2) 如何输出非文本数据(生成图像/音频)。理解与生成所需要的表征可能不同(语义 vs 精细细节)。
    • 类比:描述一张照片(理解)只需要抓住大意;把它重画出来(生成)要求像素级还原。同一种编码很难同时满足两者。
  • CLIP(Contrastive Language-Image Pretraining):同时训练图像编码器与文本编码器,使配对的 (图像, 文本) 相似度高、不配对的相似度低——在约 32K 的批次上做批级排序目标。
    • 数据:从网络抓取的 4 亿对 (图像, 描述)(未公开;OpenCLIP 用 LAION-5B 复现)。
    • 视觉编码器:ViT(或 ResNet);最佳配置 ViT-L/14@336px;attention pooling;图像缩放(短边 336)+ 中心裁剪。
    • 文本编码器:GPT-2 风格 Transformer(63M);编码 [BOS]…[EOS],取最高层的 [EOS] 激活。
    • 标志性结果:zero-shot CLIP 在 ImageNet 上超过用 120 万张 ImageNet 图训练的 ResNet-50。消融显示:直接”由图预测文本”的计算效率远低于 CLIP 式排序。
    • 类比:CLIP 像一个学生,通过把成千上万张照片与说明文字配对来学会”猫是什么”——没人告诉它”这是猫”,但描述的共现教会了它这个概念。
  • SigLIP:思路相同,但把批级 softmax 换成逐对二分类(是否配对)——从而把 batch size 与损失解耦,在 <16K 的 batch 下表现更好;32 块 TPUv4 训 5 天 vs CLIP 的 256 块 TPUv3 训 10 天。数据:WebLI(十亿级网络图文对,OCR 过滤,100 种语言)。
  • LLaVA(Large Language and Vision Assistant):标准的 VLM 模板——视觉编码器(CLIP)+ 投影器 + LLM(Vicuna)
    • 数据:基于 MS-COCO 图像、由 GPT-4 生成的 15.8 万条对话(把描述/检测框变成问题与对话)。
    • 训练:阶段 1(对齐):冻结视觉编码器与 LLM,只训练投影器 W;阶段 2(微调):冻结视觉编码器,训练 W 与 LLM。
    • AnyRes(LLaVA 1.5+):按编码器原生分辨率把图像切成 a×b 块、逐块编码后拼接,以保留高分辨率(对 OCR 至关重要)。
  • LLaVA-OneVision:SigLIP 编码器(取最后一层 Transformer 前后的网格特征)、Qwen-2-72B 解码器、2 层 MLP 投影器;通过为每种模态调分辨率使单图/多图/视频产生大致相同的 token 数(”质量优先于数量”、”由易到难”训练);具备跨模态迁移(OCR → GUI 智能体、视觉提示 → 视频)。
  • Qwen-VL:OpenCLIP ViT-bigC + 1 层交叉注意力适配器(带 2D 位置编码,固定 256 长度)+ 特殊 token(<img><box><ref>);三阶段训练(冻结 LM 做对齐 → 全参数在高分辨率任务数据上训练 → 冻结编码器做指令微调)。
  • Qwen2-VL:更大的 ViT(675M);动态分辨率(224×224 块,2×2 压缩 → 66 个 token);视频 2 fps、最多 16384 个 token;MRoPE(多模态 RoPE:时间/宽/高三轴);三阶段训练。
  • Qwen3-VL:SigLIP-2 编码器 + 交错式 MRoPE([t w h t w h…] 而不是 [t t t w w w h h h])+ 显式视频时间戳;按 token 的平方根归一化损失以平衡文本与长视频序列;DeepStack 跨层适配器(把视觉信息注入多层);4 阶段预训练(适配器 → 在 8K/32K/256K 长度上全参数训练)+ 长 CoT SFT + 蒸馏 + RL。SOTA,但”做了大量数据工作,细节不多”。
  • Chameleon(迈向全能):把一切映射为离散 token:图像经 VQ-VAE(512×512 图像 → 1024 个 token,码本大小 8192;再解码回去、最小化重建损失),然后用同一个自回归 Transformer 训练混合的文本/图像 token 流——从而以统一方式既能分析又能生成。
    • 训练:阶段 1 占 80%,无监督(2.9T 文本 token + 1.5T 图文 token + 4000 亿交错 token);阶段 2 占 20%,高质量混合数据。
    • 稳定性:文本 token 熵低、图像 token 熵高 → 导致范数增长与 logit 漂移;修法:QK-normz-loss(来自第 3 讲)。
    • 取舍:优雅(纯下一 token 预测)但性能较弱——离散化丢失信息(OCR 明显吃亏)。
  • 混合模态训练稳定性:平衡图像/视频(信息密度低)与文本;按 token 的损失归一化(Qwen3-VL 的平方根技巧)可防止视频序列主导训练。

代码示例:对比损失(CLIP 风格)——概念实现

代码(Python):

import torch
import torch.nn.functional as F

def clip_loss(image_embeds, text_embeds, temperature=0.07):
    """对比损失:让每张图与其描述相互对齐(双向)。
    image_embeds, text_embeds: [batch, d](已做 L2 归一化)
    """
    image_embeds = F.normalize(image_embeds, dim=-1)
    text_embeds = F.normalize(text_embeds, dim=-1)
    logits = image_embeds @ text_embeds.T / temperature      # [B, B]
    labels = torch.arange(logits.shape[0], device=logits.device)
    loss_i = F.cross_entropy(logits, labels)                 # 图 -> 文
    loss_t = F.cross_entropy(logits.T, labels)               # 文 -> 图
    return (loss_i + loss_t) / 2

代码做了什么: 在一个批次内构造图像与描述的 B×B 相似度矩阵,用对称交叉熵训练”每张图更偏好自己的描述而非其他描述”(反之亦然)——即 CLIP 目标(SigLIP 则用逐对 sigmoid 的二分类损失替代它)。

实现深挖:

  • 为什么对称(双向):匹配必须是双向的——图像检索文本、文本检索图像;这也把训练信号翻倍。
  • 为什么需要大 batch:对比损失的难度(负样本数量)随 batch 增大而增大——CLIP 用了约 32K;SigLIP 的二分类改写把 batch size 与损失解耦(这是它效率的关键)。
  • 为什么有 temperature:把 logits 缩放到交叉熵可用的范围(实践中可学习)。
  • 为什么要归一化:余弦相似度(L2 归一化)避免嵌入模长带来的伪影。

与作业的联系:作业不直接实现它,但架构模式(编码器 + 投影 + LLM)与评测思维(第 12 讲的基准,含多模态 HLE)都适用。作业 4 的质量分类器训练也用了类似对比的思想(正负样本对 → fastText)。

代码示例:LLaVA 式视觉语言模型(架构草图)

代码(Python):

import torch
from torch import nn

class LLaVA(nn.Module):
    def __init__(self, vision_encoder, projector, llm):
        super().__init__()
        self.vision_encoder = vision_encoder   # 冻结的 CLIP/SigLIP ViT
        self.projector = projector             # 例如 2 层 MLP(或线性层 W)
        self.llm = llm                          # 语言模型

    def forward(self, images, input_ids, pixel_values=None):
        # 1. 编码图像 -> patch 嵌入(或网格特征)
        img_feats = self.vision_encoder(images)          # [B, num_patches, d_vit]
        # 2. 投影到 LLM 的嵌入空间
        img_tokens = self.projector(img_feats)           # [B, num_patches, d_model]
        # 3. 把图像 token 与文本 token 交错,走标准 LM 前向
        #    (例如把 <image> token 放进序列,配合因果掩码)
        return self.llm(input_ids=input_ids, img_tokens=img_tokens)

代码做了什么: 勾画标准 VLM:冻结的视觉编码器产出 patch 特征,投影器把它们映射进 LLM 的嵌入空间,LLM 消费交错的图像/文本 token 流。

实现深挖:

  • 为什么要冻结视觉编码器:LLaVA 阶段 1(对齐)冻结编码器与 LM、只训练投影器——便宜且稳定;阶段 2 再解冻 LM。Qwen-VL 的阶段 1 反过来冻结 LM、训练编码器 + 适配器——”冻结哪一部分”是反复出现的设计决策。
  • 为什么投影器重要:线性投影(LLaVA)最简;2 层 MLP(OneVision)与交叉注意力适配器(Qwen-VL)在容量与 token 数之间做权衡。投影器负责把 d_vit → d_model。
  • 为什么分辨率处理(AnyRes)必不可少:CLIP 式的缩放+裁剪会毁掉精细信息(OCR、图表);按原生分辨率切块能保留细节——代价是更多 token(因此 OneVision 要为每种模态单独调分辨率)。

与作业的联系:这是现代开源 VLM 的架构谱系;虽然作业 1–5 都是纯文本,但分词那一讲的原则(第 1 讲:”把一切转成 token”)正是它向图像(Chameleon 的 VQ-VAE)的延伸,而训练稳定性技巧(QK-norm、z-loss)你在作业 1 的模型实现中也会再次遇到。

关键要点

  1. 全能模型的目标:任意输入 → 任意输出;今天的答案是”把一切转成 token”(文本与 Chameleon 图像用离散 token,CLIP 式注入用连续嵌入)。
  2. CLIP/SigLIP 通过对比学习给出与文本对齐的图像编码器;SigLIP 的二分类损失效率高得多(与 batch size 解耦)。
  3. 标准 VLM 配方:冻结/半冻结的视觉编码器 + 投影器 + LLM,配合分阶段训练(对齐 → 微调 → 指令微调)与保分辨率技巧(AnyRes、动态分辨率、MRoPE)。
  4. 生成需要离散或连续的输出 token:Chameleon 的 VQ-VAE 方案优雅但丢失细节;扩散模型是高保真生成的另一条路。
  5. 混合模态训练并不稳定(logit 漂移、范数增长):QK-norm、z-loss 与逐 token 损失归一化是实用解法。

常见陷阱

  • 破坏分辨率:缩放到 336×336 再裁剪会毁掉 OCR/阅读类任务;要用 AnyRes/动态分辨率流程。
  • 模态不平衡:长视频序列会主导损失;要按 token 归一化(平方根技巧)或平衡数据。
  • 混合训练不稳定:图像 token 熵高;没有 QK-norm/z-loss 会出现 logit 漂移与范数增长。
  • 冻结策略搞错:忘记各阶段冻结的是编码器、LM 还是投影器,会破坏分阶段训练配方。
  • 离散 token 的信息损失:VQ-VAE 离散化会损害细粒度任务(OCR);选择 Chameleon 式建模前要清楚这个取舍。
  • 位置编码冲突:RoPE 遇到视频/多图轴需要 MRoPE/交错方案;朴素位置编码无法处理三维(时间、高、宽)token 网格。

复习题

  1. 问: 为什么 SigLIP 在同质量下比 CLIP 便宜这么多?
    • 答: CLIP 的损失是批次内 B×B 的 softmax(对所有配对做对比),需要巨大 batch 才有足够负样本。SigLIP 把每个 (图像, 文本) 对当作独立的二分类(sigmoid),把 batch size 与损失解耦——因此用少得多的 TPU 就能训好(32 块 TPUv4 训 5 天 vs CLIP 的 256 块 TPUv3 训 10 天)。
  2. 问: LLaVA 训练的各个阶段分别冻结了什么?
    • 答: 阶段 1(特征对齐):冻结视觉编码器与 LLM,只训练投影器 W。阶段 2(端到端微调):冻结视觉编码器,训练投影器 + LLM(在指令数据上)。(Qwen-VL 的变体是先冻结 LM、训练编码器 + 适配器。)
  3. 问: 为什么 Chameleon 需要 VQ-VAE?它的主要弱点是什么?
    • 答: 为了让图像能被与文本相同的自回归 Transformer 生成,图像必须变成离散 token——VQ-VAE 用重建损失把图像 patch 映射为码本索引(512×512 → 1024 个 token)。弱点是离散化丢失细粒度信息(例如 OCR 细节),使它在理解类任务上不如连续编码器方案。