• [yolo系列:yolov7添加可变形卷积Deformable Conv V2]


    yolo系列文章目录


    一、可变形卷积是什么?

      可变形卷积即DCN(缩写取自Deformable ConvNets)提出于ICCV 2017的paper:Deformable Convolutional Networks
    
    • 1

    论文paper地址:https://openaccess.thecvf.com/content_ICCV_2017/papers/Dai_Deformable_Convolutional_Networks_ICCV_2017_paper.pdf

    codebase地址:(很多框架中都已实现,这里选择以pytorch的为例)https://github.com/4uiiurz1/pytorch-deform-conv-v2/blob/master/deform_conv_v2.py
    DCN原文链接
    代码链接

    《可变形卷积网络(Deformable Convolutional Networks,缩写为DCN)》是一种革命性的卷积神经网络架构,它的提出源于2017年的ICCV(International Conference on Computer Vision)论文《Deformable Convolutional Networks》。这项创新性的研究由华中科技大学的研究人员马翔、Ross Girshick、Piotr Dollár等合作完成。DCN的引入使得卷积神经网络在处理非刚性目标、不规则目标形状以及精细目标边界等方面取得了巨大的突破,为计算机视觉领域的目标检测、图像分割等任务带来了显著的性能提升。

    1. DCN的基本原理

    DCN的关键创新点在于引入了“可变形卷积核”的概念。传统的卷积操作使用固定形状和位置的卷积核,而DCN允许卷积核在空间上进行形变,从而适应不规则目标的形状。这种形变性质由一个学习模块来控制,使得网络可以自适应地学习到目标的变化和形状特征。
    2. DCN的关键组成部分

    可变形卷积层:DCN网络中的核心组件,它允许卷积核在输入特征图上进行自适应形变。这种形变是通过偏移量(offsets)来实现的,这些偏移量是由网络学习得到的,可以用来调整卷积核的形状和位置。
    
    可变形池化层:类似于可变形卷积层,可变形池化层允许网络学习如何对输入特征图进行自适应的空间下采样,从而更好地捕捉目标的特征。
    
    • 1
    • 2
    • 3
    1. DCN的优势和应用

      适应性和灵活性:DCN具有非常强的适应性,可以适应各种不规则形状的目标。这使得它在处理遮挡、姿态变化等问题时表现出色。

      精细特征学习:DCN可以学习到目标边界和纹理等细节特征,使得网络更加关注目标的微观结构,提高了目标检测和分割的精度。

      广泛应用:DCN不仅在目标检测任务中取得了显著的性能提升,还被广泛应用于图像分割、人体姿态估计、人脸识别等领域,为这些任务带来了更准确的结果。
      本文提出了两个新模块:可变形卷积和可变形RoI池化

    新模块可以很容易地取代现有CNN中的普通模块,并且可以通过标准反向传播轻松地进行端到端训练。

    DCN目前也出到了v2,值得一提的是,DCN的思维也算一种可学习的自适应模块,跟注意力机制模块BAM/CBAM的思路有点像。

    mmdetection里也有相关实现,可轻松移植进自己的项目,DCN对于大多数检测场景尤其是比赛都是有用的。

    二、使用步骤

    1.在models/common.py文件添加

    class DCNv2(nn.Module):
        def __init__(self, in_channels, out_channels, kernel_size, stride=1,
                     padding=1, groups=1, act=True, dilation=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 = (autopad(kernel_size, padding), autopad(kernel_size, 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 = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())
            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_()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    2.然后再yolo.py里面添加DCNv2

    在这里插入图片描述

    3.修改yolov7的yaml

    添加到主干,只需要修改卷积核为3的,为1的没有必要修改,
    在这里插入图片描述

    总结

    一般可变形卷积是添加到主干网上,如果想添加到head部分,自行尝试。

    参考文章

    [yolov5修改]在yolov5中加入可变形卷积模块
    【YOLOv8/YOLOv7/YOLOv5/YOLOv4/Faster-rcnn系列算法改进NO.57】引入可形变卷积
    可变形卷积:Deformable ConvNets

  • 相关阅读:
    集合数据丢失distinct与EqualsAndHashCode的Bug问题
    【校招VIP】前端计算机网络之UDP相关
    06_es分布式搜索引擎2
    Maven依赖导入
    HTTP/2的三大改进:头部压缩、多路复用和服务器推送
    软件测试/测试开发丨Web自动化—capability参数配置 学习笔记
    继续折腾Centos7开启BBR加速有效提升访问和下载速度(亲测有效)
    安装njnx --chatGPT
    体验提升-一个“小技巧”彻底解决锦礼商品可见不可售
    【LeetCode-中等题】34. 在排序数组中查找元素的第一个和最后一个位置
  • 原文地址:https://blog.csdn.net/weixin_47869094/article/details/133687806