Q-Former:少量查询怎样读取视觉特征?

多模态第六课,从逐条投影到查询式连接器

目录

  第五课的逐位置 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)

  1. 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.↩