🔥 本文定位:CSDN 原创干货 | 新加坡科技设计大学 CVPR 2026 域泛化多模态3D检测 SOTA 方案
🎯 核心收益:一次性解决多模态3D检测跨域部署三大致命问题——模态不平衡(LiDAR主导梯度)、2D查询深度不准、融合解码器过度依赖单一模态!基于查询解耦损失(Query Decoupled Loss)+ LiDAR引导深度先验(LiDAR-Guided Depth Prior)+ 互补跨模态掩码(Complementary Cross-Modal Masking)打造均衡双分支融合架构,Rain +2.8 mAP,Night +1.3 mAP,Boston +3.2 mAP,Oracle全量训练mAP 73.6%(SOTA),源域性能零损失,完美适配自动驾驶跨城/跨国部署、雨夜极端天气感知、未知场景零样本泛化、传感器降级自适应融合、双分支检测器模态均衡
📌 核心创新矩阵:
✅ 适配场景:自动驾驶跨城部署 | 夜间/暴雨3D感知 | 从新加坡→波士顿零样本泛化 | 传感器降级自适应融合 | 双分支查询检测器 | 域泛化数据增强
🔖 前言
本文介绍的 CCF(Complementary Collaborative Fusion)来自新加坡科技设计大学(SUTD),CVPR 2026接收,代码已开源(https://github.com/IMPL-Lab/CCF)。核心洞察优雅而精准:两种传感器在不同域上降质互补——雨弱化LiDAR但保留图像,夜弱化图像但保留LiDAR。因此需要训练模型根据当前域自适应选择依赖哪个模态,而不是刻死LiDAR主导。基于此,作者提出三组件:Query Decoupled Loss给Camera分支独立梯度,LiDAR-Guided Depth Prior用LiDAR几何先验修正深度,Complementary Cross-Modal Masking模拟互补降质强制学习自适应融合。
模型仅在源域(新加坡晴朗白天)训练,不接触任何目标域数据,不引入目标域数据增强——直接零样本泛化到暴雨、夜间、波士顿三类域偏移。结果:rain mAP +2.8%,night +1.3%,Boston +3.2%,源域性能不降。Oracle全量训练mAP 73.6%全面SOTA。本文全程 论文 1:1 对齐 + 可运行完整代码复现 + 实验全解读。
🔖 一、CCF 整体架构

核心设计亮点:三个组件的分工精确互不重叠——Query Decoupled Loss解决"梯度到不了Camera分支"(训练信号),LiDAR-Guided Depth Prior解决"2D查询位置初始化不准"(输入质量),Complementary Cross-Modal Masking解决"解码器学会了只信LiDAR"(行为偏好)。三者联合才形成完整的"均衡化"方案。
🔖 二、核心模块逐行拆解
2.1 Query Decoupled Loss — 查询解耦损失
解决的4个核心问题:
- 问题1:匈牙利匹配对3D查询天然偏心——3D查询由LiDAR定位初始化,与GT框IoU更高,匹配时抢占绝大多数GT。2D查询匹配量仅为其1/37.5,梯度几乎为零
- 问题2:简单分离查询+共享解码器会导致短路学习——在自注意力中2D查询可以偷看3D查询信息,不独立优化自身定位能力
- 问题3:合并Loss权重无法解决根因——调大2D Loss权重只能放大少量匹配的梯度,无法解决匹配本身的结构性偏差
- 问题4:推理效率不能牺牲——域泛化是为了实际部署,训练增强不能拖慢推理
Step 1:三路并行解码器架构
共享权重 + 独立自注意力:三个解码器使用完全相同的参数(FFN权重、交叉注意力权重),但自注意力层各自独立的查询集合:
Decoder2d(q2d,0,Fmulti)→q2d,L\\text{Decoder}_{2d}(q_{2d,0}, F_{multi}) \\rightarrow q_{2d,L}Decoder2d(q2d,0,Fmulti)→q2d,L
Decoder3d(q3d,0,Fmulti)→q3d,L\\text{Decoder}_{3d}(q_{3d,0}, F_{multi}) \\rightarrow q_{3d,L}Decoder3d(q3d,0,Fmulti)→q3d,L
Decoderfused([q2d,0,q3d,0],Fmulti)→qL\\text{Decoder}_{fused}([q_{2d,0}, q_{3d,0}], F_{multi}) \\rightarrow q_LDecoderfused([q2d,0,q3d,0],Fmulti)→qL
三路都attend到相同的多模态特征token FmultiF_{multi}Fmulti。2D-only和3D-only中查询只能和同类自注意力——阻断了Camera查询依赖LiDAR查询的捷径。
Step 2:独立匈牙利匹配 + 独立Loss
Ltotal=L2d+L3d+Lfused\\mathcal{L}_{total} = \\mathcal{L}_{2d} + \\mathcal{L}_{3d} + \\mathcal{L}_{fused}Ltotal=L2d+L3d+Lfused
L(⋅)=Lcls(⋅)+Lbox(⋅)\\mathcal{L}_{(\\cdot)} = \\mathcal{L}_{cls}^{(\\cdot)} + \\mathcal{L}_{box}^{(\\cdot)}L(⋅)=Lcls(⋅)+Lbox(⋅)
每条分支独立做匈牙利匹配。2D-only分支中只有2D查询竞争GT——不再被3D查询"欺负",获得100%匹配通道。分类用Focal Loss,回归用L1 Loss。
Step 3:推理时零额外开销
推理仅用Fused pass。2D-only和3D-only仅在训练时提供专属梯度信号,推理时移除。这是设计核心——用训练时"分"换取推理时"合"的鲁棒性。
消融实验(Tab.3):单独用DL → Rain mAP +0.9%,但Night -0.8%(夜间Camera退化严重,强制监督反而有害)。需配合DP和CM互补。
2.2 LiDAR-Guided Depth Prior — LiDAR引导深度先验

解决的4个核心问题:
- 问题1:纯图像深度预测误差大——Faster R-CNN RoI特征做深度回归,源域MAE 1.78m,雨域3.01m。深度不准导致2D查询3D位置初始化错误,直接输在起跑线
- 问题2:LiDAR点云在2D框内有几何信息但未被利用——2D proposal对应的3D锥台内通常有LiDAR点云,它们的深度分布是天然先验
- 问题3:两种深度源可靠性随实例变化——近处物体LiDAR点稠密可靠,远处物体LiDAR稀疏图像反而更可靠。简单平均/拼接无法自适应
- 问题4:LiDAR点云在雨域也会稀疏——锥台内点数可能为零,需要fallback机制
Step 1:双源深度分布构建
对每个2D proposal bi2db^{2d}_ibi2d,从两个源估计深度分布:
di2d∈RD—— 轻量深度预测器从RoI特征输出D=25个bin的概率分布d^{2d}_i \\in \\mathbb{R}^D \\quad \\text{—— 轻量深度预测器从RoI特征输出D=25个bin的概率分布}di2d∈RD—— 轻量深度预测器从RoI特征输出D=25个bin的概率分布
di3d∈RD—— 将锥台内LiDAR点深度离散化为直方图,无点时用均匀分布d^{3d}_i \\in \\mathbb{R}^D \\quad \\text{—— 将锥台内LiDAR点深度离散化为直方图,无点时用均匀分布}di3d∈RD—— 将锥台内LiDAR点深度离散化为直方图,无点时用均匀分布
Step 2:Product-of-Experts自适应融合
λi∈[0,1]—— 3层MLP置信度网络预测\\lambda_i \\in [0,1] \\quad \\text{—— 3层MLP置信度网络预测}λi∈[0,1]—— 3层MLP置信度网络预测
difused=σ(λi⋅log(di2d)+(1−λi)⋅log(di3d))d^{fused}_i = \\sigma\\left(\\lambda_i \\cdot \\log(d^{2d}_i) + (1-\\lambda_i) \\cdot \\log(d^{3d}_i)\\right)difused=σ(λi⋅log(di2d)+(1−λi)⋅log(di3d))
为什么用Product-of-Experts而不是加法融合?PoE在log空间中加权求和 = 原始空间中分布相乘。两个专家都"同意"的区域(两个分布都高)被增强,一方"反对"的区域(一个高一个低)被抑制。相比加法(Sum-of-Experts)容易产生多峰虚假分布,PoE天然倾向保守——只在"两方共识"处给高置信度。
Step 3:深度期望替换参考点
ri,new2d=ExpectedValue(difused)r^{2d}_{i, new} = \\text{ExpectedValue}(d^{fused}_i)ri,new2d=ExpectedValue(difused)
用融合分布的期望深度替换原始2D查询的参考点深度,改善3D位置初始化。消融实验(Tab.3):DP单独用 → Rain +0.4 mAP,Boston +0.1 mAP。但夜间Camera退化时略有下降。
2.3 Complementary Cross-Modal Masking — 互补跨模态掩码
解决的4个核心问题:
- 问题1:解码器学成"LiDAR奴隶"——即使Camera查询增强了,融合解码器仍习惯只信3D查询。需要强制打破这个固定偏好
- 问题2:现有mask增强不匹配域偏移模式——CMT的Modal Dropout完全丢弃一整个模态、Consistent GridMask同时遮两个模态——都不符合真实场景中"一个坏一个好"的互补模式
- 问题3:直接上高概率mask训练不稳定——模型还没学会完整多模态推理就被迫处理残缺输入
- 问题4:需要保留空间对齐关系——图像和LiDAR在空间上对应,mask必须保持这种对应才能让互补有意义
Step 1:空间对齐互补掩码
M∈{0,1}H×W—— GridMask生成结构化空间掩码M \\in \\{0,1\\}^{H\\times W} \\quad \\text{—— GridMask生成结构化空间掩码}M∈{0,1}H×W—— GridMask生成结构化空间掩码
Imasked=I⊙M—— 图像被遮区域置零I_{masked} = I \\odot M \\quad \\text{—— 图像被遮区域置零}Imasked=I⊙M—— 图像被遮区域置零
Pmasked={pi∈P∣M[K(Rpi+t)]=0}—— LiDAR保留图像被遮区域对应的点P_{masked} = \\{p_i \\in P \\mid M[K(Rp_i + t)] = 0\\} \\quad \\text{—— LiDAR保留图像被遮区域对应的点}Pmasked={pi∈P∣M[K(Rpi+t)]=0}—— LiDAR保留图像被遮区域对应的点
核心设计——互补而非一致:M=0M=0M=0的位置,图像像素被遮(看不到),但LiDAR点被保留(看得到)。M=1M=1M=1的位置反过来:图像完整,LiDAR点被过滤。每个空间位置至少有一个模态可见——真正模拟雨(遮LiDAR远距离点但图像可见)和夜(遮图像暗区但LiDAR点可见)的互补降质模式。
Step 2:课程学习
pmask=tT⋅pmax=tT⋅0.7p_{mask} = \\frac{t}{T} \\cdot p_{max} = \\frac{t}{T} \\cdot 0.7pmask=Tt⋅pmax=Tt⋅0.7
训练开始时 pmask=0p_{mask}=0pmask=0(无mask),线性增长至 pmax=0.7p_{max}=0.7pmax=0.7。模型先在完整多模态输入上学好基础融合,再逐步适应互补残缺输入。消融(Tab.4)确认课程学习对稳定性至关重要——无课程学习时Night mAP甚至低于Image GridMask基线。
Step 3:消融验证
Tab.4给出掩码策略全面对比:(a) Image GridMask → (b) Modal Mask(CMT风格)仅微升0.1% → © Consistent GridMask(同mask遮两路)边际收益 → (d) Complementary GridMask表现显著更好 → (f) +课程学习达最优。RandomMask替换GridMask效果相近——证明互补性是关键而非掩码形状。
🔖 三、论文 1:1 对齐完整可运行 PyTorch 复现代码
3.1 环境依赖
# 基础环境
conda create -n ccf python=3.8 -y
conda activate ccf
# PyTorch
pip install torch==2.0.1 torchvision==0.15.2
# 检测框架
git clone https://github.com/IMPL-Lab/CCF.git
cd CCF
pip install -r requirements.txt
# spconv
pip install spconv-cu118
3.2 完整代码实现
Query Decoupled Loss — 三路并行解码器训练
# ====== models/query_decoupled_loss.py ======
import torch
import torch.nn as nn
from scipy.optimize import linear_sum_assignment
class QueryDecoupledDecoder(nn.Module):
"""
三路并行共享权重解码器:2D-only / 3D-only / Fused
训练时三路独立匈牙利匹配 + 独立Loss
推理时仅用Fused pass,零额外开销
"""
def __init__(self, d_model=256, nhead=8, num_layers=6):
super().__init__()
# 🚀 共享Transformer解码器层
decoder_layer = nn.TransformerDecoderLayer(
d_model=d_model, nhead=nhead, batch_first=True)
self.shared_decoder = nn.TransformerDecoder(
decoder_layer, num_layers=num_layers)
# 分类+回归头(三路共享)
self.cls_head = nn.Linear(d_model, num_classes)
self.box_head = nn.Linear(d_model, 7)
def forward_train(self, q_2d, q_3d, memory, gt_boxes, gt_labels):
"""
Args:
q_2d: (B, M_2d, C) 2D查询
q_3d: (B, M_3d, C) 3D查询
memory: (B, N, C) 多模态特征
gt_boxes, gt_labels: 真值
Returns:
total_loss, loss_dict
"""
B = q_2d.shape[0]
# 🚀 Pass 1: 2D-only — 仅2D查询自注意力
q_2d_L = self.shared_decoder(
tgt=q_2d, memory=memory)
loss_2d, _ = self._hungarian_loss(
q_2d_L, gt_boxes, gt_labels, modality='2d')
# 🚀 Pass 2: 3D-only — 仅3D查询自注意力
q_3d_L = self.shared_decoder(
tgt=q_3d, memory=memory)
loss_3d, _ = self._hungarian_loss(
q_3d_L, gt_boxes, gt_labels, modality='3d')
# 🚀 Pass 3: Fused — 拼接查询联合自注意力
q_fused = torch.cat([q_2d, q_3d], dim=1)
q_fused_L = self.shared_decoder(
tgt=q_fused, memory=memory)
loss_fused, _ = self._hungarian_loss(
q_fused_L, gt_boxes, gt_labels, modality='fused')
# 🚀 三路Loss求和:每路独立匹配+独立监督
total_loss = loss_2d + loss_3d + loss_fused
return total_loss, {
'loss_2d': loss_2d.item(),
'loss_3d': loss_3d.item(),
'loss_fused': loss_fused.item()
}
@torch.no_grad()
def forward_inference(self, q_2d, q_3d, memory):
"""推理:仅Fused pass"""
q_fused = torch.cat([q_2d, q_3d], dim=1)
q_out = self.shared_decoder(tgt=q_fused, memory=memory)
cls_pred = self.cls_head(q_out)
box_pred = self.box_head(q_out)
return cls_pred, box_pred
def _hungarian_loss(self, queries, gt_boxes, gt_labels, modality):
"""独立匈牙利匹配 + Focal Loss + L1 Loss"""
B = queries.shape[0]
total_loss = 0.0
for b in range(B):
# 计算IoU成本矩阵
pred_boxes = self.box_head(queries[b])
cost = –iou_3d(pred_boxes, gt_boxes[b]) # N_query × N_gt
# 🚀 匈牙利匹配
row_idx, col_idx = linear_sum_assignment(
cost.detach().cpu().numpy())
# 匹配的查询做Loss
matched_pred_cls = self.cls_head(queries[b, row_idx])
matched_pred_box = pred_boxes[row_idx]
loss_cls = focal_loss(matched_pred_cls, gt_labels[b][col_idx])
loss_box = l1_loss(matched_pred_box, gt_boxes[b][col_idx])
total_loss += loss_cls + loss_box
return total_loss / B, {}
LiDAR-Guided Depth Prior
# ====== models/lidar_depth_prior.py ======
import torch
import torch.nn as nn
import torch.nn.functional as F
class LidarGuidedDepthPrior(nn.Module):
"""
LiDAR引导深度先验:Product-of-Experts融合
图像深度分布 + LiDAR深度直方图 → 自适应融合深度
"""
def __init__(self, d_model=256, num_bins=25, depth_range=(0, 40)):
super().__init__()
self.num_bins = num_bins
self.depth_min, self.depth_max = depth_range
self.bin_width = (depth_range[1] – depth_range[0]) / num_bins
# 图像深度预测器(轻量MLP)
self.depth_predictor = nn.Sequential(
nn.Linear(d_model, 128),
nn.ReLU(),
nn.Linear(128, num_bins)
)
# 🚀 置信度网络:预测融合权重 λ
self.confidence_net = nn.Sequential(
nn.Linear(num_bins * 2, 64), # concat两个分布
nn.ReLU(),
nn.Linear(64, 1),
nn.Sigmoid() # λ ∈ [0, 1]
)
def forward(self, roi_features, lidar_points_in_frustum):
"""
Args:
roi_features: (M, C) RoI特征
lidar_points_in_frustum: list of (N_i, 3) 每个proposal锥台内LiDAR点
Returns:
fused_depth: (M,) 融合深度期望值
depth_dist: (M, D) 融合深度分布
"""
M = roi_features.shape[0]
# 🚀 Source 1: 图像深度分布
d_2d_logits = self.depth_predictor(roi_features) # (M, D)
d_2d = F.softmax(d_2d_logits, dim=–1)
# 🚀 Source 2: LiDAR深度直方图
d_3d = torch.zeros(M, self.num_bins, device=roi_features.device)
for i, points in enumerate(lidar_points_in_frustum):
if len(points) > 0:
depths = points[:, 0] # x = depth in LiDAR frame
bin_idx = ((depths – self.depth_min)
/ self.bin_width).long().clamp(0, self.num_bins–1)
d_3d[i] = torch.bincount(bin_idx, minlength=self.num_bins).float()
d_3d[i] = d_3d[i] / (d_3d[i].sum() + 1e-8) # 归一化
else:
# 🚀 无LiDAR点时用均匀分布
d_3d[i] = torch.ones(self.num_bins,
device=roi_features.device) / self.num_bins
# 🚀 Product-of-Experts 融合
# λ * log(d_2d) + (1-λ) * log(d_3d) → softmax
concat_dist = torch.cat([d_2d, d_3d], dim=–1) # (M, 2D)
lambda_i = self.confidence_net(concat_dist) # (M, 1)
log_d_fused = (lambda_i * torch.log(d_2d + 1e-8) +
(1 – lambda_i) * torch.log(d_3d + 1e-8))
d_fused = F.softmax(log_d_fused, dim=–1)
# 🚀 融合深度 = 分布期望
bin_centers = torch.linspace(
self.depth_min + self.bin_width/2,
self.depth_max – self.bin_width/2,
self.num_bins, device=roi_features.device)
fused_depth = (d_fused * bin_centers).sum(dim=–1) # (M,)
return fused_depth, d_fused
Complementary Cross-Modal Masking
# ====== data/complementary_masking.py ======
import torch
import numpy as np
class ComplementaryCrossModalMask:
"""
互补跨模态掩码增强:
图像被遮→保留LiDAR;LiDAR被遮→保留图像
强制学习自适应模态选择
"""
def __init__(self, max_prob=0.7, grid_ratio=0.3, curriculum=True):
self.max_prob = max_prob
self.grid_ratio = grid_ratio
self.curriculum = curriculum
self.current_step = 0
self.total_steps = 1
def set_progress(self, step, total):
self.current_step = step
self.total_steps = total
@property
def mask_prob(self):
"""课程学习:线性增长 p = t/T * p_max"""
if not self.curriculum:
return self.max_prob
return min(self.max_prob,
self.current_step / self.total_steps * self.max_prob)
def __call__(self, image, lidar_points, calib):
"""
Args:
image: (H, W, 3) 原始图像
lidar_points: (N, 4) [x, y, z, intensity]
calib: 相机内参K + 外参[R|t]
Returns:
masked_image, filtered_lidar, mask
"""
if np.random.random() > self.mask_prob:
return image, lidar_points, None
H, W = image.shape[:2]
# 🚀 GridMask:结构化空间掩码
mask = self._grid_mask(H, W)
# 🚀 互补原则:
# 图像:mask区域置零
masked_image = image * mask[:, :, None] # (H, W, 3)
# 🚀 LiDAR:保留mask区域对应的点(互补!)
K, R, t = calib['K'], calib['R'], calib['t']
pts_cam = lidar_points[:, :3] @ R.T + t # 变换到相机坐标系
pts_img = pts_cam @ K.T # 投影到图像平面
u, v = (pts_img[:, 0] / pts_img[:, 2]).long(), \\
(pts_img[:, 1] / pts_img[:, 2]).long()
valid = (u >= 0) & (u < W) & (v >= 0) & (v < H)
# 🚀 关键:mask=0处保留点云,mask=1处过滤点云
keep = valid & (mask[v[valid], u[valid]].cpu().numpy() == 0)
filtered_lidar = lidar_points[keep]
return masked_image, filtered_lidar, mask
def _grid_mask(self, H, W):
"""生成GridMask"""
mask = np.ones((H, W), dtype=np.uint8)
grid_h = int(H * self.grid_ratio)
grid_w = int(W * self.grid_ratio)
# 随机偏移
offset_h = np.random.randint(0, grid_h)
offset_w = np.random.randint(0, grid_w)
# 棋盘状遮罩
for i in range(offset_h, H, grid_h * 2):
mask[i:i+grid_h, :] = 0
for j in range(offset_w, W, grid_w * 2):
mask[:, j:j+grid_w] = 0
return mask
🔖 四、YOLO 一键迁移适配教程
Step 1:放入模块
将核心三组件保存为 ultralytics/nn/modules/ccf_modules.py:QueryDecoupledDecoder、LidarGuidedDepthPrior、ComplementaryCrossModalMask。
Step 2:注册
ultralytics/nn/modules/__init__.py:
from .ccf_modules import (
QueryDecoupledDecoder,
LidarGuidedDepthPrior,
)
Step 3:parse_model注册
ultralytics/nn/tasks.py parse_model 函数的 elif 分支:
elif m is LidarGuidedDepthPrior:
c1 = ch[f]
c2 = args[0]
args = [c1, c2, *args[1:]]
elif m is QueryDecoupledDecoder:
c1 = ch[f]
c2 = args[0]
args = [c1, c2]
注意:CCF基于双分支检测框架(MV2DFusion),纯YOLO迁移需适配。建议仅移植LiDAR-Guided Depth Prior作为YOLO Neck的深度修正插件——在FPN层后插入,用深度分布期望修正特征金字塔的空间权重。Cross-Modal Masking可直接作为数据增强pipeline使用。
🔖 五、实验结果全解析
5.1 域泛化 SOTA 对比
| mAP/NDS | mAP/NDS | mAP/NDS | mAP/NDS | mAP/NDS | |||
| FSDv2(LiDAR-only) | TPAMI’24 | L | 59.6/62.7 | 23.4/41.6 | 36.6/42.8 | 28.2/45.1 | 29.4/43.2 |
| CMT | ICCV’23 | L+C | 61.4/62.3 | 35.7/46.5 | 37.8/42.0 | 42.1/50.8 | 38.5/46.4 |
| MOAD | arXiv’24 | L+C | 64.1/64.4 | 39.2/49.4 | 41.1/44.3 | 43.9/53.0 | 41.4/48.9 |
| MEFormer | arXiv’24 | L+C | 63.4/63.7 | 40.1/50.1 | 41.1/44.0 | 44.3/53.0 | 41.8/49.0 |
| ISFusion | CVPR’24 | L+C | 66.3/65.4 | 39.8/49.4 | 41.8/45.1 | 45.4/53.4 | 42.3/49.3 |
| MoME | CVPR’25 | L+C | 63.6/64.0 | 37.7/48.5 | 39.5/43.3 | 42.9/52.4 | 40.0/48.1 |
| Baseline(MV2DFusion) | – | L+C | 68.4/65.7 | 41.9/50.0 | 42.9/44.5 | 47.4/53.6 | 44.1/49.4 |
| CCF (Ours) | CVPR’26 | L+C | 68.2/65.9 | 44.7/52.5 | 44.2/45.3 | 50.6/56.8 | 46.5/51.5 |
✅ 核心亮点:
- 源域性能几乎无损失(68.2 vs 68.4),目标域三项全面提升
- Boston跨地理域泛化提升最大(+3.2 mAP/+3.2 NDS)——从新加坡到波士顿直接零样本迁移
- 比CVPR’25的MoME强+6.5 Avg mAP——MoME侧重传感器完全缺失(modality dropout),CCF处理"两个都在但质量不同"的更实际场景
5.2 Oracle 全量训练对比(上界)
| mAP/NDS | mAP/NDS | mAP/NDS | |
| TransFusion | 67.3/71.2 | 67.5/71.9 | 39.8/44.7 |
| BEVFusion | 68.5/71.4 | 69.9/- | 42.8/- |
| CMT | 70.3/72.9 | 70.5/73.7 | 42.8/46.3 |
| ISFusion | 72.7/73.8 | 72.8/74.8 | 45.0/47.4 |
| MoME | 71.2/73.6 | 72.1/74.6 | 42.7/46.5 |
| CCF | 73.6/74.2 | 72.9/74.5 | 46.9/48.3 |
✅ Oracle设定下全面SOTA——模型容量在域内和域外都达到极致。
5.3 消融实验
| 68.4/65.7 | 41.9/50.0 | 42.9/44.5 | 47.4/53.6 | |||
| ✓ | 68.6/66.0 | 42.3/50.6 | 41.8/44.4 | 47.5/53.8 | ||
| ✓ | 68.4/65.8 | 44.5/51.4 | 43.4/45.2 | 49.6/56.4 | ||
| ✓ | ✓ | 68.7/66.1 | 44.7/51.5 | 44.1/45.4 | 49.7/56.3 | |
| ✓ | 68.4/66.1 | 42.8/52.4 | 42.1/44.7 | 48.1/56.0 | ||
| ✓ | ✓ | 68.8/66.4 | 44.7/53.6 | 42.2/44.6 | 50.0/56.9 | |
| ✓ | ✓ | 68.4/66.2 | 44.3/51.2 | 43.9/45.8 | 50.2/56.9 | |
| ✓ | ✓ | ✓ | 68.2/65.9 | 44.7/52.5 | 44.2/45.3 | 50.6/56.8 |
DL=Query Decoupled Loss, DP=LiDAR-Guided Depth Prior, CM=Complementary Cross-Modal Masking。消融在50%数据上进行。
✅ 核心亮点:
- CM单独贡献最大——互补掩码本身就能大幅提升跨域鲁棒性(Rain +2.6 mAP)
- DL单独在Night上掉点(-0.8)——夜间图像退化,强制监督低质量2D查询适得其反。需DP配合
- 三者叠加达最优——设计上恰好互补:DL给梯度、DP给精度、CM给行为偏好
5.4 掩码策略消融
| Image GridMask | ✗ | 42.8/50.7 | 42.5/45.3 | 48.3/54.7 |
| Modal Mask(CMT) | ✗ | 42.9/49.7 | 42.6/44.5 | 48.4/55.4 |
| Consistent GridMask | ✗ | 42.8/49.8 | 42.2/44.3 | 48.9/55.5 |
| Complementary GridMask | ✗ | 43.9/50.0 | 43.1/44.2 | 49.2/55.1 |
| Complementary RandomMask | ✓ | 44.1/51.1 | 44.1/46.0 | 49.7/55.2 |
| Complementary GridMask | ✓ | 44.3/51.2 | 43.9/45.8 | 50.2/56.9 |
✅ 互补性>>课程学习>>掩码形状——无论GridMask还是RandomMask,互补策略都显著优于一致策略。验证了核心假设:真实域偏移中模态缺陷是互补的。
🔖 六、总结
🔖 收藏本文,域泛化多模态3D检测直接起飞!
📌 标签:#CVPR2026 #域泛化3D检测 #多模态融合 #自动驾驶 #LiDAR-Camera



