YOLOv8改进 | 注意力机制 | 增强模型在图像分类和目标检测BAM注意力【小白必备 + 附完整代码】

秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转


💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡


专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有50+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck、NMS等创新点改进——点击即可跳转


近期深度神经网络的发展已经通过架构搜索实现了更强的表征能力。提出了一种名为瓶颈注意力模块(BAM)的简单而有效的注意力模块。它可以与任何前馈卷积神经网络集成。我们的模块沿着两个独立的路径(通道和空间)推断注意力图。我们将模块放置在模型的每个瓶颈处,即特征图降采样发生的地方。我们的模块在瓶颈处构建了一个分层的注意力,并且具有可训练的参数,可以与任何前馈模型进行端到端的联合训练。文章在介绍主要的原理后,将手把手教学如何进行模块的代码添加和修改,并将修改后的完整代码放在文章的最后方便大家一键运行,小白也可轻松上手实践。以帮助您更好地学习深度学习目标检测YOLO系列的挑战。

专栏地址YOLOv8改进——更新各种有效涨点方法——点击即可跳转

目录

1.原理

2. 将BAM添加到YOLOv8中

2.1 BAM代码实现

2.2 更改init.py文件

2.3 添加yaml文件

2.4 在task.py中进行注册

2.5 执行程序

3. 完整代码分享

4. GFLOPs

5. 进阶

6. 总结


1.原理

论文地址:BAM: Bottleneck Attention Module——点击即可跳转

官方代码:官方代码仓库——点击即可跳转

BAM(瓶颈注意模块)的主要原理如下:

1. 模块概述

BAM是一种简单且有效的注意力模块,旨在提高深度神经网络的表征能力。它可以与任何前馈卷积神经网络(CNN)集成使用,主要在网络的瓶颈处(即特征图下采样的位置)进行操作。

2. 结构设计

BAM模块通过两个独立的路径推断出一个注意力图:通道路径和空间路径。它的具体结构如下:

通道注意力分支

  1. 全局平均池化:对输入特征图 F \in \mathbb{R}^{C \times H \times W}进行全局平均池化,得到通道向量 F_c \in \mathbb{R}^{C \times 1 \times 1}

  2. 多层感知机(MLP):使用一个带有一个隐藏层的MLP来估计通道间的注意力。为了减少参数开销,隐藏层的激活大小设置为 \frac{C}{r} \times 1 \times 1 ,其中 r 是缩减比。

  3. 批量归一化:在MLP之后添加批量归一化层 BN以调整与空间分支输出的规模。

  4. 通道注意力:计算通道注意力 M_c(F)

空间注意力分支

  1. 空间注意力:通过卷积操作生成空间注意力图 M_s(F)

3. 注意力融合

BAM模块将通道和空间注意力进行融合,得到最终的3D注意力图 M(F) : M(F) = \sigma(M_c(F) + M_s(F)) 其中( \sigma ) 是sigmoid函数。融合后的注意力图用于增强输入特征图 ( F ),计算公式为: F' = F + F \otimes M(F) 其中 \otimes表示逐元素乘法。

4. 优势和应用

BAM模块具有轻量级设计,参数和计算开销很小,可以在多个基准测试(如CIFAR-100、ImageNet-1K、VOC 2007和MS COCO)上验证其有效性。它可以显著提高分类和检测性能,并能构建层次化的注意力机制,从低级特征(如背景纹理)逐渐聚焦到高级语义目标。

2. 将BAM添加到YOLOv8中

2.1 BAM代码实现

关键步骤一: 将下面代码粘贴到在/ultralytics/ultralytics/nn/modules/block.py中,并在该文件的__all__中添加“BAMBlock”

class Flatten(nn.Module):
    def forward(self, x):
        return x.view(x.shape[0], -1)


class ChannelAttention(nn.Module):
    def __init__(self, channel, reduction=16, num_layers=3):
        super().__init__()
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        gate_channels = [channel]
        gate_channels += [channel // reduction] * num_layers
        gate_channels += [channel]

        self.ca = nn.Sequential()
        self.ca.add_module('flatten', Flatten())
        for i in range(len(gate_channels) - 2):
            self.ca.add_module('fc%d' % i, nn.Linear(gate_channels[i], gate_channels[i + 1]))
            self.ca.add_module('bn%d' % i, nn.BatchNorm1d(gate_channels[i + 1]))
            self.ca.add_module('relu%d' % i, nn.SiLU())
        self.ca.add_module('last_fc', nn.Linear(gate_channels[-2], gate_channels[-1]))

    def forward(self, x):
        res = self.avgpool(x)
        res = self.ca(res)
        res = res.unsqueeze(-1).unsqueeze(-1).expand_as(x)
        return res


class SpatialAttention(nn.Module):
    def __init__(self, channel, reduction=16, num_layers=3, dia_val=2):
        super().__init__()
        self.sa = nn.Sequential()
        self.sa.add_module('conv_reduce1',
                           nn.Conv2d(kernel_size=1, in_channels=channel, out_channels=channel // reduction))
        self.sa.add_module('bn_reduce1', nn.BatchNorm2d(channel // reduction))
        self.sa.add_module('relu_reduce1', nn.SiLU())
        for i in range(num_layers):
            self.sa.add_module('conv_%d' % i, nn.Conv2d(kernel_size=3, in_channels=channel // reduction,
                                                        out_channels=channel // reduction,
                                                        padding=autopad(3, None, dia_val), dilation=dia_val))
            self.sa.add_module('bn_%d' % i, nn.BatchNorm2d(channel // reduction))
            self.sa.add_module('relu_%d' % i, nn.SiLU())
        self.sa.add_module('last_conv', nn.Conv2d(channel // reduction, 1, kernel_size=1))

    def forward(self, x):
        res = self.sa(x)
        res = res.expand_as(x)
        return res


class BAMBlock(nn.Module):
    def __init__(self, channel=512, reduction=16, dia_val=2):
        super().__init__()
        self.ca = ChannelAttention(channel=channel, reduction=reduction)
        self.sa = SpatialAttention(channel=channel, reduction=reduction, dia_val=dia_val)
        self.sigmoid = nn.Sigmoid()

    def init_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                init.kaiming_normal_(m.weight, mode='fan_out')
                if m.bias is not None:
                    init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                init.constant_(m.weight, 1)
                init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                init.normal_(m.weight, std=0.001)
                if m.bias is not None:
                    init.constant_(m.bias, 0)

    def forward(self, x):
        b, c, _, _ = x.size()
        sa_out = self.sa(x)
        ca_out = self.ca(x)
        weight = self.sigmoid(sa_out + ca_out)
        out = (1 + weight) * x
        return out

BAM (Bottleneck Attention Module) 处理图片的主要流程如下:

  1. 输入图像: 首先输入图像到卷积神经网络(CNN)中。

  2. 初始卷积处理: 使用一系列卷积层提取图像的特征,这些卷积层能够捕捉不同尺度和复杂度的特征信息。

  3. 特征提取和降维: 在初始特征提取之后,经过多个卷积层的处理,将特征图传递到 BAM 中。在这里,首先会进行特征图的降维处理,以减少计算量。

  4. 计算通道注意力: 通过全局平均池化 (Global Average Pooling, GAP) 和全局最大池化 (Global Max Pooling, GMP) 计算特征图在通道维度上的注意力分布。

  5. 计算空间注意力: 使用卷积操作计算特征图在空间维度上的注意力分布,捕捉图像中重要的空间位置。

  6. 融合注意力权重: 将通道注意力和空间注意力相结合,得到综合的注意力权重。这些权重用于调整原始特征图中的特征响应。

  7. 特征增强: 使用融合后的注意力权重对初始特征图进行加权调整,增强重要特征,抑制无关或冗余特征。

  8. 输出特征图: 最终输出经过 BAM 处理后的特征图,送入后续的网络层进行进一步的处理和分类等任务。

这个流程通过在特征提取过程中引入注意力机制,有效地增强了卷积神经网络对图像重要信息的捕捉能力,提升了模型的整体性能。

2.2 更改init.py文件

关键步骤二:修改modules文件夹下的__init__.py文件,先导入函数

然后在下面的__all__中声明函数

2.3 添加yaml文件

关键步骤三:在/ultralytics/ultralytics/cfg/models/v8下面新建文件yolov8_BAM.yaml文件,粘贴下面的内容

# 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-SPPCSPC.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 GFLOPs

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

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

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

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

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

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

2.4 在task.py中进行注册

关键步骤四:在task.py的parse_model函数中进行注册, ​​

elif m in {BAMBlock}:
            c1, c2 = ch[f], args[0]
            if c2 != nc:  # if not output
                c2 = make_divisible(min(c2, max_channels) * width, 8)
            args = [c1, c2, *args[1:]]

2.5 执行程序

关键步骤五:在ultralytics文件中新建train.py,将model的参数路径设置为yolov8_BAM.yaml的路径即可

如果你的添加导致报错请看: YOLOv8报错 | 添加注意力机制报错 | ValueError: Expected more than 1 value per channel when training, got input

from ultralytics import YOLO
 
# Load a model
# model = YOLO('yolov8n.yaml')  # build a new model from YAML
# model = YOLO('yolov8n.pt')  # load a pretrained model (recommended for training)
 
model = YOLO(r'/projects/ultralytics/ultralytics/cfg/models/v8/yolov8_BAM.yaml')  # build from YAML and transfer weights
 
# Train the model
model.train(batch=16)

 🚀运行程序,如果出现下面的内容则说明添加成功🚀

3. 完整代码分享

https://pan.baidu.com/s/18gR-Da_hD3BZZt-jCM5IeQ?pwd=hkxo 

提取码:hkxo  

4. GFLOPs

关于GFLOPs的计算方式可以查看:百面算法工程师 | 卷积基础知识——Convolution

未改进的YOLOv8nGFLOPs

改进后的GFLOPs

5. 进阶

可以结合损失函数或者卷积模块进行多重改进

6. 总结

Bottleneck Attention Module (BAM) 的主要原理是通过结合通道注意力和空间注意力两种机制来提高卷积神经网络(CNN)的特征提取能力。BAM 的设计灵感来自于人类视觉系统的“是什么”(通道)和“在哪里”(空间)路径,这两条路径共同作用于视觉信息的处理。

BAM 的主要结构包括两个分支:通道注意力分支和空间注意力分支。通道注意力分支通过全局平均池化来捕捉每个通道上的全局信息,然后使用多层感知器(MLP)计算每个通道的注意力权重。空间注意力分支则通过卷积操作来捕捉特征图在空间维度上的注意力分布。两者的输出通过逐元素加法(element-wise summation)进行融合,形成最终的注意力图。这个注意力图用于加权调整原始特征图,以增强重要特征和抑制无关或冗余特征。

具体来说,给定输入特征图F \in \mathbb{R}^{C \times H \times W},BAM 计算出一个 3D 注意力图 M(F) \in \mathbb{R}^{C \times H \times W}。经过 BAM 处理后的特征图 \(F'\) 通过以下公式计算得到:
F' = F + F \otimes M(F)
其中,\otimes表示逐元素相乘。

在通道注意力分支中,首先对特征图 \(F\) 进行全局平均池化,得到通道向量 F_c \in \mathbb{R}^{C \times 1 \times 1}。然后通过一个多层感知器(MLP)计算通道注意力M_c(F)。空间注意力分支则通过卷积操作计算空间注意力图 M_s(F) \in \mathbb{R}^{H \times W}。最终注意力图 M(F) 通过以下公式计算得到:
M(F) = \sigma(M_c(F) + M_s(F)) 
其中,\sigma 是 sigmoid 函数。

BAM 的设计不仅提升了模型的性能,而且只增加了极少的计算开销。这使得 BAM 特别适合在资源受限的移动设备和嵌入式系统中应用。通过在网络中的瓶颈处(bottleneck)插入 BAM,可以显著提升模型的特征提取能力和整体性能 。

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

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

相关文章

【模块化与包管理】:解锁【Python】编程的高效之道

目录 1.什么是模块? 2. 模块的导入过程 3. 理解命名空间 4. import语句的多种形式 5. 模块的执行与重新导入 6. 包(Package) 7. sys模块和os模块 sys模块 常用属性 示例:使用sys模块 os模块 常用功能 示例&#xff1…

前端埋点数据收集和数据上报

原文地址 什么是埋点 学名叫时间追踪(Event Tracking), 主要针对用户行为或者业务过程进行捕获,处理和发送相关技术及实施过程. 埋点是数据领域的一个专业术语,也是互联网领域的俗称,是互联网领域的俗称 埋点是产品数据分析的基础&#xf…

【AIGC】一、本地docker启动私有大模型

本地docker启动私有大模型 一、最终效果中英文对话生成代码 二、资源配置三、搭建步骤启动docker容器登录页面首次登录请注册登录后的效果 配置模型尝试使用选择模型选项下载模型选择适合的模型开始下载 试用效果返回首页选择模型中英文对话生成代码 四、附录资源监控 五、参考…

动手学深度学习54 循环神经网络

动手学深度学习54 循环神经网络 1. 循环神经网络RNN2. QA 1. 循环神经网络RNN h t h_t ht​ 与 h t − 1 h_{t-1} ht−1​ x t − 1 x_{t-1} xt−1​有关 x t x_t xt​ 与 h t h_t ht​ x t − 1 x_{t-1} xt−1​ 有关 怎么把潜变量变成RNN–假设更简单 潜变量和隐变量的区…

Java面试八股之什么是布隆过滤器

什么是布隆过滤器 布隆过滤器(Bloom Filter)是一种空间效率极高的概率型数据结构,用于判断一个元素是否可能存在于一个集合中。布隆过滤器可以给出“可能存在”或“一定不存在”的答案,但不能保证“一定存在”。其主要特点是&…

WTM的项目中EFCore如何适配人大金仓数据库

一、WTM是什么 WalkingTec.Mvvm框架(简称WTM)最早开发与2013年,基于Asp.net MVC3 和 最早的Entity Framework, 当初主要是为了解决公司内部开发效率低,代码风格不统一的问题。2017年9月,将代码移植到了.Net Core上&…

开源项目有哪些机遇与挑战

目录 1.概述 2.开源项目的发展趋势 2.1. 开源项目的发展现状 2.2. 开源社区的活跃度 2.3. 开源项目在技术创新中的作用 3.参与开源的经验分享 3.1. 选择开源项目 3.2. 理解项目结构和文档 3.3. 贡献代码 3.4. 与开源社区的合作 3.5. 学习和成长 4.开源项目的挑战 …

buuctf 二维码

文件下载下来是一个png的文件 做misc永远的好习惯就是先运行,后010 先运行,这个运行肯定就是扫码 啥也没有 里面还有个ZIP文件(zip的发明人名字是PK) 放在kali上binwalk分离 CTF工具隐写分离神器Binwalk安装和详细使用方法_binwalk下载-CSDN博客 里面有个text,需要密码 我…

ESP32驱动摄像头:1.驱动OV2640模块(待验证)

一、装ArduCam库和ESPAsyncWebServer库 二、参考代码 #include <Wire.h> #include <ArduCAM.h> #include <SPI.h> #include <WiFi.h> #include <ESPAsyncWebServer.h>#define CAM_CS 32 // modify according to your own wiring #define OV2640…

IP 地址:优化网络游戏

IP地址和网络游戏 在现代网络游戏中&#xff0c;IP地址不仅用于服务器分配&#xff0c;还能针对性进行玩家匹配与优化网络延迟。本文将探讨IP地址在网络游戏中的具体应用。 *服务器分配* 全球服务器分布&#xff1a; 网络游戏需要在全球范围内提供快速、稳定的连接&#xff…

【机器学习】主成分分析(PCA):数据降维的艺术

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 主成分分析&#xff08;PCA&#xff09;&#xff1a;数据降维的艺术引言PCA的基…

【TypeScript 学习】TypeScript 枚举类型发散:基于位运算的权限管理 CRUD 操作

文章目录 TypeScript 枚举类型发散&#xff1a;基于位运算的权限管理 CRUD 操作1 问题由来2 具体实现2.1 新增权限2.2 删除权限2.3 查询权限&#xff08;即判定存在与否&#xff09;2.4 修改权限2.5 完整测试 3 小结 TypeScript 枚举类型发散&#xff1a;基于位运算的权限管理 …

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【加解密(C/C++)】

加解密(C/C) 以AES 256密钥为例&#xff0c;完成加解密。具体的场景介绍及支持的算法规格。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生成密钥 指定密钥别名。初始化密钥属性集。调用OH_Huks_GenerateKeyItem生成密钥)…

[Linux安全运维] Linux用户以及权限管理

Linux用户以及权限管理 Linux用户和组 用户信息文件pasawd /etc/passwd文件用于存储用户的信息 :用于分割不同的字段信息 字段示例&#xff08;第一行&#xff09;含义说明1root用户名2x密码占位符x代表用户有密码存储在shadow文件中无内容代表用户登录系统不需要密码30UID…

一款24小时实时检测的六氟化硫气体泄漏报警系统

尽管当前工业生产模式越来越趋于自动化、智能化&#xff0c;但安全生产仍然是时下屡被提及的话题。在配电室等使用六氟化硫气体的众多领域中&#xff0c;由于气体泄漏而引发的中毒、火灾、爆炸、窒息事故仍高发频发。因此&#xff0c;安装六氟化硫气体泄漏报警监测系统仍是企业…

C语言 | Leetcode C语言题解之第226题翻转二叉树

题目&#xff1a; 题解&#xff1a; struct TreeNode* invertTree(struct TreeNode* root) {if (root NULL) {return NULL;}struct TreeNode* left invertTree(root->left);struct TreeNode* right invertTree(root->right);root->left right;root->right le…

如何探索高效知识管理:FlowUs知识库体验很好

在当今信息爆炸的时代&#xff0c;有效的知识管理对于个人和团队的发展至关重要。FlowUs 知识库作为一款创新的知识管理工具&#xff0c;正逐渐成为众多用户的首选&#xff0c;为他们带来了高效、便捷和有条理的知识管理体验。 FlowUs 知识库的一大特色在于其简洁直观的界面设计…

基于单片机的温控光控智能窗帘设计探讨

摘 要&#xff1a; 文章使用的核心原件是 AT89C52 单片机&#xff0c;以此为基础进行模块化的设计&#xff0c;在整个设计中通过加入光检测模块和温度检测模块&#xff0c;从而对室内的温度和光照强度进行检测&#xff0c;然后将检测得到的数据传输给单片机&#xff0c;单片机…

【自用】【高昆轮概率论与数理统计笔记】2.1 分布函数的概念与性质

不定期更新&#xff0c;前面的章节会在学完后补回来&#xff0c;重新学学概率&#xff0c;当年考研考的数学二&#xff0c;没有概率基础&#xff0c;想自己补补&#xff0c;视频课是高昆轮老师讲的浙大四版概率论教材的视频课&#xff0c;地址&#xff1a; 第一章&#xff1a;h…

印尼“支付宝” DANA 如何借力 OceanBase 实现3个“关键零”

当前&#xff0c;移动支付在东南亚正迅猛发展&#xff0c;据谷歌、淡马锡与贝恩公司发布的报告预测&#xff0c;东盟地区蓬勃兴起的移动支付市场有望在2030年突破至2万亿美元的交易规模。 在此背景下&#xff0c;DANA作为印尼——东南亚最大经济体中的一员&#xff0c;秉持着推…