目录
第五课的逐位置 Projector 把每条视觉向量转换到语言宽度,通常保留原来的 Token 数。如果视觉编码器给出很多位置,能不能先提取成少量向量,再交给 LLM?
Q-Former 使用一组可学习查询,从视觉特征中读取信息。可以把它想成几张等待填写的笔记卡:每张卡根据当前图片选择怎样汇总内容,而不是直接保留某个固定 Patch。BLIP-2 用这类模块连接冻结的视觉编码器与语言模型。[1]
1、先看六个位置怎样变成两条表示
假设视觉编码器产生六条特征,准备两条查询,让每条查询都能读取这六个位置,最终得到两条包含图像信息的输出。两条查询的初始向量是共享模型参数,但读取后的输出随图片改变;它们没有预先规定“第一条看角色,第二条看背景”。
图中的 6 与 2 只是教学例子。原始 BLIP-2 实验使用 32 条查询,每条宽度 768,再将输出投影到 LLM 所需宽度;查询数是配置,不是 Q-Former 的固定定义。[1]
2、查询怎样读取视觉特征?
2.1 Cross-Attention:Q 和 K、V 来自不同地方
设查询状态为 $U\in\mathbb R^{M\times d_q}$,视觉特征为 $H\in\mathbb R^{N\times d_v}$。忽略 Batch,以单个 Head 为例:
\[Q=UW_Q,\qquad K=HW_K,\qquad V=HW_V\] \[A=\operatorname{softmax}_{\text{每行}}\left(\frac{QK^T}{\sqrt{d_h}}\right),\qquad O=AV\]$Q$ 来自查询,$K$ 与 $V$ 来自视觉特征,所以叫交叉注意力;Self-Attention 则从同一组状态生成三者。$d_h$ 是 Head 宽度,投影让不同来源的向量能够参与比较。
| 张量 | 形状 | 怎样读 |
|---|---|---|
| Q | [M,dh] |
M 条查询 |
| K、V | [N,dh] |
N 个视觉位置 |
| A | [M,N] |
每条查询对全部视觉位置的权重 |
| O | [M,dh] |
每条查询读到的结果 |
2.2 一条查询是一组加权读取
如果第一条查询的权重是 [0.5,0.2,0.1,0.1,0.05,0.05],输出就是对应六条 V 的加权和。它偏重第一个位置,但没有把其他位置直接删掉;第二条查询可以使用另一组权重。
因此输出条数由查询数 $M$ 决定,而不是视觉位置数 $N$。这些输出是汇总后的表示,不能再简单当成与原始网格一一对应的 Patch。
2.3 完整 Q-Former 不只有一次读取
Q-Former 还包含查询之间的 Self-Attention、前馈网络和残差等结构,查询状态可逐层交流并再次读取视觉信息。原始 BLIP-2 的训练还涉及文本分支和任务对应的注意力掩码;一层 Cross-Attention 只能演示其中的读取机制。[1]
3、这些查询怎样学会读取有用信息?
随机查询能产生正确形状,却不保证有用。原始 BLIP-2 先做图文表示学习,再接入冻结 LLM 做生成学习:前一步包含图文对比、匹配与图像条件文本生成,后一步让查询输出支持语言生成。[1]
可以把训练过程理解为“先学提取适合语言任务的视觉信息,再学怎样交给语言模型”。最终仍需要投影匹配 LLM 的宽度,Q-Former 和 Projector 并不是互相排斥的两种模块。
冻结 LLM 只是不更新其参数,如果要从答案损失训练上游查询模块,仍需保留穿过 LLM 的梯度路径。
4、最小代码:亲手检查输出条数
下面用 PyTorch 演示六条视觉特征被两条查询读取。特征随机生成,代码没有完整 Q-Former 的训练目标与文本分支,也不代表已经提取出语义。
import torch
from torch import nn
torch.manual_seed(0)
batch, n, m, dim = 2, 6, 2, 8
visual = torch.randn(batch, n, dim)
queries = nn.Parameter(torch.randn(1, m, dim))
attention = nn.MultiheadAttention(
embed_dim=dim, num_heads=2, batch_first=True
)
u = queries.expand(batch, -1, -1)
output, weights = attention(u, visual, visual)
print(output.shape) # torch.Size([2, 2, 8])
print(weights.shape) # torch.Size([2, 2, 6])
# weights 是默认按 Head 平均后的注意力权重
print(weights.sum(dim=-1)) # 每条查询的权重总和约为 1
把 n 改成 12,输出仍然只有两条;把 m 改成 4,输出才会变成四条。这两个修改分别改变“有多少信息可读”和“用多少个位置承载结果”。
5、少量输出带来什么,又会失去什么?
当 $M<N$ 时,交给 LLM 的视觉位置更少,但视觉编码器仍要处理原图,查询模块也增加了计算。单个 Cross-Attention Head 的分数表有 $M\times N$ 个元素,因此“LLM 输入变短”不等于“整个系统成本按同样比例下降”。
| 连接方式 | 输出长度 | 信息怎样流动 |
|---|---|---|
| 逐位置 Linear / MLP | 通常保留 N 条 | 每条视觉特征分别变换宽度 |
| 查询式连接器 | 由查询数 M 决定 | 查询从整组视觉特征加权读取 |
有限查询形成信息瓶颈,可能丢掉对任务重要的细节。游戏截图中的小目标、准星位置或文字信息,是否被保留需要任务评估,不能仅凭输出向量数少就断言更好。
查询权重也不等于物体框:一条查询可以混合多个区域,不保证恰好对应一个对象。将某一层权重画成热图可以辅助观察,但不能当作模型判断正确的证明。
6、记住这条路线
图片先产生一组视觉特征,可学习查询通过 Cross-Attention 读取它们,输出再投影到语言宽度,作为视觉输入交给 LLM;查询学什么,由数据和训练目标共同决定。
试着回答:为什么输出条数取决于查询数?查询向量是参数,为什么同一条查询的输出仍随图片改变?为什么压缩可能影响小目标理解?
下一课把接口放回完整系统,学习 LLaVA 的图文输入、训练与回答生成流程。
7、参考文献(References)
- Li, J., Li, D., Savarese, S., and Hoi, S. “BLIP-2: Bootstrapping Language-Image Pre-training with Frozen Image Encoders and Large Language Models.” ICML, 2023. arXiv:2301.12597.↩