【目标检测实验系列】YOLOv5/YOLOv8改进:CARAFE轻量级上采样算子,聚合上下文信息,助力模型涨点(文内附源码)

1. 文章主要内容

       本篇博客主要涉及轻量级上采样算子CARAFE,将YOLOv5/YOLOv8模型中最近邻上采样算子改为CARAFE算子,使模型聚合上下文信息,助力模型涨点。

2. 简要概括

       论文地址:CARAFE论文地址
       论文Github代码:Github代码

       CARAFE具有以下特点:
       1.感受野大。不同于以往只利用亚像素邻域的工作(如双线性插值),CARAFE可以在一个大的接收域中聚合上下文信息。
       2.内容感知。CARAFE不是为所有的样本使用一个固定的内核(例如反卷积,也就是transposed conv),而是支持特定于实例的内容感知处理,它可以动态地生成自适应的内核。
       3.轻量级、计算速度快。CARAFE引入了很少的计算开销,可以很容易地集成到现有的网络架构中。其结构如下图所示:
在这里插入图片描述
       分析:CARAFE作为上采样算子,其轻量级、计算资源小并且高效的特点能够助力YOLOv5/YOLOv8模型涨点。YOLOv5/YOLOv8模型的金字塔结构,也就是Neck结构部分,是需要通过上采样的算子将图片的分辨率进行扩大,以便层级的进行融合,从而融合层级的特征。然而,在上采样的过程中,原模型使用的是最近邻的静态上采样方法,容易丢失信息,尤其是小目标的信息特征(因为小目标本来在图像中的占比像素就比较少),这样就会导致模型识别目标的精度会降低,出现漏检、误检等问题。而CARAFE算子动态的进行上采样,而且有一个大的感受野聚合上下文信息,从而能够抑制小目标信息过多丢失,助力模型涨点!

3. 详细代码改进流程

       接下来手把手将CARAFE算子添加到YOLOv5/YOLOv8模型中某一个地方的全实验过程。首先给出CARAFE算子的源码,新建一个CARAFE.py存放源代码(注意:YOLOv5拷贝下面全部源代码,但在YOLOv8中需要去掉源代码中的import torch 、from torch import nn、from models.common import Conv这三行导包代码),如下所示:

import torch
from torch import nn

from models.common import Conv


class CARAFE(nn.Module):
    def __init__(self, c, k_enc=3, k_up=5, c_mid=64, scale=2):
        """ The unofficial implementation of the CARAFE module.
        The details are in "https://arxiv.org/abs/1905.02188".
        Args:
            c: The channel number of the input and the output.
            c_mid: The channel number after compression.
            scale: The expected upsample scale.
            k_up: The size of the reassembly kernel.
            k_enc: The kernel size of the encoder.
        Returns:
            X: The upsampled feature map.
        """
        super(CARAFE, self).__init__()
        self.scale = scale

        self.comp = Conv(c, c_mid)
        self.enc = Conv(c_mid, (scale * k_up) ** 2, k=k_enc, act=False)
        self.pix_shf = nn.PixelShuffle(scale)

        self.upsmp = nn.Upsample(scale_factor=scale, mode='nearest')
        self.unfold = nn.Unfold(kernel_size=k_up, dilation=scale,
                                padding=k_up // 2 * scale)

    def forward(self, X):
        b, c, h, w = X.size()
        h_, w_ = h * self.scale, w * self.scale

        W = self.comp(X)  # b * m * h * w
        W = self.enc(W)  # b * 100 * h * w
        W = self.pix_shf(W)  # b * 25 * h_ * w_
        W = torch.softmax(W, dim=1)  # b * 25 * h_ * w_

        X = self.upsmp(X)  # b * c * h_ * w_
        X = self.unfold(X)  # b * 25c * h_ * w_
        X = X.view(b, c, -1, h_, w_)  # b * 25 * c * h_ * w_

        X = torch.einsum('bkhw,bckhw->bchw', [W, X])  # b * c * h_ * w_
        return X


       然后分别来讲融合到YOLOv5和YOLOv8模型的教程,这里先从YOLOv5模型开始。

3.1 YOLOv5融合CARAFE算子

3.1.1 新建一个yolov5-CARAFE.yaml文件

       然后,新建一个yolov5-CARAFE.yaml文件,同时 注意nc改为自己数据集的类别数这里是将CARAFE算子替换了Neck部分的两个上采样部分。yaml文件源代码如下所示:

# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 4  # 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  output_channel, kernel_size, stride, padding
   [-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, SPPF, [1024, 5]],  # 9
  ]

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, CARAFE, [3, 5]],
   #[-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, CARAFE, [3, 5]],
   #[-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)
  ]

3.1.2 将CARAFE引入到yolo.py文件中

       在下图的红色圈内位置处,引入CARAFE,并手动导入相应的包即可。代码和示意图如下:

 elif m is CARAFE:
            c2 = ch[f]
            args = [c2, *args]

在这里插入图片描述

3.1.3 修改train.py启动文件

       修改配置文件为yolov5-CARAFE.yaml即可,如下图所示:
在这里插入图片描述

3.2 YOLOv8融合CARAFE算子

3.2.1 新建一个yolov8-CARAFE.yaml文件

       然后,新建一个yolov8-CARAFE.yaml文件,同时 注意nc改为自己数据集的类别数这里是将CARAFE算子替换了Neck部分的两个上采样部分。yaml文件源代码如下所示:

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# Parameters
nc: 10 # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'
  # [depth, width, max_channels]
  n: [0.33, 0.25, 1024] # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024] # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768] # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512] # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512] # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs

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

# YOLOv8.0n head
head:
  - [-1, 1, CARAFE, []]
  - [[-1, 6], 1, Concat, [1]] # cat backbone P4
  - [-1, 3, C2f, [512]] # 12

  - [-1, 1, CARAFE, []]
  - [[-1, 4], 1, Concat, [1]] # cat backbone P3
  - [-1, 3, C2f, [256]] # 15 (P3/8-small)

  - [-1, 1, Conv, [256, 3, 2]]
  - [[-1, 12], 1, Concat, [1]] # cat head P4
  - [-1, 3, C2f, [512]] # 18 (P4/16-medium)

  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]] # cat head P5
  - [-1, 3, C2f, [1024]] # 21 (P5/32-large)

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

3.2.2 将CARAFE源码拷贝到conv.py中并在__init__.py全局注册

       conv.py的路径在这里:ultralytics/nn/modules/conv.py
       init.py的路径在这里:ultralytics/nn/modules/init.py
       第一步:将源码拷贝到conv.py的随便一处,然后在conv.py的最上面有个__all__的地方注册CARAFE引用,如下图所示:
在这里插入图片描述
       第二步:在__init__.py中的.conv中import CARAFE算子,然后同时在此文件的最下放的__all__处也注册CARAFE算子,分别如下图所示:
在这里插入图片描述
在这里插入图片描述

3.2.3 将CARAFE引入到task.py中,并添加相应的代码

       将CARAFE的逻辑代码引入到task.py中,并导入相应的包,这一步其实和YOLOv5中的yolo.py有异曲同工之妙。另外task.py的路径在这里:ultralytics/nn/tasks.py,代码和操作如下所示:

        elif m is CARAFE:
            c1 = ch[f]
            args = [c1]

在这里插入图片描述
在这里插入图片描述

3.2.4 启动train.py即可

       将train.py中训练YOLOv8的模型文件改为YOLOv8n-CARAFE.yaml即可。这里需要注意到,我在YOLOv8后面加了一个n,程序会自动识别调用n的模型大小,我们的yaml文件不需要重命名后面多加一个n。

4. 总结

       本篇博客主要介绍了CARAFE轻量级上采样算子,聚合上下文信息,助力YOLOv5/YOLOv8模型涨点。另外,在修改过程中,要是有任何问题,评论区交流;如果博客对您有帮助,请帮忙点个赞,收藏一下;后续会持续更新本人实验当中觉得有用的点子,如果很感兴趣的话,可以关注一下,谢谢大家啦!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

弗兰随风小欢

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

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

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

打赏作者

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

抵扣说明:

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

余额充值