
三年前我第一次把激光雷达的稀疏点云投影成 BEV 特征图再把环视相机的图像特征也拍到同一张鸟瞰图上做拼接时mAP 直接掉了两个多点。更诡异的是单独跑激光雷达分支时远处卡车检测得好好的加上相机分支之后那辆卡车的框开始左右抖动有时甚至一分为二。这个现象后来成了我反复琢磨跨模态冲突的起点——两种传感器在 BEV 空间里并不是简单地一加一它们各自带着自己的误差、自己的空间假设、自己的失效模式粗暴地融在一起等于把对方的噪声也一并喂进了网络。这篇内容围绕消除 BEV 空间中的跨模态冲突实现 LiDAR 相机 3D 目标检测展开讲的是一套我从冲突溯源、对齐设计到门控加权、一致性约束的完整落地思路。它解决的核心问题是为什么两种模态在 BEV 里会打架打架打在哪些地方以及用什么网络结构、什么训练策略、什么工程手段能把这种冲突压下去。适合已经跑通过单模态检测、正打算上多模态融合的开发者也适合已经把融合框架搭起来但发现性能不如单模态、被掉点折磨过的同行。1. 先把问题看清楚BEV 融合的三种打法与冲突根源1.1 点级、特征级、查询级融合各自翻车的点做多模态 3D 检测融合位置的选择基本决定了后面要处理什么问题。我在实际项目里把主流的三种路线都摸过一遍结论是没有一种能天然免疫跨模态冲突只是冲突出现的位置不同。点级融合的思路最直观——用相机分支输出的语义分割结果给每个激光雷达点上色再喂给点云检测头。它的好处是保留了原始几何精度坏处也明显图像分割一旦出错错误会直接污染点云特征。我遇到过逆光场景下图像把护栏分割成了路面结果整片护栏的点云被赋予地面语义网络自然就把它当可行驶区域忽略了。这类错误的麻烦在于它发生在融合之前后面再补救都没用。特征级融合是现在的主流做法两个分支各自编码成 BEV 特征图再在 BEV 上做拼接或者相加。听着简单但相机分支要先做视角变换这一步涉及深度估计而深度估计恰恰是冲突的最大来源。激光雷达给的是精确的 3D 坐标相机给的是每个像素可能有 D 种深度的概率分布两者在 BEV 上的空间精度根本不在一个量级拼在一起就会出现一张图上有两种模糊尺度的怪象。查询级融合用一组可学习的 object query 去两个模态的特征上采样绕开了显式 BEV 对齐。它灵活但对 query 初始化很敏感训练早期 query 分布还没收敛的时候两个模态采到的特征经常对不上同一个物体学出来的注意力图会出现一个 query 盯住激光雷达的车、另一个 query 盯住图像里同一辆车的影子这种重复建模。三种路线的对比如下融合范式几何精度来源主要冲突表现训练稳定性部署复杂度点级融合完全依赖点云图像语义错误污染点特征较高低特征级融合依赖深度估计质量BEV 特征错位、拖尾、尺度不一中等中等查询级融合依赖 query 收敛重复建模、注意力错位较低高我最终选的是特征级融合为主、查询级做补充的混合方案。原因很实际特征级融合的推理链路是确定的每个 BEV 格子对应哪个物理位置可以精确回溯出问题能查查询级方法虽然上限高但调试时你很难定位到底是 query 没学好还是特征本身有错工程上不友好。1.2 跨模态冲突的四种典型表现在动手改网络之前我花了大概两周时间专门做冲突观测——不加任何新模块只把融合后的 BEV 特征、每个模态单独的 BEV 特征、以及检测结果都可视化出来逐帧对比。这一步非常值得因为它把抽象的冲突变成了可以指着屏幕说的具体现象。第一种是空间错位型冲突同一个物体激光雷达 BEV 上的热区中心和相机 BEV 上的热区中心差了半个格子到一个格子。根源通常是外参标定误差或者时间戳不同步。车辆在运动时一帧图像和一帧点云如果差了几十毫秒60 km/h 下就是接近一米的位移BEV 上直接就错开了。第二种是拖尾弥散型冲突相机分支在物体后面拖出一条长长的尾巴尤其在远处和遮挡边缘特别明显。这是深度估计不准导致的——网络对某个像素的深度分布估计得又宽又平投影到 BEV 时就沿着射线方向糊成一片。激光雷达那边是干干净净一个小点团两边一拼BEV 特征图上就有了实体幽灵的叠加。第三种是置信度倒挂型冲突图像分支对某个区域非常确信比如看到红色车身就认为有车但激光雷达那边一个点都没有。这种情况在广告牌、屏幕显示的车、玻璃反射里特别常见。融合时如果不做抑制网络会倾向于相信高置信度的那一边产生误检。第四种是模态缺失型冲突雨雾天激光雷达回波衰减、点云变稀或者相机被泥水糊住。这时候融合模块如果还是按固定权重去拼等于把失效模态的噪声强行注入性能比单模态还差。这四类冲突我在后面的章节里会逐一给出对应的处理手段但先记住一个原则冲突不是靠一个大模块一次性解决的而是要靠对齐—加权—约束三个动作分别压制不同层面的问题。1.3 我采用的对齐—加权—约束三段式思路整体架构上我没有去追最新的花哨结构而是老老实实按三个层次来设计。第一层是几何对齐层目标是先把物理上该重合的东西对齐。这里我做了两件事一是用带不确定性的深度分布引导相机特征投影让弥散程度可控二是在融合前做一次基于 BEV 网格的邻域重采样把可能存在的系统性偏移拉回来一点。这一层不改变特征语义只调整空间位置。第二层是冲突感知加权层目标是在每个 BEV 位置上判断这一刻该信谁。我用了一个轻量的门控网络输入是两个模态的 BEV 特征和它们的局部一致性度量输出是逐位置、逐通道的融合权重。激光雷达点稀的地方权重往相机偏相机深度估计熵高的地方权重往激光雷达偏。第三层是一致性约束层只在训练时起作用。我在两个模态的 BEV 特征之间加了对比式的一致性损失让同一物理位置的特征互相靠近不同位置的特征互相推开。这一层相当于给网络一个软提示这两个特征描述的是同一个东西别学出两套语义。这个三段式的价值在于职责分离。调试的时候我可以单独关掉某一层看效果出问题也能快速定位是哪一层没做好。很多融合方案把所有东西塞进一个大 transformer 里效果上限可能更高但一旦不 work你很难说清楚是哪部分拖了后腿。2. 冲突溯源把每一类误差拆到可量化的程度2.1 外参与时间戳最容易被忽视的硬冲突我在排查最初那次掉点时前三天都在怀疑网络结构最后发现问题出在标定文件上。相机和激光雷达的外参是用一个旧版本的标定结果平移量差了大概 4 厘米旋转差了 0.3 度。这个量级人眼看不出但在 BEV 上一个 40 米外的物体投影位置会偏出接近 20 厘米正好是一个格子的宽度。外参误差的可怕之处在于它是系统性偏移不是随机噪声网络学不会也压不住。我用过一个很土但有效的验证方法拿一段静止场景的数据把激光雷达点云投影到图像上看边缘是否严丝合缝地对齐物体轮廓。如果车道线、杆子、车身边缘都对齐得很好外参基本没问题如果整体往一个方向偏那就是标定误差。这个方法比任何数值检查都直观。时间同步的问题更隐蔽。多传感器系统里相机和激光雷达的采集频率不同时间戳对齐通常靠硬件触发或者软件插值。我见过一种情况硬件触发是准的但软件在打包数据时把时间戳按最近帧做了四舍五入导致实际配对的两帧差了半个采集周期。低速时看不出来一上高速融合后的框就开始在运动方向上拉长。处理这类硬冲突我的做法是三步标定复检把外参投影误差量化到像素级别超过 2 个像素就重新标定。运动补偿用自车里程计或者 IMU 把点云补偿到图像曝光时刻补偿量按Δd v * Δt估算v 是自车速度Δt 是时间差。60 km/h、20 ms 的时间差对应 0.33 米这个量级不能忽略。残差学习在对齐之后再让网络学一个小的空间偏移量作为标定误差的兜底。这个偏移量的学习率要设得很小否则网络会用它去作弊拟合其他误差。提示标定复检一定要在多个距离段分别做近处对齐好不代表远处对齐好。我习惯取 10 米、30 米、50 米三个距离的参照物分别检查。2.2 深度分布不确定图像到 BEV 的马赛克从哪来相机分支要把 2D 特征变到 BEV绕不开深度估计。主流做法是给每个像素预测一组深度概率分布然后沿射线把特征撒到 BEV 空间。这一步的精度直接决定了相机 BEV 特征的质量也直接决定了它和激光雷达特征能不能对上。问题的核心是深度分布预测天生就是模糊的。一个像素对应的可能是一辆车的前脸也可能穿过车窗看到后面的座椅网络只能给一个分布而这个分布往往在多个深度上都有关联值。投影到 BEV 时特征就沿着射线方向被抹开了。我做过一个统计在自建数据集上深度估计的误差分布大概是这样的距离段平均绝对误差误差 90 分位表现0–20 米0.4 米1.1 米基本可用20–40 米1.2 米3.5 米出现明显拖尾40–60 米3.0 米8.0 米特征严重弥散60 米以上6.0 米以上超过 15 米基本不可信这张表解释了很多现象为什么融合后近处效果好、远处反而变差为什么小目标在远处容易漏。远处的相机 BEV 特征本身就是一团糊和激光雷达的精确点团拼在一起相当于给一个清晰信号叠加了一个低质量的模糊副本信噪比反而下降。我的处理思路不是硬去提升深度精度那是个无底洞而是把不确定性显式建模出来让融合模块知道哪里该信、哪里不该信。具体做法是给深度预测头输出一个熵值熵高的位置在后续融合时降低相机分支的权重。这个思路在后面 3.2 节会给具体实现。2.3 特征分布鸿沟稀疏几何与稠密语义怎么和解就算空间完全对齐了两个模态的 BEV 特征在统计分布上依然差异巨大。激光雷达特征的特点是稀疏、高对比、几何主导——有回波的地方值很大没回波的地方接近零特征图看起来像一片黑底上撒了些亮点。相机特征是稠密、平滑、语义主导——每个格子都有值纹理和颜色信息丰富但边界相对模糊。把这两种分布直接 concat 或者相加会出现一个很典型的问题相机特征的整体能量远大于激光雷达特征。我测过融合前的特征幅值相机分支的均值大概是激光雷达分支的 3 到 5 倍。这意味着简单相加时激光雷达的几何信息实际上被淹没了网络退化成了一个以相机为主、激光雷达当辅助的模型。这也解释了为什么有些融合模型在夜间或者强光下表现不如纯激光雷达——它其实一直在依赖相机。解决办法有几个层面归一化对齐融合前对两个分支分别做 LayerNorm 或者 BatchNorm把幅值拉到同一量级。这是最省事的一步效果立竿见影。通道重标定用通道注意力让网络自己学每个通道该给多少权重而不是全局统一缩放。分布约束损失训练时加一个 MMD 或者对抗式的分布对齐损失让两个模态的 BEV 特征分布尽量接近。这一招效果不错但训练容易不稳我一般只用很低的权重0.01 到 0.05 量级作为辅助。2.4 模态缺失下的鲁棒性设计实际跑车的时候模态缺失是常态不是异常。夏天暴雨、冬天结霜、隧道进出口的强光、大车溅起的泥水任何一个都能让某一路相机或者激光雷达短暂失效。如果融合模块默认两个模态永远都在且都可靠一旦出现缺失输出会崩得比单模态还惨。我在这块踩过的坑是训练时从来没模拟过缺失部署时第一次遇到相机被遮挡模型直接把整片区域判成了无障碍因为相机分支输出的是一片均匀的低纹理特征融合模块把它当成了这里确实什么都没有。后来我加了模态丢弃训练每个 batch 里随机选 10% 到 15% 的样本把相机分支或者激光雷达分支整个置零强制网络学会单模态也能出结果。这个技巧很简单但效果非常明显尤其是对某一路相机失效这种局部缺失场景。更进一步的是逐区域可靠性估计。不是整路丢弃而是让网络自己判断每个 BEV 区域的两个模态特征是否可信。我在门控网络里加了一个辅助头预测该位置相机特征可靠度用图像亮度、纹理丰富度、深度熵作为监督信号。这个辅助头不需要精确标注用简单的启发式规则生成伪标签就行。3. 落地实现从网格参数到代码3.1 BEV 网格与深度分箱的参数计算参数选择看着琐碎但它直接决定了冲突的分辨率。我见过不少项目直接照抄别人的配置结果发现自己的场景根本不适配。这里把计算过程摊开讲。BEV 网格范围要覆盖检测需求的最远距离同时兼顾显存。假设检测范围是前后左右各 54 米那 BEV 的物理尺寸就是 108 米 × 108 米。分辨率选 0.075 米/格网格数就是108 / 0.075 1440也就是 1440 × 1440。这个尺寸在 256 通道下显存占用不小如果显存吃紧可以放到 0.1 米/格得到 1080 × 1080远处小目标的定位精度会损失一些但整体可用。高度方向我一般取 -5 米到 3 米因为地面以下的点没意义而大部分交通参与者的高度不会超过 3 米除非要检测大型车辆。如果任务里包含卡车、公交车可以放宽到 4 米。深度分箱是相机分支的关键参数。我的经验是不要用纯线性分箱因为近处的深度误差影响大、远处的深度误差影响小线性分箱会让远处分得太粗。用对数增长的方案更合理import numpy as np def make_depth_bins(d_min1.0, d_max60.0, num_bins88): # 对数增长分箱近密远疏 bins np.linspace(np.log(d_min), np.log(d_max), num_bins) bins np.exp(bins) # 转成每个 bin 的边界 return bins按d_min1.0、d_max60.0、num_bins88算下来第一个 bin 宽度大约 0.016 米最后一个 bin 宽度大约 1.4 米。这个分布符合近处要准、远处可以粗的直觉。如果检测距离拉到 80 米bin 数要相应增加到 100 以上否则远处分辨率不够。相机内参的处理要注意归一化。不同相机的分辨率不同做视角变换前要统一把像素坐标归一化到[-1, 1]区间否则多相机拼接时会出现尺度不一致。外参矩阵则是从相机坐标系到自车坐标系的变换这个矩阵的精度直接决定了投影位置对不对。3.2 深度不确定性引导的几何对齐模块这是压制拖尾弥散型冲突的核心模块。设计思路是不改变深度预测的方式而是在投影时给每个深度上的特征乘一个基于不确定性的权重让分布平坦的深度贡献变小。先看深度预测头它在每个像素上输出D个深度的 logitsimport torch import torch.nn as nn import torch.nn.functional as F class DepthUncertaintyHead(nn.Module): def __init__(self, in_channels, num_depth_bins): super().__init__() self.num_bins num_depth_bins self.conv nn.Conv2d(in_channels, num_depth_bins, 1) def forward(self, feat): # feat: [B*N, C, H, W] logits self.conv(feat) # [B*N, D, H, W] prob F.softmax(logits, dim1) # 计算每个像素的深度分布熵 entropy -(prob * torch.log(prob 1e-8)).sum(dim1) entropy entropy / np.log(self.num_bins) # 归一化到 [0,1] return prob, entropy熵值归一化之后1 表示完全平坦不可信0 表示完全尖锐可信。接下来在投影到 BEV 时用熵反过来做衰减def lift_to_bev(feat, prob, entropy, geometry, bev_shape): feat: [B*N, C, H, W] prob: [B*N, D, H, W] entropy: [B*N, H, W] geometry: 预先算好的像素-深度到 BEV 的索引映射 B, C, H, W feat.shape D prob.shape[1] # 不确定性衰减因子熵越高因子越小 reliability (1.0 - entropy).unsqueeze(1).repeat(1, D, 1, 1) # [B*N, D, H, W] weight prob * reliability # 后面接 voxel pooling把 weight 和 feat 的外积累加进 BEV 网格 frustum_feat feat.unsqueeze(2) * weight.unsqueeze(1) # [B*N, C, D, H, W] bev_feat voxel_pooling(frustum_feat, geometry, bev_shape) return bev_feat这里有个细节值注意衰减因子不能太狠。我一开始直接用(1 - entropy)平方结果远距离的相机特征几乎被抹没了融合变成了纯激光雷达模型。后来改成温和的线性衰减并且给衰减因子设了个下限0.2保证再不可信的相机特征也保留一点信息让融合模块自己去判断。实测下来线性衰减配上 0.2 的下限在 40 米以内的召回率比不加衰减高一个多点40 米以外基本持平但误检明显减少。3.3 冲突感知门控融合到了这一步两个模态的 BEV 特征已经空间对齐、幅值归一化了。接下来要解决的是逐位置该信谁。我的门控网络结构很轻输入是三个东西激光雷达 BEV 特征F_l、相机 BEV 特征F_c、以及一个局部一致性度量S。S的计算方式是让F_l和F_c各自过一个 1×1 卷积降到低维算余弦相似度再过一个小的卷积核平滑一下。相似度高的地方说明两个模态看法一致可以直接融合相似度低的地方说明有冲突需要按可靠性分配权重。class ConflictAwareGate(nn.Module): def __init__(self, dim, reduce4): super().__init__() hidden dim // reduce self.proj_l nn.Conv2d(dim, hidden, 1) self.proj_c nn.Conv2d(dim, hidden, 1) # 门控网络输入 LiDAR、相机、一致性图 self.gate nn.Sequential( nn.Conv2d(dim * 2 1, hidden, 3, padding1), nn.BatchNorm2d(hidden), nn.ReLU(inplaceTrue), nn.Conv2d(hidden, dim, 1), nn.Sigmoid() ) def forward(self, feat_l, feat_c): # 局部一致性余弦相似度 pl F.normalize(self.proj_l(feat_l), dim1) pc F.normalize(self.proj_c(feat_c), dim1) sim (pl * pc).sum(dim1, keepdimTrue) # [B,1,H,W] inp torch.cat([feat_l, feat_c, sim], dim1) g self.gate(inp) # [B,C,H,W] fused g * feat_l (1.0 - g) * feat_c return fused, g门控输出的g可以理解为该位置该给激光雷达多少权重。训练稳定之后我把g可视化出来发现规律很符合直觉车辆正后方、地面、护栏这些点云稠密区域g接近 0.8 以上远处天空、稀疏区域g掉到 0.3 以下主要由相机提供语义而在两者都模棱两可的区域g在 0.5 附近摇摆说明网络自己也不确定。这个门控还有个额外好处g图可以直接当调试工具用。如果某段场景的检测出问题我先看g图如果某个本该是车的地方g异常低说明相机分支在那里输出了错误的高置信特征顺着查就能找到根源。3.4 一致性约束与训练配置训练阶段的一致性约束本质是给网络一个两个模态应该描述同一件事的软监督。我用的是一组对比式的损失在 BEV 特征图上采样正负样本对。具体做法对每个 BEV 位置(i, j)激光雷达特征F_l[i,j]和相机特征F_c[i,j]构成正样本对F_l[i,j]和相机特征图上距离超过阈值的随机位置构成负样本对。用 InfoNCE 的形式约束def cross_modal_consistency_loss(feat_l, feat_c, pos_radius2, num_neg64, tau0.1): B, C, H, W feat_l.shape fl F.normalize(feat_l.flatten(2).transpose(1, 2), dim-1) # [B, HW, C] fc F.normalize(feat_c.flatten(2).transpose(1, 2), dim-1) # 正样本同位置 pos_sim (fl * fc).sum(dim-1) / tau # [B, HW] loss_pos -pos_sim.mean() # 负样本随机采样远处位置 idx torch.randint(0, H * W, (num_neg,), devicefeat_l.device) neg fc[:, idx, :] # [B, num_neg, C] neg_sim torch.einsum(bnc,bmc-bnm, fl, neg) / tau loss_neg F.logsumexp(neg_sim, dim-1).mean() return loss_pos loss_neg这个损失不能权重太高。我试过 0.5训练前期 loss 直接爆炸两个模态互相拉扯检测头根本学不动。最后定在 0.05作为辅助项存在主损失还是检测头的分类损失和回归损失。训练配置上还有几个关键点值得说。学习率要用分组设置图像分支的骨干网络通常加载预训练权重学习率设成 1e-4 量级激光雷达分支和融合模块是随机初始化的学习率设成 1e-3 量级。把两者混在一起用同一个学习率要么图像分支学崩了要么融合模块学不动。数据增强要模态一致。翻转、旋转这类几何增强必须同时作用在两个模态上而且变换矩阵要同步应用。我曾经因为只对图像做了水平翻转、忘了翻转点云训练出来的模型对左右方向完全没有概念检测框经常左右飘。这个错误很低级但排查花了两天因为 loss 曲线看着还挺正常。预热阶段分开训练。前两三个 epoch 我通常先把两个分支单独训一下让各自的 BEV 特征先有基本语义再开启融合模块。直接端到端训融合前期两个模态的特征都是随机噪声一致性损失会把它们拉到一个共同但没意义的表示上反而拖慢收敛。4. 实车与离线数据上的问题排查记录4.1 常见问题速查表下面这张表是我在调试过程中攒下来的基本覆盖了融合模型最常见的症状。遇到问题时先对照症状定位能省掉大量瞎试的时间。症状最可能的原因排查手段处理方式融合后 mAP 低于单模态外参/时间戳错位静止场景点云投影叠图重新标定、加运动补偿远处目标框抖动、分裂相机深度弥散可视化相机 BEV 特征加大不确定性衰减、提高深度监督权重夜间/逆光性能崩塌过度依赖相机屏蔽相机分支单独评估提高门控对激光雷达的偏置、加模态丢弃训练小目标漏检严重BEV 分辨率不足统计漏检目标的距离分布提高 BEV 分辨率或加小目标采样训练 loss 震荡不收敛一致性损失权重过高逐步降低权重对比权重降到 0.05 以下某一路相机失效整体崩无缺失鲁棒性训练时强制遮挡单路加逐路 drop 训练相邻帧结果跳变时序特征未对齐检查 BEV 特征时序一致性加时序平滑或时序融合模块融合特征幅值失衡相机能量压过激光雷达统计两分支特征均值方差融合前做 LayerNorm4.2 几个只有踩过才知道的点第一不要迷信融合一定比单模态好。我在两个数据集上验证过纯激光雷达模型在 30 米以内的小目标上检测精度比某些融合方案还高。融合的价值主要体现在远处的语义补充和遮挡场景如果在近距离稠密点云区域强行融合相机分支反而在引入噪声。所以后来我在门控里加了个先验偏置点云密度高的位置初始权重偏向激光雷达。这个先验不需要可学习直接在门控的输入里加一个密度图的通道就够。第二深度监督的标注质量决定融合上限。相机分支的深度估计如果只靠几何自监督精度很难上去。我强烈建议用激光雷达点云投影到图像上生成稀疏深度监督虽然稀疏但对网络来说是非常强的锚点。做法是把点云投影到每个相机视角落在图像内的点作为该像素的深度真值只在有投影的位置算损失。这个监督加进去之后40 米以外的深度误差大概能降三成拖尾现象肉眼可见地缓解。第三BEV 空间里的空不等于没有。激光雷达没有回波的 BEV 格子可能是真的空地也可能是黑色车漆、玻璃、雨雾导致的漏检。相机分支在这种位置往往有响应融合时如果直接按激光雷达的空去否定相机就会漏检。我在门控的输入里加了一个点云有效回波计数通道让网络能区分这里是空的和这里没有数据这两个概念在 BEV 上长得一样但对融合决策的意义完全不同。第四训练和推理的模态可用性要匹配。训练时如果永远两个模态齐全推理时遇到缺失就会崩。但如果训练时丢弃得太狠比如 50%模型又会退化成对单模态的依赖融合模块学不到东西。我的经验值是 10% 到 15% 的丢弃比例并且要保证每个 batch 里至少有一半样本是完整模态的这样融合模块才有足够的学习信号。第五可视化是排查跨模态冲突最有效的工具没有之一。我给自己搭了个小工具把激光雷达 BEV 特征、相机 BEV 特征、门控权重图、一致性图、最终检测结果五张图并排显示逐帧翻。很多问题看 loss 曲线永远看不出来但一眼看五联图就明白了。这个工具花了我半天时间写但省下的调试时间是以周计的。4.3 关于部署侧的一个补充离线指标好看不等于车上能跑。融合模型的推理耗时主要压在相机分支的视角变换上那一步涉及大量的索引操作在嵌入式平台上很容易成为瓶颈。我做过一次耗时拆解视角变换大概占了整个前向的 35% 到 40%。优化手段有两条一是把 BEV 网格分辨率在推理时降一档精度损失不大但耗时能降两成二是把 voxel pooling 的索引提前离线算好运行时只做查表和累加能省掉重复的坐标计算。另一个容易被忽略的点是融合模块的量化友好性。门控里的 sigmoid 输出在量化到 int8 之后0.5 附近的权重会出现明显的跳变导致融合结果不稳定。我的处理是把门控权重保持浮点计算只对卷积部分做量化虽然混合精度麻烦一点但结果稳定得多。还有个小技巧门控权重g其实可以离线统计出一个分布如果某类场景下g长期偏向某一侧说明融合模块在该场景下已经退化成了单模态这时候可以考虑针对性补数据或者调整先验偏置。我把这个统计做成了日常监控项每跑完一批新数据就看一眼g的均值曲线比看 mAP 更早发现模型退化。一路调下来我最大的体会是跨模态冲突不是靠某个模块消灭的而是靠一层一层的约束把它压到不影响决策的程度。对齐做扎实了冲突的量级就降一个数量级不确定性建模做好了弥散的部分就不会污染融合结果门控和一致性约束再把剩下的矛盾点兜住。这三层缺一层模型都能跑但在极端场景下就会露馅。至于具体每个模块的权重和参数没有放之四海皆准的配置得拿自己场景的数据一轮一轮试尤其是门控的先验偏置和一致性损失的权重这两个我认为最需要按场景调。