YOLOv8添加多种attention注意力机制

yolov8发布了快半年的时间,由于它还没有一个固定的版本,所以它的源码可能会和我下载的有所差异,但是大体上应该是差不多的。这里就不赘述yolov8相对于yolov5改了哪些东西,主要的就是一些像C3模块优化为C2f,SPP优化为SPPF等等。下面就讲一下如何在YOLOv8中加入一些自己的attention注意力机制。

这里我用CBAM这个attention举例,它是2018年提出了一种轻量的注意力模块( CBAM,Convolutional Block Attention Module ),可以在通道和空间维度上进行 Attention ,它对小目标检测有较好的鲁棒性。

论文题目:《CBAM: Convolutional Block Attention Module》
论文地址:https://arxiv.org/pdf/1807.06521.pdf

一、复制注意力机制代码

我这里有十几种不同注意力机制的代码,由于复制太麻烦了,所以就用这个CBAM的作为例子,想要其他的可以私信我哦

import numpy as np
import torch
from torch import nn
from torch.nn import init


class ChannelAttention(nn.Module):
    def __init__(self, channel, reduction=16):
        super().__init__()
        self.maxpool = nn.AdaptiveMaxPool2d(1)
        self.avgpool = nn.AdaptiveAvgPool2d(1)
        self.se = nn.Sequential(
            nn.Conv2d(channel, channel // reduction, 1, bias=False),
            nn.ReLU(),
            nn.Conv2d(channel // reduction, channel, 1, bias=False)
        )
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        max_result = self.maxpool(x)
        avg_result = self.avgpool(x)
        max_out = self.se(max_result)
        avg_out = self.se(avg_result)
        output = self.sigmoid(max_out + avg_out)
        return output


class SpatialAttention(nn.Module):
    def __init__(self, kernel_size=7):
        super().__init__()
        self.conv = nn.Conv2d(2, 1, kernel_size=kernel_size, padding=kernel_size // 2)
        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        max_result, _ = torch.max(x, dim=1, keepdim=True)
        avg_result = torch.mean(x, dim=1, keepdim=True)
        result = torch.cat([max_result, avg_result], 1)
        output = self.conv(result)
        output = self.sigmoid(output)
        return output


class CBAMBlock(nn.Module):

    def __init__(self, channel=512, reduction=16, kernel_size=7):
        super().__init__()
        self.ca = ChannelAttention(channel=channel, reduction=reduction)
        self.sa = SpatialAttention(kernel_size=kernel_size)

    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()
        out = x * self.ca(x)
        out = out * self.sa(out)
        return out

在ultralytics/nn这个目录下新建一个py文件,将复制的attention代码粘贴进去

然后在ultralytics/nn这个目录下的task.py修改一些信息

首先在开头导入一下这个模块

 注意from ultralytics.nn.后面的是你粘贴代码那个py文件的名字

然后在解析函数中加入以下代码

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

大约在650行的位置,{}这个里面的是你要导入类的名称,这里还有一点就是有的注意力机制有通道数,有的不接收通道数,这个后面在详细说,目前这个按照这些步骤是没有问题的

 到这里就差不多了,这不像添加那些DCNv2、v3需要去__init__中声明一下,然后就可以修改yaml配置文件了

 我这个是在Backbone最后一层添加的,CBAMBlock就是attention中最后那个类的名字,[16,7]就是默认接受的参数,这里不填好像也可以,用的就是代码中默认的参数

至此,网络结构就修改完成了,然后就可以训练了,可以在终端输出的网络结构中看看自己的注意力机制有没有成功添加进去。

这段代码中,`SelfAttention`层的输入通道数需要与其前面的`PointnetSAModuleMSG`层输出通道数相同。而`PointnetSAModuleMSG`层的输出通道数通过计算其内部`mlps`列表中每层线性层的输出通道数之和得到,因此需要保证`mlps`列表中每层线性层的输入通道数与`PointnetSAModuleMSG`层输入通道数相同。 以下是修正代码,对其中的`mlps`列表进行了修改,使得每层线性层的输入通道数与`PointnetSAModuleMSG`层输入通道数相同: ``` class Pointnet2MSG(nn.Module): def __init__(self, input_channels=6, use_xyz=True): super().__init__() self.SA_modules = nn.ModuleList() channel_in = input_channels skip_channel_list = [input_channels] for k in range(cfg.RPN.SA_CONFIG.NPOINTS.len()): mlps = cfg.RPN.SA_CONFIG.MLPS[k].copy() channel_out = 0 for idx in range(mlps.len()): # 修改每层线性层的输入通道数 mlps[idx] = [channel_in] + mlps[idx][:-1] channel_out += mlps[idx][-1] mlps.append([channel_out]) self.SA_modules.append( nn.Sequential( PointnetSAModuleMSG( npoint=cfg.RPN.SA_CONFIG.NPOINTS[k], radii=cfg.RPN.SA_CONFIG.RADIUS[k], nsamples=cfg.RPN.SA_CONFIG.NSAMPLE[k], mlps=mlps, use_xyz=use_xyz, bn=cfg.RPN.USE_BN ), SelfAttention(channel_out) ) ) skip_channel_list.append(channel_out) channel_in = channel_out ``` 其中,`mlps[idx][:-1]`表示将`mlps`列表中每层线性层的输出通道数去掉,只留下输入通道数。最后一层线性层的输出通道数则为`channel_out`,因此在`mlps`列表中添加了一个只有1个元素的列表`[channel_out]`作为最后一层线性层的参数。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值