YOLOv5模型改进策略源码示例

YOLOv5模型改进策略源码示例

YOLO目标检测算法作为单阶段目标检测算法的代表在各个领域都有广泛的应用,在前几篇文章中我们已经对YOLO的Backbone、Neck、Head进行了较为详细的解读,这篇文章主要是从添加注意力机制来提升YOLO检测效果的角度出发,深入探讨如何将不同的注意力机制加入到YOLO中。

1 几点必要知识

1.1 YOLO网络结构

Backbone解读
Neck解读
Head解读

1.2 注意力机制

Channel Attention通道注意力网络结构、源码解读系列一
BAM&DAN原文、结构、源码详解

1.3 修改哪?

YOLO的网络结构主要由yolo文件夹下的models文件夹下的相关配置文件及脚本进行解析,其中比较重要的几个部分:
(1)yaml配置文件:配置文件中包含网络结构的组成部分,修改网络结构就是对配置文件进行修改,如yolov5s.yaml原始文件内容:

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],#256 16 16
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 14], 1, Concat, [1]],  # cat head P4
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

(2)common.py:yaml配置文件中的网络结构组成部分的细节代码主要存在与common.py中,如Conv模块、C3模块、SPPF模块。也就是说,如果我们要往网络结构中添加新的模块,不仅要在yaml配置文件中列出,更要在common.py中定义好,这样在后续的网络结构解析过程中才不会报错。
(3)yolo.py:yolo这个脚本是根据上述两个内容进行网络结构解析的关键部分,主要依靠parse_model()函数实现。在parse_model函数内部,它会根据配置文件传入的模块去查找这部分代码,将其按照网络结构的顺序加入到总体结构中,所以我们需要注意一点:common.py中新添加的模块也需要在yolo的parse_model中指出来,比如我们要新添加CBAM模块,那就应该在parse_model的if判断中这么写(最后加上CBAM):

if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
         BottleneckCSP, C3, C3TR, C3SPP, C3Ghost,CBAM]:
    c1, c2 = ch[f], args[0]

2 添加CBAM模块

2.1 修改网络结构配置文件

如果我们要在Backbone中加入一层新的网络,那么势必会造成总体网络数量的增长,所以要注意加入后的后续网络序列顺序问题:原来SPPF是第9层,我们在SPPF之前加入CBAM,那么SPPF及其之后的网络序列都发生了变化,即网络序列+1,那么在concat和Detect的时候我们就要注意,CBAM模块之后的序列+1,CBAM之前的不用变。当然,有些时候不改也不会报错,但其实与原来的网络结构是不符的,会导致训练结果不具有说服力,具体配置文件:

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple
anchors:
  - [10,13, 16,30, 33,23]  # P3/8
  - [30,61, 62,45, 59,119]  # P4/16
  - [116,90, 156,198, 373,326]  # P5/32

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
#   [-1, 1, DepthSeperabelConv2d, [32, 3, 2]],  # 1-P2/4
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3, [1024]],
   [-1, 1, CBAM,[1024]],# 新添加的模块,序列为9,
   [-1, 1, SPPF, [1024, 5]],  # 10
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 14

   [-1, 1, Conv, [256, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 18 (P3/8-small)

   [-1, 1, Conv, [256, 3, 2]],
   [[-1, 15], 1, Concat, [1]],  # cat head P4,注意这里有变化
   [-1, 3, C3, [512, False]],  # 21 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 11], 1, Concat, [1]],  # cat head P5,注意这里有变化
   [-1, 3, C3, [1024, False]],  # 24 (P5/32-large)

   [[18, 21, 24], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5),注意这里有变化
  ]

2.2 common.py中定义网络的新结构

这里不多赘述,对注意力机制有疑问的同学可以移步之前的注意力机制专题讲解。

class ChannelAttention(nn.Module):
    def __init__(self, in_planes, ratio=16):
        super(ChannelAttention, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        self.max_pool = nn.AdaptiveMaxPool2d(1)
        self.f1 = nn.Conv2d(in_planes, in_planes // ratio, 1, bias=False)
        self.relu = nn.ReLU()
        self.f2 = nn.Conv2d(in_planes // ratio, in_planes, 1, bias=False)
        self.sigmoid = nn.Sigmoid()
    def forward(self, x):
        avg_out = self.f2(self.relu(self.f1(self.avg_pool(x))))
        max_out = self.f2(self.relu(self.f1(self.max_pool(x))))
        out = self.sigmoid(avg_out + max_out)
        return out
class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super(SpatialAttention, self).__init__()
        assert kernel_size in (3, 7), 'kernel size must be 3 or 7'
        padding = 3 if kernel_size == 7 else 1
        self.conv = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
        self.sigmoid = nn.Sigmoid()
    def forward(self, x):
        avg_out = torch.mean(x, dim=1, keepdim=True)
        max_out, _ = torch.max(x, dim=1, keepdim=True)
        x = torch.cat([avg_out, max_out], dim=1)
        x = self.conv(x)
        return self.sigmoid(x)

class CBAM(nn.Module):
    # CSP Bottleneck with 3 convolutions
    def __init__(self, c1, c2, ratio=16, kernel_size=7):  # ch_in, ch_out, number, shortcut, groups, expansion
        super(CBAM, self).__init__()
        self.channel_attention = ChannelAttention(c1, ratio)
        self.spatial_attention = SpatialAttention(kernel_size)
    def forward(self, x):
        out = self.channel_attention(x) * x
        out = self.spatial_attention(out) * out
        return out

2.3 在yolo中加入新的结构

if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, MixConv2d, Focus, CrossConv,
         BottleneckCSP, C3, C3TR, C3SPP, C3Ghost,CBAM]:
    c1, c2 = ch[f], args[0]

2.4 验证网络结构是否完成修改

在yolo.py中添加main函数进行检验:

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--cfg', type=str, default='这里填修改后的yaml文件路径,如yolov5s_cbam.yaml', help='model.yaml')
    parser.add_argument('--device', default='0', help='cuda device, i.e. 0 or 0,1,2,3 or cpu')
    parser.add_argument('--profile', action='store_true', help='profile model speed')
    opt = parser.parse_args()
    opt.cfg = check_yaml(opt.cfg)  # check YAML
    print_args(FILE.stem, opt)
    set_logging()
    device = select_device(opt.device)

    # Create model
    model = Model(opt.cfg).to(device)
    model.train()

    # Profile
    if opt.profile:
        img = torch.rand( 1, 3, 640, 640).to(device)
        print(img.shape)
        y = model(img, profile=True)

如果修改无误,那么将会得到新的网络输出:
在这里插入图片描述

  • 16
    点赞
  • 93
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论
Yolov5+DeepSort是一种目标检测和目标跟踪的算法组合,可以在视频中实现实时的多目标跟踪。在GitHub上,你可以找到相关的源码和使用教程。 以下是使用Yolov5+DeepSort源码的一般步骤: 1. 下载源码:首先,你需要在GitHub上找到Yolov5和DeepSort的源码仓库,并将其下载到本地。 2. 安装依赖:在运行源码之前,你需要安装相关的依赖库。通常,这些依赖库包括PyTorch、NumPy、OpenCV等。你可以根据源码仓库中的要求进行安装。 3. 准备数据集:为了训练和测试模型,你需要准备一个适当的数据集。这个数据集应该包含标注好的图像或视频,并且标注信息应该包括目标的类别和位置。 4. 训练模型:使用准备好的数据集,你可以开始训练Yolov5模型。根据源码仓库中的指导,你需要运行相应的训练脚本,并设置好相关的参数,如学习率、批大小等。训练过程可能需要一定的时间,具体取决于你的硬件配置和数据集的大小。 5. 测试模型:在训练完成后,你可以使用训练好的Yolov5模型进行目标检测。根据源码仓库中的指导,你需要运行相应的测试脚本,并提供待检测的图像或视频作为输入。测试过程将输出检测到的目标及其位置。 6. 应用DeepSort:一旦你完成了目标检测,你可以将DeepSort算法应用于检测到的目标,以实现目标跟踪。根据源码仓库中的指导,你需要运行相应的跟踪脚本,并提供目标检测的结果作为输入。跟踪过程将输出每个目标的唯一ID和轨迹信息。 以上是一般的使用教程概述,具体的步骤和细节可能因源码仓库的不同而有所差异。建议你在GitHub上找到对应的源码仓库,并参考其中的详细文档和示例代码来进行具体操作。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Marlowee

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

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

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

打赏作者

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

抵扣说明:

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

余额充值