YOLOFuse代码实例:infer_dual.py推理脚本深度解读
1. 引言:YOLOFuse 多模态目标检测框架
在复杂环境下的目标检测任务中,单一模态(如可见光图像)往往受限于光照不足、烟雾遮挡等问题。为提升鲁棒性与检测精度,多模态融合技术应运而生。YOLOFuse是基于 Ultralytics YOLO 架构构建的双流多模态目标检测框架,支持RGB 图像与红外(IR)图像的融合检测,特别适用于夜间、低光或恶劣天气等场景。
该框架采用双分支网络结构,分别处理可见光和红外输入,并通过多种融合策略(决策级、早期特征级、中期特征级)实现信息互补。infer_dual.py作为核心推理脚本,承担了模型加载、双模态数据预处理、前向推断与结果可视化等关键职责。本文将对其源码进行逐层解析,帮助开发者深入理解其运行机制并快速定制化部署。
2. 推理流程总体架构
2.1 脚本功能概览
infer_dual.py的主要功能包括:
- 加载训练好的双流融合模型权重
- 同时读取配对的 RGB 和 IR 图像
- 对两路输入进行独立预处理与归一化
- 执行双流前向推理
- 根据配置选择融合方式(early/mid/late fusion)
- 输出融合后的边界框与类别预测
- 生成带标注的可视化图像并保存
整个流程遵循“输入→预处理→双流推理→融合决策→输出”的标准 pipeline,具备良好的模块化设计。
2.2 程序执行入口分析
脚本通常以如下命令启动:
python infer_dual.py默认行为是使用预置的测试图像对(位于data/images和data/imagesIR)进行推理,输出结果至runs/predict/exp目录。可通过命令行参数自定义输入路径、模型权重、设备类型等选项。
典型调用链如下:
main() → parse_args() # 解析命令行参数 → load_model() # 加载YOLO双流模型 → process_images() # 遍历图像对 → preprocess_pair() # 双图预处理 → model.infer() # 前向推理 → fuse_results() # 融合策略应用 → visualize_and_save() # 结果绘制与保存3. 核心模块详解
3.1 模型加载与初始化
YOLOFuse 继承了 Ultralytics 的模型接口风格,使用DualModel类封装双流结构。模型初始化代码示例如下:
from models.dual_yolo import DualYOLO def load_model(weights='runs/fuse/weights/best.pt', device='cuda'): model = DualYOLO(config='cfg/models/dual_yolov8.yaml') model.load_state_dict(torch.load(weights, map_location=device)) model.to(device).eval() return model其中:
DualYOLO定义了共享或独立的主干网络(backbone),支持 ResNet、CSPDarknet 等结构。- 权重文件路径默认指向训练后最优模型
best.pt。 - 设备自动检测是否启用 GPU(CUDA)加速。
提示:若显存有限,可设置
device='cpu'进行 CPU 推理,但速度显著下降。
3.2 双模态图像预处理
由于 RGB 与 IR 图像成像机制不同,需分别进行标准化处理。常见做法是对两路输入采用不同的均值与方差:
transform_rgb = T.Compose([ T.ToTensor(), T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) transform_ir = T.Compose([ T.ToTensor(), T.Normalize(mean=[0.5], std=[0.5]) # 单通道红外图 ])预处理函数会同步加载同名图像对(如001.jpg和001.jpg分别来自images/与imagesIR/),确保时空一致性。
3.3 双流前向推理机制
双流推理的核心在于保持两个分支的独立性直至融合点。根据融合阶段的不同,可分为三类模式:
| 融合类型 | 特点 | 实现位置 |
|---|---|---|
| 早期融合(Early Fusion) | 输入层拼接通道(如 RGB+IR → 4通道) | Backbone 输入前 |
| 中期融合(Mid Fusion) | 在 Neck 层合并特征图(如 PAN-FPN 中间层) | Feature Aggregation 阶段 |
| 决策级融合(Late Fusion) | 分别输出检测结果后融合(NMS 合并) | Head 输出后 |
以中期融合为例,其前向逻辑如下:
def forward(self, rgb_img, ir_img): # 分支独立提取特征 f_rgb = self.backbone_rgb(rgb_img) f_ir = self.backbone_ir(ir_img) # 在Neck层进行特征拼接与融合 fused_features = [] for i in range(len(f_rgb)): cat_feat = torch.cat([f_rgb[i], f_ir[i]], dim=1) fused_feat = self.fusion_blocks[i](cat_feat) fused_features.append(fused_feat) # 共享Head输出检测结果 return self.head(fused_features)这种设计既保留了模态特异性,又实现了高层语义融合。
3.4 融合策略对比与选择建议
不同融合策略在精度、速度与参数量之间存在权衡:
| 策略 | mAP@50 | 推理延迟 (ms) | 显存占用 (MB) | 适用场景 |
|---|---|---|---|---|
| 早期融合 | 93.8% | 42 | 1800 | 输入维度允许扩展 |
| 中期融合 | 94.7% | 38 | 1650 | ✅ 推荐:平衡性能与效率 |
| 决策级融合 | 95.5% | 51 | 1700 | 多模型集成需求 |
| DE-YOLO | 95.2% | 58 | 2100 | 学术研究导向 |
工程实践建议:
- 若追求轻量化部署,优先选用中期融合
- 若已有两个独立训练的单模态模型,可尝试决策级融合 + 加权NMS
- 早期融合需修改输入通道数,适配性较差,不推荐新手使用
4. 关键代码片段解析
以下是从infer_dual.py提取的核心代码段及其详细注释:
# infer_dual.py 核心推理逻辑节选 import torch from utils.general import non_max_suppression, scale_boxes from models.dual_yolo import DualYOLO def run_inference(): device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = DualYOLO('cfg/dual_yolov8m.yaml').to(device) model.load_state_dict(torch.load('runs/fuse/weights/best.pt')) model.eval() # 加载图像对 rgb_img = cv2.imread('data/images/001.jpg') # BGR format ir_img = cv2.imread('data/imagesIR/001.jpg', cv2.IMREAD_GRAYSCALE) # 预处理:调整大小、归一化、张量转换 rgb_tensor = preprocess_image(rgb_img, is_rgb=True).to(device) ir_tensor = preprocess_image(ir_img, is_rgb=False).to(device) # 前向推理 with torch.no_grad(): outputs = model(rgb_tensor, ir_tensor) # [batch, num_boxes, 6] # 后处理:NMS去重 predictions = non_max_suppression(outputs, conf_thres=0.25, iou_thres=0.45) # 可视化结果 for det in predictions: if len(det): det[:, :4] = scale_boxes(rgb_tensor.shape[2:], det[:, :4], rgb_img.shape).round() for *xyxy, conf, cls in det: label = f'{model.names[int(cls)]} {conf:.2f}' plot_one_box(xyxy, rgb_img, label=label, color=(0,255,0)) cv2.imwrite('runs/predict/exp/result_fused.jpg', rgb_img) print("✅ 推理完成,结果已保存至 runs/predict/exp/")代码要点说明:
non_max_suppression:去除重叠框,支持跨模态合并scale_boxes:将归一化坐标映射回原始图像尺寸plot_one_box:绘制边界框与标签,便于直观评估效果- 输出路径遵循 Ultralytics 默认规则,便于与其他工具链对接
5. 自定义推理与扩展建议
5.1 修改输入源
除了本地文件,还可接入摄像头或视频流:
cap_rgb = cv2.VideoCapture(0) # RGB摄像头 cap_ir = cv2.VideoCapture(1) # 红外摄像头(需硬件支持) while True: ret_rgb, frame_rgb = cap_rgb.read() ret_ir, frame_ir = cap_ir.read() if not (ret_rgb and ret_ir): break # 直接传入帧数据进行推理 result = infer_once(model, frame_rgb, frame_ir) cv2.imshow('Fused Detection', result) if cv2.waitKey(1) == ord('q'): break注意:需保证两路视频流时间同步,否则会影响融合效果。
5.2 添加置信度加权融合
对于决策级融合,可引入模态置信度权重提升稳定性:
def weighted_nms(dets_rgb, dets_ir, w_rgb=0.6, w_ir=0.4): # 按加权得分重新排序 scores = w_rgb * dets_rgb[:, 4] + w_ir * dets_ir[:, 4] dets_rgb[:, 4] = scores return non_max_suppression(dets_rgb, ...)此方法在白天场景增强 RGB 权重,在夜间提高 IR 权重,实现动态适应。
5.3 日志与性能监控
建议添加推理耗时统计:
import time start = time.time() outputs = model(rgb_tensor, ir_tensor) print(f"⏱️ 推理耗时: {(time.time()-start)*1000:.2f} ms")可用于评估不同融合策略的实际性能差异。
6. 总结
infer_dual.py作为 YOLOFuse 框架的核心推理脚本,完整实现了多模态目标检测的全流程闭环。通过对双流结构的设计、多阶段融合机制的支持以及与 Ultralytics 生态的无缝集成,极大降低了开发者在复杂环境下部署高性能检测系统的门槛。
本文从整体架构、核心模块到关键代码进行了系统性解读,并提供了实用的优化建议与扩展方向。结合预装镜像提供的开箱即用环境,用户可在无需繁琐配置的情况下快速验证算法效果,进而开展个性化训练与部署。
未来可进一步探索自适应融合权重、跨模态注意力机制等前沿方向,持续提升多模态检测的智能化水平。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。