YOLOv5、YOLOv8改进:HorNet(递归门卷积(g nConv))

news2024/11/17 15:30:52

1.简介

论文地址:https://arxiv.org/abs/2207.14284
代码地址:https://github.com/raoyongming/HorNet

视觉Transformer的最新进展表明,在基于点积自注意力的新空间建模机制驱动的各种任务中取得了巨大成功。在本文中,作者证明了视觉Transformer背后的关键成分,即输入自适应、长程和高阶空间交互,也可以通过基于卷积的框架有效实现。作者提出了递归门卷积(g n Conv),它用门卷积和递归设计进行高阶空间交互。新操作具有高度灵活性和可定制性,与卷积的各种变体兼容,并将自注意力中的二阶交互扩展到任意阶,而不引入显著的额外计算。g nConv可以作为一个即插即用模块来改进各种视觉Transformer和基于卷积的模型。基于该操作,作者构建了一个新的通用视觉主干族,名为HorNet。在ImageNet分类、COCO对象检测和ADE20K语义分割方面的大量实验表明,HorNet在总体架构和训练配置相似的情况下,优于Swin Transformers和ConvNeXt。HorNet还显示出良好的可扩展性,以获得更多的训练数据和更大的模型尺寸。除了在视觉编码器中的有效性外,作者还表明g n Conv可以应用于任务特定的解码器,并以较少的计算量持续提高密集预测性能。本文的结果表明,g n Conv可以作为一个新的视觉建模基本模块,有效地结合了视觉Transformer和CNN的优点。

(a)标准卷积运算没有明确考虑空间交互。

(b) 动态卷积 [27, 4] SE [25] 引入了动态权重,以通过额外的空间交互来提高卷积的建模能力。

(c) 自注意力操作 通过两个连续的矩阵乘法执行二阶空间交互。

 (d) gnConv 使用具有门控卷积和递归设计的高效实现来实现任意阶空间交互。

在本文中,作者总结了视觉Transformers成功背后的关键因素是通过自注意力操作实现输入自适应、远程和高阶空间交互的空间建模新方法。虽然之前的工作已经成功地将元架构、输入自适应权重生成策略和视觉Transformers的大范围建模能力迁移到CNN模型,但尚未研究高阶空间交互机制。作者表明,使用基于卷积的框架可以有效地实现所有三个关键要素。作者提出了递归门卷积(g nConv),它与门卷积和递归设计进行高阶空间交互。与简单地模仿自注意力中的成功设计不同,g n Conv有几个额外的优点:1)**效率。**基于卷积的实现避免了自注意力的二次复杂度。在执行空间交互期间逐步增加通道宽度的设计也使能够实现具有有限复杂性的高阶交互;2) 可扩展。将自注意力中的二阶交互扩展到任意阶,以进一步提高建模能力。由于没有对空间卷积的类型进行假设,g n Conv与各种核大小和空间混合策略兼容;3) 平移等变性。g n Conv完全继承了标准卷积的平移等变性,这为主要视觉引入了有益的归纳偏置。

                                       

基于g n Conv,作者构建了一个新的通用视觉主干族,名为HorNet。作者在ImageNet分类、COCO对象检测和ADE20K语义分割上进行了大量实验,以验证本文模型的有效性。凭借相同的7×7卷积核/窗口和类似的整体架构和训练配置,HorNet优于Swin和ConvNeXt在不同复杂度的所有任务上都有很大的优势。通过使用全局卷积核大小,可以进一步扩大差距。HorNet还显示出良好的可扩展性,可以扩展到更多的训练数据和更大的模型尺寸,在ImageNet上达到87.7%的top-1精度,在ADE20K val上达到54.6%的mIoU,在COCO val上通过ImageNet-22K预训练达到55.8%的边界框AP。除了在视觉编码器中应用g n Conv外,作者还进一步测试了在任务特定解码器上设计的通用性。通过将g n Conv添加到广泛使用的特征融合模型FPN,作者开发了HorFPN来建模不同层次特征的高阶空间关系。作者观察到,HorFPN还可以以较低的计算成本持续改进各种密集预测模型。结果表明,g n Conv是一种很有前景的视觉建模方法,可以有效地结合视觉Transofrmer和CNN的优点。

2.YOLOv5代码修改

2.1 修改yaml文件  neck部分修改

# YOLOv5 v6.0 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [64, 6, 2, 2]],  # 0-P1/2
   [-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, 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, 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, HorBlock, [512]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, HorBlock, [1024]],  # 23 (P5/32-large)

   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

backbone修改

# YOLOAir 🚀 by 🥭, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.25  # 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
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, HorBlock, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, HorBlock, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, HorBlock, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, HorBlock, [1024]],
   [-1, 1, SPPF, [1024, 5]],  # 9
  ]

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

2.2 common添加代码

class HorLayerNorm(nn.Module):
    r""" LayerNorm that supports two data formats: channels_last (default) or channels_first. 
    The ordering of the dimensions in the inputs. channels_last corresponds to inputs with 
    shape (batch_size, height, width, channels) while channels_first corresponds to inputs 
    with shape (batch_size, channels, height, width).# https://ar5iv.labs.arxiv.org/html/2207.14284
    """
    def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last"):
        super().__init__()
        self.weight = nn.Parameter(torch.ones(normalized_shape))
        self.bias = nn.Parameter(torch.zeros(normalized_shape))
        self.eps = eps
        self.data_format = data_format
        if self.data_format not in ["channels_last", "channels_first"]:
            raise NotImplementedError # by iscyy/air
        self.normalized_shape = (normalized_shape, )
    
    def forward(self, x):
        if self.data_format == "channels_last":
            return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
        elif self.data_format == "channels_first":
            u = x.mean(1, keepdim=True)
            s = (x - u).pow(2).mean(1, keepdim=True)
            x = (x - u) / torch.sqrt(s + self.eps)
            x = self.weight[:, None, None] * x + self.bias[:, None, None]
            return x

class GlobalLocalFilter(nn.Module):
    def __init__(self, dim, h=14, w=8):
        super().__init__()
        self.dw = nn.Conv2d(dim // 2, dim // 2, kernel_size=3, padding=1, bias=False, groups=dim // 2)
        self.complex_weight = nn.Parameter(torch.randn(dim // 2, h, w, 2, dtype=torch.float32) * 0.02)
        trunc_normal_(self.complex_weight, std=.02)
        self.pre_norm = HorLayerNorm(dim, eps=1e-6, data_format='channels_first')
        self.post_norm = HorLayerNorm(dim, eps=1e-6, data_format='channels_first')

    def forward(self, x):
        x = self.pre_norm(x)
        x1, x2 = torch.chunk(x, 2, dim=1)
        x1 = self.dw(x1)

        x2 = x2.to(torch.float32)
        B, C, a, b = x2.shape
        x2 = torch.fft.rfft2(x2, dim=(2, 3), norm='ortho')

        weight = self.complex_weight
        if not weight.shape[1:3] == x2.shape[2:4]:
            weight = F.interpolate(weight.permute(3,0,1,2), size=x2.shape[2:4], mode='bilinear', align_corners=True).permute(1,2,3,0)

        weight = torch.view_as_complex(weight.contiguous())

        x2 = x2 * weight
        x2 = torch.fft.irfft2(x2, s=(a, b), dim=(2, 3), norm='ortho')

        x = torch.cat([x1.unsqueeze(2), x2.unsqueeze(2)], dim=2).reshape(B, 2 * C, a, b)
        x = self.post_norm(x)
        return x

class gnconv(nn.Module):
    def __init__(self, dim, order=5, gflayer=None, h=14, w=8, s=1.0):
        super().__init__()
        self.order = order
        self.dims = [dim // 2 ** i for i in range(order)]
        self.dims.reverse()
        self.proj_in = nn.Conv2d(dim, 2*dim, 1)

        if gflayer is None:
            self.dwconv = get_dwconv(sum(self.dims), 7, True)
        else:
            self.dwconv = gflayer(sum(self.dims), h=h, w=w)
        
        self.proj_out = nn.Conv2d(dim, dim, 1)

        self.pws = nn.ModuleList(
            [nn.Conv2d(self.dims[i], self.dims[i+1], 1) for i in range(order-1)]
        )
        self.scale = s

    def forward(self, x, mask=None, dummy=False):
        # B, C, H, W = x.shape gnconv [512]by iscyy/air
        fused_x = self.proj_in(x)
        pwa, abc = torch.split(fused_x, (self.dims[0], sum(self.dims)), dim=1)
        dw_abc = self.dwconv(abc) * self.scale
        dw_list = torch.split(dw_abc, self.dims, dim=1)
        x = pwa * dw_list[0]
        for i in range(self.order -1):
            x = self.pws[i](x) * dw_list[i+1]
        x = self.proj_out(x)

        return x

def get_dwconv(dim, kernel, bias):
    return nn.Conv2d(dim, dim, kernel_size=kernel, padding=(kernel-1)//2 ,bias=bias, groups=dim)


class HorBlock(nn.Module):
    r""" HorNet block
    """
    def __init__(self, dim, drop_path=0., layer_scale_init_value=1e-6, gnconv=gnconv):
        super().__init__()

        self.norm1 = HorLayerNorm(dim, eps=1e-6, data_format='channels_first')
        self.gnconv = gnconv(dim)
        self.norm2 = HorLayerNorm(dim, eps=1e-6)
        self.pwconv1 = nn.Linear(dim, 4 * dim)
        self.act = nn.GELU()
        self.pwconv2 = nn.Linear(4 * dim, dim)

        self.gamma1 = nn.Parameter(layer_scale_init_value * torch.ones(dim), 
                                    requires_grad=True) if layer_scale_init_value > 0 else None

        self.gamma2 = nn.Parameter(layer_scale_init_value * torch.ones((dim)), 
                                    requires_grad=True) if layer_scale_init_value > 0 else None
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

    def forward(self, x):
        B, C, H, W  = x.shape # [512]
        if self.gamma1 is not None:
            gamma1 = self.gamma1.view(C, 1, 1)
        else:
            gamma1 = 1
        x = x + self.drop_path(gamma1 * self.gnconv(self.norm1(x)))

        input = x
        x = x.permute(0, 2, 3, 1) # (N, C, H, W) -> (N, H, W, C)
        x = self.norm2(x)
        x = self.pwconv1(x)
        x = self.act(x)
        x = self.pwconv2(x)
        if self.gamma2 is not None:
            x = self.gamma2 * x
        x = x.permute(0, 3, 1, 2) # (N, H, W, C) -> (N, C, H, W)

        x = input + self.drop_path(x)
        return x

2.3 YOLO注册

找到 parse_model并注册

def parse_model(d, ch):  # model_dict, input_channels(3)

   elif m in [CARAFE, SPPCSPC, SPPFCSPC, RepConv, BoT3, CA, CBAM, NAMAttention, GAMAttention, Involution, Stem, ResCSPC, ResCSPB, \
                   ResXCSPB, ResXCSPC, BottleneckCSPB, BottleneckCSPC,
                   ASPP, BasicRFB, SPPCSPC_group, HorBlock, CNeB,C3GC ,C3C2, nn.ConvTranspose2d]:

 如何修改hornet进行整体替换或者只修改gnconv 后续会给大家出相关教学.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Flux语言 -- InfluxDB笔记二

1. 基础概念理解 1.1 语序和MySQL不一样,像净水一样通过管道一层层过滤 1.2 不同版本FluxDB的语法也不太一样 2. 基本表达式 import "array" s 10 * 3 // 浮点型只能与浮点型进行运算 s1 9.0 / 3.0 s2 10.0 % 3.0 // 等于 1 s3 10.0 ^ 3.0 // 等于…

pdf怎么转换成jpg图片?

随着数字文档的广泛应用,将PDF转换为JPG图片格式成为了一个常见的需求。无论是为了在网页上展示内容,还是为了与他人分享图片,以下是一些简单的方法,帮助您将PDF文件快速转换为高质量的JPG图片。 方法一:在线PDF转JPG…

《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的

《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的 罗伯特清崎,日裔美国人,投资家、教育家、企业家。 萧明 译 文章目录 《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的[toc]摘录各阶层现金流图支…

大模型 Dalle2 学习三部曲(一)clip学习

clip论文比较长48页,但是clip模型本身又比较简单,效果又奇好,正所谓大道至简,我们来学习一下clip论文中的一些技巧,可以让我们快速加深对clip模型的理解,以及大模型对推荐带来革命性的变化。 clip结构 首选…

线上问诊:数仓开发(一)

系列文章目录 线上问诊:业务数据采集 线上问诊:数仓数据同步 线上问诊:数仓开发(一) 文章目录 系列文章目录前言一、Hive on yarn二、数仓开发1.ODS开发2.DIM开发3.DWD开发 总结 前言 上次我们已经将MYSQL的数据传送到了HDFS,但…

【跟小嘉学 Rust 编程】二十三、Cargo 使用指南

系列文章目录 【跟小嘉学 Rust 编程】一、Rust 编程基础 【跟小嘉学 Rust 编程】二、Rust 包管理工具使用 【跟小嘉学 Rust 编程】三、Rust 的基本程序概念 【跟小嘉学 Rust 编程】四、理解 Rust 的所有权概念 【跟小嘉学 Rust 编程】五、使用结构体关联结构化数据 【跟小嘉学…

四款简洁好看 自适应的APP下载单页源码

分享四款简洁好看 自适应的APP下载单页源码,采用了底部自动获取ICP备案号,还有蓝奏云文件直链解析。不光可以做APP下载引导页,也可以随便改下按钮做网站引导页,自由发挥即可! 蓝奏云直链解析的好处:APP放在…

交换机之间用管理vlan互联,并用ACL进行管控的实例

交换机之间用管理vlan互联,用网管机可以对其进行运维, 拓朴描述: 网关起在S2上,管理vlan999,IP:1.1.1.1/30,lookback 0 地址用2.2.2.2/32当做外网接口IP S1上:管理vlan999&#x…

多线程与高并发——并发编程(3)

文章目录 三、锁1 锁的分类1.1 可重入锁、不可重入锁1.2 乐观锁、悲观锁1.3 公平锁、非公平锁1.4 互斥锁、共享锁2 深入synchronized2.1 类锁、对象锁2.2 synchronized的优化2.3 synchronized实现原理2.4 synchronized的锁升级2.5 重量级锁底层 ObjectMonitor3 深入ReentrantLo…

家政保洁行业小程序如何快速搭建

随着互联网的快速发展,家政保洁行业也逐渐向数字化转型。小程序作为一种轻量级应用,越来越成为各行各业进行线上推广的重要工具。那么,如何快速搭建家政保洁行业的小程序呢?本文将为你提供详细的步骤和指导。 一、准备开发环境 在…

合宙Air724UG LuatOS-Air LVGL API控件--容器 (Container)

容器 (Container) 容器是 lvgl 相当重要的一个控件了,可以设置布局,容器的大小也会自动进行调整,利用容器可以创建出自适应成都很高的界面布局。 代码示例 – 创建容器 cont lvgl.cont_create(lvgl.scr_act(), nil) lvgl.obj_set_auto_re…

第 3 章 栈和队列(用递归函数求解迷宫问题(求出所有解))

1. 背景说明: 若迷宫 maze 中存在从入口 start 到出口 end 的通道,则求出所有合理解并求出最优解 迷宫示意图: 输入文本: 10 10181 3 1 7 2 3 2 7 3 5 3 6 4 2 4 3 4 4 5 4 6 2 6 6 7 2 7 3 7 4 7 6 7 7 8 11 18 8 2. 示例代码…

Ae 效果:CC Threads

生成/CC Threads Generate/CC Threads CC Threads(CC 编织条)效果基于当前图层像素生成编织条图案和纹理。可以用在各种设计中,如背景设计、图形设计、文字设计等。 ◆ ◆ ◆ 效果属性说明 Width 宽度 设置编织的宽度。 默认值为 50。值越大…

【计算机组成 课程笔记】3.1 算数运算和逻辑运算

课程链接: 计算机组成_北京大学_中国大学MOOC(慕课) 3 - 1 - 301-算术运算和逻辑运算(13-7--)_哔哩哔哩_bilibili 计算机的核心功能就是运算,运算的基本类型包括算数运算和逻辑运算。想要了解计算机是如何实现运算的,我…

linux免密登录报错 Bad owner or permissions on /etc/ssh/ssh_config.d/05-redhat.conf

问题:权限不对的 解决: 1.检查文件的所有者和权限。 确保文件的所有者是正确的。 运行以下命令来确定文件的所有者和权限: ls -l /etc/ssh/ssh_config.d/05-redhat.conf 通常情况下,SSH配置文件应该属于root用户。如果所有者不是…

HDLBits 练习 Always if2

Always if2 一个常见的错误:如何避免产生锁存器。 当设计一的电路的时候,你首先应该从电路的角度去思考。 我想要一个逻辑门我想要一个有着3和输入和3输出的组合逻辑电路。我想要一个后边跟着一个触发器的组合逻辑电路。 你必须不能先写代码&#xf…

VC++6.0下载安装使用教程

一、前言 微软原版的 VC6.0 已经不容易找到,网上提供的都是经过第三方修改的版本,删除了一些使用不到的功能,增强了兼容性。这里我们使用 VC6.0 完整绿色版,它能够支持一般的 C/C 应用程序开发以及计算机二级考试。 二、VC6.0 下…

设计模式大白话——适配器模式

适配器模式 概述示例适配器的种类小结 概述 ​ 适配器其实非常好理解,放到生活中来,我们身边处处都有这样的例子,最常见的是用的比较多的各种转接线(如:USB 转 Type-C),有了这个“适配器”&…

基于 kube-vip 部署 kubernetes 高可用集群

kube-vip 简介 kube-vip 是一个开源项目,旨在简化为 Kubernetes 集群提供负载均衡服务。 kube-vip 为 Kubernetes 集群提供虚拟 IP 和负载均衡器,用于控制平面(用于构建高可用集群)和 Kubernetes 服务类型,而无需依赖…

智己 LS6 用实力和你卷,最强 800v ?

2023 成都车展期间,智己 LS6 正式公布预售价格,新车预售价为 23-30 万元。新车会在 10 月份进行上市,11 月正式交付。 此前我们对智己 LS6 做过非常详细的静态体验,感兴趣的可点击此链接了解。 造型方面,新车前脸相比…