Flamingo 与用于少样本 VLM 的门控交叉注意力
DeepMind 的 Flamingo(2022)抢在所有人前面做了两件事。它证明了单个模型能处理任意交错的图像、视频、文本序列。它还证明了 VLM 能做 in-context 学习——给一个带三个 (图像, caption) 示例的少样本 prompt,模型就能给一张新图配上 caption,一步梯度都不走。机制是:门控交叉注意力层,插在冻结 LLM 已有的层之间,配一个从零起步的可学习 tanh 门,于是 LLM 的文本能力在初始化时被完整保留。本节课走一遍 Flamingo 的 Perceiver resampler 和门控交叉注意力架构——它是 Gemini 交错输入和 Idefics2 视觉 token 的祖先。
类型: Learn 语言: Python(标准库,门控交叉注意力 + Perceiver resampler 演示) 前置要求: Phase 12 · 03(BLIP-2 Q-Former) 预计时间: ~120 分钟
学习目标
- 解释门控交叉注意力如何通过 tanh(gate) = 0 在初始化时保留冻结 LLM 的文本能力。
- 走一遍 Perceiver resampler:N 个图像 patch → 通过交叉注意力变成 K 个固定的"latent"query。
- 描述 Flamingo 如何用尊重图像位置的因果掩码来处理交错的图文序列。
- 复现一个少样本多模态 prompt 结构(3 个图-caption 示例后接一张查询图)。
问题背景
BLIP-2 把 32 个视觉 token 喂进冻结 LLM 的输入层。每个 prompt 一张图时这能用。但如果你想喂很多张图、和文本交错呢,就像"这是图 A,给它配 caption;这是图 B,给它配 caption;现在这是图 C,给它配 caption"?LLM 的自注意力就得在单一一条流里同时处理图像 token 和文本 token,而哪些位置能关注哪些图像这个问题会变得很烦人。
Flamingo 的答案:根本不改 LLM 的输入流。在已有的 LLM 块之间插入额外的交叉注意力层。文本 token 照旧流过 LLM 的因果自注意力。每隔几个 LLM 块,文本 token 还会通过一个新的门控层交叉关注图像特征。这个门(初始化为零)意味着第 0 步时新层是 no-op——模型的行为与预训练 LLM 一模一样。随着训练推进,门打开,视觉信息开始流入。
Flamingo 回答的第二个问题:每个 prompt 里图像数量可变(0 张、1 张或很多张)时怎么处理?用一个 Perceiver resampler——一个小型交叉注意力模块,无论你有多少个 patch,都产出固定数量的视觉 latent token。无论 prompt 里有几张图,LLM 的交叉注意力层看到的形状都一样。
核心概念
冻结的 LLM
Flamingo 从一个冻结的 Chinchilla 70B LLM 起步。全部 70B 权重原封不动。已有的文本自注意力和 FFN 正常运转。
Perceiver resampler
对 prompt 里的每张图,ViT 产出 N 个 patch token。Perceiver resampler 有 K 个固定的可学习 latent(Flamingo 用 K=64)。每个 resampler 块分两个子步骤:
- 交叉注意力:K 个 latent 关注 N 个 patch token(Q 来自 latent,K/V 来自 patch)。
- latent 内部的自注意力 + FFN。
过完 6 个 resampler 块,输出是 K=64 个维度 1024 的视觉 token,无论 ViT 产出了多少 patch。一张 224x224 的图(196 个 patch)和一张 480x480 的图(900 个 patch)都以 64 个 resampler token 的形式出来。
对视频,resampler 在时间维上应用:每帧的 patch 产出 64 个 latent,一个时间位置编码让模型能区分 t=0 和 t=N。整段视频变成 T * 64 个视觉 token。
门控交叉注意力
在冻结 LLM 每隔 M 层(Flamingo 用 M=4),插入一个新的门控交叉注意力块:
x_after_llm_block = llm_block(x_before)
cross = cross_attn(x_after, resampler_output)
gated = tanh(alpha) * cross + x_after
x_before_next_block = gatedalpha是一个初始化为零的可学习标量。tanh(0) = 0,所以初始化时门控分支贡献为零。- 随着
alpha偏离零,交叉注意力的贡献平滑增长。 - 残差连接意味着即使门完全打开,也不会覆盖 LLM 的文本表示;它只是在上面叠加视觉信息。
这是 Flamingo 里最重要的一个设计选择:视觉条件是加性的、门控的、初始化为零的。第 0 步的 Flamingo 在纯文本输入上是一个完美的 Chinchilla 70B。
用于交错输入的掩码交叉注意力
在像"<image A> caption A <image B> caption B <image C> ?"这样的 prompt 里,每个文本 token 应该只看到序列中排在它前面的图像。交叉注意力掩码强制:位置 t 处的文本 token 只关注图像索引 i < i_t 的那些图像 resampler token,其中 i_t 是位置 t 之前最近的那张图。"只看最近的前一张图"和"看前面所有图"都是合法选择;Flamingo 选了前者。
in-context 少样本学习
一个 Flamingo prompt 长这样:
<image1> A photo of a cat. <image2> A photo of a dog. <image3> A photo of a模型看到这个补全模式,输出"bird"(或 image3 显示的任何东西)。不走梯度。冻结 LLM 的 in-context 学习能力穿过门控交叉注意力传递了过来——这是论文的点睛之处,也是它重要的原因。
训练数据
Flamingo 在三个数据集上训练:
- MultiModal MassiveWeb(M3W):4300 万个图文交错的网页,重建了阅读顺序。
- 图文对(ALIGN + LTIP):44 亿对。
- 视频文本对(VTP):2700 万段短视频。
OBELICS(2023)是交错网页语料的开放复现,Idefics、Idefics2 和大多数开放的"类 Flamingo"模型都在它上面训练。
OpenFlamingo 与 Otter
OpenFlamingo(2023)是开放复现。架构完全相同(Perceiver resampler + 冻结 LLaMA 或 MPT 上的门控交叉注意力)。有 3B、4B、9B 的 checkpoint。由于基座 LLM 更小、数据更少,质量落后于 Flamingo。
Otter(2023)在 OpenFlamingo 基础上用 MIMIC-IT(一个多模态指令数据集)做指令微调,证明了门控交叉注意力对指令遵循也有效。
后代
- Idefics / Idefics2 / Idefics3:Hugging Face 的门控交叉注意力一脉,逐步简化(Idefics2 砍掉了 resampler,改用带自适应池化的直接 patch token)。
- Flamingo 到 Chameleon 的转变:到 2024 年许多团队转向早融合(第 12.11 课);在需要冻结骨干的场景里,Flamingo 式门控交叉注意力仍在生产中。
- Gemini 的交错输入:概念上继承了 Flamingo 交错格式的灵活性,尽管确切机制是专有的。
与 BLIP-2 的对比
| BLIP-2 | Flamingo | |
|---|---|---|
| 视觉桥 | 输入处一次 Q-Former | 每 M 层一次门控交叉注意力 |
| 视觉 token | 每张图 32 个 | 每张图每个交叉注意力层 64 个 |
| 冻结 LLM | 是 | 是 |
| 少样本 in-context | 弱 | 强——论文的核心卖点 |
| 交错输入 | 无原生支持 | 有,正是设计目标 |
| 训练数据 | 1.3 亿对 | 13 亿对 + 4300 万交错页 |
| 参数量 | 训 188M | 训约 10B(交叉注意力层) |
| 算力 | 8 张 A100 跑几天 | 上千张 TPUv4 跑几周 |
预算有限做单图 VQA 选 BLIP-2。做交错、少样本或多图推理选 Flamingo/Idefics2。
cross-attention-fusion实际使用
code/main.py 演示:
- 在 36 个假 patch token 上跑一个带 8 个可学习 latent 的 Perceiver resampler(纯 Python 交叉注意力)。
- 一个门控交叉注意力步骤:
alpha = 0→ 输出等于输入(LLM 不变),然后alpha = 2.0→ 视觉贡献被混入。 - 一个交错掩码构建器,为"(图 1) (文本 1) (图 2) (文本 2)"序列产出二维注意力掩码。
拿去用
本节课产出 outputs/skill-gated-bridge-diagnostic.md。给定一个开放 VLM 的配置(是否有 resampler、交叉注意力频率、门控方案),它识别出 Flamingo 一脉的元素,并解释冻结策略。这对排查"为什么一次微调把文本性能搞退化了"很有用(答案:门开得太快太大了)。
练习
算一下 Flamingo-9B 的视觉参数量:9B LLM + 1.4B 门控交叉注意力层 + 64M resampler。被训练的参数占总数的多少?
用 PyTorch 实现门控残差
y = tanh(alpha) * cross + x。用实验展示:alpha=0时,初始化处y==x完全相等。读 OpenFlamingo 第 3.2 节(arXiv:2308.01390),看他们在一个 batch 里每个 prompt 图像数量不同时是怎么处理多张图的。描述其填充策略。
为什么 Flamingo 的交叉注意力掩码让文本 token 只关注最近的前一张图,而不是前面所有图?读 Flamingo 论文第 2.4 节并解释这个取舍。
in-context 少样本:为一个新的 Flamingo 变体构造一个带 4 个"图像 → 主体物体颜色"示例的 prompt。描述当你把示例数从 0 变到 8 时预期的准确率走势。
关键术语
| 术语 | 大家怎么说 | 它实际指什么 |
|---|---|---|
| Perceiver resampler | "固定 latent 交叉注意力" | 从数量可变的输入 patch 产出 K 个固定 token 的模块 |
| 门控交叉注意力 | "tanh 门控桥" | 残差层 y = tanh(alpha)*cross + x,alpha 可学习,初始为 0 |
| 交错输入 | "混合序列" | 图像和文本按阅读顺序自由混排的 prompt 格式 |
| 冻结 LLM | "无 LLM 梯度" | 文本 LLM 权重不更新;只训 resampler + 交叉注意力层 |
| 少样本 | "in-context 示例" | 在 prompt 里给几个 (图像, 答案) 对;模型无需微调即泛化 |
| OBELICS | "交错网页语料" | 一个开放数据集,1.41 亿个按阅读顺序排布图像和文本的网页 |
| Chinchilla | "70B 冻结基座" | Flamingo 冻结的文本 LLM,来自 DeepMind 的 Chinchilla 论文 |
| 门控调度 | "alpha 怎么变" | 训练中交叉注意力门打开的速率 |
| 交叉注意力频率 | "每 M 层" | 多久插入一个门控交叉注意力块;Flamingo 用 M=4 |
| OpenFlamingo | "开放复现" | MosaicML/LAION 的 3-9B 开放 checkpoint;架构与 Flamingo 完全相同 |
延伸阅读
- Alayrac et al. — Flamingo (arXiv:2204.14198) —— 原论文。
- Awadalla et al. — OpenFlamingo (arXiv:2308.01390) —— 开放复现。
- Laurençon et al. — OBELICS (arXiv:2306.16527) —— 交错网页语料。
- Jaegle et al. — Perceiver IO (arXiv:2107.14795) —— 通用的 Perceiver 架构。
- Li et al. — Otter (arXiv:2305.03726) —— 指令微调的 Flamingo 后代。
- Laurençon et al. — Idefics2 (arXiv:2405.02246) —— Flamingo 方法的现代简化版。