YOLOv8改进 | 细节创新篇 | iAFF迭代注意力特征融合助力多目标细节涨点

news2024/12/26 21:21:33

一、本文介绍

本文给大家带来的改进机制是iAFF(迭代注意力特征融合),其主要思想是通过改善特征融合过程来提高检测精度。传统的特征融合方法如加法或串联简单,未考虑到特定对象的融合适用性。iAFF通过引入多尺度通道注意力模块(我个人觉得这个改进机制就算融合了注意力机制的求和操作),更好地整合不同尺度和语义不一致的特征。该方法属于细节上的改进,并不影响任何其它的模块,非常适合大家进行融合改进,单独使用也是有一定的涨点效果。

推荐指数:⭐⭐⭐⭐

涨点效果:⭐⭐⭐⭐

专栏目录:YOLOv8改进有效系列目录 | 包含卷积、主干、检测头、注意力机制、Neck上百种创新机制

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备    

训练结果对比图-> 

目录

一、本文介绍

二、iAFF的基本框架原理

三、iAFF的核心代码

四、手把手教你添加iAFF

4.1 iAFF添加步骤

4.1.1 步骤一

4.1.2 步骤二

4.1.3 步骤三

五、C2f_iAFF的yaml文件和运行记录

5.1 C2f_iAFF的yaml文件

5.2 C2f_iAFF的训练过程截图 

六、本文总结


二、iAFF的基本框架原理

官方论文地址: 官方论文地址点击即可跳转

官方代码地址: 官方代码地址点击即可跳转


iAFF的主要思想在于通过更精细的注意力机制来改善特征融合,从而增强卷积神经网络。它不仅处理了由于尺度和语义不一致而引起的特征融合问题,还引入了多尺度通道注意力模块,提供了一种统一且通用的特征融合方案。此外,iAFF通过迭代注意力特征融合来解决特征图初始整合可能成为的瓶颈。这种方法使得模型即使在层数或参数较少的情况下,也能取得到较好的效果。 

iAFF的创新点主要包括:

1. 注意力特征融合:提出了一种新的特征融合方式,利用注意力机制来改善传统的简单特征融合方法(如加和或串联)。

2. 多尺度通道注意力模块:解决了在不同尺度上融合特征时出现的问题,特别是语义和尺度不一致的特征融合问题。

3. 迭代注意力特征融合(iAFF):通过迭代地应用注意力机制来改善特征图的初步整合,克服了初步整合可能成为性能瓶颈的问题。

​ 

这张图片是关于所提出的AFF(注意力特征融合)和iAFF(迭代注意力特征融合)的示意图。图中展示了两种结构:

(a) AFF: 展示了一个通过多尺度通道注意力模块(MS-CAM)来融合不同特征的基本框架。特征图X和Y通过MS-CAM和其他操作融合,产生输出Z。

(b) iAFF: 与AFF类似,但添加了迭代结构。在这里,输出Z回馈到输入,与X和Y一起再次经过MS-CAM和融合操作,以进一步细化特征融合过程。

(这两种方法都是文章中提出的我仅使用了iAFF也就是更复杂的版本,大家对于AFF有兴趣的可以按照我的该法进行相似添加即可)


三、iAFF的核心代码

该代码的使用方式需要两个图片,有人去用其替换Concat操作,但是它的两个输入必须是相同shape,但是YOLOv8中我们Concat一般两个输入在图像宽高上都不一样,所以我用其替换Bottlenekc中的残差相加操作,算是一种比较细节上的创新。

import torch
import torch.nn as nn

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 iAFF(nn.Module):
    '''
    多特征融合 iAFF
    '''

    def __init__(self, channels=64, r=2):
        super(iAFF, self).__init__()
        inter_channels = int(channels // r)

        # 本地注意力
        self.local_att = nn.Sequential(
            nn.Conv2d(channels, inter_channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(inter_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(inter_channels, channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(channels),
        )

        # 全局注意力
        self.global_att = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(channels, inter_channels, kernel_size=1, stride=1, padding=0),
            nn.ReLU(inplace=True),
            nn.Conv2d(inter_channels, channels, kernel_size=1, stride=1, padding=0),
        )

        # 第二次本地注意力
        self.local_att2 = nn.Sequential(
            nn.Conv2d(channels, inter_channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(inter_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(inter_channels, channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(channels),
        )
        # 第二次全局注意力
        self.global_att2 = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(channels, inter_channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(inter_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(inter_channels, channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(channels),
        )

        self.sigmoid = nn.Sigmoid()

    def forward(self, x, residual):

        xa = x + residual
        xl = self.local_att(xa)
        xg = self.global_att(xa)
        xlg = xl + xg
        wei = self.sigmoid(xlg)
        xi = x * wei + residual * (1 - wei)

        xl2 = self.local_att2(xi)
        xg2 = self.global_att(xi)
        xlg2 = xl2 + xg2
        wei2 = self.sigmoid(xlg2)
        xo = x * wei2 + residual * (1 - wei2)
        return xo


class AFF(nn.Module):
    '''
    多特征融合 AFF
    '''

    def __init__(self, channels=64, r=4):
        super(AFF, self).__init__()
        inter_channels = int(channels // r)

        self.local_att = nn.Sequential(
            nn.Conv2d(channels, inter_channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(inter_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(inter_channels, channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(channels),
        )

        self.global_att = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(channels, inter_channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(inter_channels),
            nn.ReLU(inplace=True),
            nn.Conv2d(inter_channels, channels, kernel_size=1, stride=1, padding=0),
            nn.BatchNorm2d(channels),
        )

        self.sigmoid = nn.Sigmoid()

    def forward(self, x, residual):
        xa = x + residual
        xl = self.local_att(xa)
        xg = self.global_att(xa)
        xlg = xl + xg
        wei = self.sigmoid(xlg)

        xo = 2 * x * wei + 2 * residual * (1 - wei)
        return xo



class C2f_iAFF(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), (3, 3)), e=1.0) for _ in range(n))

    def forward(self, x):
        """Forward pass through C2f layer."""
        y = list(self.cv1(x).chunk(2, 1))
        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))

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 = Conv(c_, c2, k[1], 1, g=g)
        self.add = shortcut and c1 == c2
        self.iAFF = iAFF(c2)
    def forward(self, x):
        """'forward()' applies the YOLO FPN to input data."""
        if self.add:
           results =  self.iAFF(x , self.cv2(self.cv1(x)))
        else:
            results = self.cv2(self.cv1(x))
        return results


if __name__ == '__main__':
    x = torch.ones(8, 64, 32, 32)
    channels = x.shape[1]
    model = C2f_iAFF(channels, channels, True)
    output = model(x)
    print(output.shape)


四、手把手教你添加iAFF

4.1 iAFF添加步骤

4.1.1 步骤一

首先我们找到如下的目录'ultralytics/nn/modules',然后在这个目录下创建一个py文件,名字可以根据你自己的习惯起,然后将iAFF的核心代码复制进去。

4.1.2 步骤二

之后我们找到'ultralytics/nn/tasks.py'文件,在其中注册我们的iAFF模块。

首先我们需要在文件的开头导入我们的iAFF模块,如下图所示->

4.1.3 步骤三

我们找到parse_model这个方法,可以用搜索也可以自己手动找,大概在六百多行吧。 我们找到如下的地方,然后将C2f_iAFF添加进去即可,模仿我添加即可。

到此我们就注册成功了,可以修改yaml文件中输入C2f_iAFF使用这个模块了。


五、C2f_iAFF的yaml文件和运行记录

5.1 C2f_iAFF的yaml文件

下面的添加C2f_iAFF是我实验结果的版本。

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect

# 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]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPs
  s: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOP

# 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_iAFF, [128, True]]
  - [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8
  - [-1, 6, C2f_iAFF, [256, True]]
  - [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16
  - [-1, 6, C2f_iAFF, [512, True]]
  - [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32
  - [-1, 3, C2f_iAFF, [1024, True]]
  - [-1, 1, SPPF, [1024, 5]]  # 9

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

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


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


  - [-1, 1, Conv, [512, 3, 2]]
  - [[-1, 9], 1, Concat, [1]]  # cat head P5
  - [-1, 3, C2f, [1024]]  # 21 (P5/32-large)


  - [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)

5.2 C2f_iAFF的训练过程截图 

下面是添加了C2f_iAFF的训练截图。

大家可以看下面的运行结果和添加的位置所以不存在我发的代码不全或者运行不了的问题大家有问题也可以在评论区评论我看到都会为大家解答(我知道的)。


六、本文总结

到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv8改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

专栏回顾:YOLOv8改进系列专栏——本专栏持续复习各种顶会内容——科研必备

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

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

相关文章

花几分钟整点jmeter花活,轻松超越90%软件测试

jmeter 可以做性能测试,这个很多人都知道,那你知道,jmeter 可以在启动运行时,指定线程数和运行时间,自定义性能场景吗? 前言 jmeter 性能测试,动态设定性能场景 平时,我们使用 jmet…

使用.Net nanoFramework 驱动ESP32的OLED显示屏

本文介绍如何使用.Net nanoFramework 驱动ESP32的OLED显示屏。我们将会从最基础的部分开始,逐步深入,让你能够理解并实现整个过程。无论你是初学者还是有一定经验的开发者,这篇文章都会对你有所帮助。 1. 硬件准备 1.1 ESP32开发板 这里我们…

安装中望CAD2023 SP2

1.下载中望CAD2023 SP2,并安装; 2.把“flxNetCommon.dll”拷贝到安装目录(与“ZWCAD.exe”同一个目录); 3.运行“ZwLicenseManager.exe” 4.点击“激活许可证”; 5.点击“浮动许可” ->“仅配置不查询…

Hotspot源码解析-第十一章

第十一章 11.1 线程 11.1.1 线程的概念 说起线程,首先得提起进程,相信很面试者在回答进程与线程的区别时都会用一句话:“进程是操作系统资源分配的基本单位,而线程是任务调度和执行的基本单位”,只能说这句话部分正…

十大排序总结之——冒泡排序、插入排序

同样,这两几乎也是被淘汰了的算法,尽管它们是稳定的,但是时间复杂度没人喜欢,了解一下就好,没啥好说的,注意最后一句话就行了 一,冒泡排序 1. 算法步骤 共n-1趟,谁两敢冒泡就换了…

SpringBoot多环境配置,让你部署无忧

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:SpringBoot多环境配置,让你部署无忧 📚个人知识库: Leo知识库,欢迎大家访…

vite项目中动态引入src失败的问题解决:require is not defined

问题复现 静态引入路径(无问题) <el-menu-item v-for"(item,index) in menuList" :index"item.name" :key"index"><img class"menuItemImg" src"../svg/router/homePage.svg" alt"">{{ item.meta.c…

vue中使用echarts实现省市地图绘制,根据数据显示省市天气图标及温度信息

一、实现效果 使用echarts实现省市地图绘制根据数据显示省下市的天气图标根据数据显示省下市的温度信息 二、实现方法 1、安装echarts插件 npm install echarts --save2、获取省市json数据 https://datav.aliyun.com/portal/school/atlas/area_selector 通过 阿里旗下的高…

hubSpot有哪些功能?

HubSpot是一款综合性的市场营销、销售和服务软件平台&#xff0c;旨在帮助企业实现更有效的客户关系管理和增长。以下是HubSpot的一些主要功能&#xff1a; 市场营销自动化&#xff1a; 制定和执行多渠道的市场营销活动。 创建和管理电子邮件营销、社交媒体发布和广告活动。 …

WMS仓储管理系统可以处理哪些仓库异常情况

随着现代物流行业的快速发展&#xff0c;仓库管理作为其中的核心环节&#xff0c;面临着越来越大的挑战。传统的仓库管理方式已经难以满足日益复杂的需求&#xff0c;因此&#xff0c;WMS仓储管理系统解决方案应运而生。WMS仓储管理系统不仅简化了仓库的日常操作&#xff0c;更…

Redis:原理+项目实战——Redis实战1(session实现短信登录(并剖析问题))

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis的Java客户端 &#x1f4da;订阅专栏&#xff1a;Redis速成 希望文章对你们有所帮助…

拓扑排序【邻接矩阵邻接表】

拓扑排序 TuoPuSort 一、概念 我们再说拓扑排序时,我们首先了解下​DAG​ 将有向无环图G(V,E)中的所有顶点排成一个线性序列,使图中任意一对顶点u,v,之间不存在环路 DAG是一种特殊的有向图&#xff0c;它由一组顶点和一组有向边组成&#xff0c;且不存在任何环路。 每个顶点表…

华脉智联融合通讯基础引擎平台V2.0发布

华脉智联始于2012年&#xff0c;成立于2017年。历经11年在融合通讯、指挥调度领域的持续研发&#xff0c;于2024年发布华脉智联融合通讯基础引擎平台V2.0。 系统组成 1 核心平台 2 WEB调度台 3 PC调度台 4 云集群APP 5 云执法APP 系统特点 1 多网融合 可以支持多种网络接入和融…

【电商项目实战】购物车完善

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《电商项目实战》。&#x1f3af;&#x1f3af; &am…

windows11此应用无法在你的电脑上运行怎么解决

在使用电脑运行软件的时候&#xff0c;系统弹出了“此应用无法在你的电脑上运行”提示&#xff0c;导致没办法正常使用该软件&#xff0c;不知道怎么回事&#xff0c;针对这一问题&#xff0c; 方法一&#xff1a; 1、如果是win11里的软件&#xff0c;可以右键该软件&#xff0…

电子电器架构(E/E)演化 —— 车载以太网

电子电器架构&#xff08;E/E&#xff09;演化 —— 车载以太网 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 本文13000字。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一…

2024年01月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2024年01月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…

Linux——进程初识(二)

1. 对当前目录创建文件的理解 我们知道在创建一个文件时&#xff0c;它会被默认创建到当前目录下&#xff0c;那么它是如何知道当前目录的呢&#xff1f; 对于下面这样一段代码 #include <stdio.h> #include <unistd.h>int main() {fopen("tmp.txt", …

polar CTF WEB-veryphp

1、题目 <?php error_reporting(0); highlight_file(__FILE__); include("config.php"); class qwq {function __wakeup(){die("Access Denied!");}static function oao(){show_source("config.php");} } $str file_get_contents("ph…

图神经网络——图学习

图学习 0. 前言1. 图2. 图学习3. 图神经网络小结 0. 前言 近年来&#xff0c;从社交网络到分子生物学等各个领域&#xff0c;数据的图表示越来越普遍。图神经网络 (Graph Neural Network, GNN) 是专为处理图结构数据而设计的&#xff0c;要充分挖掘图表示的潜力&#xff0c;深…