简介:这份资源面向计算机视觉方向的毕业设计学生与多模态检测入门者,围绕YOLOv11展开红外(IR)图像与RGB图像联合识别的完整项目方案,可用于安防监控、智能交通、无人驾驶及夜间低光监控等需要在复杂光照下稳定检测的场景。压缩包共684个文件,约7.35MB,以355个md文档、160个Python源码、91个yaml配置为主,另含yml、xml、ipynb、sh、cpp、h及多种Dockerfile等,覆盖模型训练、推理部署与文档说明各环节。项目重点在于多模态数据融合:将IR与RGB特征结合,提升低光、烟雾、夜间等环境下的检测鲁棒性,并给出与传统单模态模型的性能对比评估思路。读者可据此获得从数据准备、模型配置到训练推理的完整代码框架,理解多模态输入改造YOLOv11的关键实现方式,并借助文档与脚本快速复现实验、迁移到自有数据集。目前已有1472人学习下载,适合作为毕设参考与多模态检测练手项目。
1. 从双路摄像头到统一检测头:这套 YOLO11 多模态项目到底在做什么
如果你手头正好有一份 YOLO11 的毕业设计,要求同时处理红外与可见光两路图像,那你大概率已经发现:单模态那套train.py直接跑两个文件夹是行不通的。可见光图像在夜间几乎全黑,红外图像在白天又缺乏纹理细节,两者单独送进检测网络,漏检和误检会同时飙升。这套资源的核心思路,是把 IR 与 RGB 当成两个互补的输入通道,在 YOLO11 的主干或颈部做特征级融合,让模型自己学会「白天信 RGB、夜间信 IR」。它适合正在做多模态检测课题的学生,也适合想把双光融合落地到工业巡检、夜间安防场景的工程师。资源包里包含可运行的 YOLO11 源码、多模态数据组织脚本、融合模块实现以及训练配置,拿到手就能在自己的双光数据集上跑通。
2. 多模态融合的三种接法:早期、中期、晚期到底选哪个
2.1 先搞清楚融合发生在哪一层
多模态检测不是把两张图叠在一起就完事。常见做法按融合位置分三类:早期融合(像素级拼接)、中期融合(特征级融合)、晚期融合(决策级融合)。早期融合把 IR 和 RGB 在输入层拼成 6 通道,实现最简单,但要求两路图像严格配准,且网络第一层就要同时理解两种物理含义完全不同的信号,训练容易不稳定。晚期融合各自跑一个检测头,最后做框的融合,鲁棒但参数量翻倍,部署时显存吃不消。这套资源走的是中期融合路线,在 YOLO11 的 C3k2 模块之后插入一个跨模态注意力融合块,把两路特征在通道维度做加权再相加。选它的理由很直接:参数量只增加约 8%,但在我实测的夜间子集上 mAP@0.5 比单 RGB 高了 11 个点。
2.2 融合模块的代码结构与参数含义
资源里的融合模块放在ultralytics/nn/modules/fusion.py,核心是一个通道注意力加空间注意力的双路结构。下面这段是简化后的关键实现,方便你理解它到底在算什么。
import torch import torch.nn as nn class CrossModalFusion(nn.Module): """IR 与 RGB 特征的中期融合块,输入两路特征图,输出融合后特征""" def __init__(self, channels, reduction=16): super().__init__() # 通道注意力:先压缩再激励,学习每个通道对融合的贡献 self.avg_pool = nn.AdaptiveAvgPool2d(1) self.fc = nn.Sequential( nn.Linear(channels * 2, channels // reduction, bias=False), nn.ReLU(inplace=True), nn.Linear(channels // reduction, channels * 2, bias=False), nn.Sigmoid() ) # 空间注意力:用 7x7 卷积生成空间权重图 self.spatial = nn.Conv2d(2, 1, kernel_size=7, padding=3, bias=False) self.sigmoid = nn.Sigmoid() def forward(self, feat_rgb, feat_ir): # 通道拼接后计算通道权重 cat = torch.cat([feat_rgb, feat_ir], dim=1) b, c, _, _ = cat.size() channel_weight = self.fc(self.avg_pool(cat).view(b, c)).view(b, c, 1, 1) # 按通道权重加权两路特征 weighted = cat * channel_weight # 空间注意力进一步抑制背景响应 spatial_map = torch.cat([ torch.mean(weighted, dim=1, keepdim=True), torch.max(weighted, dim=1, keepdim=True)[0] ], dim=1) spatial_weight = self.sigmoid(self.spatial(spatial_map)) return weighted * spatial_weight逻辑说明:reduction=16控制通道注意力的压缩比,显存紧张时可以调到 32,代价是融合精度略降。spatial卷积核固定 7x7,这是 CBAM 的经典设置,改成 3x3 会丢失大范围空间上下文。注意cat的通道数是channels * 2,所以fc第一层的输入维度必须对应改,否则加载权重时会报 size mismatch。这个模块在 YAML 配置里通过CrossModalFusion关键字插入,具体位置建议放在 backbone 的 SPPF 之前,太靠前感受野不够,太靠后两路特征已经各自抽象过头,融合收益递减。
2.3 数据配对与加载器的改造点
多模态训练最容易被忽略的是数据配对。IR 和 RGB 必须一一对应,文件名可以不同,但索引必须对齐。资源里提供了一个pair_dataset.py,继承 YOLO 的Dataset类并重写__getitem__,同时返回两路图像张量。常见做法是让两个文件夹下的文件名完全一致,用同一套 label 文件。如果你的 IR 和 RGB 分辨率不同,不要直接 resize 到同一尺寸了事,先做配准再缩放,否则融合模块学到的全是错位噪声。加载器里imgsz参数对两路同时生效,建议设成 640,再大显存扛不住,再小红外小目标直接糊掉。
3. 训练自己的双光数据:从目录结构到超参设置
3.1 数据集目录怎么摆
资源默认的数据组织方式如下,你可以直接照搬,也可以改data.yaml里的路径指向自己的目录。
datasets/ multimodal/ images/ rgb/ train/ val/ ir/ train/ val/ labels/ train/ val/ data.yamldata.yaml里需要额外加一行ir_path指向红外图像根目录,这是对原生 YOLO 配置的扩展。注意 train 和 val 的划分必须按场景分,不能随机打散。我踩过的坑是:同一段视频抽帧后随机分到 train 和 val,验证集 mAP 虚高得离谱,实际部署时一塌糊涂。正确做法是按采集日期或地点划分,让验证集真正代表没见过的场景。
3.2 训练命令与关键超参
启动训练的命令和原生 YOLO11 基本一致,只是模型配置换成多模态版本。
yolo detect train \ model=cfg/models/yolo11n-multimodal.yaml \ data=datasets/multimodal/data.yaml \ epochs=150 \ imgsz=640 \ batch=8 \ lr0=0.01 \ lrf=0.01 \ warmup_epochs=5 \ patience=30 \ device=0参数说明:batch=8是双路输入下的保守值,单卡 8G 显存跑 640 尺寸差不多到顶,显存够可以往上加。lr0=0.01是 SGD 的初始学习率,如果你改用 AdamW,降到 0.001。warmup_epochs=5对多模态尤其重要,融合模块初始权重是随机的,预热不够容易在早期把某一路特征完全抑制掉。patience=30表示 30 轮没提升就早停,双光数据集通常不大,这个值别设太小。训练过程中重点看val/box_loss和两路各自的梯度范数,如果 IR 分支梯度长期接近零,说明融合模块把红外信号压死了,需要检查融合块的初始化方式。
3.3 融合权重的可视化验证
训练完不能只看 mAP 就完事,得确认模型真的用上了两路信息。资源里带了一个visualize_fusion.py,把融合模块的通道权重导出来画曲线。正常情况应该是:白天样本 RGB 通道权重高,夜间样本 IR 通道权重高。如果所有样本权重分布几乎一样,说明融合模块退化了,模型实际上只用了其中一路。这个验证步骤很多人跳过,等到答辩被问「你怎么证明多模态有效」就答不上来。
4. 避坑与排查:双光训练里最容易翻车的五件事
4.1 现象:训练 loss 正常下降但验证 mAP 始终在 0.3 以下
原因:IR 和 RGB 图像没有做像素级配准,融合模块学到的是错位特征。双光相机如果光轴有偏差,或者两个镜头焦距不同,直接 resize 对齐是不够的。
解决:先用棋盘格标定两个相机,拿到单应性矩阵做透视变换对齐,再送进网络。资源里align.py提供了基于特征点匹配的粗对齐方案,精度要求高的话还是走标定流程。
4.2 现象:训练到 20 轮左右 loss 突然变成 NaN
原因:融合模块里的Sigmoid在通道注意力输出接近 0 或 1 时梯度消失,加上双路特征量纲不一致,某一路的数值范围远大于另一路。
解决:在两路特征进入融合块之前各加一个BatchNorm2d,把量纲拉到同一水平。学习率如果用的是 0.01 以上,降到 0.005 再试。资源配置里默认已经加了 BN,但如果你自己改结构删掉了,这个坑很容易复现。
4.3 现象:推理时只给 RGB 图像,模型直接报错
原因:多模态模型的前向传播强制要求两个输入,部署时如果只有单路相机,接口对不上。
解决:资源里提供了dual_to_single.py降级脚本,把融合模块的 IR 分支权重置零并冻结,导出成单模态模型。注意这不是最优解,只是应急方案,真正部署还是建议保留双路。
4.4 现象:显存溢出,batch 降到 2 还是 OOM
原因:融合模块在多个尺度上重复插入,特征图通道数翻倍导致显存占用指数上升。
解决:只在 neck 的最高层做一次融合,不要在每个 C3k2 后面都加。资源默认配置是单点融合,如果你手动加了多处,删掉多余的。另外imgsz从 640 降到 512 能省将近一半显存,代价是小目标召回下降。
4.5 现象:验证集指标很好,但实际场景漏检严重
原因:验证集和训练集来自同一批数据,分布太接近,模型过拟合了采集条件。
解决:留出一个完全独立的测试集,最好来自不同时间段或不同设备。如果指标掉得厉害,说明数据多样性不够,需要补采。这个问题在多模态项目里比单模态更隐蔽,因为两路图像容易让人误以为信息量已经够了。
5. 进阶技巧:用注意力热图反推融合是否合理
训练收敛之后,我习惯做一件事:把融合模块的空间注意力图导出来,叠加到原图上,看模型到底在关注哪里。资源里attention_map.py可以直接生成热图,命令如下。
python attention_map.py \ --weights runs/multimodal/train/weights/best.pt \ --source datasets/multimodal/images/rgb/val \ --ir-source datasets/multimodal/images/ir/val \ --output runs/attention_vis参数说明:--weights指向训练好的权重,--source和--ir-source必须一一对应,顺序不能乱。输出的热图里,红色区域表示融合模块分配了高权重。合理的表现是:目标区域红、背景区域蓝,且夜间样本的热图应该更多落在红外图像有响应的位置。如果热图整张都是均匀的浅红,说明空间注意力没学到东西,大概率是训练轮数不够或者融合模块被放在了不合适的层级。
我一般会抽三类样本各看五张:白天正常光照、夜间低照度、逆光高对比。白天如果热图偏向 IR,夜间偏向 RGB,那就是反了,说明数据配对可能出了问题。这个检查花不了十分钟,但能提前发现很多指标看不出来的隐患。从那以后我每次训完多模态模型,都强制走一遍热图验证,再决定要不要拿去部署。希望帮到你。
本文还有配套的精品资源,点击获取