YOLOv5中添加SE模块详解——原理+代码

news2024/11/27 12:57:27

目录

  • 一、SENet
      • 1. 设计原理
      • 2. SE Block
        • 2.1 Squeeze:Global Information Embedding
        • 2.2 Excitation:Adaptive Recalibration
      • 3. SE-Inception and SE-ResNet
  • 二、YOLOv5中添加SENet
      • 1.修改common.py
      • 2.修改yolo.py
      • 3.修改yolov5s.yaml
  • 参考文章

一、SENet

论文地址:Squeeze-and-Excitation Networks [CVPR2017]
Caffe代码地址:SENet-Caffe
Pytorch代码地址:SENet-Pytorch

1. 设计原理

  论文中提到,在SENet提出之前,大部分工作专注于研究特征图的空间编码质量(可以理解为每个通道的特征图的特征提取质量),即只关注每个通道中特征图的表达能力,而没有关注不同通道的特征图的融合(如果一个特征图的维度为 C × H × W C×H×W C×H×W的话,SENet之前的工作只关注了 H H H W W W维度,而没有关注 C C C维度,不同通道的特征图融合还是通过卷积相加的方式完成)

  SENet关注了通道关系,提出了Squeeze-and-Excitation模块,通过显式地模拟通道之间的相互依赖关系,自适应地重新校准通道的特征响应(普通卷积过程的通道关系本质上是隐式的和局部的(除了最顶层的通道关系,因为最顶层的通道与任务相关,比如分割网络的最顶层通道数为分割类别数,而中间层的通道数通常是经验所得))

2. SE Block

在这里插入图片描述

图1 SE Block结构图

  SE Block的结构如图1所示,首先通过卷积操作 F t r F_{tr} Ftr将输入特征图 X ∈ R H ′ × W ′ × C ′ X\in R^{H'\times W'\times C'} XRH×W×C映射到特征图 U ∈ R H × W × C U\in R^{H\times W\times C} URH×W×C,在这个过程中,用 V = [ v 1 , v 2 , . . . , v C ] V=[v_{1},v_{2},...,v_{C}] V=[v1,v2,...,vC]表示卷积核的集合,输出可表示为 U = [ u 1 , u 2 , . . . , u C ] U=[u_{1},u_{2},...,u_{C}] U=[u1,u2,...,uC],则:
u c = v c ∗ X = ∑ s = 1 C ′ v c s ∗ x s u_c=v_{c}*X=\sum_{s=1}^{C'}v_{c}^s*x^s uc=vcX=s=1Cvcsxs

  这里 ∗ * 表示卷积操作, u c ∈ R H × W u_{c}\in R^{H\times W} ucRH×W v c = [ v c 1 , v c 2 , . . . , v c C ′ ] v_{c}=[v_{c}^1,v_{c}^2,...,v_{c}^{C'}] vc=[vc1,vc2,...,vcC] X = [ x 1 , x 2 , . . . , x C ′ ] X=[x^{1},x^{2},...,x^{C'}] X=[x1,x2,...,xC] v c s v_{c}^s vcs是一个二维卷积核,表示 v c v_{c} vc的单个通道作用于 X X X的相应通道上。

2.1 Squeeze:Global Information Embedding

  为了考虑输出特征图中每个通道的信息,论文通过全局平均池化的方式,将全局空间信息压缩到一个通道描述符 z c z_{c} zc中:

z c = F s q ( u c ) = 1 H × W ∑ i = 1 H ∑ j = 1 W u c ( i , j ) z_{c}=F_{sq}(u_{c})=\frac{1}{H\times W}\sum_{i=1}^{H}\sum_{j=1}^{W}u_{c}(i,j) zc=Fsq(uc)=H×W1i=1Hj=1Wuc(i,j)

2.2 Excitation:Adaptive Recalibration

  为了完全捕获通道依赖关系,论文选择使用一种简单的带有Sigmoid激活的门控机制:

s = F e x ( z , W ) = σ ( g ( z , W ) ) = σ ( W 2 δ ( W 1 z ) ) s=F_{ex}(z,W)=\sigma (g(z,W))=\sigma (W_{2}\delta (W_{1}z)) s=Fex(z,W)=σ(g(z,W))=σ(W2δ(W1z))

  其中, δ \delta δ为ReLU函数, W 1 ∈ R C r × C W_{1}\in R^{\frac{C}{r}\times C} W1RrC×C W 2 ∈ R C × C r W_{2}\in R^{C\times\frac{C}{r}} W2RC×rC

  通过s重新缩放U,得到SE Block最后的输出:

x ˉ c = F s c a l e ( u c , s c ) = s c u c \bar{x}_{c}=F_{scale}(u_{c},s_{c})=s_{c}u_{c} xˉc=Fscale(uc,sc)=scuc

3. SE-Inception and SE-ResNet

  图2为原文设计的SE-Inception模块和SE-ResNet模块,这是一个即插即用模块。为了解决通道之间的依赖关系,作者使用全局平均池化操作来压缩全局空间信息,这就是Sequeeze操作。为了利用在Sequeeze操作中聚合的信息,作者通过FC-ReLU-FC-Sigmoid操作来完全捕获通道依赖性,这就是Excitation操作。

在这里插入图片描述

图2 SE Module
class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)        #全局平均池化,输入BCHW -> 输出 B*C*1*1
        self.fc = nn.Sequential(
            nn.Linear(channel, channel // reduction, bias=False),   #可以看到channel得被reduction整除,否则可能出问题
            nn.ReLU(inplace=True),
            nn.Linear(channel // reduction, channel, bias=False),
            nn.Sigmoid()
        )
 
    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avg_pool(x).view(b, c)     #得到B*C*1*1,然后转成B*C,才能送入到FC层中。
        y = self.fc(y).view(b, c, 1, 1)     #得到B*C的向量,C个值就表示C个通道的权重。把B*C变为B*C*1*1是为了与四维的x运算。
        return x * y.expand_as(x)           #先把B*C*1*1变成B*C*H*W大小,其中每个通道上的H*W个值都相等。*表示对应位置相乘。

二、YOLOv5中添加SENet

1.修改common.py

  在models/common.py中添加下列代码

class SElayer(nn.Module):
    def __init__(self, c1, c2, ratio=16):
        super(SElayer, self).__init__()
        #c*1*1
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.l1 = nn.Linear(c1, c1 // ratio, bias=False)
        self.relu = nn.ReLU(inplace=True)
        self.l2 = nn.Linear(c1 // ratio, c1, bias=False)
        self.sig = nn.Sigmoid()

    def forward(self, x):
        b, c, _, _ = x.size()
        y = self.avgpool(x).view(b, c)
        y = self.l1(y)
        y = self.relu(y)
        y = self.l2(y)
        y = self.sig(y)
        y = y.view(b, c, 1, 1)
        return x * y.expand_as(x)

2.修改yolo.py

  在models/yolo.py中的parse_model函数中添加SElayer模块

        if m in [Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, CrossConv, BottleneckCSP,
                 C3, C3TR, ASPP, SElayer]:
            c1, c2 = ch[f], args[0]  
            if c2 != no:  
                c2 = make_divisible(c2 * gw, 8)  
            args = [c1, c2, *args[1:]] 

3.修改yolov5s.yaml

  在Backbone的倒数第二层添加SElayer,修改后的yolov5s.yaml如下所示:

# parameters
nc: 20  # number of classes
depth_multiple: 0.33  # model depth multiple
width_multiple: 0.50  # layer channel multiple

# anchors
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 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, 9, 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, SElayer, [1024]],
   [-1, 1, SPPF, [512, 512]], # 10
  ]

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]],  # 14

   [-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]],  # 18 (P3/8-small)

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

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

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

参考文章

SE-ResNet的实现
YOLOv5-6.1添加注意力机制(SE、CBAM、ECA、CA)

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

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

相关文章

UI设计 ,这7个网站,真的太好用了。

下面这几个UI设计网站,设计师们一定要收藏起来,每天坚持浏览这些网站,可以快速的提升你的UI设计水平。 1、菜鸟图库 https://www.sucai999.com/searchlist/UIsheji----all-0-0.html?vNTYxMjky 菜鸟图库提供了超多免费设计素材,在…

logistic回归的参数梯度更新方法的个人理解

logistic回归参数更新看了几篇博文,感觉理解不透彻,所以自己写一下,希望能有更深的理解。logistic回归输入是一个线性函数Wxb\boldsymbol{W}\boldsymbol{x}\boldsymbol{b}Wxb,为了简单理解,考虑batchsize为1的情况。这…

ChatGPT的影响力和未来发展

ChatGPT是一种基于深度学习的自然语言处理技术,它是由OpenAI开发的一种语言模型。ChatGPT作为一个大型语言模型,可以在很多方面对程序职业产生影响。值得注意的是,ChatGPT和其他语言模型一样,只是一种技术工具,它的应用…

Postman 接口传参报错解决与@RequestBody的注解作用记录

文章目录前言一、接口代码1.1 代码说明1.2 测试结果1.3 问题解决1.4 RequestBody 作用前言 记录接口传参报错与解决和RequestBody的作用记录 一、接口代码 1.1 代码说明 以下面测试代码作为例子:前端发送 POST 请求,请求体里面携带 List 集合的字符串…

C++回顾(十九)—— 容器string

19.1 string概述 1、string是STL的字符串类型,通常用来表示字符串。而在使用string之前,字符串通常是 用char * 表示的。string 与char * 都可以用来表示字符串,那么二者有什么区别呢。 2、string和 char * 的比较 (1&#xff09…

【wed前端初级课程】第一章 什么是HTML

什么是WEB前端? 简单来说就是网页,只是这个网页它是由多种技术参与制作的,用来向用户展示的页面。 HTML(超文本标签语言):它决定了网页的结构。 CSS:网页的装饰器。 JavaScript:JavaScrip最初是因为校验…

【Linux系统编程】06:共享内存

共享内存 OVERVIEW共享内存一、文件上锁flock二、共享内存1.关联共享内存ftok2.获取共享内存shmget3.绑定共享内存shmat4.绑定分离shmdt5.控制共享内存shmctl三、亲缘进程间通信1.共享内存写入与读取2.共享内存解绑与删除3.共享内存综合四、非亲缘进程间通信1.通过sleep同步2.通…

Android 进阶——Binder IPC之Native 服务的启动及代理对象的获取详解(六)

文章大纲引言一、Binder线程池的启动1、ProcessState#startThreadPool函数来启动线程池2、IPCThreadState#joinThreadPool 将当前线程进入到线程池中去等待和处理IPC请求二、Service 代理对象的获取1、获取Service Manager 代理对象BpServiceManager2、调用BpServiceManager#ge…

【算法数据结构体系篇class16】:图 拓扑排序

一、图1)由点的集合和边的集合构成2)虽然存在有向图和无向图的概念,但实际上都可以用有向图来表达3)边上可能带有权值二、图结构的表达1)邻接表法 类似哈希表, key就是当前节点。value就是对应有指向的邻接节点2&…

LeetCode——1590. 使数组和能被 P 整除

一、题目 给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空),使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。 请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1…

PostgreSQL 数据库大小写规则

PostgreSQL 数据库对大小写的处理规则如下: 严格区分大小写默认把所有 SQL 语句都转换成小写再执行加双引号的 SQL 语句除外 如果想要成功执行名称中带有大写字母的对象,则需要把对象名称加上双引号。 验证如下: 想要创建数据库 IZone&…

Windows WSL配置ubuntu环境并登录

一、Windows WSL配置ubuntu环境1、管理员运行cmd,执行以下命令启用“适用于 Linux 的 Windows 子系统”dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart2、管理员运行cmd,执行以下命令启用“虚拟机功…

浅谈ChatGPT

ChatGPT概述 ChatGPT是一种自然语言处理模型,ChatGPT全称Chat Generative Pre-trained Transformer,由OpenAI开发。它使用了基于Transformer的神经网络架构,可以理解和生成自然语言文本。ChatGPT是当前最强大和最先进的预训练语言模型之一&a…

windows应用(vc++2022)MFC基础到实战(3)-基础(3)

目录框架调用代码MFC 对象之间的关系访问其他对象CWinApp:应用程序类initInstance 成员函数运行成员函数OnIdle 成员函数ExitInstance 成员函数CWinApp 和 MFC 应用程序向导特殊 CWinApp 服务Shell 注册文件管理器拖放CWinAppEx 类用于创建 OLE 应用程序的操作顺序用…

【算法题目】【Python】一文刷遍贪心算法题目

文章目录介绍分配饼干K 次取反后最大化的数组和柠檬水找零摆动序列单调递增的数字介绍 贪心算法是一种基于贪心思想的算法,它每次选择当前最优的解决方案,从而得到全局最优解。具体来说,贪心算法在每一步都做出局部最优选择,希望…

Flutter——Isolate主线机制

简述 在DartFlutter应用程序启动时,会启动一个主线程其实也就是Root Isolate,在Root Isolate内部运行一个EventLoop事件循环。所以所有的Dart代码都是运行在Isolate之中的,它就像是机器上的一个小空间,具有自己的私有内存块和一个运行事件循…

Linux下LED灯驱动模板详解

一、地址映射我们先了解MMU,全称是Memory Manage Unit。在老版本的Linux中要求处理器必须有MMU,但是现在Linux内核已经支持五MMU。MMU主要完成的功能如下:1、完成虚拟空间到物理空间的映射2、内存保护,设置存储器的访问权限&#…

【Linux学习笔记】mmap-共享内存进程通信 vs 有名信号量和无名信号量

mmap和信号量实现进程间通信相关mmap1. mmap 使用的注意事项2. mmap的两种映射3. mmap调用接口以及参数4. 使用存储映射区实现父子进程间通信(有名)父子进程通信的三种方式unlink5. 创建匿名存储映射区6. 通过存储映射区实现非血缘关系进程间的通信信号量…

SiteSucker for macOS + CRACK

SiteSucker for macOS CRACK SiteSucker是一个简单的macOS应用程序,允许您下载网站。它还可以将网站、网页、背景图片、视频和许多其他文件复制到Mac的硬盘上。 SiteSucker是一个Macintosh应用程序,可以自动下载Internet上的网页。它通过将网站的页面、…

遥感影像道路提取算法——SGCN

论文介绍 Split Depth-wise Separable Graph Convolution Network for Road Extraction in Complex Environment from High-resolution Remote Sensing Imagery(TGRS) 用于从高分辨率遥感图像(TGRS)中提取复杂环境中道路的分割深…