【YOLOv5改进系列(4)】高效涨点----添加可变形卷积DCNv2

在这里插入图片描述


可变形卷积

  • 🚀🚀🚀前言
  • 一、1️⃣ 什么是可变形卷积
  • 二、2️⃣如何在yolov5中添加DCNv2模块
    • 2.1 🎓 修改common.py模块
    • 2.2 ✨修改yolo.py文件
    • 2.3 ⭐️修改yolov5s.yaml文件
    • 2.4 🎯训练可能报错结果
  • 三、3️⃣DCNv2实验结果
    • 3.1 🎓 正常训练
    • 3.2 ✨修改实验1
    • 3.3 ⭐️修改实验2
    • 3.4 🎯修改实验3


在这里插入图片描述

👀🎉📜系列文章目录

【YOLOv5改进系列(1)】高效涨点----使用EIoU、Alpha-IoU、SIoU、Focal-EIOU替换CIou
【YOLOv5改进系列(2)】高效涨点----Wise-IoU详细解读及使用Wise-IoU(WIOU)替换CIOU
【YOLOv5改进系列(3)】高效涨点----Optimal Transport Assignment:OTA最优传输方法

🚀🚀🚀前言

目前可变形卷积一共有4个版本,分别是DCNv1~DCNv4,在本文中使用的是带有可变形卷积DCNv2的方法替换yolov5-v6.0版本中的C3模块。本次使用的数据集是热轧钢带的六种典型表面缺陷数据集,通过在backbone的不同位置添加可变形卷积进行训练,经过实验测试结果,最后的map@0.5提高了近5个百分点。


一、1️⃣ 什么是可变形卷积

🚀概念
可变形卷积指卷积核在每个元素上增加了一个参数方向参数,这样卷积核就能在训练过程中扩展到很大的范围。它允许卷积核在空间上进行动态调整,以适应目标对象的形变或者复杂结构。

传统的卷积操作是固定的,卷积核的权重在整个图像上是不变的,而可变形卷积则引入了额外的参数,用于控制卷积核的采样位置。这些额外的参数通常是由一个学习模块来学习得到的,通常称为偏移量(offset)。在进行可变形卷积时,卷积核的采样位置会根据输入特征图的内容进行动态调整,从而实现对目标对象形状的适应性。

🔥为什么要使用可变形卷积?
卷积核的目的是为了提取输入物的特征。传统的卷积核通常是固定尺寸、固定大小的。这种卷积核存在的最大问题就是,对于未知的变化适应性差,泛化能力差。网络内部缺乏能够解决这些问题的模块,这会产生显著的问题,同一 CNN 层的激活单元的感受野尺寸都相同,这对于编码位置信息的浅层神经网络并不可取,因为不同的位置可能对应有不同尺度或者不同形变的物体,这些层需要能够自动调整尺度或者感受野的方法。再比如,目标检测虽然效果很好但是都依赖于基于特征提取的边界框,这并不是最优的方法,尤其是对于非网格状的物体而言。

✨因此,希望卷积核可以根据实际情况调整本身的形状,更好的提取输入的特征。

  • 更好的感受野覆盖:由于卷积核的采样位置可以自适应地调整,因此可变形卷积可以更好地适应目标对象的形状和结构,从而提高感受野的覆盖能力。
  • 对目标形变的鲁棒性:可变形卷积可以处理目标对象形变的情况,例如目标的畸变、变形或者姿态变化等,从而提高了模型的鲁棒性和泛化能力。
  • 更强的表达能力:通过引入额外的偏移参数,可变形卷积可以增加模型的表达能力,使其能够更好地捕捉目标对象的细微特征和结构信息。

二、2️⃣如何在yolov5中添加DCNv2模块

2.1 🎓 修改common.py模块

找到models文件下的common.py文件,将鼠标定位到该文件的最后一行代码。

在这里插入图片描述
📌将下面修改的的可变形卷积DCNv2模块代码粘贴到最后一行,这段代码的作用就是构建带有DCNv2的C3模块

# ====================添加DCN V2=====================
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
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, shortcut, groups, expansion
        super().__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = DCNv2(c_, c2, 3, 1, groups=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 C3_DCN(C3):
    #  带有DCNv2的C3模块
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):
        super().__init__(c1, c2, n, shortcut, g, e)
        c_ = int(c2 * e)
        self.m = nn.Sequential(*(Bottleneck_DCN(c_, c_, shortcut, g, e=1.0) for _ in range(n)))

2.2 ✨修改yolo.py文件

📌首先找到models文件夹下的yolo.py,在该文件中找到parse_model网络解析函数,大概是在第300行左右。

在这里插入图片描述
📌在parse_model函数中需要在两处添加C3_DCN(也就是带有DCN的C3模块),添加位置如下:

在这里插入图片描述

2.3 ⭐️修改yolov5s.yaml文件

🚀找到models文件夹下的yolov5s.yaml配置文件,前面我们已经定义好C3_DCN模块,接下来就是需要将可变形卷积替换掉原始的C3模块。
☀️温馨提示:看过很多论文添加可变形卷积,一般是在backbone特征提取部分添加,如果有兴趣也可以在Neck特征融合部分添加可变形卷积。
我是将backbone的特征金字塔特征融合输出的三个部分C3模块替换成了C3_DCN可变形卷积,我添加的比较多,训练过程中的参数量也会大大增加,所以会增加训练时间,如果不想训练速度太慢,也可以只替换最后一个C3模块。
在这里插入图片描述

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args] 输出640*640
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2 320*320    64表示输出的channel,但是需要乘以width_multiple,6表示卷积核的大小,2表示padding大小,2表示stride大小
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4   160*160*128      2表示stride大小
   [-1, 3, C3, [128]],

   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8   80*80*256
   [-1, 6, C3_DCN, [256]],

   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16   40*40*512
   [-1, 9, C3_DCN, [512]],

   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32   20*20
   [-1, 3, C3_DCN, [1024]],

   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

2.4 🎯训练可能报错结果

在将C3模块替换成C3_DCN模块之后可能会报一个错误,也是我遇到的,报错内容如:

Variable._execution_engine.run_backward( # Calls into the C++ engine to run the backward pass RuntimeError: adaptive_max_pool2d_backward_cuda does not have a deterministic implementation, but you set ‘torch.use_deterministic_algorithms(True)’. You can turn off determinism just for this operation, or you can use the ‘warn_only=True’ option

如果出现这个错误可以通过寻找报错来源可以通过修改train.py文件中的

init_seeds(opt.seed + 1 + RANK, deterministic=True)

将True改成False

init_seeds(opt.seed + 1 + RANK, deterministic=False)
  • opt.seed + 1 + RANK的目的是使每个进程具有不同的随机种子。通过在种子值中添加进程排名,可以确保每个进程使用不同的种子,从而生成独立的随机序列。
  • deterministic=True参数的作用是启用确定性算法

⚡️目前我也不知道为什么修改初始化随机种子就能解决这个问题。有大佬了解的可以评论区讨论。

三、3️⃣DCNv2实验结果

3.1 🎓 正常训练

F1置信度分数为0.71、map@0.5=0.779
在这里插入图片描述

3.2 ✨修改实验1

修改内容:只修改backbone网络中的最后一个C3模块,将其替换成C3_DCN。

backbone:
  # [from, number, module, args] 输出640*640
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2 320*320    64表示输出的channel,但是需要乘以width_multiple,6表示卷积核的大小,2表示padding大小,2表示stride大小
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4   160*160*128      2表示stride大小
   [-1, 3, C3, [128]],

   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8   80*80*256
   [-1, 6, C3, [256]],

   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16   40*40*512
   [-1, 9, C3, [512]],

   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32   20*20
   [-1, 3, C3_DCN, [1024]],

   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

实验结果:F1置信度分数为0.76、map@0.5=0.801,两个评估指标都有所增长。

在这里插入图片描述

3.3 ⭐️修改实验2

修改内容:只修改backbone网络中的第2个和最后一个C3模块,将其替换成C3_DCN。

backbone:
  # [from, number, module, args] 输出640*640
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2 320*320    64表示输出的channel,但是需要乘以width_multiple,6表示卷积核的大小,2表示padding大小,2表示stride大小
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4   160*160*128      2表示stride大小
   [-1, 3, C3, [128]],

   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8   80*80*256
   [-1, 6, C3_DCN, [256]],

   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16   40*40*512
   [-1, 9, C3, [512]],

   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32   20*20
   [-1, 3, C3_DCN, [1024]],

   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

实验结果F1置信度分数为0.76、map@0.5=0.819,两个评估指标都有所增长。

在这里插入图片描述

3.4 🎯修改实验3

修改内容:将backbone的特征金字塔特征融合输出的三个部分C3模块替换成了C3_DCN可变形卷积

backbone:
  # [from, number, module, args] 输出640*640
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2 320*320    64表示输出的channel,但是需要乘以width_multiple,6表示卷积核的大小,2表示padding大小,2表示stride大小
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4   160*160*128      2表示stride大小
   [-1, 3, C3, [128]],

   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8   80*80*256
   [-1, 6, C3_DCN, [256]],

   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16   40*40*512
   [-1, 9, C3_DCN, [512]],

   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32   20*20
   [-1, 3, C3_DCN, [1024]],

   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

实验结果F1置信度分数为0.75、map@0.5=0.818,两个评估指标都有所增长。相较于修改实验2,这一次训练时间大大增加,但是评估指标并没有明显增加。
在这里插入图片描述


在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/489492.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【好书推荐3】Python网络爬虫入门到实战

【好书推荐3】Python网络爬虫入门到实战 写在最前面内容简介作者简介目录前言/序言 🌈你好呀!我是 是Yu欸 🌌 2024每日百字篆刻时光,感谢你的陪伴与支持 ~ 🚀 欢迎一起踏上探险之旅,挖掘无限可能&#xff…

关于《海岛奇兵》中n点能量可造成最大伤害的计算

最近在玩海岛奇兵, 里面有 武器A, 第n次使用消耗(10 6 * (n - 1))点能量并造成18315伤害; 武器B, 第n次使用消耗 (3 2 * (n - 1))点能量并造成8124伤害, 就想着能不能写一个程序计算一下, 当有x点能量时, 可造成的最大伤害是多少? 分别使用AB武器各多少次? 讨论: https://…

《仙剑7》登陆Xbox主机平台年末大作空窗期

首发一年后,《仙剑奇侠传7》终于登陆Xbox主机平台,而这也恰逢Xbox平台年末大作的窗口期。 随着年底大作的稀缺,以及海外3A RPG《星空》的延期,2022年底的这段时间给Xbox玩家体验《刀剑7》留下了一段空白。 可以说是因祸得福。 《仙…

微服务的可观测性

微服务是是一个大型的分布式系统,服务之间相互依赖支撑系统功能。同时对微服务系统的监控也是微服务体系的重要组成分。对微服务系统的监控主要分为三大部分,Trace追踪,Metrics指标,Log日志。 这三大部分几乎记录了微服务的前部信…

Stable Diffusion之核心基础知识和网络结构解析

Stable Diffusion核心基础知识和网络结构解析 一. Stable Diffusion核心基础知识1.1 Stable Diffusion模型工作流程1. 文生图(txt2img)2. 图生图3. 图像优化模块 1.2 Stable Diffusion模型核心基础原理1. 扩散模型的基本原理2. 前向扩散过程详解3. 反向扩散过程详解4. 引入Late…

【linux】进程地址空间(进程三)

目录 快速了解:引入最基本的理解:细节:如何理解地址空间:a.什么是划分区域:b.地址空间的理解: 为什么要有进程空间?进一步理解页表与写时拷贝: 快速了解: 先来看这样一段…

算法系列--两个数组的dp问题(1)

💕"低头要有勇气,抬头要有底气。"💕 作者:Mylvzi 文章主要内容:算法系列–两个数组的dp问题(1) 大家好,今天为大家带来的是算法系列--两个数组的dp问题(1),两个数组的dp问题在动态规划问题中属于较难的部分…

c++之旅第八弹——多态

大家好啊,这里是c之旅第八弹,跟随我的步伐来开始这一篇的学习吧! 如果有知识性错误,欢迎各位指正!!一起加油!! 创作不易,希望大家多多支持哦! 一&#xff0…

AI研报:从Sora看多模态大模型发展

《从Sora看多模态大模型发展》的研报来自浙商证券,写于2024年2月。 这篇报告主要探讨了多模态大模型的发展趋势,特别是OpenAI发布的视频生成模型Sora,以及其对行业发展的影响。以下是报告的核心内容概述: Sora模型的发布&#x…

【C++航海王:追寻罗杰的编程之路】queue

目录 1 -> queue的介绍和使用 1.1 -> queue的介绍 1.2 -> queue的使用 1.3 -> queue的模拟实现 1 -> queue的介绍和使用 1.1 -> queue的介绍 queue的文档介绍 1. 队列是一种容器适配器,专门用于在FIFO(先进先出)上下文中操作,其…

C语言例4-4:putchar()函数的调用格式和使用的例子

代码如下&#xff1a; //putchar()函数的调用格式和使用的例子 #include<stdio.h> //编译预处理命令&#xff0c;即文件包含命令 int main(void) {char ch1N, ch2E, ch3W;putchar(ch1);putchar(ch2);putchar(ch3); //输出变量c1、c2和c3中的字符putchar(\n);putcha…

Protocol Buffers设计要点

概述 一种开源跨平台的序列化结构化数据的协议。可用于存储数据或在网络上进行数据通信。它提供了用于描述数据结构的接口描述语言&#xff08;IDL&#xff09;&#xff0c;也提供了根据 IDL 产生代码的程序工具。Protocol Buffers的设计目标是简单和性能&#xff0c;所以与 XM…

长安链共识算法切换:动态调整,灵活可变

#功能发布 长安链3.0正式版发布了多个重点功能&#xff0c;包括共识算法切换、支持java智能合约引擎、支持后量子密码、web3生态兼容等。我们接下来为大家详细介绍新功能的设计、应用与规划。 随着长安链应用愈加成熟与广泛&#xff0c;一些在生产中很实用的需求浮出水面。长安…

MySQL进阶-----索引的结构与分类

目录 前言 一、认识索引 二、索引结构 1.概述 2. 二叉树 3 .B-Tree 4.BTree 5.Hash 三、索引的分类 1 .索引分类 2 .聚集索引&二级索引 前言 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维…

基于nginx 动态 URL反向代理的实现

背景&#xff1a; 我们在项目中在这样一个场景&#xff0c;用户需要使用固定的软件资源&#xff0c;这些资源是以服务器或者以容器形式存在的。 资源以webAPI方式在内网向外提供接口&#xff0c;资源分类多种类型&#xff0c;每种类型的资源程序和Wapi参数都一样。这些资源部属…

javaWeb在线考试系统

一、简介 在线考试系统是现代教育中一项重要的辅助教学工具&#xff0c;它为学生提供了便捷的考试方式&#xff0c;同时也为教师提供了高效的考试管理方式。我设计了一个基于JavaWeb的在线考试系统&#xff0c;该系统包括三个角色&#xff1a;管理员、老师和学生。管理员拥有菜…

ubuntu2004自动更新内核导致nvidia驱动无法正常启动的问题

症状 开机后&#xff0c;nvidia-smi无法正常显示显卡状态&#xff0c;另外无法连接多个显示屏 解决 参考这个文章&#xff1a; ls /usr/src可以看到已安装的nvidia驱动版本是nvidia-535.54.03 然后运行下面的指令&#xff1a; sudo apt-get install dkmssudo dkms instal…

Mimikatz介绍

一、Mimikatz定义 mimikatz是benjamin使用C语言编写的一款非常强大的安全工具&#xff0c;它可以从机器内存中提取明文密码、密码Hash、PIN码和Kerberos票据等。它的功能非常强大&#xff0c;得到全球安全研究员的广泛使用。 Mimikatz 是一款功能强大的轻量级调试神器&#xff…

Java版直播商城免 费 搭 建:平台规划与常见营销模式,电商源码、小程序、三级分销及详解

【saas云平台】打造全行业全渠道全场景的saas产品&#xff0c;为经营场景提供一体化解决方案&#xff1b;门店经营区域化、网店经营一体化&#xff0c;本地化、全方位、一站式服务&#xff0c;为多门店提供统一运营解决方案&#xff1b;提供丰富多样的营销玩法覆盖所有经营场景…

在vue中使用echarts饼图示例

1.安装 npm install echarts --save 2.官方示例 option {title: {text: Referer of a Website,subtext: Fake Data,left: center},tooltip: {trigger: item},legend: {orient: vertical,left: left},series: [{name: Access From,type: pie,radius: 50%,data: [{ value: 104…