多模态学习这个词这两年出现频率很高,但真正动手把视觉、听觉、触觉三路信号塞进同一个模型里跑通的人并不多。大多数人卡在第一步:三路数据的时间戳对不上、采样率差三个数量级、标签还得靠人工一个个标注。我自己在做一个材质与抓取判断的小项目时,前后折腾了小半年才把这三条数据流对齐并训出一个能用的模型。这篇就把整个过程拆开讲:三种模态各自的数据特性是什么、融合应该在哪一层做、对齐为什么比模型结构更难、训练配置怎么调,以及我踩过的那些坑。适合已经有点深度学习基础、想往具身智能或者多传感器融合方向走的人看,也适合做质检、机器人操作、材料识别的同行参考。
1. 三条数据流各自的脾气:视觉、听觉、触觉的模态特性差异
在动手写任何一行模型代码之前,我花了差不多两周时间只是看数据。这个阶段很多人会跳过,直接上架构,结果后面所有问题都要推倒重来。三种模态的数据形态差异大到什么程度?视觉是三维张量 H×W×C,帧率几十赫兹;听觉是一维长波形,采样率动辄上万赫兹;触觉则可能是一段几百赫兹的六维力序列,也可能是触觉传感器输出的低分辨率图像。它们的维度、频率、噪声模型、语义密度全都不一样。理解这些差异,决定了后面融合层怎么设计、损失函数怎么配比、甚至决定了这个任务到底值不值得做多模态。
1.1 视觉:信息密度最高,也最容易被"喂坏"
视觉最大的优势是语义密度高,一张图里能同时包含形状、颜色、纹理、空间位置,而且有大量预训练权重可以拿来用。但这也是它最大的陷阱:因为视觉太强,模型很容易学会只依赖视觉,把另外两路信号当成噪声忽略掉。我在第一版模型里就吃过这个亏,把三路特征拼在一起训,最后验证集准确率 87%,看起来不错,但做一个消融实验把音频和触觉输入全置零,准确率只掉了 1.2 个点。也就是说那两路信号基本没起作用。
视觉预处理的几个关键决策,我按重要性排序:
- 分辨率不是越高越好。做材质分类这类任务,224×224 足够了,再高只会让显存炸掉、训练变慢,而材质纹理在低分辨率下依然保留得不错。做精细抓取位姿估计才需要上到 640 以上。
- 颜色增强要慎用。这条是我踩过的坑。通用图像分类的标准做法是随机调色相、饱和度、亮度,但在材质判断任务里,颜色本身就是强判别特征(比如金属和塑料的色泽差异),随机色相抖动直接把关键线索破坏了。我的做法是颜色类增强强度降到常规值的四分之一,几何类增强(随机裁剪、翻转)保持正常。
- 深度图比 RGB 更值得投入。如果硬件条件允许,加一路深度或者直接上 RGB-D,对触觉相关的任务帮助非常大,因为深度图能提供接触面的几何信息,和触觉信号在物理意义上是互补的。
还有一个容易忽略的点:视觉帧率通常和触觉、音频不同步。相机 30fps 意味着每帧间隔 33 毫秒,而触觉传感器可能 500Hz,一帧图像对应十几个触觉采样点。这个对应关系必须在数据加载阶段就处理掉,别指望模型自己去学。
1.2 听觉:从波形到频谱图,这一步决定了模型的上限
原始音频波形对神经网络来说非常不友好,一维长序列、局部相关性弱、直接卷积效果差。业内的通用做法是先转成时频谱图,再当成图像处理。这个转换过程里有几个参数会直接决定信息损失多少:
| 参数 | 常见取值 | 影响 | 我的建议 |
|---|---|---|---|
| 采样率 | 16kHz / 44.1kHz | 决定可保留的最高频率 | 材料撞击声的高频成分重要,用 44.1kHz |
| 窗长 | 1024 / 2048 | 频率分辨率 vs 时间分辨率 | 短促撞击声用 512-1024 |
| 帧移 | 窗长的 1/4 到 1/2 | 时间粒度 | 撞击类事件用 1/4,保留更多时间细节 |
| 频带数 | 64 / 128 Mel | 频率压缩程度 | 128 起步,低频频段信息别压太狠 |
做材料识别的时候,听觉路其实承担了一个很特殊的角色:敲击声里包含了材料的共振频率和阻尼特性,这是视觉和触觉都不容易直接拿到的信息。金属敲击有长衰减和清晰的高频共振峰,木头衰减快、频谱更平,塑料介于两者之间。这些特征在梅尔频谱图上表现为不同的能量分布模式,卷积网络能学到,但前提是你别把频率轴压得太狠。
我还遇到过一个问题:环境噪声。实验室里安静,实际场景里有风扇声、人说话声、设备运转声。解决方案一是采集时就尽量控制,二是训练时做加性噪声增强,把一段真实录制的背景噪声按不同信噪比混进去。信噪比范围我一般取 5dB 到 30dB,太低的信噪比对模型是纯粹的干扰。
注意:频谱图增强(时间掩蔽、频率掩蔽)在语音识别里是标配,但在声学事件检测任务里要收敛着用。频率掩蔽如果遮住宽度过大,可能正好把判别性的共振峰遮掉,模型反而学到更差的不变表示。
1.3 触觉:采样率低、噪声大、跨设备迁移最痛
触觉是三路里最麻烦的。麻烦不在于信号复杂,而在于数据难搞、设备差异大、标注成本高。常见的触觉信号有两类:一类是力/力矩传感器输出的几维时序信号(比如六维力、单点压力),一类是视触觉传感器输出的接触面图像。前者便宜好部署但信息量少,后者信息丰富但硬件贵、标定麻烦。
时序触觉信号的处理要点:
- 必须做基线校准。传感器静置时的读数不是零,会随温度、老化漂移。我的做法是每次采集会话开始和结束各采 5 秒静置数据,取均值作为零点偏移,全部数据减掉这个偏移。不做这一步,不同天的数据分布差异会大到让模型彻底学不动。
- 重采样到统一频率。500Hz 和 200Hz 的数据混在一起训练,必须统一到较低的那个频率,或者都插值到中间频率。我一般统一到 100Hz,对于抓取、按压这类动作,100Hz 已经完全够用,再高只是增加噪声。
- 差分特征比绝对值更有用。接触瞬间的变化率往往比绝对压力值更有判别性,我会额外算一阶差分作为第二通道输入。
视触觉传感器的图像数据则要注意光照和形变标定,不同批次的凝胶硬度不同,同一力度按压产生的形变面积不一样。这个差异如果不处理,模型学到的其实是"哪台设备",不是"什么材质"。
我在实际项目里吃过一个很典型的亏:训练数据全部来自一台设备,测试时换了一台同型号但凝胶更换过的传感器,准确率从 85% 掉到 61%。后来加了按静置基线归一化、以及在训练时对不同设备的数据做对抗式去偏,才把跨设备性能拉回到 78% 左右。这个教训很贵,但值得。
2. 融合该放在哪一层:从向量拼接走到跨模态注意力
搞清楚三路数据长什么样之后,接下来的核心问题是:在哪一层把它们合起来。这个问题的答案不是唯一的,取决于你的模态可靠性、数据量和任务类型。我前后试过四种融合方式,每一种都有明确的适用边界,盲目上最复杂的那个往往得不偿失。
2.1 早期融合、晚期融合与中期融合的取舍
早期融合就是把三路原始数据或低层特征直接拼起来,送进一个统一网络。优点是实现简单、跨模态的低层交互能被捕获;缺点是对模态缺失极其脆弱,而且不同模态的尺度差异巨大,拼接后容易让数值范围大的那一路主导梯度。
晚期融合是每路各自出一个预测,最后加权平均或投票。优点是鲁棒,某一路失效影响可控,训练也简单,每路可以独立调;缺点是丢掉了跨模态的细粒度交互信息,比如"敲击声的衰减时间"和"触觉的接触持续时间"之间的关联就学不到。
中期融合(也叫特征级融合)是我最后采用的方式:每路先用各自的编码器提特征,在中间层做融合,再送进决策头。这样既保留了模态独立性,又能学到跨模态关系,代价是结构复杂一些、调参成本高。
基于注意力的融合可以看作是中期融合的进阶版,用跨模态注意力让每一路特征去"查询"其他路的相关信息。这个方案在多模态数据充足时效果最好,但小样本场景下很容易过拟合。
下面这张表是我实测下来的对比,任务是用视觉+听觉+触觉判断十种常见材质:
| 融合方式 | 参数量 | 验证集准确率 | 单模态缺失时准确率 | 训练耗时 |
|---|---|---|---|---|
| 早期融合 | 约 12M | 82.3% | 54.1% | 1.0x |
| 晚期融合 | 约 14M | 84.7% | 76.8% | 0.9x |
| 中期融合(拼接) | 约 16M | 87.2% | 71.5% | 1.2x |
| 跨模态注意力 | 约 21M | 88.9% | 79.3% | 1.7x |
从这个结果能看出两件事:一是注意力融合确实带来了最高的完整输入准确率,二是晚期融合在模态缺失场景下最稳。如果你的实际部署环境里三路传感器不可能永远同时在线,那这个权衡就要认真考虑。
2.2 跨模态注意力到底在注意什么
很多人把跨模态注意力当成黑盒,其实它的逻辑很直白:把一路特征当作查询,另外几路当作键和值,算出来的注意力权重表示"当前这段视觉特征,应该从听觉和触觉里取多少信息"。
举个具体例子。模型看到一块浅色、有光泽、边缘规整的物体,视觉特征激活了"疑似金属"的假设。这时候跨模态注意力会让视觉特征去查询听觉特征,如果敲击声的频谱里存在长衰减的高频共振峰,注意力权重就会高,把这份证据整合进来强化"金属"判断;如果声音是短促闷响,注意力权重低,甚至会把假设往"塑料"方向拉。
这个机制的价值在于它是有条件的、动态的。固定权重的拼接做不到这一点,因为拼接给每一路分配的是恒定权重,不管当前样本哪一路更可信。实测下来,注意力融合在"某一模态质量突然变差"的场景下优势最明显:比如光照过曝导致视觉失效,注意力会自动降低视觉权重。
实现上我用的就是标准的单头或多头注意力,但有两个细节必须注意:
- 加模态类型嵌入。三路特征的语义完全不同,如果不加一个标识向量告诉模型"这是触觉特征",注意力很容易在数值相近但语义无关的位置上建立错误关联。这个做法借鉴自序列建模里位置编码的思路。
- 注意力层不要堆太深。我试过四层堆叠,参数量翻倍但准确率只涨了 0.3 个点,而且训练明显更容易发散。两层基本够用,除非你的数据量真的很大。
2.3 一个可落地的最小融合网络结构
说说我实际在用的结构,参数不多但跑得稳:
第一层是三路独立编码器。视觉用一个轻量的卷积骨干,输入 224×224×3,输出 512 维;听觉把 128×128 的梅尔频谱图喂进一个小卷积网络,输出 256 维;触觉用一个一维卷积沿时间轴提取,输入是 100 帧 × 8 通道(六维力加两维差分),输出 128 维。
第二层做维度对齐。三路特征维度不同没法直接算注意力,各自接一个线性投影到统一的 256 维,同时加上可学习的模态类型嵌入。
第三层是双向跨模态注意力。视觉查听觉+触觉,触觉查视觉+听觉,各算一次,输出拼接后再过一层前馈网络。
第四层是池化和分类头。把融合特征做平均池化,接两层全连接输出类别。
整个网络参数量控制在 20M 以内,单卡能跑,推理在边缘设备上大概 40 毫秒一帧,对于抓取决策这类任务频率够了。这里的关键取舍是编码器一定要轻,因为三路并行意味着显存占用是三倍,骨干网络一旦上大模型,训练成本会失控。
提示:如果你手头数据量少于一万个样本,别急着上跨模态注意力。先把中期拼接融合调到一个合理的基线,再逐步替换成注意力,每次替换都做消融,这样出问题时能快速定位是哪一步引入的退化。
3. 对齐问题:多模态学习里最难也最容易被低估的一环
模型结构可以抄,损失函数可以查文档,但对齐这件事没有任何现成方案可以直接用,它和你自己的硬件、采集流程、任务定义强绑定。我见过太多项目在架构上花了大力气,最后败在数据对不齐上。这一节展开讲我遇到的对齐问题以及解决思路。
3.1 时间对齐:毫秒级偏差如何毁掉一次抓取判断
三路信号的时钟是独立的。相机有自己的帧时间戳,音频设备有自己的采样时钟,触觉控制器有另一套。即使你在软件层面同时启动录制,实际采集到的第一个样本在物理时间上也可能差几十毫秒。
对于材质判断任务,这个偏差的后果是什么?敲击动作持续大约 100 到 200 毫秒,触觉的接触峰值出现在敲击后 20 到 50 毫秒,声音的起始点紧随其后。如果你把音频窗口和触觉窗口按固定偏移对齐,实际偏差了三四十毫秒,那么模型学到的就是"敲击前的静默"配"接触后的力",这两者在语义上毫无关系。
我的处理链路是这样的:
- 硬件层面尽量统一时钟源。如果条件允许,用一个微控制器同时触发相机曝光、音频录制开始、触觉采样开始,这是最可靠的方案。
- 软件层面用事件做锚点。如果没法统一时钟,就找一个物理事件作为对齐锚点。敲击任务里最好用的锚点是触觉信号的突变点——力值在极短时间内跃升,这个时刻非常容易检测。以它为基准,往前找音频的能量突增点,往后找视觉帧里物体位置变化的帧。
- 对齐后做一致性校验。把所有样本的对齐偏移量画成直方图,如果分布很宽(比如标准差超过 20 毫秒),说明对齐逻辑有问题,得回头查。
这套流程做下来,我的样本对齐误差能控制在 8 毫秒以内,对材质判断任务已经足够。但要注意,如果你的任务是精细操作(比如插孔、拧螺丝),毫秒级误差都可能致命,那就必须上硬件同步。
3.2 语义对齐:对比学习为什么能起作用
时间对齐解决的是"哪一段配哪一段",语义对齐解决的是"这两段在讲同一件事吗"。后者更难,因为三路信号对同一件事的表达方式完全不同。
对比学习是目前最有效的手段。核心思路很朴素:同一个样本的不同模态表示在特征空间里应该靠近,不同样本的表示应该远离。损失函数用 InfoNCE,形式上是把一个正样本对的相似度和一批负样本的相似度做 softmax。
这个思路为什么有效?因为它强迫模型学到一个跨模态共享的语义空间。在这个空间里,"金属"这个概念不管是通过视觉纹理、敲击声还是触感表达,最终都会映射到相近的位置。一旦这个空间建起来,即使某个模态在推理时缺失,也能从其他模态的特征去近似。
实操上有几个关键点:
- 温度系数很关键。我一开始用 0.07 这个常见值,训练后期损失下降很慢,把温度调到 0.1 之后收敛明显更顺。这个值和你的批次大小、特征维度都相关,需要自己调。
- 负样本的质量决定效果。如果批次内负样本都是明显不同的类别(比如金属配木头),任务太简单,学到的表示不具备细粒度区分能力。我的做法是提高批次内同类样本的比例,让模型去区分"这块铝"和"那块铝"。
- 别只用对比损失。对比学习学到的是判别性表示,但分类任务还需要类别边界。我最终用的是对比损失加交叉熵的联合目标,权重比 0.3:1,实测比单用任何一个都好。
3.3 用对比损失做预训练的实操细节
我把对比预训练和下游微调分成了两个阶段。预训练阶段不接分类头,只用三路特征算对比损失,目标是让编码器学到跨模态共享表示。这个阶段用了大约 8 万个无标注样本,训练了 40 个 epoch。
具体的实现结构是:三路编码器分别输出特征,各自过一个投影头(两层全连接,中间加激活),投影到 128 维的对比空间。然后两两算对比损失,三个模态对(视觉-听觉、视觉-触觉、听觉-触觉)的损失取平均。
这里有个容易忽略的细节:投影头的输出要归一化到单位球面上再算相似度,不然特征模长会主导相似度计算。这个技巧在各种对比学习实现里都有,但自己写的时候很容易漏。
预训练完成之后,丢掉投影头,保留编码器,接上融合模块和分类头,用少量有标注数据微调 10 到 15 个 epoch。微调阶段的学习率要比预训练低一个数量级,不然会把预训练学到的表示冲掉。
实测下来,这套两阶段方案比直接从零训练端到端模型,在标注数据只有 3000 个样本的情况下,准确率提升了 9 个百分点左右。效果主要来自两点:无标注数据让编码器见到了更多变化,对比目标提供了比分类损失更强的结构约束。
4. 把三模态模型跑通:数据管线、训练配置与验证方法
前面讲的是设计和原理,这一节讲落地。从数据采集到模型收敛,中间有一大堆工程细节会决定成败,而且这些细节在论文里基本看不到。
4.1 数据采集与同步的工程方案
我的采集装置大致是这样:一台工业相机做俯视拍摄,一个麦克风放在距敲击点 15 厘米的位置,一套力传感器装在执行末端,一个微控制器负责统一触发。
采集流程的每一步都有讲究:
- 每个样本单独触发。不要连续录制再切分,那样时间关系容易乱。每个样本从触发到结束大约 2 秒,包含接近、敲击、回撤三个阶段。
- 样本之间留间隔。至少 1 秒,让传感器回到基线状态,也避免上一个动作的余振干扰下一个样本。
- 同步保存元数据。每次采集记录设备编号、传感器批次、环境温度、操作人员代号、样本编号。这些信息在做数据分析和排查问题时极其重要,我当时就是因为漏记了设备批次,导致后面发现分布偏移时无法快速定位原因。
标注方面,我用的是"动作级标注":一次敲击对应一个材质标签,三路数据共用这个标签。这样能省去逐帧标注的成本,代价是无法做细粒度的时间定位任务。
数据量上,十个类别每个类别采了 800 个样本,总共 8000 个有标注样本,加上无标注的补充采集大概 8 万个。这个量级对于三模态训练来说偏小,所以前面才需要对比预训练来撑。
4.2 训练配置与损失权重
配置这块我列一份实测可用的参数表:
| 配置项 | 取值 | 说明 |
|---|---|---|
| 优化器 | AdamW | 权重衰减 0.01 |
| 学习率 | 预训练 3e-4 / 微调 3e-5 | 余弦退火 |
| 批次大小 | 64 | 受显存限制,梯度累积到等效 128 |
| 训练轮数 | 预训练 40 / 微调 15 | 早停耐心 5 |
| 损失权重 | 对比 0.3 / 分类 1.0 | 微调阶段 |
| 模态丢弃率 | 0.2 | 训练时随机整路丢弃 |
| 混合精度 | 开启 | 显存省约 35% |
模态丢弃这一项要重点说。它是我认为性价比最高的一个技巧:训练时以一定概率把某一整路输入置零(不是置为随机值,是置零并标记为缺失),强迫模型学会在有模态缺失的情况下依然做出合理预测。这个技巧让模型在部署时对传感器偶发失效有了容错能力,实测单模态缺失时准确率能提升 6 到 8 个点。
损失权重需要自己调。我一开始给对比损失和分类损失各 0.5,结果分类边界学得不够清晰;后来把对比降到 0.3,分类提到 1.0,效果明显更好。核心逻辑是:对比损失负责把特征空间整理好,分类损失负责画出决策边界,主次不能颠倒。
4.3 验证集怎么切才不骗自己
这一条我用了很长时间才想明白,也是我认为最容易犯的错。多模态时序数据如果按帧或按时间窗口随机切分训练集和验证集,会严重高估模型性能,因为相邻的窗口来自同一次敲击动作,特征高度相似,本质上就是数据泄漏。
正确的切分粒度应该是"独立样本"级别,也就是一次完整的敲击动作只能出现在训练集或验证集其中一边。如果你的数据是在不同天采集的,更好的做法是按采集批次切分,用前几天做训练、后几天做验证,这样能真实反映模型在新数据上的表现。
我用两种切法做过对比:按窗口随机切分得到 96.2% 的验证准确率,按样本切分是 87.2%,按采集批次切分则只有 81.5%。差距这么大,就是因为前两种切法都或多或少存在泄漏。如果你只做按窗口随机切分,上线时的心理落差会非常大。
还有一个细节:验证集要覆盖所有设备和所有类别。如果验证集里缺少某个设备的数据,你根本发现不了跨设备泛化的问题。
5. 实测中最常见的四类坑与排查链路
这一节讲我踩过的坑,以及我是怎么一步步定位的。排查思路比结论更有价值,因为你的问题大概率不是我遇到的这一个,但定位方法可以复用。
5.1 模态缺失与模态失效:模型在偷偷"偷懒"
现象:完整输入时验证准确率 87%,把音频和触觉置零后仍有 85.8%。
排查链路是这样的:先做单模态消融,分别只用视觉、只用听觉、只用触觉训三个小模型,结果视觉单独就有 79%,听觉单独 68%,触觉单独 71%。这说明单模态信息量是够的,问题出在融合环节。
再看训练过程中的梯度范数,发现视觉编码器的梯度范数比另外两路高一个数量级。原因清楚了:视觉特征在初始阶段就比其他两路更有判别性,梯度更大,更新更快,模型很快收敛到"只信视觉"的局部最优。这在多模态学习里叫模态主导或者模态竞争。
解决办法有四条,我全用上了:
- 单模态辅助损失。每路特征各自接一个小的分类头,也参与损失计算。这样每路编码器都有直接的监督信号,不会被融合层饿死。
- 梯度归一化。监控各模态编码器的梯度范数,动态调整各路的损失权重,让它们的更新速度保持在同一量级。
- 训练时模态丢弃,前面说过的 0.2 概率,让模型不能完全依赖任何一路。
- 模态随机失活细化到通道。不只是整路丢弃,还在特征层面随机 mask 一部分通道,进一步降低单路的垄断性。
这一套组合下来,把音频和触觉置零后的准确率掉到了 62% 左右,说明那两路信号真正被用起来了。
5.2 模态强弱不均:视觉把其他两路压死了
这个坑和上一个相关但不完全一样。上一个讲的是训练动态,这个讲的是特征尺度。
现象:合并后的特征向量里,视觉部分数值范围在 [-8, 8],触觉部分在 [-0.3, 0.3],听觉在 [-1.2, 1.2]。直接拼接之后送进全连接层,权重初始化时会天然对数值大的维度更敏感。
我的处理是每一路特征在融合前都做一次层级归一化,把每路的特征向量归一化到同一量级(均值零、方差一),再加一个可学习的缩放参数。这个缩放参数初始化为 1,让模型自己去学每路应该占多大比重。
这个改动听起来很小,实测带来的提升是 3.5 个百分点。而且训练稳定性明显变好,之前那种"训到一半 loss 突然跳起来"的情况少了很多。
5.3 小样本与过拟合:参数量不是越多越好
现象:训练集准确率 98%,验证集 74%,典型的过拟合。
我先怀疑是模型太大,把融合层的注意力头数从 8 降到 4,隐藏维度从 512 降到 256,参数量从 21M 砍到 13M。验证集涨到 79%,但还是过拟合。
接着做数据增强。视觉做随机裁剪和轻微旋转,听觉做小幅度时间掩蔽,触觉加高斯噪声(信噪比 25dB 左右)。这一轮涨到 83%。
最后一招是正则化。Dropout 加到 0.3,权重衰减从 0.01 提到 0.05,标签平滑用 0.1。组合起来到了 87%,训练集准确率降到 91%,过拟合基本被压住了。
这里的心得是:小样本多模态任务里,模型容量宁小勿大。多模态的编码器是三个,参数量天然比单模态多,很容易在数据不足时过拟合。如果数据量在几千这个量级,先把总参数量控制在 15M 以内,再考虑性能优化。
5.4 跨设备泛化:换个传感器就崩
这个坑前面提过一次,这里展开讲排查过程。
现象:同型号但更换过凝胶的触觉传感器,跨设备测试准确率从 85% 掉到 61%。
第一步先确认是不是所有类别都掉。做分类别混淆矩阵后发现,掉得最厉害的是那几个触觉特征相似的类别(比如不同种类的塑料),而金属类别的准确率基本没变。这提示问题不在语义层面,而在触觉特征的分布偏移上。
第二步看特征分布。把两台设备的触觉特征做降维可视化,发现同一类别在两台设备上的特征簇明显分离,几乎是两个簇。这就是典型的设备偏差。
第三步找原因。对比两台设备的原始信号,发现同样的按压力度,新设备的读数整体偏低且波动更大——凝胶老化了,形变更小。
解决方案分三层:硬件层面每次采集做静置基线校准;数据层面用对抗训练让特征对设备标签不可分;训练层面在数据增强里模拟不同凝胶硬度(对形变信号做幅度缩放和噪声注入)。三层叠加把跨设备准确率拉回到 78%。
最后的经验是:涉及触觉的项目,从一开始就要规划多设备采集。哪怕只有两台设备,采集时交替使用,也比后期补救强得多。
6. 我在这套三模态方案上留下来的几条实用习惯
写到这里,把几条贯穿始终的习惯单独拎出来,这些不属于某个具体环节,但对整个项目的影响很大。
第一条是永远先做单模态基线。在动手搭融合网络之前,先训三个单模态模型,把每个模态的能力边界摸清楚。这个基线不仅是后面融合效果的参照系,更能帮你判断某个模态到底值不值得投入。我见过一些项目用了三路传感器,但其中一路单独分类准确率只有 55%,那还不如省掉这个传感器减少复杂度。
第二条是特征可视化当日常操作。每训完一个版本,我都会把各模态特征做一次降维可视化,看类别簇是否分离、看模态之间是否对齐。这比看 loss 曲线直观得多,很多问题在可视化里一眼就能看出来,比如某类样本的特征簇和另一类完全重叠,那基本就是标注错误或者数据采集有问题。
第三条是保留所有中间产物。预训练特征、融合中间层输出、注意力权重图,全部落盘保存。排查问题时经常需要回看这些,重新跑一遍推理的成本比存下来高得多。注意力权重图尤其有用,能直观看到模型在某次预测时到底依赖了哪一路信号,配合业务判断很快就能发现模型是不是在走捷径。
第四条是参数记录要细。上面那张配置表里的每一个值,都是我在不同版本间对比试出来的。批次大小、温度系数、损失权重、丢弃率,这些参数互相影响,改动一个就要重新验证。没有详细的实验记录,很容易陷入反复试同一个坑的循环。我的做法是每次训练产出一个配置快照,包含所有超参数、数据版本、代码 commit、结果指标,存进一个统一的表格里,事后追溯非常方便。
这套东西跑下来,整个项目从数据采集到可用的三模态模型大概用了五个月,其中数据相关的工作占了六成以上。如果让我给刚入门的同行一句建议:把注意力放在数据和评估方法上,模型结构反而是最容易标准化的一部分。多模态学习的门槛不在算法,在工程细节。