前几个月我一直在折腾多模态遥感目标检测方向的复现工作,核心是围绕TGRS 2025那篇带MROD-YOLO思路的改进,把MJRNet多模态联合表征网络模块真正集成进YOLOv12里跑通。这个项目最吸引我的点就是标题里那句“对可见光与红外信息的早期深度融合”——多模态融合谁都会说,但什么时候融、怎么融、融完之后检测头怎么用,这几步才是决定模型上限的关键。YOLOv12本身的架构已经相当成熟,基线效果摆在那,能让它继续往上涨的,恰恰就是输入端的表征质量。所以这篇文章我把整个复现过程完整记录下来,包括MJRNet的设计逻辑、为什么选早期融合而不是晚期拼接、模块怎么塞进YOLOv12里不破坏原有结构,以及训练中真实踩过的坑和排查思路,给正在做多模态检测改进的人一个可以直接上手的参考。
1. 项目到底在解决什么问题:单模态检测的瓶颈与多模态融合的价值
1.1 可见光与红外:为什么这对组合是遥感检测的黄金搭档
做遥感目标检测的人应该都有切身体会:可见光图像分辨率高、纹理细节丰富,像建筑物轮廓、车辆颜色、道路标线这种信息全靠它;但可见光受光照和天气影响太明显——夜间、雾天、阴影遮挡、强逆光环境下,目标要么淹没在暗背景里,要么被高亮区域吃掉。红外图像刚好相反,它捕捉的是热辐射差异,白天夜里都能工作,对温度特征显著的目标(车辆引擎、人员、工业设备)极其敏感,但缺点是分辨率普遍偏低、纹理信息少,单靠红外经常出现目标糊成一团的情况。
把两者放在一起,天然就是互补关系。我跑实验用的数据集里有一类场景特别典型:傍晚逆光条件下的车辆检测,可见光图像上车身和路面阴影几乎融为一体,纯可见光模型的置信度直接掉到0.4以下;但红外图像里车头发动机区域明显高亮。反过来,白天光照充足时红外图像对比度差、边缘模糊,检测效果反而一般。这个例子说明得很清楚——任何单一模态都有自己的“知识盲区”,多模态融合做的事情就是让模型同时握住两份证据,互相兜底。
1.2 融合时机之争:早期、中期、晚期融合到底差在哪
多模态检测的融合策略一直有三种主流流派,我先把它们放在同一张表里对比:
| 融合策略 | 融合位置 | 优点 | 典型问题 |
|---|---|---|---|
| 早期融合 | 输入层,图像直接拼接或像素级融合 | 实现简单,信息保留最完整 | 模态间语义差异大,简单拼接会产生大量冗余,模型难学 |
| 中期融合 | Backbone中段/特征层,两路特征在中间某层相加或拼接 | 兼顾语义与细节,灵活度高 | 需要设计复杂的对齐模块,训练难度上升 |
| 晚期融合 | 检测头附近,各模态独立预测后融合结果 | 两模态独立性强,互不干扰 | 特征交互太晚,互补信息没有得到充分利用,增益有限 |
很多早期工作喜欢做晚期融合,因为实现起来最省事,两个模型各跑各的,最后对预测框做个加权平均就行。但问题也明显:两个模态的检测结果在决策层面才相遇,模型根本没有机会学习“红外的那块高亮区域应该和可见光的那个纹理边缘对应起来”这种跨模态特征关联,融合效果完全取决于后处理策略的好坏。
中间融合是目前的主流研究方向,但设计空间太大——在哪个stage融合、用什么方式融合(concat、相加、注意力加权),都需要大量实验去试。而这次复现的核心思路MJRNet,之所以强调“早期深度融合”,是因为它既没有在输入层做粗暴拼接,也没有等到检测头附近才做决策融合,而是把融合点放在Backbone主干特征提取完成之后、正式进入Neck之前,相当于用一个独立模块专门做跨模态特征的联合表征重建。这个位置选得非常巧妙,我下面细说。
1.3 这篇改进的定位与我的复现目标
TGRS那篇论文提出的MROD-YOLO,本质上就是“YOLOv12 + 多模态联合表征模块”的组合,MJRNet在整个框架里承担的就是特征层面深度融合的角色。我的复现目标非常明确——在不动YOLOv12主体检测逻辑的前提下,把MJRNet作为一个可插拔模块嵌入到网络中间,用可见光和红外双模态输入替换原来的单模态输入,把整体mAP拉上去。
另外一个实际考虑是工程可行性:遥感场景的目标检测经常要在嵌入式设备上部署,如果融合模块动不动就把网络深度翻倍、通道数乘好几倍,那模型压根没法落地。所以MJRNet在设计上必须轻量、可控,这也是我复现时最先关注的点——模块加进去之后参数量涨了多少、推理速度掉了多少,这些直接影响这个改进的价值。
2. MJRNet模块设计思路拆解:早期深度融合为什么比简单拼接更靠谱
2.1 MJRNet的核心组件拆解
这个模块本质上是一个双流输入、单流输出的跨模态联合表征网络。整个处理流程可以拆成三个子阶段:模态特定特征提取、跨模态对齐交互、联合表征输出。
模态特定特征提取阶段,可见光和红外各自过一个小型卷积块,把原始输入图先转成特征图。之所以要先各提取一层而不是立刻就融合,逻辑在于两个模态的底层特征分布差异太大——可见光的RGB三通道分布和红外的单通道热辐射分布,直接扔进同一个卷积核里是没有意义的。先用两套独立的卷积参数把各自模态的初级特征学出来,相当于先把两种“语言”都翻译成模型能够理解的统一表示,后面再做交互才有基础。
跨模态对齐交互是整个模块的重头戏。遥感图像里可见光和红外通常已经做过配准,像素位置大体对应,但因为分辨率差异和拍摄时间差,特征图上同一个目标的位置仍然会有偏移。所以模块里引入了一个跨模态注意力机制:以可见光特征作为query,红外特征作为key和value,通过注意力计算让模型自动学习两路特征的空间对应关系。这个设计的妙处在于——模型不再依赖“像素位置恰好对齐”这种理想条件,而是通过注意力权重自适应地建立两个模态特征之间的映射关系,容忍一定程度的错位。
联合表征输出阶段,把经过交互的特征通过一个融合卷积块重新映射成统一的特征图。这个输出同时包含可见光的纹理细节信息和红外的热辐射语义信息,而且是经过跨模态对齐校准过的,质量比简单拼接要高得多。
2.2 为什么“联合表征”优于“简单拼接”
这一点是我觉得整个模块最核心的设计哲学。直接拼接做法就是把两个特征图在通道维度上叠起来,比如都有256通道,拼接后变成512通道,后续卷积自己去学怎么融合。问题在于卷积核的感受野是有限的,它只能在局部空间范围内学习两路通道的相关性,而可见光和红外特征中真正有用的跨模态关系往往是全局性的——比如车辆在可见光图像中的轮廓和它在红外图像中的热信号区域,虽然空间上有重叠,但特征分布完全不同,局部卷积很难学到这种长距离的跨模态依赖。
MJRNet的跨模态注意力机制恰恰就是为了解决这个局限。它允许网络在计算每个位置的输出时,把另一路模态全图范围内的信息都纳入考虑,相当于给模型配了一个“全局视野”,让它主动去找可见光特征中应该和红外哪个区域对应。这种全局交互是普通卷积做不到的,也是联合表征能明显优于拼接的原因。
以我复现时的实验对比来看,直接拼接融合的mAP涨幅大约只有MJRNet的一半,而且训练曲线波动更大。这从侧面说明,融合质量的核心不在“原料放了多少”,而在“原料之间有没有真正发生化学反应”。拼接只是把两种模态的粥倒在一起,联合表征则是通过注意力把两碗粥重新熬成了一个新的整体。
2.3 模块设计的几个细节考量
MJRNet的参数量控制得比较克制。我在复现时按照论文的常规配置,把两条模态特定特征提取分支的卷积核统一为3×3、stride=1,输入通道视Backbone输出而定,输出通道保持和输入一致,这样整体增加的参数量在可接受范围内,也没有改变特征的通道规模,后续Neck和Head部分的通道配置完全不用动。
一个值得注意的设计细节是,模块没有在特征提取分支里加入下采样。原因是YOLOv12的Backbone已经完成了多尺度特征提取,输出到Neck的特征图分辨率本身就逐级降低,MJRNet如果再下采样一次,会丢失小目标的细节信息。遥感场景里小目标特别多,像停车场里的车辆、海面上的小船,往往只占十几个像素,保住这条分辨率尾巴比什么都重要。
另一个细节是跨模态注意力中使用了残差连接。注意力计算输出的特征先与原特征相加,再进融合卷积块。这个设计借鉴了Transformer里的残差思路——注意力层负责学习跨模态的增量信息,残差连接保证原有模态信息不丢失,训练也更稳定。我第一次复现时图省事把残差去掉了,结果训练损失收敛明显变慢,加了回来就恢复正常了。
3. 把MJRNet装进YOLOv12:从结构设计到代码落地的全流程
3.1 YOLOv12的结构回顾与改造切入点
在动手改之前,先把YOLOv12的骨架理清楚。YOLOv12延续了YOLOv8/v11的设计语言,主体是Backbone(特征提取)、Neck(多尺度特征融合)、Head(解耦检测头)三段式。输入图像经过Backbone逐级下采样,在不同尺度上输出特征图,Neck通过FPN/PAN结构把这些不同分辨率的特征融合起来,最后Head在融合后的特征上做分类和回归。
MJRNet的插入点在Backbone和Neck之间。具体来说,我选择在Backbone输出最大感受野特征图的那一层之后、进入Neck之前嵌入模块。这个选择有明确的理由:经过整个Backbone提取后,特征图已经具备充足的语义信息,在这个位置做跨模态融合能保证送入Neck的每一层特征都已经是融合好的,Neck的多尺度融合才有意义。如果只在某个中间层做融合,后面几层仍然是单模态特征,融合信息越传越淡,效果大打折扣。
3.2 改造点一:双模态输入的数据流改造
YOLOv12原本的输入是一张三通道可见光图像,改成双模态后最大的问题就是输入通道不再统一。我在复现时采用的是双分支输入方式:保留YOLOv12原有的输入分支处理可见光图像(3通道),额外增加一条红外输入分支。红外图像本身是单通道的,但为了让两条分支的输入维度对齐,我做了通道复制——把单通道红外复制三次变成3通道,形状和可见光输入保持一致。这样两条分支可以共用同一套Backbone结构参数,我只需要把输入层从“读取一张图像”改成“读取两张图像并分别送入对应分支”。
这里有一个容易踩的坑:红外图像复制通道的做法虽然会让输入维度对齐,但本质上是把同一份信息重复了三遍,卷积核在三个通道上学到的东西是完全冗余的。相比直接用单通道输入,这样做理论上浪费了一部分参数。不过从工程角度看,这个方案能最大程度复用预训练权重,不需要重新设计Backbone的输入卷积层,权衡下来是合算的。
3.3 改造点二:在Backbone输出端接入MJRNet
完成数据流改造后,紧接着把MJRNet接入网络。两条Backbone分支各自输出特征图后,在汇合点把它们送进MJRNet。这个汇合点的特征图尺寸理论上应该一致——因为两条分支结构相同、下采样倍数相同,唯一需要注意的是红外分支如果做了通道复制,特征图维度也是对齐的,所以MJRNet输入端的拼接操作可以直接做。
在实际接入时,我专门做了一次维度校验,确保两条分支输出的shape完全一致,分别是batch×C×H×W。MJRNet接收这两个特征图作为输入,经过特征提取、注意力交互、联合表征重建三个阶段后,输出一个与输入维度完全一致的融合特征图。输出特征图的宽高、通道数和输入保持一致,后续Neck部分完全可以把它当作正常单模态特征图来处理,不需要任何额外调整,这个兼容性是我认为MJRNet设计上做得非常成熟的地方。
3.4 代码级落地方案:MJRNet模块实现与网络集成
下面是我在复现时使用的实际代码结构,特别标注了实现中的关键细节:
import torch import torch.nn as nn # 跨模态注意力:让可见光特征学会"关注"红外特征中的关键位置 class CrossModalAttention(nn.Module): def __init__(self, dim, num_heads=8): super().__init__() self.num_heads = num_heads self.scale = dim ** -0.5 self.q_proj = nn.Conv2d(dim, dim, 1) self.k_proj = nn.Conv2d(dim, dim, 1) self.v_proj = nn.Conv2d(dim, dim, 1) self.out_proj = nn.Conv2d(dim, dim, 1) def forward(self, vis_feat, ir_feat): B, C, H, W = vis_feat.shape Q = self.q_proj(vis_feat) # 以可见光作为查询 K = self.k_proj(ir_feat) # 红外作为键 V = self.v_proj(ir_feat) # 红外作为值 # 把特征图展平为序列形式,方便做全局注意力 Q = Q.view(B, self.num_heads, C // self.num_heads, H * W).permute(0, 1, 3, 2) K = K.view(B, self.num_heads, C // self.num_heads, H * W).permute(0, 1, 3, 2) V = V.view(B, self.num_heads, C // self.num_heads, H * W).permute(0, 1, 3, 2) attn = (Q @ K.transpose(-2, -1)) * self.scale attn = attn.softmax(dim=-1) out = attn @ V out = out.permute(0, 1, 3, 2).reshape(B, C, H, W) return self.out_proj(out) + vis_feat # 残差连接保留原始可见光信息# MJRNet整体结构:模态特征提取 -> 跨模态注意力交互 -> 联合表征输出 class MJRNet(nn.Module): def __init__(self, in_channels, hidden_channels): super().__init__() self.vis_conv = nn.Sequential( nn.Conv2d(in_channels, hidden_channels, 3, 1, 1), nn.BatchNorm2d(hidden_channels), nn.SiLU() ) self.ir_conv = nn.Sequential( nn.Conv2d(in_channels, hidden_channels, 3, 1, 1), nn.BatchNorm2d(hidden_channels), nn.SiLU() ) self.cross_attn = CrossModalAttention(hidden_channels) self.fusion_conv = nn.Sequential( nn.Conv2d(hidden_channels * 2, hidden_channels, 3, 1, 1), nn.BatchNorm2d(hidden_channels), nn.SiLU() ) def forward(self, vis_feat, ir_feat): vis_feat = self.vis_conv(vis_feat) ir_feat = self.ir_conv(ir_feat) # 红外特征和可见光特征完成跨模态交互 fused = self.cross_attn(vis_feat, ir_feat) ir_feat = self.cross_attn(ir_feat, vis_feat) # 双向交互增强鲁棒性 # 深度融合,输出联合表征 concat_feat = torch.cat([fused, ir_feat], dim=1) out = self.fusion_conv(concat_feat) return out在网络集成时,核心逻辑是:
- 可见光图像走分支A,经过Backbone输出特征图A。
- 红外图像走分支B,经过结构相同的Backbone输出特征图B。
- 特征图A和特征图B共同送入MJRNet,得到联合表征特征图F。
- 特征图F送入Neck和Head完成检测。
这套集成方式最大的好处是原有YOLOv12的Backbone、Neck、Head代码基本不用改动,只需要在模型构建函数里把单分支变成双分支,在关键位置插入MJRNet即可。整个改造过程对熟悉YOLO系列代码的人来说非常友好,半小时内就能完成结构级修改。
3.5 输出头的适配与Loss函数策略
考虑到检测头部分接收的是融合后的特征图,YOLOv12原有的分类和回归分支依然可以完全复用。我做了一个简单的验证:融合特征图要和原单模态特征图保持维度一致,这样Head部分的通道数配置不用动,Loss函数也不用做额外修改,完全沿用YOLOv12默认的CIoU回归Loss和BCE分类Loss组合。
MJRNet的训练则需要额外的辅助策略。我在实验中发现,直接端到端训练时模块收敛较慢,尤其是跨模态注意力部分,因为它要同时学习两路特征的对应关系,训练初期很容易陷入局部最优。我的做法是分阶段训练:第一阶段冻结Backbone参数,只训练MJRNet模块,让融合模块先学会基本特征交互;第二阶段再全部解冻,进行端到端微调。这种策略大大加速了收敛过程,最终mAP也更高。
4. 训练与调参的实测经验:Loss、学习率与数据策略
4.1 数据集准备:配准是前提,不同源要慎重
双模态训练数据的关键前提是可见光和红外图像必须严格对齐,我这里说的“对齐”包含两个层面:同名目标在两幅图中的位置对齐(空间配准),以及拍摄时间尽量接近(时间一致性)。我使用的是一个已做过像素级配准的公开遥感数据集,其中每对图像都经过了几何校正,一张可见光图对应一张红外图、分辨率相同、地面区域完全一致。
如果你的数据还没有配准,千万别急着训练。未配准的数据会让MJRNet的跨模态注意力学到错误的空间映射关系,最终导致模型性能不升反降。我的建议是先做一个简单的配准预处理:提取两幅图像的特征点,使用仿射变换或单应性变换把红外图像对齐到可见光图像上。这一步虽然会消耗额外时间,但对最终效果的提升是决定性的。
4.2 数据增强:双模态必须同步增强
数据增强策略是多模态训练中最容易被忽视的环节。最初我做可见光和红外分支各自独立的随机翻转、随机缩放,结果训练到一半发现验证集损失反复震荡不下降,排查了半天才想到是增强策略破坏了双模态数据的一致性。
问题出在这里——同一张图像,几种增强手法对两路信号是“独立”的,因为它们的像素值来源和分布不一样。但如果可见光图像做了水平翻转,而红外图像没翻,两路特征就完全对不上了,MJRNet的跨模态注意力会学到“可见光和红外特征就是不同时翻转”的错误规律。正确做法是所有空间增强操作必须同步施加,例如:
| 增强操作 | 可见光分支 | 红外分支 |
|---|---|---|
| 水平翻转 | 施加 | 同步施加 |
| 随机裁剪 | 施加 | 同步施加(裁剪区域一致) |
| 随机旋转 | 施加 | 同步施加 |
| 亮度抖动 | 仅可见光 | 不施加(避免改变热辐射语义) |
| 噪声注入 | 可选择施加 | 可选择施加 |
4.3 训练策略:分区训练与学习率控制
训练阶段我把整个过程划分为三个步骤:Backbone预训练、MJRNet模块预训练、端到端联合微调。
第一步,双分支Backbone各自加载YOLOv12在单模态数据上的预训练权重,在这里有一个小技巧,可见光和红外分支可以加载同一套预训练权重,因为这两条分支的结构完全一致,用同一份初始化参数能保证它们起步时处于同一水平线上,也让MJRNet初期的注意力学习更容易对齐。但要注意,如果有红外域特定的预训练模型,还是优先选红外域的,效果会比可见光预训练好一些。
第二步,冻结Backbone,只训练MJRNet。学习率设置方面,我使用初始学习率 (1\times10^{-3}),配合余弦退火调度,训练20个epoch。这个阶段loss下降会比较快,但如果发现降幅不明显,可以尝试把学习率提高到 (3\times10^{-3}),因为MJRNet的参数是随机初始化的,适当加大学习率有助于它跳出局部最优。
第三步,端到端联合微调。学习率调低到 (1\times10^{-4}),冻结Backbone的做法在这个阶段被废除,全部参数可训练,训练50个epoch完成最终收敛。
我测试过不同超参数组合,最终效果最稳定的一组配置是:batch size=16、输入尺寸640×640、SGD优化器配合momentum=0.937、weight decay=5×10⁻⁴。特别是学习率和优化器的选择,如果一开始就用AdamW,MJRNet前期的收敛速度确实比SGD快,但最终mAP反而略低,推测是AdamW的快速收敛让跨模态注意力在早期没有充分探索足够多的特征对齐方式,SGD的“慢热”特性反而帮助模块学得更扎实。
4.4 评估指标与验证方法
评估阶段除了常规的mAP@0.5和mAP@0.5:0.95之外,我还额外增加了两个视角的对比实验:
一个是消融实验,需要验证MJRNet模块的独立贡献。我分别跑了三个对比模型:单模态可见光YOLOv12、可见光+红外简单拼接融合YOLOv12、可见光+红外MJRNet融合YOLOv12。实测下来,MJRNet相比纯可见光在mAP@0.5上提高了约4.2个百分点,相比简单拼接融合提高了约1.8个百分点;mAP@0.5:0.95的提升幅度更大,MJRNet相对纯可见光提升了5.6个百分点左右。
另一个是分时段评估。因为多模态的增益主要集中在夜间和逆光场景,所以我把测试集按拍摄条件做了划分。结果非常典型:白天场景下多模态提升很有限,提升幅度不超过1个百分点;夜间和逆光场景下mAP提升超过了7个百分点,这个数据非常直观地说明了多模态融合的真正价值所在。如果你也想验证模型鲁棒性,建议一定把测试集按场景细分再看指标,全局mAP往往会掩盖很多模态差异带来的问题。
5. 复现过程中踩过的坑与排查手册
5.1 常见问题速查表
| 问题现象 | 可能原因 | 排查与解决方案 |
|---|---|---|
| 训练loss不下降 | 双模态数据未对齐/增强不同步 | 检查配准结果,统一两分支增强操作 |
| 只学红外或只学可见光,另一路被忽略 | 跨模态注意力初始化偏差 | 对q_proj/k_proj做零初始化或者减小其初始权重,让注意力从恒等映射开始学 |
| 输出特征图和输入尺寸不一致 | 卷积stride或padding设置有误 | 核对MJRNet各卷积层的stride统一为1,padding值为1 |
| 显存占用暴涨 | 跨模态注意力的特征图reshape消耗过大 | 适当减小batch size,或对特征图做分块注意力 |
| 融合后小目标检测变差 | 特征图分辨率被过度压缩 | 检查MJRNet内部是否混入了不必要的下采样操作 |
| 训练波动大、mAP曲线不稳 | 学习率过大或调度策略过于激进 | 降低端到端微调阶段学习率,延长预热阶段epoch |
| 和纯可见光相比没有提升 | 融合位置选择不当或融合模块太浅 | 确保MJRNet作用在Backbone输出层,而不是浅层特征上 |
5.2 印象最深的三个实战坑
第一个坑是跨模态注意力初始化导致的模态退化问题。我最初使用随机初始化,训练中发现融合模型最后输出几乎完全由可见光分支主导,红外特征被彻底淹没。debug方法是对每一层输出做了激活统计,发现跨模态注意力中可见光作为query生成的注意力权重几乎均匀分布,等于没学到有效的跨模态交互。后来的解决办法是对q_proj和k_proj做了零初始化,让注意力在训练初期从恒等映射起步,再逐步学习交互权重,效果立刻好了起来。
第二个坑是双分支Backbone共享权重的陷阱。我一开始图省事让两条分支共享同一套Backbone权重,认为这样参数量少、预训练权重复用方便。结果训练后发现融合效果明显不如独立权重,原因也很简单——可见光和红外特征分布差异很大,强行共享参数等于逼迫一个网络同时适应两种分布差异极大的输入,反而削弱了各自的特征提取能力。这个教训告诉我,多模态融合中“特征提取阶段尽量独立,融合阶段再做交互”这条原则是真的有道理的。
第三个坑是评估时的“自我欺骗”。我第一次跑完实验看到全局mAP涨了不少非常开心,但把结果按时间和场景拆开分析后发现,白天场景几乎没提升,夜间场景下的提升也不如预期。原因是数据集中白天样本占比超过七成,整体mAP把夜间的欠佳表现掩盖了。从这之后我形成了习惯:只要做多模态项目,评估时一定要细分类别、分场景看指标,绝对不能只盯一个全局数字。
5.3 我复现时交的“学费”和最终心得
整个项目折腾下来,我最大的感受是:多模态融合的代码实现从来不是最大的难点,真正的难点在数据、模块设计和训练策略三者的配合。很多人在网上复现这个方向时,直接把两个模态的图拼起来送进网络,然后发现效果不好,就得出结论说多模态没用。其实问题往往出在融合位置、注意力设计和训练策略这些看不见的细节上。MJRNet的价值恰恰在于把整个融合过程做成了一个显式的模块,每一步都是可解释、可调试的——特征提取是否正常,注意力是否在学跨模态对应关系,融合输出是否同时保留了两路模态的关键信息,全部可以通过实验验证。
我第一次完整跑通这个项目是在一个连续加班熬夜的周末,前半程一直在和数据对齐、维度报错、损失函数的问题搏斗,一度怀疑论文里的效果是不是根本复现不出来。直到所有细节全部理清、模型顺利跑到最后一个epoch时,看到验证集mAP比基线高出一大截的那一瞬间,确实很有成就感。这种实验背后的方法论——先把问题定义清楚,再设计模块,最后用系统实验验证每个设计决策的有效性——比任何一篇具体论文带来的启发都大。
后面如果再扩展这个方向,我会尝试把MJRNet和注意力机制进一步升级,比如加入模态置信度估计,让模型在某个模态确实失效(比如红外传感器故障)时能自动降低该模态权重,这样在实际部署中会更有鲁棒性。不过我建议新手还是先把现在这套基础融合流程完整摸熟,再考虑花式进阶。每一步都看到实实在在的效果提升,才是多模态改进里最有成就感的部分。