YOLOV8改进-C2f添加Deformable Conv V2

本文介绍了如何在YOLOV8中集成DeformableConvolutionVersion2(DCNv2),这是一种改进的卷积层,通过学习输入特征的偏移量增强模型对物体几何变化的适应性。作者详细展示了在Blocks.py中的代码实现步骤,包括模块导入、参数解析和模型配置文件的更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1 Deformable Conv V2介绍

2 YOLOV8添加Deformable Conv V2

2.1 代码添加到Blocks

2.1.1 C2f_DCN代码

2.1.2 加入_all_导入

2.1.3 加入modules导入

2.2 添加至运行模块tasks

2.2.1 导入包

2.2.2 解析参数添加

2.3 在_init_中增加名称

2.4 模型配置文件yaml替换

1 Deformable Conv V2介绍

论文地址:https://arxiv.org/abs/1811.11168https://arxiv.org/abs/1811.11168

        DCN v1根据输入特征学习到的偏移量,改变了卷积的采样位置,使得其具有更强的适应物体几何变化的能力,其采样位置更接近物体的真实结构,但有部分采样点超出了感兴趣区域,导致提取的特征受到无关图像内容的影响。而V2堆叠更多可变形卷积层,引入调制机制,提出了一种特征模拟方案,指导网络训练。

2 YOLOV8添加Deformable Conv V2

2.1 代码添加到Blocks.py

        Deformable Conv V2添加到C2f中,形成C2f_DCN。

2.1.1 C2f_DCN代码

        C2f_DCN代码复制到block路径下与C2F路径一致,在ultralytics/nn/modules/block.py,其中包括DCNv2,Bottleneck_DCN,C2f_DCN。

import math
import torch
import torch.nn as nn
class DCNv2(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                 padding=1, dilation=1, groups=1, deformable_groups=1):
        super(DCNv2, self).__init__()

        self.in_channels = in_channels
        self.out_channels = out_channels
        self.kernel_size = (kernel_size, kernel_size)
        self.stride = (stride, stride)
        self.padding = (padding, padding)
        self.dilation = (dilation, dilation)
        self.groups = groups
        self.deformable_groups = deformable_groups

        self.weight = nn.Parameter(
            torch.empty(out_channels, in_channels, *self.kernel_size)
        )
        self.bias = nn.Parameter(torch.empty(out_channels))

        out_channels_offset_mask = (self.deformable_groups * 3 *
                                    self.kernel_size[0] * self.kernel_size[1])
        self.conv_offset_mask = nn.Conv2d(
            self.in_channels,
            out_channels_offset_mask,
            kernel_size=self.kernel_size,
            stride=self.stride,
            padding=self.padding,
            bias=True,
        )
        self.bn = nn.BatchNorm2d(out_channels)
        self.act = Conv.default_act
        self.reset_parameters()

    def forward(self, x):
        offset_mask = self.conv_offset_mask(x)
        o1, o2, mask = torch.chunk(offset_mask, 3, dim=1)
        offset = torch.cat((o1, o2), dim=1)
        mask = torch.sigmoid(mask)
        x = torch.ops.torchvision.deform_conv2d(
            x,
            self.weight,
            offset,
            mask,
            self.bias,
            self.stride[0], self.stride[1],
            self.padding[0], self.padding[1],
            self.dilation[0], self.dilation[1],
            self.groups,
            self.deformable_groups,
            True
        )
        x = self.bn(x)
        x = self.act(x)
        return x

    def reset_parameters(self):
        n = self.in_channels
        for k in self.kernel_size:
            n *= k
        std = 1. / math.sqrt(n)
        self.weight.data.uniform_(-std, std)
        self.bias.data.zero_()
        self.conv_offset_mask.weight.data.zero_()
        self.conv_offset_mask.bias.data.zero_()

class Bottleneck_DCN(nn.Module):
    # Standard bottleneck with DCN
    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):  # ch_in, ch_out, shortcut, groups, kernels, expand
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        if k[0] == 3:
            self.cv1 = DCNv2(c1, c_, k[0], 1)
        else:
            self.cv1 = Conv(c1, c_, k[0], 1)
        if k[1] == 3:
            self.cv2 = DCNv2(c_, c2, k[1], 1, groups=g)
        else:
            self.cv2 = Conv(c_, c2, k[1], 1, g=g)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))

class C2f_DCN(nn.Module):
    # CSP Bottleneck with 2 convolutions
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__()
        self.c = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)
        self.m = nn.ModuleList(Bottleneck_DCN(self.c, self.c, shortcut, g, k=(3, 3), e=1.0) for _ in range(n))

    def forward(self, x):
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

2.1.2 在_all_导入

        还是在block.py路径下,添加C2f_DCN

__all__ = [
    'DFL', 'HGBlock', 'HGStem', 'SPP', 'SPPF', 'C1', 'C2', 'C3', 'C2f', 'C3x', 'C3TR', 'C3Ghost', 'GhostBottleneck',
    'Bottleneck', 'BottleneckCSP', 'Proto', 'RepC3',
    'C2f_DCN','C2f_DSConv']

2.1.3 在modules.py导入

        路径D:\learn\sdxx\mbjc\ultralytics\ultralytics\nn\modules\__init__.py导入C2f_DCN。

from .block import (C1, C2, C3, C3TR, DFL, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x, GhostBottleneck,
                    HGBlock, HGStem, Proto, RepC3,
                    C2f_DCN)#自己加的
__all__ = [
    'Conv', 'LightConv', 'RepConv', 'DWConv', 'DWConvTranspose2d', 'ConvTranspose', 'Focus', 'GhostConv',
    'ChannelAttention', 'SpatialAttention', 'CBAM', 'Concat', 'TransformerLayer', 'TransformerBlock', 'MLPBlock',
    'LayerNorm2d', 'DFL', 'HGBlock', 'HGStem', 'SPP', 'SPPF', 'C1', 'C2', 'C3', 'C2f', 'C3x', 'C3TR', 'C3Ghost',
    'GhostBottleneck', 'Bottleneck', 'BottleneckCSP', 'Proto', 'Detect', 'Segment', 'Pose', 'Classify',
    'TransformerEncoderLayer', 'RepC3', 'RTDETRDecoder', 'AIFI', 'DeformableTransformerDecoder',
    'DeformableTransformerDecoderLayer', 'MSDeformAttn', 'MLP','deattn',
    'C2f_DCN']

2.2 添加至运行模块tasks.py

        将模块名称加入到tasks.py中,路径在ultralytics/nn/tasks.py。

2.2.1 导入包

from ultralytics.nn.modules import (AIFI, C1, C2, C3, C3TR, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x,
                                    Classify, Concat, Conv, ConvTranspose, Detect, DWConv, DWConvTranspose2d, Focus,
                                    GhostBottleneck, GhostConv, HGBlock, HGStem, Pose, RepC3, RepConv, RTDETRDecoder,
                                    Segment,CBAM,C2f_DCN)

2.2.2 解析参数

        在task.py下面def parse_model中加入C2f_DCN。这两个代码中加入C2f_DCN。
这代码是传入模块的通道数。
if m in (Classify, Conv, ConvTranspose, GhostConv, Bottleneck, GhostBottleneck, SPP, SPPF, DWConv, Focus,
                 BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, nn.ConvTranspose2d, DWConvTranspose2d, C3x, RepC3,BasicRFB_a,C2f_DCN):

这个代码模块进行多次使用

if m in (BottleneckCSP, C1, C2, C2f, C3, C3TR, C3Ghost, C3x, RepC3,C2f_DCN):

2.3 在_init_中增加名称

        C2f_DCN是block中的一个,在ultralytics/nn/modules/__init__.py路径下,增加导入包,以及增加名称。
from .block import (C1, C2, C3, C3TR, DFL, SPP, SPPF, Bottleneck, BottleneckCSP, C2f, C3Ghost, C3x, GhostBottleneck,
                    HGBlock, HGStem, Proto, RepC3,C2f_DCN)
__all__ = [
    'Conv', 'LightConv', 'RepConv', 'DWConv', 'DWConvTranspose2d', 'ConvTranspose', 'Focus', 'GhostConv',
    'ChannelAttention', 'SpatialAttention', 'CBAM', 'Concat', 'TransformerLayer', 'TransformerBlock', 'MLPBlock',
    'LayerNorm2d', 'DFL', 'HGBlock', 'HGStem', 'SPP', 'SPPF', 'C1', 'C2', 'C3', 'C2f', 'C3x', 'C3TR', 'C3Ghost',
    'GhostBottleneck', 'Bottleneck', 'BottleneckCSP', 'Proto', 'Detect', 'Segment', 'Pose', 'Classify',
    'TransformerEncoderLayer', 'RepC3', 'RTDETRDecoder', 'AIFI', 'DeformableTransformerDecoder',
    'DeformableTransformerDecoderLayer', 'MSDeformAttn', 'MLP','deattn','C2f_DCN']

2.4 模型配置文件yaml替换

        在ultralytics/models/v8中yaml配置文件中,将任意的C2f改为C2f_DCN,通道多参数就多。

# 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: 11  # 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_DCN, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f_DCN, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f_DCN, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9

# YOLOv8.0n head
head:
  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-1, 6], 1, Concat, [1]]  # cat backbone P4
  - [-1, 3, C2f, [512]]  # 12


  - [-1, 1, nn.Upsample, [None, 2, 'nearest']]
  - [[-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 main调用

        左边调用模型配置文件,右边调用数据配置文件

from ultralytics import YOLO
if __name__ == '__main__':

    model = YOLO("ultralytics/models/v8/yolov8.yaml").train(**{'cfg': 'ultralytics/yolo/cfg/break.yaml'})

**C2D_DISABLED是一个与MATLAB软件中c2d函数相关的概念,它指的是在某些情况下,连续时间系统的离散化过程可能被禁用或不适用**。 在MATLAB中,c2d函数用于将连续时间系统转换为离散时间系统。这个转换过程对于数字信号处理和控制系统设计来说非常重要,因为它允许设计师在数字域内分析和实现原本在连续域内定义的系统。c2d函数的基本语法是`sysd = c2d(sysc, Ts, method)`,其中`sysc`是连续时间系统的描述(如传输函数或状态空间模型),`Ts`是采样时间间隔,`method`是指定的离散化方法。 然而,在某些情况下,可能会遇到C2D_DISABLED的情况,这通常意味着由于某些限制或特定的系统特性,标准的离散化方法无法应用。例如,如果系统的特性使得它在离散化过程中不稳定或者会产生不可接受的误差,那么可能需要寻找替代的离散化方法或者调整系统参数。 此外,c2d函数支持多种离散化方法,包括零阶保持器法(zoh)、一阶保持器法(foh)、双线性变换法(tustin)和脉冲响应不变法(imp)。这些方法适用于不同的应用场景和系统要求。 总之,C2D_DISABLED通常指的是在某些特定情况下,连续时间系统的离散化过程需要特别注意或者不能使用标准方法。在实际应用中,了解不同离散化方法的优缺点和适用场景对于正确使用c2d函数至关重要。
评论 71
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值