Flamingo 与门控交叉注意力:少样本 VLM 本节摘要:DeepMind 的 Flamingo(2022)抢在所有人之前做了两件事。它证明单一模型可以处理图像、视频、文本任意交错的序列;也证明 VLM 能上下文内学习——给一个含三对(图像,caption)示例的少样本 prompt,模型就能给新图配 caption,无需任何梯度更新。机制是:门控交叉注意力层,插在冻结 LLM 现有层之间,用一个初始化为零、可学习的 tanh 门,确保初始化时 LLM 的文本能力不被破坏。本节走读 Flamingo 的 Perceiver resampler 与门控交叉注意力架构——Gemini 交错输入与 Idefics2 视觉 token 的祖先。
本节摘要:DeepMind 的 Flamingo(2022)抢在所有人之前做了两件事。它证明单一模型可以处理图像、视频、文本任意交错的序列;也证明 VLM 能上下文内学习——给一个含三对(图像,caption)示例的少样本 prompt,模型就能给新图配 caption,无需任何梯度更新。机制是:门控交叉注意力层,插在冻结 LLM 现有层之间,用一个初始化为零、可学习的 tanh 门,确保初始化时 LLM 的文本能力不被破坏。本节走读 Flamingo 的 Perceiver resampler 与门控交叉注意力架构——Gemini 交错输入与 Idefics2 视觉 token 的祖先。
阅读完本节,你应当能够:
tanh(gate) = 0 在初始化时保留冻结 LLM 的文本能力。BLIP-2 把 32 个视觉 token 喂进冻结 LLM 的输入层,适合每条 prompt 一张图。但如果你想喂很多张与文本交错的图,比如「这是图 A,给它配 caption;这是图 B,给它配 caption;现在这是图 C,配 caption」呢?LLM 的自注意力得在一条流里同时处理图像 token 与文本 token,而「哪些位置能看到哪几张图」会变得很麻烦。
Flamingo 的回答:完全不动 LLM 的输入流。在 LLM 现有层之间插入额外的交叉注意力层。文本 token 照旧流过 LLM 的因果自注意力。每隔几层,文本 token 还通过一个新的门控层交叉关注图像特征。门(初始化为零)意味着第零步时这些新层是空操作——模型表现得和预训练 LLM 一模一样。随着训练推进,门逐渐打开,视觉信息开始流入。
Flamingo 回答的第二个问题:每条 prompt 的图像数可变(0、1 或多张)怎么办?用 Perceiver resampler——一个小型交叉注意力模块,无论你有几个 patch,都产出固定数量的视觉 latent token。LLM 交叉注意力层看到的形状与 prompt 里有多少张图无关。
Flamingo 从冻结的 Chinchilla 70B 起步,700 亿权重原封不动,既有的文本自注意力与 FFN 正常运行。
对 prompt 里的每张图,ViT 产出 N 个 patch token。Perceiver resampler 有 K 个固定的可学习 latent(Flamingo 用 K=64)。每个 resampler 块有两个子步:
经过 6 个 resampler 块后,无论 ViT 产出多少 patch,输出都是 K=64 个、维度 1024 的视觉 token。224×224 的图(196 patch)和 480×480 的图(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 = gated
alpha 是可学习标量,初始化为零。tanh(0) = 0,故初始化时门控分支贡献为零。alpha 偏离零,交叉注意力贡献平滑增长。这是 Flamingo 单一最重要的设计选择:视觉条件化是加性的、门控的、初始化为零。第零步的 Flamingo 在纯文本输入上就是一个完美的 Chinchilla 70B。
在像「<图A> captionA <图B> captionB <图C> ?」这样的 prompt 里,每个文本 token 只应看到在序列中位于它之前的图。交叉注意力掩码强制:位置 t 的文本 token 只关注其图像索引 i < i_t 的图像 resampler token,其中 i_t 是位置 t 之前最近的图。「只看最近的前一张图」或「看所有前面的图」都成立;Flamingo 选前者。
一个 Flamingo prompt 长这样:
<图1> A photo of a cat. <图2> A photo of a dog. <图3> A photo of a
模型看到补全模式,输出「bird」(或图 3 里的东西)。零梯度步。冻结 LLM 的上下文学习能力透过门控交叉注意力延续——这是论文的点睛之笔,也是它重要的原因。
Flamingo 在三个数据集上训练:
OBELICS(2023)是这个交错网页语料的开源复现,Idefics、Idefics2 以及大多数开源「类 Flamingo」模型都在它上面训练。
OpenFlamingo(2023) 是开源复现,架构完全一致(Perceiver resampler + 冻结 LLaMA 或 MPT 上的门控交叉注意力),提供 3B、4B、9B 的 checkpoint。因基础 LLM 更小、数据更少,质量落后于 Flamingo。
Otter(2023) 在 OpenFlamingo 基础上,用 MIMIC-IT(多模态指令数据集)做指令微调,证明门控交叉注意力也适用于指令跟随。
| BLIP-2 | Flamingo | |
|---|---|---|
| 视觉桥 | 输入层一次性的 Q-Former | 每 M 层一个门控交叉注意力 |
| 视觉 token | 每图 32 个 | 每图每交叉注意力层 64 个 |
| 冻结 LLM | 是 | 是 |
| 上下文内少样本 | 弱 | 强——论文核心 |
| 交错输入 | 无原生支持 | 是,设计目标 |
| 训练数据 | 1.3 亿对 | 13 亿对 + 4300 万交错页 |
| 参数量 | 训练 1.88 亿 | 训练约 100 亿(交叉注意力层) |
| 算力 | 8 张 A100 训几天 | 数千 TPUv4 训几周 |
预算有限做单图 VQA 选 BLIP-2;做交错、少样本、多图推理选 Flamingo/Idefics2。
code/main.py 演示:
alpha = 0 → 输出等于输入(LLM 不变);alpha = 2.0 → 视觉贡献混入。# 输入: 文本隐藏态 x (T, D), resampler 输出 v (K, D), 可学习 alpha (标量, init 0) q = x @ Wq # Q 来自文本 k = v @ Wk # K 来自视觉 latent val = v @ Wv attn = softmax(q @ k.T / sqrt(D), axis=-1) # (T, K) cross = attn @ val # (T, D) gated = tanh(alpha) * cross + x # 残差叠加, alpha=0 时退化为 x
💡 关键设计:
tanh(alpha)把门控约束在(-1, 1),即便训练后alpha很大,视觉贡献也只会平滑增长,不会爆炸性地覆写文本表示。初始化alpha=0是「不破坏预训练」的保险。
# 输入: patch P (N, D), 可学习 latent L (K, D) for block in range(6): # 交叉注意力: latent 关注 patch q, k, v = L @ Wq, P @ Wk, P @ Wv L = softmax(q @ k.T / sqrt(D)) @ v + L # 残差 # latent 内部自注意力 + FFN L = FFN(self_attn(L)) + L return L # 输出恒为 K 个 token
# 序列: [图1, 文1, 图2, 文2] # 文本 token 只看其之前最近的图 # 文1 看 图1; 文2 看 图2 (不看 图1) mask = build_interleaved_mask(seq_layout, rule="most_recent_preceding_image")
FlamingoModel 封装 Perceiver resampler + 每 M 层门控交叉注意力,提供冻结 LLaMA/MPT 的 3B/9B checkpoint,API 暴露 alpha 便于调试门控。Idefics2Model 接 OBELICS 数据流。OtterForConditionalGeneration 暴露指令拼接接口。工程取舍:需要冻结骨干 + 真正的上下文内少样本用 OpenFlamingo/Idefics;追求简化与吞吐用 Idefics2;做指令跟随用 Otter。
本节产出 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(arXiv:2308.01390)3.2 节,看它如何在每条 prompt 图像数不同时做批处理,描述其 padding 策略。
掩码选择:为什么 Flamingo 的交叉注意力掩码让文本 token 只看最近的前一张图,而非所有前面的图?读 Flamingo 论文 2.4 节解释权衡。
少样本曲线:为一个 Flamingo 变体构造 4 个「图像 → 主物体颜色」的示例 prompt,描述示例数从 0 变到 8 时预期的准确率曲线。
gated = tanh(alpha)·cross + x,alpha 初始化为零,第零步模型就是完美的 Chinchilla 70B。下一节,我们将进入 LLaVA——它丢掉 Q-Former 与门控交叉注意力,改用一个 MLP 投影器把全部 patch token 直接喂进 LLM,再用「视觉指令微调」把模型变成可对话的助手,开启了开源 VLM 的主流路线。