yolov5-7.0 添加BiFPN

1. BiFPN特征融合

BiFPN是目标检测中神经网络架构设计的选择之一,为了优化目标检测性能而提出。主要用来进行多尺度特征融合,对神经网络性能进行优化。来自EfficientDet: Scalable and Efficient Object Detection这篇论文。
在这篇论文中,作者主要贡献如下:

  • 首先,提出了一种加权双向特征金字塔网络(BIFPN),该网络可以简单快速的实现多尺度特征融合
  • 其次,提出了一种Compound Scaling方法,该方法可以同时对所有的主干网络、特征网络和框/类预测网络的分辨率、深度和宽度进行统一缩放
    双向特征金字塔网络BIFPN
    在这里插入图片描述
    对于多尺度特征统合,在融合不同的输入特征时,以往的研究(FPN以及一些对FPN的改进工作)大多是没有去别的特征相加;然而由于这些不同的输入特征具有不同的分辨率,因此对特征融合的贡献往往也是不平等的。
    为了解决这个问题,作者提出了一种简单却有效的加权特征金字塔网络BiFPN,引入了可学习的全职来学习不同输入特征的贡献,同时反复应用自顶而下和自下而上的多尺度特征融合。
  • 新的Neck部分—BiFPN:多尺度特征融合的目的,是聚合不同分辨率的特征;以往的特征融合方法对所有输入特征一视同仁,为了解决这个问题,BiFPN引入了加权策略(类似于attention,SENet中的注意力通道)
    FPN:p3-p7是输入图像的下采样,分辨率分别为输入图像的 1 / 2 i 1/2^i 1/2i,最后特征融合的公式为:
    在这里插入图片描述
    其中,Resize的通常操作是upsampling 或者 downsampling
  • 加权:加上一个可学习的权重,也就是 O = ∑ i w i ⋅ I i O=\sum_iw_i\cdot I_i O=iwiIi,其中 w i w_i wi是一个可学习的参数,如果不对 w i w_i wi进行限制,很容易导致训练不稳定,于是作者很自然的想到了对每个权重使用softmax,即 O = ∑ i e i w ϵ + ∑ j w j ⋅ I i O = \sum_i \frac{e^w_i}{\epsilon + \sum_j w_j}\cdot I_i O=iϵ+jwjeiwIi,但是这样速度太慢了,于是又提出了加速限制方法 O = ∑ i w i ϵ + ∑ j w j ⋅ I i O = \sum_i \frac{w_i}{\epsilon + \sum_j w_j}\cdot I_i O=iϵ+jwjwiIi
  • 双向 :最终的特征图结合了双向尺度链接和快速归一化融合。
    具体例子由下图所描述:
    在这里插入图片描述

2. yolov5添加BiFPN(以yolov5s为例)

2.1 修改yolov5s.yaml

BiFPN_Add本质是add操作,不是concat操作,因此,BiFPN_Add的各个输入层要求大小完全一致(通道数、feature map大小等),因此,这里要修改之前的参数[-1, 13, 6],来满足这个要求:

  • -1层就是上一层的输出,原来上一层的输出channel数为256,这里改成512
  • 13层就是这里[-1, 3, C3, [512, False]], # 13
  • 这样修改后,BiFPN_Add各个输入大小都是[bs,256,40,40]
  • 最后BiFPN_Add后面的参数层设置为[256, 256]也就是输入输出channel数都是256
    将concat替换成BIFPN_ADD
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 80  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # 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, 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 BiFPN head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 6], 1, BiFPN_Add2, [256, 256]],  # 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, BiFPN_Add2, [128, 128]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

   [-1, 1, Conv, [512, 3, 2]],  # 为了BiFPN正确add,调整channel数
   [[-1, 13, 6], 1, BiFPN_Add3, [256, 256]],  # cat P4 <--- BiFPN change 注意v5s通道数是默认参数的一半
   [-1, 3, C3, [512, False]],  # 20 (P4/16-medium)

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, BiFPN_Add2, [256, 256]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)

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

** 打印模型参数**
对模型文件进行测试并查看输出结果

          from  n    params  module                                  arguments                     
  0                -1  1      3520  models.common.Conv                      [3, 32, 6, 2, 2]              
  1                -1  1     18560  models.common.Conv                      [32, 64, 3, 2]                
  2                -1  1     18816  models.common.C3                        [64, 64, 1]                   
  3                -1  1     73984  models.common.Conv                      [64, 128, 3, 2]               
  4                -1  2    115712  models.common.C3                        [128, 128, 2]                 
  5                -1  1    295424  models.common.Conv                      [128, 256, 3, 2]              
  6                -1  3    625152  models.common.C3                        [256, 256, 3]                 
  7                -1  1   1180672  models.common.Conv                      [256, 512, 3, 2]              
  8                -1  1   1182720  models.common.C3                        [512, 512, 1]                 
  9                -1  1    656896  models.common.SPPF                      [512, 512, 5]                 
 10                -1  1    131584  models.common.Conv                      [512, 256, 1, 1]              
 11                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']          
 12           [-1, 6]  1     65794  models.common.BiFPN_Add2                [256, 256]                    
 13                -1  1    296448  models.common.C3                        [256, 256, 1, False]          
 14                -1  1     33024  models.common.Conv                      [256, 128, 1, 1]              
 15                -1  1         0  torch.nn.modules.upsampling.Upsample    [None, 2, 'nearest']          
 16           [-1, 4]  1     16514  models.common.BiFPN_Add2                [128, 128]                    
 17                -1  1     74496  models.common.C3                        [128, 128, 1, False]          
 18                -1  1    295424  models.common.Conv                      [128, 256, 3, 2]              
 19       [-1, 13, 6]  1     65795  models.common.BiFPN_Add3                [256, 256]                    
 20                -1  1    296448  models.common.C3                        [256, 256, 1, False]          
 21                -1  1    590336  models.common.Conv                      [256, 256, 3, 2]              
 22          [-1, 10]  1     65794  models.common.BiFPN_Add2                [256, 256]                    
 23                -1  1   1051648  models.common.C3                        [256, 512, 1, False]          
 24      [17, 20, 23]  1    229245  models.yolo.Detect                      [80, [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], [128, 256, 512]]
Model Summary: 278 layers, 7384006 parameters, 7384006 gradients, 17.2 GFLOPs

2.2 修改commen.py

添加下面的代码:

# 结合BiFPN 设置可学习参数 学习不同分支的权重
# 两个分支add操作
class BiFPN_Add2(nn.Module):
    def __init__(self, c1, c2):
        super(BiFPN_Add2, self).__init__()
        # 设置可学习参数 nn.Parameter的作用是:将一个不可训练的类型Tensor转换成可以训练的类型parameter
        # 并且会向宿主模型注册该参数 成为其一部分 即model.parameters()会包含这个parameter
        # 从而在参数优化的时候可以自动一起优化
        self.w = nn.Parameter(torch.ones(2, dtype=torch.float32), requires_grad=True)
        self.epsilon = 0.0001
        self.conv = nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0)
        self.silu = nn.SiLU()

    def forward(self, x):
        w = self.w
        weight = w / (torch.sum(w, dim=0) + self.epsilon)
        return self.conv(self.silu(weight[0] * x[0] + weight[1] * x[1]))


# 三个分支add操作
class BiFPN_Add3(nn.Module):
    def __init__(self, c1, c2):
        super(BiFPN_Add3, self).__init__()
        self.w = nn.Parameter(torch.ones(3, dtype=torch.float32), requires_grad=True)
        self.epsilon = 0.0001
        self.conv = nn.Conv2d(c1, c2, kernel_size=1, stride=1, padding=0)
        self.silu = nn.SiLU()

    def forward(self, x):
        w = self.w
        weight = w / (torch.sum(w, dim=0) + self.epsilon)  # 将权重进行归一化
        # Fast normalized fusion
        return self.conv(self.silu(weight[0] * x[0] + weight[1] * x[1] + weight[2] * x[2]))

2.3 修改yolo.py

parse_model函数中找到elif m is Concat:语句,在其后面加上BiFPN_Add相关语句:

elif m is Concat:
    c2 = sum(ch[x] for x in f)
# 添加bifpn_add结构
elif m in [BiFPN_Add2, BiFPN_Add3]:
    c2 = max([ch[x] for x in f])

2.4 optimizer的修改

之前的版本需要修改train.py,向优化器中添加BIFPN的权重参数,将BiFPN_Add2和BiFPN_Add3函数中定义的w参数,加入g1

    g0, g1, g2 = [], [], []  # optimizer parameter groups
    for v in model.modules():
        # hasattr: 测试指定的对象是否具有给定的属性,返回一个布尔值
        if hasattr(v, 'bias') and isinstance(v.bias, nn.Parameter):  # bias
            g2.append(v.bias)  # biases
        if isinstance(v, nn.BatchNorm2d):  # weight (no decay)
            g0.append(v.weight)
        elif hasattr(v, 'weight') and isinstance(v.weight, nn.Parameter):  # weight (with decay)
            g1.append(v.weight)
        # BiFPN_Concat
        elif isinstance(v, BiFPN_Concat2) and hasattr(v, 'w') and isinstance(v.w, nn.Parameter):
            g1.append(v.w)
        elif isinstance(v, BiFPN_Concat3) and hasattr(v, 'w') and isinstance(v.w, nn.Parameter):
            g1.append(v.w)

按照之前的版本是可以直接在train.py进行修改的,但是在yolov5-v7.0版本中,这个部分优化成智能的optimizer。
yolov5-v7.0中,大概在150行左右加入了智能的optimizer。
在这里插入图片描述

optimizer = smart_optimizer(model, opt.optimizer, hyp['lr0'], hyp['momentum'], hyp['weight_decay'])

接着进入这个函数,可以发现optimizer这个函数进行重构,之前的一重for循环优化成两重for

def smart_optimizer(model, name='Adam', lr=0.001, momentum=0.9, decay=1e-5):
    # YOLOv5 3-param group optimizer: 0) weights with decay, 1) weights no decay, 2) biases no decay
    g = [], [], []  # optimizer parameter groups
    bn = tuple(v for k, v in nn.__dict__.items() if 'Norm' in k)  # normalization layers, i.e. BatchNorm2d()
    for v in model.modules():
        for p_name, p in v.named_parameters(recurse=0):
            if p_name == 'bias':  # bias (no decay)
                g[2].append(p)
            elif p_name == 'weight' and isinstance(v, bn):  # weight (no decay)
                g[1].append(p)
            else:
                g[0].append(p)  # weight (with decay)


    if name == 'Adam':
        optimizer = torch.optim.Adam(g[2], lr=lr, betas=(momentum, 0.999))  # adjust beta1 to momentum
    elif name == 'AdamW':
        optimizer = torch.optim.AdamW(g[2], lr=lr, betas=(momentum, 0.999), weight_decay=0.0)
    elif name == 'RMSProp':
        optimizer = torch.optim.RMSprop(g[2], lr=lr, momentum=momentum)
    elif name == 'SGD':
        optimizer = torch.optim.SGD(g[2], lr=lr, momentum=momentum, nesterov=True)
    else:
        raise NotImplementedError(f'Optimizer {name} not implemented.')

    optimizer.add_param_group({'params': g[0], 'weight_decay': decay})  # add g0 with weight_decay
    optimizer.add_param_group({'params': g[1], 'weight_decay': 0.0})  # add g1 (BatchNorm2d weights)
    LOGGER.info(f"{colorstr('optimizer:')} {type(optimizer).__name__}(lr={lr}) with parameter groups "
                f'{len(g[1])} weight(decay=0.0), {len(g[0])} weight(decay={decay}), {len(g[2])} bias')
    return optimizer

与以前的代码相比,相似度很高,虽然g0, g1, g2 = [], [], []被 g = [], [], []所替代,但这些就是我们需要关注的地方。

  • 新版将这个地方关于weight的顺序翻转了一下,这样只要不是bias或者weight no decay,那么就全都归结于weight with decay上.
  • 与之前需要elif 进行判断Bi_FPN进行模型的添加相比,这里不在需要添加判断条件了,因为最后的else会把 剩余非bias 和非weight nodecay 部分全部加到weight with decay上。
  • 也就是说,添加其他Neck时,不需要额外对optimizer进行添加elif判断,也就实现了一个所谓智能的优化。
    所以新版本对于参数g的修改,结论就是不修改,直接略过即可,智能优化器会对多余的部分进行自动增加权重

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

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

相关文章

Linux的学习

学习笔记&#xff0c;只写重点&#xff0c;不连贯&#xff0c;写得很水。 视频from:2021韩顺平 一周学会Linux。学习地址&#xff1a;https://www.bilibili.com/video/BV1Sv411r7vd 老师说明&#xff1a;后面我们的Redis、ginx包括项目都会使用到Linux,也是和我讲解的Linux版本…

Seata AT模式源码解析二(Seata Client端启动流程)

文章目录 初始化TM和RM数据源代理 由于我们一般都是在springboot中使用的&#xff0c;而与springboot集成的我们一般就先看starter的spring.factories文件&#xff0c;看看它的自动装配 这里面主要关注SeataAutoConfiguration和SeataDataSourceAutoConfiguration。 SeataAutoCo…

破解极域(4):万能密码法(可以获取到原密码)

破解极域&#xff08;4&#xff09;&#xff1a;万能密码法 1.思路2.实现2.1 获得密码2.2 解除控制2.3 特别注意 3.视频展示 今天来分享下破解极域的第4种方法——万能密码法 1.思路 首先&#xff0c;我们要知道的是&#xff0c;极域这个东西它有一个万能密码&#xff0c;万能…

如何检查Linux硬盘大小、类型和硬件详细信息?

在Linux系统中&#xff0c;了解硬盘的大小、类型和硬件详细信息对于系统管理和故障排除非常重要。本文将详细介绍如何使用命令行工具来检查Linux硬盘的大小、类型和硬件详细信息。 1. 检查硬盘大小 要检查Linux硬盘的大小&#xff0c;可以使用lsblk命令。该命令显示了系统中所…

我用AI帮我唱了首“基尼太美”,颠覆了我的认知!太牛逼了

目录 前言 AI唱"基尼太美"是什么感觉 使用so-vits-svc打造自己专属歌手 1.声音素材整理 2.训练模型 3.让AI唱歌​编辑 AI歌手背后的技术 AI歌手会成为主流吗 写到最后 大家好&#xff0c;我是大侠&#xff0c;AI领域的专业博主 前言 在5月份&#xff0c;孙…

vue2_模版语法

目录 模版语法 react用jsx语法编译后的null作用 插值表达式{{}} v-bind和{{}} 关于国内谷歌自带翻译停用如何解决&#xff08;额外&#xff09; 会一点的插值表达式&#xff0c;也有限制 模版语法 更接近原生js的写法jsx语法 jsx是react提出的&#xff1b;后很多前端框架…

说说你对slot的理解?slot使用场景有哪些?

vue的slot的理解&#xff1f;slot使用场景有哪些&#xff1f; 定义 在Vue.js中&#xff0c;slot&#xff08;插槽&#xff09;是一种用于组件之间内容分发的机制。它允许你在父组件中编写子组件的内容&#xff0c;从而增加了组件的灵活性和可重用性。 Slot 艺名插槽&#xf…

汇编寄存器之内存访问

1.内存中字的存储: 在CPU中用一个16位寄存器来存储一个字, 高8位存高字节,低8位存低字节 如AX寄存器存在一个字,那么AH存高字节,AL存低字节 在内存中存储字时是用两个连续的字节来存储字的, 这个字的低字节存在低单元,高字节存在高单元. 如下表示: 内存单元编号 单元中…

【微博-计算Cell子控件的frame Objective-C语言】

一、计算Cell子控件的frame 1.来,看一下,刚才我们已经做到把这个模型设置给自定义的cell了吧, 那么,在这个自定义Cell里面呢,我们是不是要开始设置数据了, 设置数据,我们,设置数据,其实很简单,就是把我们这里边的每一个控件,对应的值,从模型里面取出来,给了它,…

【独立版】智慧城市同城V4_2.2.7全开源全插件VUE版,修复房产信息组件商户发布二手房房源信息未和商户关联的问题

源码介绍 【独立版】智慧城市同城V4 查看更多关于 智慧城市同城V4 的文章 _2.2.7全开源全插件VUE版&#xff0c;修复房产信息组件商户发布二手房房源信息未和商户关联的问题&#xff01; 智慧城市同城是一套专注于多城市生活服务同城技术解决方案,全面覆盖同堿信息、商家联盟、…

【Linux】搭建SFTP文件服务器

一、协议介绍1.1 FTP 协议1.11 特点1.12 基本工作原理 1.2 SFTP协议1.21 特点1.22 基本工作原理 1.3 ssh协议1.31 特点1.32 基本工作原理 1.4 其他常见文件传输协议 二、搭建Linux的SFTP文件服务器三、连接测试3.1 电脑连接3.2 手机连接 一、协议介绍 1.1 FTP 协议 1.11 特点…

AI落地:高效学习指南

高效学习中有一个共识&#xff1a;学习最小可用知识&#xff0c;然后立马开始实践&#xff0c;做中学&#xff0c;不断获得反馈&#xff0c;不断在实践中改进。 现实生活中&#xff0c;如果我们想实现这种高效学习&#xff0c;基本上只能找一个老师1对1指导&#xff0c;费用贵…

【开发者指南】如何在MyEclipse中使用 XML编辑器

XML编辑器包括高级XML编辑功能。通过本文&#xff0c;你将了解其编辑功能和网页XML编辑&#xff0c;一起来看看吧~ 1. Web XML编辑器 MyEclipse Web XML编辑器包括高级XML编辑功能&#xff0c;如: 语法高亮显示标签和属性内容辅助实时验证(在您输入时)文档内容的源视图、设计…

160743-62-4,DMG PEG2000,1,2-二肉豆蔻酰-rac-甘油-3-甲氧基聚乙二醇2000

DMG PEG2000&#xff0c;DMG-mPEG2000&#xff0c;1,2-二肉豆蔻酰-rac-甘油-3-甲氧基聚乙二醇2000 Product structure&#xff1a; Product specifications&#xff1a; 1.CAS No&#xff1a;160743-62-4 2.Molecular formula&#xff1a; C34H66O 3.Molecular weight&#xff…

Java内部类(成员内部类、静态嵌套类、方法内部类、匿名内部类)

文章目录 一、内部类的共性二、为什么需要内部类三、静态内部类&#xff08;静态嵌套类&#xff09;四、成员内部类五、局部内部类&#xff08;方法内部类&#xff09;六、匿名内部类 Java 类中不仅可以定义变量和方法&#xff0c;还可以定义类&#xff0c;这样定义在类内部的类…

挂耳式耳机品牌排行榜,看看谁被推荐上榜

下班路上就想放空自己刷会儿视频&#xff0c;但是马路、地铁还有公交上都会有嘈杂的声音影响&#xff0c;如果佩戴入耳式耳机放大声音不仅会过度屏蔽外界&#xff0c;同时还会损伤我们的耳朵&#xff0c;所以新近流行的开放式耳机很好的解决了这些问题&#xff0c;但也有很多小…

【Linux】深入了解冯诺依曼体系结构与操作系统

目录 导读 &#x1f31e;专栏导读 &#x1f31e;冯诺依曼 &#x1f31e;冯诺依曼体系结构 &#x1f31b;木桶效应 &#x1f31e;操作系统(Operator System) &#x1f31b;概念 &#x1f31b;设计OS的目的 &#x1f31b;系统调用和库函数概念 导读 六一儿童节快到了&…

杜绝开源依赖风险,许可证扫描让高效合规「两不误」

目录 开源许可证及其常见类型 开源许可证扫描是软件研发过程中&#xff0c;不可或缺的工具 极狐GitLab 开源许可证扫描的优势与应用 Step 1&#xff1a;启用及设置许可证策略 Step 2&#xff1a;自动创建策略文件存放项目 Step 3&#xff1a;查看许可证合规情况 Step 4&…

实训可视化项目小结 --- 开启Python初始之旅

Python初试感悟 语言之间是相通的&#xff0c;大多数时候&#xff0c;百分之八十的问题&#xff0c;都可以用常用的容器以及内置函数来辅助解决。之前从未认真接触过Python&#xff0c;但此次学校实训要求使用Python做一个可视化&#xff0c;东西不难&#xff0c;我个人负责爬…

Hadoop学习---8、Hadoop数据压缩

1、Hadoop数据压缩 1.1 概述 1、压缩的好处和坏处 &#xff08;1&#xff09;优点&#xff1a;减少磁盘IO、减少磁盘储存空间 &#xff08;2&#xff09;缺点&#xff1a;增加CPU开销 2、压缩原则 &#xff08;1&#xff09;运算密集型的Job&#xff0c;少用压缩 &#xff08…