YOLOv10改进系列,YOLOv10添加DCNv4可变性卷积(windows系统成功编译),全网最详细教程


在这里插入图片描述

原论文摘要

引入了可变形卷积 v4 (DCNv4),这是一种为广泛视觉应用设计的高效且有效的操作算子。DCNv4通过两项关键增强解决了其前身DCNv3的局限性:1. 移除空间聚合中的softmax归一化,以增强其动态特性和表达能力;2. 优化内存访问以最小化冗余操作,从而加速计算。这些改进使得DCNv4相比DCNv3显著加快了收敛速度,并且处理速度大幅提升,前向传播速度超过三倍。DCNv4在多个任务中表现出色,包括图像分类、实例和语义分割,特别是在图像生成方面表现突出。当将DCNv4集成到生成模型(如潜在扩散模型中的U-Net)中时,它超越了基线模型,凸显了其提升生成模型性能的潜力。在实际应用中,将DCNv3替换为DCNv4并应用于InternImage模型创建FlashInternImage,速度提高高达80%,并且在无需进一步修改的情况下性能进一步提升。DCNv4在速度和效率方面的进步,加上其在多种视觉任务中的强大表现,展示了其作为未来视觉模型基础构建块的潜力。

DCNv4介绍

DCNv4在DCNv3中移除了softmax归一化,将介于0和1之间的调制标量转换为类似于卷积的无界动态权重。如图所示,这种改变进一步增强了DCN的动态性质,其中其他运算符具有一定的限制,例如有界值范围或具有输入无关聚合权的固定聚合窗口(卷积)。

在这里插入图片描述
(a) Attention 和 (b) DCNv3 使用动态权重在范围为0到1之间进行空间特征聚合。Attention的窗口(采样点集)对于每个位置是相同的,而DCNv3为每个位置使用一个专用窗口。
© 卷积 具有更灵活的无界值范围来聚合权重,并为每个位置使用专用的滑动窗口,但窗口形状和聚合权重与输入无关。
(d) DCNv4 结合了它们的优势,使用自适应聚合窗口和具有无界值范围的动态聚合权重。

在DCNv4中,使用一个线程来处理同一组中共享采样偏移和聚合权重的多个通道。这样可以减少内存读取和双线性插值系数计算等工作负载,并且可以合并多个内存访问指令。如下图所示:
在这里插入图片描述

DCNv4理论详解可以参考链接:论文地址
DCNv4代码可在这个链接找到:代码地址

本文在YOLOv10中引入DCNv4(可变性卷积),在windows下编译成功,并且解决各种报错,代码已经整理好了,跟着文章复制粘贴,即可直接运行


🎓一、YOLOv10原始版本代码下载

如果之前有在我的网盘下载的YOLOv10源码的就不需要重新下载了,没有下载从我的网盘下载,链接: YOLOv10原始版本源码下载
提取码: js2i

注意注意注意:如果在我之前的文章下载过YOLOv10源码,不用重新下载了,没有特殊说明都是用同一个版本的源码

🍀🍀1.YOLOv10模型结构图

根据yolov10n.yaml画出yolo整体结构图,如下图所示
在这里插入图片描述

🍀🍀2.环境配置

环境配置参考教程链接:链接: 环境配置链接如果已经配置好环境可以忽略此步骤

🎓二、DCNv4下载与编译,并与C2f结构融合

🍀🍀1.DCNv4源码下载

DCNv4源码下载链接: https://github.com/OpenGVLab/DCNv4

在这里插入图片描述
解压源码
在这里插入图片描述
解压完成之后把DCNv4源码复制到YOLOv10根目录下
在这里插入图片描述

🍀🍀2.DCNv4编译

电脑必须有英伟达显卡,才能编译成功,接下来手把手教你们编译,并且解决编译遇到的问题
1)在PyCharm终端,cd进入DCNv4-main/DCNv4_op文件夹
在这里插入图片描述
2)在终端输入:python setup.py build install
在这里插入图片描述
如果你电脑没有安装cuda和cudnn就会报错,如图所示
报错1:
raise NotImplementedError(‘Cuda is not available’)
NotImplementedError: Cuda is not available

在这里插入图片描述
解决方法:
安装cuda和cudnn,手把手安装教程: cuda和cudnn的安装教程(全网最详细保姆级教程)

之后重新在终端输入:python setup.py build install
安装完cuda和cudnn之后,重新编译,如果没有C++环境的话,会报错,没有报错不用管,从报错信息来看,需要你安装visual studio工具

报错2:
error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build

在这里插入图片描述

解决方法:
安装visual studio 2019工具,手把手安装教程: Visual Studio 2019安装教程(全网最详细教程)

接下来重新输入命令编译,重新在终端输入:python setup.py build install
输出下面信息代表编译成功
在这里插入图片描述
编译成功之后,也可以使用pip list命令查看自己虚拟环境是否有DCNv4
可以看到自己虚拟环境已经有DCNv4了,编译DCNv4大功告成,此时此刻心里成就感满满
在这里插入图片描述
之后,复制DCNv4_op文件夹到ultralytics文件夹下,操作如下:
在这里插入图片描述
在这里插入图片描述

🍀🍀3.DCNv4与C2f融合

DCNv4融合YOLOv10的C2f结构代码我已经写好,代码如下

# -*- coding: utf-8 -*-
"""
@Auth : 挂科边缘
@File :DCNv4.py
@IDE :PyCharm
@Motto:学习新思想,争做新青年
@Email :179958974@qq.com
@qq :179958974
"""
import torch
from torch import nn

from ultralytics.DCNv4_op.DCNv4 import DCNv4

import torch.nn as nn
import torch
import torch.nn.functional as F


def autopad(k, p=None, d=1):  # kernel, padding, dilation
    """Pad to 'same' shape outputs."""
    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p


class Conv(nn.Module):
    """Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""
    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        """Initialize Conv layer with given arguments including activation."""
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        """Apply convolution, batch normalization and activation to input tensor."""
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        """Perform transposed convolution of 2D data."""
        return self.act(self.conv(x))


class Bottleneck(nn.Module):
    """Standard bottleneck."""

    def __init__(self, c1, c2, shortcut=True, g=1, k=(3, 3), e=0.5):
        """Initializes a bottleneck module with given input/output channels, shortcut option, group, kernels, and
        expansion.
        """
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, k[0], 1)
        self.cv2 = DCNv4(c2)
        self.add = shortcut and c1 == c2

    def forward(self, x):
        """'forward()' applies the YOLO FPN to input data."""
        return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))




class C2f_DCNv4(nn.Module):
    """Faster Implementation of CSP Bottleneck with 2 convolutions."""

    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
        """Initialize CSP bottleneck layer with two convolutions with arguments 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(self.c, self.c, shortcut, g, k=(3, 3), e=1.0) for _ in range(n))

    def forward(self, x):
        """Forward pass through C2f layer."""
        x = self.cv1(x)
        x = x.chunk(2, 1)
        y = list(x)

        y.extend(m(y[-1]) for m in self.m)
        return self.cv2(torch.cat(y, 1))

    def forward_split(self, x):
        """Forward pass using split() instead of chunk()."""
        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))

🎓三、添加方法

🍀🍀1.在modules目录下添加第二章的代码

(1).在ultralytics/nn/modules目录下,新建一个文件名,我这里取名为DCNv4.py,操作如以下截图:

在这里插入图片描述

(2).把第二章的代码复制进去,如下图所示:
在这里插入图片描述

🍀🍀2.在__init__.py文件进行导入

文件路径为:ultralytics/nn/modules/init.py
(1)在__init__.py开头注释下面代码,这个步骤注释了以后可以跳过这个步骤
在这里插入图片描述
(2)之后开头导入iRMB,导入截图所示

from .DCNv4 import C2f_DCNv4

在这里插入图片描述

🍀🍀3.在tasks.py文件进行注册

(1)在tasks.py文件开头导入所有模块,该文件路径为:ultralytics/nn/tasks.py
在这个文件修改导入方法,注释掉下图红色圈出来的部分,改成*号导入,以后无需手动一个个导入新的模块,方便很多,一次性导完,这个步骤改完了,往后的文章就可以跳过这个步骤了,添加如截图所示

from ultralytics.nn.modules import *

在这里插入图片描述

(2)之后在这个文件的parse_model方法,添加DCNv4,添加如截图所示

在这里插入图片描述

看到这里已经成功把改进的模块添加进YOLOv10源码了,接下来配置yaml文件调用改进的模块就行了


🎓四、yaml文件修改

在ultralytics/cfg/models/v10目录下,新建一个yaml文件,复制yolov10n.yaml文件,然后取名为yolov10n-iRMB.yaml

🍀🍀1.第一种添加方法

yaml全部代码如下:

# Parameters
nc: 80 # 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] 

# 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_DCNv4, [256, True]]
  - [-1, 1, SCDown, [512, 3, 2]] # 5-P4/16
  - [-1, 6, C2f_DCNv4, [512, True]]
  - [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32
  - [-1, 3, C2f_DCNv4, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 1, PSA, [1024]] # 10

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

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

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

  - [-1, 1, SCDown, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 3, C2fCIB, [1024, True, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5)

🍀🍀2.第二种添加方法

yaml全部代码如下:

# Parameters
nc: 80 # 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] 

# 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, SCDown, [512, 3, 2]] # 5-P4/16
  - [-1, 6, C2f, [512, True]]
  - [-1, 1, SCDown, [1024, 3, 2]] # 7-P5/32
  - [-1, 3, C2f, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]] # 9
  - [-1, 1, PSA, [1024]] # 10

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

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

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

  - [-1, 1, SCDown, [512, 3, 2]]
  - [[-1, 10], 1, Concat, [1]] # cat head P5
  - [-1, 3, C2fCIB, [1024, True, True]] # 22 (P5/32-large)

  - [[16, 19, 22], 1, v10Detect, [nc]] # Detect(P3, P4, P5)

🎓五、训练文件修改

🍀🍀1.新建训练文件

在根目录新建一个python文件,取名为:train.py,如果之前看过我的文章,已经新建过就不用重新新建了
在这里插入图片描述

🍀🍀2.修改训练文件

YOLOv10训练方式跟YOLOv5是有区别的,但是训练数据集格式跟YOLOv5一样的,你只需把处理好的数据集就行,这里就不在阐述了,废话不多说。

把训练代码复制到train.py文件,如果之前看过我的文章,已经复制过了就不用重新复制了,只需修改参数就行,训练的代码如下:

# -*- coding: utf-8 -*-
"""
@Auth : 挂科边缘
@File :train.py
@IDE :PyCharm
@Motto:学习新思想,争做新青年
@Email :179958974@qq.com
@qq :179958974
"""


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

if __name__ == '__main__':
    # model.load('yolov8n.pt') # 加载预训练权重,改进或者做对比实验时候不建议打开,因为用预训练模型整体精度没有很明显的提升
    model = YOLOv10(model=r'D:\2-Python\1-YOLO\YOLOv10\yolov10-main\ultralytics\cfg\models\v10\yolov10n.yaml')
    model.train(data=r'data.yaml',
                imgsz=640,
                epochs=200,
                batch=4,
                workers=8,
                device='',
                optimizer='SGD',
                close_mosaic=10,
                resume=False,
                project='runs/train',
                name='exp',
                single_cls=False,
                cache=False,
                )

根据你训练需求修改指定参数就行,其中圈起来的参数需要你修改的,其他参数根据自己需求选择改或者不改就行。

在这里插入图片描述

训练代码的参数解释,标蓝色的参数为常用参数:
1.model参数:该参数填入模型配置文件的路径,改进的话建议不需要预训练模型权重来训练
2.data参数:该参数可以填入训练数据集配置文件的路径
3.imgsz参数:该参数代表输入图像的尺寸,指定为 640x640 像素
4.epochs参数:该参数代表训练的轮数
5.batch参数:该参数代表批处理大小,电脑显存越大,就设置越大,根据自己电脑性能设置
6.workers参数:该参数代表数据加载的工作线程数,出现显存爆了的话可以设置为0。默认填8,可以加快训练
7.device参数:该参数代表用哪个显卡训练,留空表示自动选择可用的GPU或CPU
8.optimizer参数:该参数代表优化器类型
9.close_mosaic参数:该参数代表在多少个 epoch 后关闭 mosaic 数据增强
10.resume参数:该参数代表是否从上一次中断的训练状态继续训练。设置为False表示从头开始新的训练。如果设置为True,则会加载上一次训练的模型权重和优化器状态,继续训练。这在训练被中断或在已有模型的基础上进行进一步训练时非常有用。
11.project参数:该参数代表项目文件夹,用于保存训练结果
12.name参数:该参数代表命名保存的结果文件夹
13.single_cls参数:该参数代表是否将所有类别视为一个类别,设置为False表示保留原有类别
14.cache参数:该参数代表是否缓存数据,设置为False表示不缓存。

训练报错常见的错误:
训练显存报错,出现以下报错情况,把workers参数改为0
(1)OSError: [WinError 1455] 页面文件太小,无法完成操作。 Error loading “D:\1-ProgramFiles\Anaconda\envs\torch\lib\site-packages\torch\lib\caffe2_detectron_ops_gpu.dll” or one of its dependencies.
在这里插入图片描述
(2)RuntimeError: CUDA out of memory. Tried to allocate 2.00 MiB (GPU 0; 8.00 GiB total capacity; 530.52 MiB already allocated; 4.87 GiB free; 558.00 MiB reserved in total by PyTorch) If reserved memory is >> allocated memory try setting max_split_size_mb to avoid fragmentation. See documentation for Memory Management and PYTORCH_CUDA_ALLOC_CONF

在这里插入图片描述

🍀🍀3.训练报错解决方法

测试一下训练,会报各种错误,接一下一一来解决
1)报错1:
在这里插入图片描述报错:
assert _d_per_group % 16 == 0
AssertionError

报错的原因是因为代码中对_d_per_group进行了一个硬性限制,即它必须是16的倍数。如果你的模型配置导致_d_per_group不是16的倍数,便会触发这个错误
解决方法:
找到dcnv4.py文件,注释掉这行代码:assert _d_per_group % 16 == 0
文件路径:ultralytics/DCNv4_op/DCNv4/modules/dcnv4.py

在这里插入图片描述
2)报错2:
在这里插入图片描述
报错:
N, L, C = input.shape
ValueError: too many values to unpack (expected 3)

报错的原因是input是一个4D张量 (N, H, W, C),代码期望input是一个3D张量 (例如,形状为 (N, L, C))
解决方法:
调整张量并转换顺序,修改如下:

 		# print(input.shape)
        # 将input的形状从(N, C, H, W)转换为(N,L, C)
        input = input.reshape((input.size(0), input.size(1), input.size(2) * input.size(3))).transpose(2, 1)

在这里插入图片描述
之后在该文件末尾,修改一下输出值就行了,代码如下:

        x = x.view(N, H, W, -1)

        if not self.without_pointwise:
            x = self.output_proj(x)
        x = x.permute(0, 3, 1, 2).contiguous()  # 将张量的维度重新排列 (N, C, H, W)
        return x

在这里插入图片描述

3)报错3:
在这里插入图片描述
报错:
output = ext.dcnv4_forward(*args)
RuntimeError: Not implemented on the CPU

报错原因是说我们的DCNv4在一些操作中用到CPU来训练,但是我们是要他在GPU上跑才行

解决方法:
代码如下:

            try:
                m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s))])  # forward
            except RuntimeError:
                try:
                    self.model.to(torch.device('cuda'))
                    m.stride = torch.tensor([s / x.shape[-2] for x in forward(torch.zeros(1, ch, s, s).to(torch.device('cuda')))])
                except RuntimeError as error:
                    raise error

在这里插入图片描述

测试一下训练,打印出来的YOLOv8结构可以看到添加改进的模块成功
在这里插入图片描述

总结

请在我提供的YOLOv10代码修改,把环境配置好,数据集处理好,训练基本能成功,创作不易,请帮忙点一个爱心,谢谢观看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

挂科边缘(毕业版)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值