大核注意力机制

news/2024/12/26 20:44:22/文章来源:https://www.cnblogs.com/louaq/p/18449903

一、本文介绍

在这篇文章中,我们将讲解如何将LSKAttention大核注意力机制应用于YOLOv8,以实现显著的性能提升。首先,我们介绍LSKAttention机制的基本原理,它主要通过将深度卷积层的2D卷积核分解为水平和垂直1D卷积核,减少了计算复杂性和内存占用。接着,我们介绍将这一机制整合到YOLOv8的方法,以及它如何帮助提高处理大型数据集和复杂视觉任务的效率和准确性。本文还将提供代码实现细节和使用方法,展示这种改进对目标检测、语义分割等方面的积极影响。通过实验YOLOv8在整合LSKAttention机制后,实现了检测精度提升。

二、LSKAttention的机制原理

论文地址:官方论文地址

代码地址:官方代码地址


《Large Separable Kernel Attention》这篇论文提出的LSKAttention的机制原理是针对传统大核注意力(Large Kernel Attention,LKA)模块在视觉注意网络(Visual Attention Networks,VAN)中的应用问题进行的改进。LKA模块在处理大尺寸卷积核时面临着高计算和内存需求的挑战。LSKAttention通过以下几个关键步骤和原理来解决这些问题:

  1. 核分解:LSKAttention的核心创新是将传统的2D卷积核分解为两个1D卷积核。首先,它将一个大的2D核分解成水平(横向)和垂直(纵向)的两个1D核。这样的分解大幅降低了参数数量和计算复杂度。

  2. 串联卷积操作:在进行卷积操作时,LSKAttention首先使用一个1D核对输入进行水平方向上的卷积,然后使用另一个1D核进行垂直方向上的卷积。这两步卷积操作串联执行,从而实现了与原始大尺寸2D核相似的效果。

  3. 计算效率提升:由于分解后的1D卷积核大大减少了参数的数量,LSKAttention在执行时的计算效率得到显著提升。这种方法特别适用于处理大尺寸的卷积核,能够有效降低内存占用和计算成本。

  4. 保持效果:虽然采用了分解和串联的策略,LSKAttention仍然能够保持类似于原始LKA的性能。这意味着在处理图像的关键特征(如边缘、纹理和形状)时,LSKAttention能够有效地捕捉到重要信息。

  5. 适用于多种任务:LSKAttention不仅在图像分类任务中表现出色,还能够在目标检测、语义分割等多种计算机视觉任务中有效应用,显示出其广泛的适用性。

总结:LSKAttention通过创新的核分解和串联卷积策略,在降低计算和内存成本的同时,保持了高效的图像处理能力,这在处理大尺寸核和复杂图像数据时特别有价值。

上图展示了在不同大核分解方法和核大小下的速度-精度权衡。在这个比较中,使用了不同的标记来代表不同的核大小,并且以VAN-Tiny作为对比的模型。从图中可以看出,LKA的朴素设计(LKA-trivial)以及在VAN中的实际设计,在核大小增加时会导致更高的GFLOPs(十亿浮点运算次数)。相比之下,论文提出的LSKA(Large Separable Kernel Attention)-trivial和VAN中的LSKA在核大小增加时显著降低了GFLOPs,同时没有降低性能

上图展示了大核注意力模块不同设计的比较,具体包括:

  1. LKA-trivial:朴素的2D大核深度卷积(DW-Conv)与1×1卷积结合(图a)。
  2. LSKA-trivial:串联的水平和垂直1D大核深度卷积与1×1卷积结合(图b)。
  3. 原始LKA设计:在VAN中包括标准深度卷积(DW-Conv)、扩张深度卷积(DW-D-Conv)和1×1卷积(图c)。
  4. 提出的LSKA设计:将LKA的前两层分解为四层,每层由两个1D卷积层组成(图d)。其中,N代表Hadamard乘积,k代表最大感受野,d代表扩张率​​。

个人总结:提出了一种创新的大型可分离核注意力(LSKA)模块,用于改进卷积神经网络(CNN)。这种模块通过将2D卷积核分解为串联的1D核,有效降低了计算复杂度和内存需求。LSKA模块在保持与标准大核注意力(LKA)模块相当的性能的同时,显示出更高的计算效率和更小的内存占用。

三、LSKAttention的代码

将下面的代码在"ultralytics/nn/modules" 目录下创建一个py文件复制粘贴进去然后按照章节四进行添加即可(需要按照有参数的注意力机制添加)

import torch
import torch.nn as nnclass LSKA(nn.Module):def __init__(self, dim, k_size):super().__init__()self.k_size = k_sizeif k_size == 7:self.conv0h = nn.Conv2d(dim, dim, kernel_size=(1, 3), stride=(1,1), padding=(0,(3-1)//2), groups=dim)self.conv0v = nn.Conv2d(dim, dim, kernel_size=(3, 1), stride=(1,1), padding=((3-1)//2,0), groups=dim)self.conv_spatial_h = nn.Conv2d(dim, dim, kernel_size=(1, 3), stride=(1,1), padding=(0,2), groups=dim, dilation=2)self.conv_spatial_v = nn.Conv2d(dim, dim, kernel_size=(3, 1), stride=(1,1), padding=(2,0), groups=dim, dilation=2)elif k_size == 11:self.conv0h = nn.Conv2d(dim, dim, kernel_size=(1, 3), stride=(1,1), padding=(0,(3-1)//2), groups=dim)self.conv0v = nn.Conv2d(dim, dim, kernel_size=(3, 1), stride=(1,1), padding=((3-1)//2,0), groups=dim)self.conv_spatial_h = nn.Conv2d(dim, dim, kernel_size=(1, 5), stride=(1,1), padding=(0,4), groups=dim, dilation=2)self.conv_spatial_v = nn.Conv2d(dim, dim, kernel_size=(5, 1), stride=(1,1), padding=(4,0), groups=dim, dilation=2)elif k_size == 23:self.conv0h = nn.Conv2d(dim, dim, kernel_size=(1, 5), stride=(1,1), padding=(0,(5-1)//2), groups=dim)self.conv0v = nn.Conv2d(dim, dim, kernel_size=(5, 1), stride=(1,1), padding=((5-1)//2,0), groups=dim)self.conv_spatial_h = nn.Conv2d(dim, dim, kernel_size=(1, 7), stride=(1,1), padding=(0,9), groups=dim, dilation=3)self.conv_spatial_v = nn.Conv2d(dim, dim, kernel_size=(7, 1), stride=(1,1), padding=(9,0), groups=dim, dilation=3)elif k_size == 35:self.conv0h = nn.Conv2d(dim, dim, kernel_size=(1, 5), stride=(1,1), padding=(0,(5-1)//2), groups=dim)self.conv0v = nn.Conv2d(dim, dim, kernel_size=(5, 1), stride=(1,1), padding=((5-1)//2,0), groups=dim)self.conv_spatial_h = nn.Conv2d(dim, dim, kernel_size=(1, 11), stride=(1,1), padding=(0,15), groups=dim, dilation=3)self.conv_spatial_v = nn.Conv2d(dim, dim, kernel_size=(11, 1), stride=(1,1), padding=(15,0), groups=dim, dilation=3)elif k_size == 41:self.conv0h = nn.Conv2d(dim, dim, kernel_size=(1, 5), stride=(1,1), padding=(0,(5-1)//2), groups=dim)self.conv0v = nn.Conv2d(dim, dim, kernel_size=(5, 1), stride=(1,1), padding=((5-1)//2,0), groups=dim)self.conv_spatial_h = nn.Conv2d(dim, dim, kernel_size=(1, 13), stride=(1,1), padding=(0,18), groups=dim, dilation=3)self.conv_spatial_v = nn.Conv2d(dim, dim, kernel_size=(13, 1), stride=(1,1), padding=(18,0), groups=dim, dilation=3)elif k_size == 53:self.conv0h = nn.Conv2d(dim, dim, kernel_size=(1, 5), stride=(1,1), padding=(0,(5-1)//2), groups=dim)self.conv0v = nn.Conv2d(dim, dim, kernel_size=(5, 1), stride=(1,1), padding=((5-1)//2,0), groups=dim)self.conv_spatial_h = nn.Conv2d(dim, dim, kernel_size=(1, 17), stride=(1,1), padding=(0,24), groups=dim, dilation=3)self.conv_spatial_v = nn.Conv2d(dim, dim, kernel_size=(17, 1), stride=(1,1), padding=(24,0), groups=dim, dilation=3)self.conv1 = nn.Conv2d(dim, dim, 1)def forward(self, x):u = x.clone()attn = self.conv0h(x)attn = self.conv0v(attn)attn = self.conv_spatial_h(attn)attn = self.conv_spatial_v(attn)attn = self.conv1(attn)return u * attn

四、手把手教你将LSKAttention添加到你的网络结构中

4.1 LSKAttention的添加教程

添加教程这里不再重复介绍、因为专栏内容有许多,添加过程又需要截特别图片会导致文章大家读者也不通顺如果你已经会添加注意力机制了,可以跳过本章节,如果你还不会,大家可以看我下面的文章,里面详细的介绍了拿到一个任意机制(C2f、Conv、Bottleneck、Loss、DetectHead)如何添加到你的网络结构中去。

需要注意的是本文的task.py配置的代码如下:

        elif m in {LSKA}:args = [ch[f], *args]

4.2 LSKAttention的yaml文件和训练截图

4.2.1 LSKAttention的yaml文件

参数位置可以填写的有7、11、23、35、41、53(代表卷积核的大小),具体哪个效果好可能要大家自己进行一定的尝试才可以,需要注意的是这里卷积核越大计算量就会变得越大

4.2.2 LSKAttention的训练过程截图

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

五、LSKAttention可添加的位置

5.1 推荐LSKAttention可添加的位置

LSKAttention可以是一种即插即用的注意力机制,其可以添加的位置有很多,添加的位置不同效果也不同,所以我下面推荐几个添加的位,置大家可以进行参考,当然不一定要按照我推荐的地方添加。

  1. 残差连接中:在残差网络的残差连接中加入注意力机制(这个位置我推荐的原因是因为DCN放在残差里面效果挺好的大家可以尝试)

  2. 特征金字塔(SPPF):在特征金字塔网络之前,可以帮助模型更好地融合不同尺度的特征。

  3. Neck部分:YOLOv8的Neck部分负责特征融合,这里添加注意力机制可以帮助模型更有效地融合不同层次的特征。

  4. 输出层前:在最终的输出层前加入注意力机制可以使模型在做出最终预测之前,更加集中注意力于最关键的特征。

大家可能看我描述不太懂,大家可以看下面的网络结构图中我进行了标注。

5.2图示LSKAttention可添加的位置

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2024熵密杯wp

第一部分:初始谜题这一部分算是开胃菜,形式也更像平时见到的CTF题目,三个题目都是python加密的,做出其中任意一个就可以进入第二部分,也就是一个更类似真实情境的大型密码渗透系统。但每个初始谜题都是有分数的,所以就算开了第二部分也当然要接着做。每个题目也都有前三血…

2024高校网络安全管理运维赛 wp

0x00 前言本文是关于“2024高校网络安全管理运维赛”的详细题解,主要针对Web、Pwn、Re、Misc以及Algorithm等多方向题目的解题过程,包含但不限于钓鱼邮件识别、流量分析、SQLite文件解析、ssrf、xxe等等。如有错误,欢迎指正。0x01 Misc签到给了一个gif,直接在线分帧得到syn…

张量矩阵乘法分块乘法概述

张量矩阵乘法分块乘法概述 介绍一下矩阵计算相关的内容, 从最基本的算法,到Cutlass这些线性代数模版库, 特别是Layout代数相关的内容,再逐渐细化到一些硬件实现访存优化和一些算子融合。 6.3.1 GEMM概述 1. GEMM定义 对于一个矩阵乘法, 定义如下: (6-1)一个矩阵乘法定义,如…

Java与线程

Java与线程 1. 线程的实现 线程是比进程更轻量级的调度执行单位,线程的引人,可以把一个进程的资源分配和执行调度分开,各个线程既可以共享进程资源(内存地址、文件IO等),又可以独立调度。目前线程是Java里面进行处理器资源调度的最基本单位。 主流的操作系统都提供了线程实…

矩阵分块乘法

矩阵分块乘法 通常可以把一个矩阵分成多个块, 例如, (6-4)可以将其划分为 4个块:(6-5) (6-6)分块后的矩阵记为:(6-7) 分块矩阵乘法如下所示:(6-7)划分不一定需要完全等间隔, 只需要满足子矩阵乘法规则即可, 如图6-27所示。图6-27 子矩阵划分不一定需要完全等间…

从硬件的视角看GEMM

从硬件的视角看GEMM 1. 分块乘法的内存层次架构 分块矩阵乘法,如图6-28所示, 通过将矩阵分块拆分,能够在处理器的Cache和寄存器内存放进行快速计算,计算完成后写回主存。图6-28 分块矩阵乘法 首先,所有的数据都在主内存中,如图6-29所示。图6-29 所有的数据都在主内存中 然…

电表行业强力推荐KY8023S6对标平替BL8023双向继电器驱动芯片

双向继电器驱动芯片KY8023S6对标平替BL8023。 产品特点 SOT23-6L和SOP-8 两种封装 静态功耗电流<1uA 输入高低转换电平为1.3V(Is=1A)左右,兼容多种单片机 工作电压5-40V,推荐工作电压5-30V 输入INA和INB端自带115k下拉电阻,一般可省略外围下拉电阻 集成高速续流二极管,…

重启后,idea 依赖爆红

没改动代码,但无法运行java项目 java: -source 1.5 中不支持……表达式/运算符java: 错误: 不支持发行版本 5解决:https://www.cnblogs.com/liu-han/p/16105953.html 文件→项目结构,SDK和项目/模块 语言级别的版本要一致SDK: 1.8 项目语言级别:SDK默认值 模块语言级别:SD…

[亲测]君临九州+单机安装教程+无需虚拟机+GM后台

今天给大家带来一款单机游戏的架设:君临九州,版本号:1.0.12.30。 另外:本人承接各种游戏架设(单机+联网) 本人为了学习和研究软件内含的设计思想和原理,带了架设教程仅供娱乐。 教程是本人亲自搭建成功的,绝对是完整可运行的,踩过的坑都给你们填上了。如果你是小白也没…

智慧园区管理系统原型

智慧园区管理系统的构建是一个复杂而系统的工程,它融合了信息化、AI、物联网等多种先进技术,旨在提升园区的管理效率、服务质量以及企业运营效率。 一、明确系统目标和需求 需求收集与分析:首先,需要对园区的实际需求进行全面分析,包括园区类型(如产业园区、办公园区、住…

POI导出excel文件加水印

百分百能用,我用的POI版本是5.2.3,效果如下import lombok.extern.slf4j.Slf4j; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.xs…