【Yolov5】涨点亲测有效,Yolov5添加PSA极化自注意力机制

最近在学习目标检测领域的yolov5算法,发现PSA(极化自注意力机制)对于该算法的改进可能有用,于是在网上几经搜寻,无果,遂自己动手写了一个,现分享给大家

PSA极化自注意力机制来源

论文链接: Polarized Self-Attention: Towards High-quality Pixel-wise Regression
代码地址: https://github.com/DeLightCMU/PSA

使用效果

图1 原图
图2 平行极化
图3 顺序极化

极化过程示意图

作者在网上没有找到pytorch框架下的PSA模块源码,于是根据论文中的流程自己动手写了一个。
论文中的流程图:
channel分支与spatial分支示意图

源代码

class PSA_Channel(nn.Module):
    def __init__(self, c1) -> None:
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = nn.Conv2d(c1, c_, 1)
        self.cv2 = nn.Conv2d(c1, 1, 1)
        self.cv3 = nn.Conv2d(c_, c1, 1)
        self.reshape1 = nn.Flatten(start_dim=-2, end_dim=-1)
        self.reshape2 = nn.Flatten()
        self.sigmoid = nn.Sigmoid()
        self.softmax = nn.Softmax(1)
        self.layernorm = nn.LayerNorm([c1, 1, 1])

    def forward(self, x): # shape(batch, channel, height, width)
        x1 = self.reshape1(self.cv1(x)) # shape(batch, channel/2, height*width)
        x2 = self.softmax(self.reshape2(self.cv2(x))) # shape(batch, height*width)
        y = torch.matmul(x1, x2.unsqueeze(-1)).unsqueeze(-1) # 高维度下的矩阵乘法(最后两个维度相乘)
        return self.sigmoid(self.layernorm(self.cv3(y))) * x

class PSA_Spatial(nn.Module):
    def __init__(self, c1) -> None:
        super().__init__()
        c_ = c1 // 2  # hidden channels
        self.cv1 = nn.Conv2d(c1, c_, 1)
        self.cv2 = nn.Conv2d(c1, c_, 1)
        self.reshape1 = nn.Flatten(start_dim=-2, end_dim=-1)
        self.globalPooling = nn.AdaptiveAvgPool2d(1)
        self.softmax = nn.Softmax(1)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x): # shape(batch, channel, height, width)
        x1 = self.reshape1(self.cv1(x)) # shape(batch, channel/2, height*width)
        x2 = self.softmax(self.globalPooling(self.cv2(x)).squeeze(-1)) # shape(batch, channel/2, 1)
        y = torch.bmm(x2.permute(0,2,1), x1) # shape(batch, 1, height*width)
        return self.sigmoid(y.view(x.shape[0], 1, x.shape[2], x.shape[3])) * x

class PSA(nn.Module):
    def __init__(self, in_channel, parallel=True) -> None:
        super().__init__()
        self.parallel = parallel
        self.channel = PSA_Channel(in_channel)
        self.spatial = PSA_Spatial(in_channel)

    def forward(self, x):
        if(self.parallel):
            return self.channel(x) + self.spatial(x)
        return self.spatial(self.channel(x))

Yolov5添加PSA极化自注意力的步骤

第一步,将☝️上面的PSA模块代码粘贴到models/common.py文件下。

第二步,构建添加PSA模块的网络。在models文件夹下面创建yolov5s-PSA.yaml文件,并且将👇下面的内容粘贴上去。

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

# YOLOv5 v6.0 head
head:
  [[-1, 1, Conv, [512, 1, 1]],
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [[-1, 8], 1, Concat, [1]],  # cat backbone P4
   [-1, 3, C3, [512, False]],  # 13

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

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

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

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

第三步,在终端输入命令python models/yolo.py --cfg=yolov5s-PSA.yaml,运行后可查看网络细节。
在这里插入图片描述
到这一步大功告成,我们就可以愉快的使用这个网络了😊

### PSA注意力机制概述 PSA (Pyramid Split Attention) 是一种用于深度学习中的新型注意力机制,其主要特是通过金字塔结构分割特征图并计算局部区域的重要性权重。这种方法能够有效捕捉不同尺度的空间信息,在图像分类、目标检以及语义分割等领域表现出显著的效果。 该方法的核心思想在于将输入特征图划分为多个子区域,并针对这些子区域分别提取空间上下文信息[^1]。随后通过对各子区域的特征进行聚合操作来增强模型对于全局和局部细节的理解能力。具体而言: - 输入特征图被均匀分成若干部分; - 对每一部分独立应用卷积层获取局部响应; - 使用 softmax 函数规范化每一分区内的激活值作为权重视图; - 将权后的分区重新组合成完整的输出特征表示。 这种设计不仅有助于提升网络的感受野范围,还能够在一定程度上缓解梯度消失问题,从而促进深层架构训练过程更稳定高效[^2]。 以下是基于 PyTorch 的简单实现代码示例: ```python import torch from torch import nn, functional as F class PSALayer(nn.Module): def __init__(self, channel=512, reduction=8, S=4): super().__init__() self.S = S # 定义通道压缩模块 self.fc = nn.Sequential( nn.Linear(channel*S, channel//reduction), nn.ReLU(inplace=True), nn.Linear(channel//reduction, channel*S), nn.Sigmoid() ) def forward(self, x): b, c, h, w = x.size() # 切分特征图到S×S网格 splited = torch.stack(torch.chunk(x.view(b,c,-1), self.S, dim=2),dim=0) # 计算每个切片上的平均池化结果 gap_splited = splited.mean(dim=-1).view(-1,b*c//self.S) # 获取注意力向量并通过全连接层调整维度大小 attens = self.fc(gap_splited).reshape(self.S,self.S,b,c).permute(2,3,0,1) # 应用softmax函数得到最终的注意力建模矩阵 out_atten = F.softmax(attens,dim=-1) # 权求和获得新的特征表达形式 output = torch.einsum('bcsr,bcrhw->bschw',out_atten,splited)\ .contiguous().view_as(x)*x + x return output ``` 上述代码定义了一个 `PSALayer` 类,它接受三个参数:`channel`(输入张量的通道数),`reduction`(缩减比例,默认为8),以及 `S`(划分数量,默认设置为4)[^3]。此版本适用于标准二维数据处理场景下的实验验证工作。
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值