【YOLO多模态图像目标检测实战指南:核心框架解析与快速应用技巧,带你快速入门多模态领域,支持YOLOv3-v11】

1. 文章主要内容

       本篇博客聚焦于支持多模态图像目标检测的YOLO框架的应用分析。我们将详细介绍多模态图像数据集的路径配置方法、数据集yaml文件的使用说明,以及模型yaml文件的简单解析等内容。目标是帮助读者快速上手入门,通读本篇博客大约需要15分钟。

2. 相关说明

       本文讨论的框架源码来自论文 YOLOv11-RGBT: Towards a Comprehensive Single-Stage Multispectral Object Detection Framework。原作者在其 GitHub 仓库的 README 中提供了详细的项目运行说明。 如果你想获取更为详细、入门友好的中文解读,包括本人对源码 yaml 文件的个性化修改,请继续阅读本文。 同时,本人始终尊重原创。如果本文对您有所帮助,请也到原作者的 GitHub 给予Star支持——这对整个社区都是互利共赢的。

3. 多模态图像目标检测框架YOLOv11-RGBT

        在这一节中,我们将从三个关键步骤解析整个框架:首先配置多模态图像数据集路径,其次设置数据集yaml文件,最后解析模型yaml文件。通过这些环节,帮助大家快速上手项目、成功运行代码,并顺利入门多模态图像目标检测领域。现在,让我们开始吧!

3.1 多模态数据集配置方法

       原作者 GitHub 链接中提供了两种存放多模态数据集路径的方式:文件夹形式和 txt 文件形式。本人习惯使用文件夹格式,因其结构更清晰易懂。因此,我将采用文件夹形式来配置多模态数据集的路径。接下来直接给出多模态图像数据集存放路径的结构图:
在这里插入图片描述
        1.dataset为多模态目标检测数据集的根目录。
        2.train和val分别为训练和验证的数据集目录,其每个目录下面都要包含visible和infrared两个文件夹,且名字一定不能写错
        3.visible和infrared文件夹分别存放可见光和红外图像数据集。为确保图像正确配对,两个文件夹中的图片数量和名称必须完全一致;否则,可能导致数据处理错误。
        4.在 visible 和 infrared 文件夹下,都必须包含两个固定的子文件夹:images 用于存放真实图片和labels 用于存放图片对应的标签。注意,images 和 labels 这两个文件夹的名称不可更改。此外,对于多模态图像数据集,通常只提供红外图像的标签。因此,你需要将这些红外图像的标签存放到 visible 文件夹下的 labels 子文件夹中,因为框架默认从该位置读取标签。

3.2 多模态数据集yaml文件配置

       数据集的YAML配置文件通常包含训练、验证和测试(测试可选,但未在配置中明确标注)目录路径,以及数据集所包含的类别。作为示例,本文将以多模态遥感图像目标检测数据集DroneVehicle为例,直接展示其配置文件的相关代码。

#DroneVehicle数据集配置文件
path: /data/xx/data/DroneVehicle_hbb_remove_white # 数据集的根目录
train: images/visible/train   # 训练集图像目录
val: images/visible/val      # 验证集图像目录
#test: images/visible/test  # 测试集图像目录(可选,未使用时注释掉)
names:
  0: car
  1: truck
  2: bus
  3: van
  4: freight_car # 类别名称列表

        1.path 表示数据集的根目录,train 和 val 分别对应训练集和验证集的目录路径,而 names 则指定了数据集的类别标签。
        2.在设置 train、val 或 test 数据集的路径时,仅需提供 visible(可见光)的路径,无需配置 infrared(红外)的路径。这是因为源码在读取路径时会自动处理替换逻辑,大家无需担心

3.3 多模态模型yaml文件解析(重点)

       模型yaml文件是整个框架的核心配置部分,直接关系到模型的改进与实验设计,是研究人员修改模型、进行实验时必须掌握的关键环节。接下来,本人将重点解析框架中的早期融合和中期融合(即特征级融合,也是目前应用最广泛的融合方式)。由于后期融合应用相对较少,此处将略过。通过本次对yaml文件的解析,目的在于帮助大家清晰理解模型结构,并明确其与单模态模型的区别所在。

3.3.1 中期融合(特征级融合)

       我们先解析中期融合,因为理解了中期融合后,早期融合的处理就会变得简单。按照惯例,我会提供中期融合的YAML文件示例。这里我选择了源码中的 yolo11-RGBRGB6C.yaml 文件(当然也可以选择 yolo11-RGBT.yaml 文件)。两者的关键区别在于:前者在初次读取数据时,将红外通道从单通道调整为3通道,再与可见光的RGB3通道在通道维度拼接;后者则直接读取红外单通道进行拼接。我个人偏好使用6通道文件,因此在此详细说明,希望能帮助大家理解得更清晰。

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# Ultralytics YOLO11 object detection model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolo11
# Task docs: https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 5 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs

ch: 6
# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Silence, []]  # 0-P1/2
    # visible
  - [0, 1, SilenceChannel, [0,3]]  # 1-P1/2
  - [-1, 1, Conv, [64, 3, 2]] # 2-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 3-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 5-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 7-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 9-P5/32
  - [-1, 2, C3k2, [1024, True]] # 10

  # infrared
  - [ 0, 1, SilenceChannel, [ 3,6 ] ]  # 11-P1/2
  - [ -1, 1, Conv, [ 64, 3, 2 ] ] # 12-P1/2
  - [ -1, 1, Conv, [ 128, 3, 2 ] ] # 13-P2/4
  - [ -1, 2, C3k2, [ 256, False, 0.25 ] ]
  - [ -1, 1, Conv, [ 256, 3, 2 ] ] # 15-P3/8
  - [ -1, 2, C3k2, [ 512, False, 0.25 ] ]
  - [ -1, 1, Conv, [ 512, 3, 2 ] ] # 17-P4/16
  - [ -1, 2, C3k2, [ 512, True ] ]
  - [ -1, 1, Conv, [ 1024, 3, 2 ] ] # 19-P5/32
  - [ -1, 2, C3k2, [ 1024, True ] ]  #20
  - [[6, 16], 1, ADD, []]  # ADD backbone P3   21
  - [[8, 18], 1, ADD, []]  # ADD backbone P4   22
  - [[10, 20], 1, ADD, []]  # ADD backbone P5   23

  - [ -1, 1, SPPF, [ 1024, 5 ] ] # 24
  - [ -1, 2, C2PSA, [ 1024 ] ] # 25

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 22], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 28

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 21], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 31 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 28], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 34 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 25], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 37 (P5/32-large)

  - [[31, 34, 37], 1, Detect, [nc]] # Detect(P3, P4, P5)


        1.nc 表示数据集中类别的总数。ch 表示在初始化时,可见光数据和红外数据拼接后的通道数目。具体而言:在 RGBRGB6C 拼接方式下,ch 为 6;在 RGBT 拼接方式下,ch 为 4。
        2.源码中的Silence类在功能上并无实际作用,因为其类实现是空的。推测作者添加它可能是为了使模型yaml文件的序号排列更整齐美观。因此,无需过多在意。
        3.源码中的SilenceChannel类扮演关键角色,其核心功能是对拼接后的可见光和红外输入进行通道切分,随后将切分结果分别送入对应的可见光分支和红外分支进行独立处理。为深入理解模型yaml文件中SilenceChannel的配置含义,我们将从该类的具体实现和task.py文件两部分展开分析。
       SilenceChannel类的源码

class SilenceChannel(nn.Module):
    def __init__(self,c_start, c_end):
        super(SilenceChannel, self).__init__()
        self.c_start=c_start
        self.c_end = c_end
    def forward(self, x):
        return x[...,self.c_start:self.c_end, :,:]

       task.py类中有关SilenceChannel的源码

     elif m is SilenceChannel:
            c2 = args[1] - args[0]

        4.在 SilenceChannel 类的实现中,c_start 和 c_end 这两个参数的实际输入值直接来源于 args[0]args[1]。而 args[0] 和 args[1] 则是由配置项(例如 [0, 1, SilenceChannel, [0,3]] 中的 0 和 3)提供的。这里的 0 和 3 分别指定了需要处理的数据(如可见光或红外模态)在通道维度上的起始索引和结束索引(即截取从第 0 个通道开始到第 3 个通道之前的数据)。这一点在类的源码逻辑 return x[..., self.c_start:self.c_end, :, :] 中得到了直接体现,该操作正是依据 c_start 和 c_end 对输入张量 x 在通道维度上进行切片。
        5.此外,代码c2 = args[1] - args[0]用于计算通道切分后输入到单模态分支的通道数目。因此,在配置args[0]和args[1]时,必须确保它们的差值正确匹配该分支所需的输入通道数。
        6.我们还可以观察到如下一段融合代码。这段代码的作用是在大、中和小三个尺度上,分别通过ADD操作融合可见光与红外模态的特征(作者同时提供了Concat版本作为替代方案)。随后的Neck和检测头部分与原始单模态YOLO保持一致,因此无需额外解释。

  - [[6, 16], 1, ADD, []]  # ADD backbone P3   21
  - [[8, 18], 1, ADD, []]  # ADD backbone P4   22
  - [[10, 20], 1, ADD, []]  # ADD backbone P5   23

3.3.1 早期融合(像素级融合)

       在深入解析中期融合后,我们转向早期融合的讨论时,理解过程会显得更加清晰直观。这是因为两者的分析框架相似——我们同样采用直接提供YAML文件的方式来进行解析。

# Ultralytics 🚀 AGPL-3.0 License - https://ultralytics.com/license

# Ultralytics YOLO11 object detection model with P3/8 - P5/32 outputs
# Model docs: https://docs.ultralytics.com/models/yolo11
# Task docs: https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 5# number of classes
scales: # model compound scaling constants, i.e. 'model=yolo11n.yaml' will call yolo11.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.50, 0.25, 1024] # summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPs
  s: [0.50, 0.50, 1024] # summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPs
  m: [0.50, 1.00, 512] # summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPs
  l: [1.00, 1.00, 512] # summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPs
  x: [1.00, 1.50, 512] # summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs

ch: 6
# YOLOv8.0n backbone
backbone:
  # [from, repeats, module, args]
  - [-1, 1, Silence, []]  # 0-P1/2
  - [0, 1, SilenceChannel, [0,6]]  # 0-P1/2
  - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
  - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
  - [-1, 2, C3k2, [256, False, 0.25]]
  - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
  - [-1, 2, C3k2, [512, False, 0.25]]
  - [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
  - [-1, 2, C3k2, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]] # 7-P5/32
  - [-1, 2, C3k2, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 2, C2PSA, [1024]] # 10

# YOLO11n head
head:
  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 8], 1, Concat, [1]] # cat backbone P4
  - [-1, 2, C3k2, [512, False]] # 13

  - [-1, 1, nn.Upsample, [None, 2, "nearest"]]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P3
  - [-1, 2, C3k2, [256, False]] # 16 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 15], 1, Concat, [1]] # cat head P4
  - [-1, 2, C3k2, [512, False]] # 19 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 12], 1, Concat, [1]] # cat head P5
  - [-1, 2, C3k2, [1024, True]] # 22 (P5/32-large)

  - [[18, 21, 24], 1, Detect, [nc]] # Detect(P3, P4, P5)

        1.在早期融合的YAML文件中,SilenceChannel类被置于最前端且仅有一个实例。随后的分支结构也仅包含一个单模态分支。这种设计表明:可见光与红外数据在初始化读取后,直接通过拼接操作(Concat)融合,并立即送入后续的卷积网络进行处理。除此之外,整个框架的逻辑流程与单模态YOLO模型完全一致。
        2.早期融合相较于中期融合更为简单,主要研究如何实现模型轻量化并提升精度,以达到精度与计算量的平衡,从而更适合边缘设备。而中期融合则更侧重于精度的提升,但由于两者均基于YOLO框架,都必须保持实时推理速度,这是一个重要的前提。

4. 运行多模态YOLO框架

       接下来,大家可以使用源码中train_RGBRGB.py文件修改相关配置即可启动整个多模态框架,这里我给出自己稍微修改一点的训练文件,可以直接使用:

import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO

if __name__ == '__main__':
    model = YOLO('ultralytics/cfg/models/11-RGBT/yolo11-RGBT-midfusion.yaml')
    # model.info(True,True)
    model.load('yolo11n.pt')  # loading pretrain weights
    model.train(data=R'ultralytics/cfg/datasets/drone_vehicle.yaml',
                cache=False,
                imgsz=640,
                epochs=200,
                batch=64,
                close_mosaic=0,
                workers=8,
                device='0,1,2,3',
                optimizer='SGD',  # using SGD
                # resume='', # last.pt path
                # amp=False, # close amp
                # fraction=0.2,
                use_simotm="RGBRGB6C",
                channels=6,  #
                project='runs/drone_vehicle_one_top',
                name='drone_vehicle_hbb_remove_white_boarder-yolo11s-RGBRGB6C-midfusion',
                )

        1.初始化模型时,使用 model = YOLO(‘yaml配置文件路径’),其中括号内指定模型的 YAML 配置文件路径。加载权重时,使用 model.load(‘权重路径’),括号内指定权重文件的路径。默认情况下,加载的模型是 n 版本。如果想使用 s 版本,只需将配置文件路径中的 'ultralytics/cfg/models/11-RGBT/yolo11-RGBT-midfusion.yaml' 改为 'ultralytics/cfg/models/11-RGBT/yolo11s-RGBT-midfusion.yaml' 即可。
        2.在调用 model = train() 函数时,参数应为数据集的 YAML 文件路径。device 参数表示 GPU 设备的索引,如果只有一张 GPU 卡,则设置为 0。use_simotmchannels 参数中,channels 设置为 ‘RGBRGB’ 表示 6 个通道,该概念在之前讨论的中期融合部分已详细解释清楚。
        3.运行完成后,project 作为根路径被创建,用于存放各种权重文件和数据文件;而每个文件的完整路径则由 project与name 组合而成。

5. 总结

        通过整篇技术博客的内容,您完全可以跑通这个多模态YOLO框架并初步掌握它。接下来,我将发布一篇文章详细解析该框架的结构图,包括我改进的三尺度跨模态设计。如果您在学习过程中遇到任何疑问,欢迎随时在评论区交流探讨!若对这个系列感兴趣,不妨点个关注,后续我会持续更新更多内容。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弗兰随风小欢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值