多视角数据广泛存在于自动驾驶的多摄像头输入、医学影像的不同模态、以及3D重建的多角度图像中。视角之间的差异可能体现在光照、尺度、遮挡、甚至数据模态上,直接将这些特征拼接后送入下游网络,往往会导致模型难以收敛或泛化性能骤降。问题的本质在于,各视角的特征映射到了不同的子空间,简单的拼接无法消除这种跨视角的不一致性。为了解决这个问题,研究者们设计了两种主流思路:一是利用交叉注意力机制在特征融合阶段进行动态对齐,二是通过特征共享从特征提取的源头就施加一致性约束。

多视角不一致的根源与度量
多视角不一致可以从几何不一致和语义不一致两个层面来理解。几何不一致体现在同一物体在视角A中的特征点和视角B中的特征点之间存在非线性变换,即使经过相机位姿标定,视角间的局部形变依然存在。语义不一致则更加棘手:比如在多模态场景中,文本描述的情感极性与面部表情的情感极性可能相互矛盾,这时的“不一致”不是校准问题,而是高层语义的冲突。
从特征空间来看,不一致通常通过分布差异来度量。常用的指标包括最大均值差异(MMD)和中心矩差异(CMD)。如果我们提取了两个视角的特征向量 H_a 和 H_b,可以计算它们在再生核希尔伯特空间中的距离,以此衡量视角间的不一致程度。然而,单纯缩小这种距离并不总能提升任务性能,因为有些差异是任务相关的——例如,在3D重建中,两个视角的深度信息本身就是互补的,强制对齐反而会抹消这种互补性。因此,如何有选择地对齐,是交叉注意力机制优于全局对齐方法的关键。
具体地说,不一致还反映在特征模长的统计量上。实践表明,不同视角的特征范数往往存在显著差异,如果模型不能自适应地调整这种能量分布,某个视角的特征可能会在融合过程中主导其他视角。交叉注意力通过计算 query-key 相似度,本质上是在重构每个视角的特征时,让其他视角的“显式信息”参与加权,从而实现一种非对称的、任务驱动的对齐。
交叉注意力机制:从单个序列到多视角交互
标准的自注意力机制中,query、key、value 都来自同一序列,用于捕捉序列内部的长距离依赖。而交叉注意力将 query 保持为当前视角的特征,key 和 value 则来自另一个视角。这样一来,视角A的每一个位置都可以去“查询”视角B中语义最相关的区域,并用这些区域的特征来更新自己的表示。形式上,给定视角A的特征 X_a (shape: [N, D]) 和视角B的特征 X_b (shape: [M, D]),交叉注意力的计算过程如下:
import torch
import torch.nn as nn
class CrossAttention(nn.Module):
def __init__(self, d_model, n_heads):
super().__init__()
self.n_heads = n_heads
self.d_k = d_model // n_heads
self.W_q = nn.Linear(d_model, d_model)
self.W_k = nn.Linear(d_model, d_model)
self.W_v = nn.Linear(d_model, d_model)
self.out_proj = nn.Linear(d_model, d_model)
def forward(self, query, key, value):
# query: [B, N, D], key & value: [B, M, D]
B = query.size(0)
N, M = query.size(1), key.size(1)
# 线性变换并分头
Q = self.W_q(query).view(B, N, self.n_heads, self.d_k).transpose(1,2)
K = self.W_k(key).view(B, M, self.n_heads, self.d_k).transpose(1,2)
V = self.W_v(value).view(B, M, self.n_heads, self.d_k).transpose(1,2)
# 注意力分数
scores = torch.matmul(Q, K.transpose(-2,-1)) / (self.d_k ** 0.5)
attn = torch.softmax(scores, dim=-1)
# 加权聚合
context = torch.matmul(attn, V) # [B, n_heads, N, d_k]
context = context.transpose(1,2).contiguous().view(B, N, -1)
return self.out_proj(context)
上述代码实现了一个简化版的多头交叉注意力模块。在实际的多视角场景中,我们可以先用共享的卷积网络或ViT提取每个视角的 patch 特征,然后将这些序列特征分别作为交叉注意力的 query 和 key/value。尤其值得注意的是,当我们处理固定数量的多个视角(如双目视觉)时,可以设计双向交叉注意力:先让视角A关注视角B,再让视角B关注视角A,交替更新后得到的特征已经隐式地融合了对方的上下文。
交叉注意力并非万能。当视角数量增大到几十甚至上百时,全连接的交叉注意力会导致计算量呈平方级增长。此时可以采用稀疏注意力或者基于聚类的近似方法,但核心思想不变:让视角间在信息丰富的区域进行细粒度交互,而在不相关区域减少耦合。与直接拼接后送入全连接层相比,交叉注意力提供了更强的归纳偏置——它天然假设视角间存在可学习的对应关系,这种结构先验在很多多视角匹配任务中已被证明是有效的。
特征共享策略:硬共享、软共享与分层共享
特征共享是一种从源头上约束多视角特征提取过程的方法。最简单的是硬共享,即多个视角使用完全相同的特征提取器,这相当于强制假设:所有视角的数据可以被同一个函数映射到统一的特征空间。硬共享在计算上十分高效,参数量不随视角数量线性增长,但当视角差异较大时,单一特征提取器的容量可能不足以同时承载所有视角的表示需求。
软共享则是在每个视角拥有独立特征提取器的基础上,通过正则化项使得各视角的网络参数或者特征分布尽量靠近。典型的做法是在损失函数中加入视角间权重矩阵的 L2 距离,或者对中间层特征施加 MMD 损失。软共享给每个视角保留了更多的表达自由度,但同时引入了额外的超参数(正则化系数)需要调节。另一种折中是分层共享,即在网络的浅层使用独立分支,在深层共享高层语义提取部分。这背后的直觉是:不同视角的低级特征(如纹理、边缘)差异较大,但高级语义概念(如物体类别)是视角无关的。分层共享可以手动指定共享层,也可以通过神经网络架构搜索(NAS)自动决定。
在选择共享策略时,需要考虑任务的对称性。如果多视角之间是完全对称的(如同一个摄像头的不同位姿),硬共享通常已经足够;如果视角模态差异巨大(如图像和点云),则需要软共享甚至分层共享来平衡特异性和通用性。一个常用的验证方式是在小规模数据上分别跑硬共享和完全独立分支的基线,如果硬共享的验证指标与独立分支相差不大,说明特征空间足够对齐,可以采用硬共享来节省资源。
交叉注意力与特征共享的协同:一个端到端示例
在实际系统设计中,交叉注意力和特征共享并非互斥,而是可以有机结合。我们可以先用硬共享的 backbone 提取所有视角的特征,再将它们送入交叉注意力模块进行视角间的相互增强。这种设计既利用了共享特征提取器带来的效率,又通过交叉注意力弥补了共享过程中可能遗漏的视角特异性信息。
例如,在三维物体重建任务中,输入是一组多视角图像,输出是体素或网格。一个常见的流程是:使用一个共享的 ResNet 提取每张图片的特征图,然后通过一个视角池化层或者交叉注意力将多视角特征融合为一个全局描述,最后送入解码器。此处的交叉注意力可以设计为以全局查询向量为 query,各个视角的特征为 key 和 value,从而让模型动态地决定在生成每个局部几何细节时应该重点关注哪些视角。
class MultiViewModel(nn.Module):
def __init__(self, backbone, d_model=256, n_views=3):
super().__init__()
self.backbone = backbone # 共享的CNN
self.cross_attn = CrossAttention(d_model, n_heads=8)
self.fc = nn.Linear(d_model, 10) # 示例分类头
def forward(self, views):
# views: list of [B, C, H, W],每个视角一张图
B = views[0].size(0)
feats = []
for v in views:
f = self.backbone(v).flatten(2).mean(-1) # GAP, [B, D]
feats.append(f)
# 堆叠为 [B, V, D]
feats = torch.stack(feats, dim=1) # V = n_views
# 交叉注意力:将第一个视角作为query,其他视角平均作为key和value(仅为演示)
query = feats[:, 0:1, :] # [B, 1, D]
key_value = feats # [B, V, D]
updated = self.cross_attn(query, key_value, key_value)
# 融合后分类
out = self.fc(updated.squeeze(1))
return out
该示例中,backbone 在所有视角间共享,交叉注意力则让第一个视角的特征接收其他视角的信息。根据具体需求,完全可以实现多轮交叉注意力或者对所有视角同时进行双向更新。需要注意的是,如果视角数量非常不对称,建议对注意力分数进行缩放或采用可学习的温度参数,避免某个视角因为特征模长过大而占据主导地位。
从消融实验来看,单独使用特征共享能带来明显的参数效率提升,但在视角间语义冲突严重时会出现性能瓶颈;单独使用交叉注意力可以更灵活地融合,但模型容量需求更大。二者的组合往往能在参数量和性能之间取得最佳平衡,这也是近期多视角和跨模态工作的一大趋势。