【目标检测实验系列】EMA高效注意力机制,融合多尺度特征,助力YOLOv5检测模型涨点(文内附源码)

1. 文章主要内容

本篇博客主要涉及多尺度高效注意力机制,融合到YOLOv5s模型中,增加模型提取多尺度特征的能力,助力模型涨点。(通读本篇博客需要7分钟左右的时间)

2. 简要概括

论文地址:EMA论文地址

如下图所示。EMA注意力提取特征主要分三个特征分支,分别是X、Y和一个3 x 3 的卷积块。另外,原论文中提出了一种跨分支学习,将其中的三个分支融合在一起,丰富多尺度感受野的特征,最后调整维度输出。更详细的细节,请阅读原论文。

亮点在于:比起CA注意力机制多了一个3x3的卷积分支,另外新增了跨分支的特征交互,丰富了提取模型的特征信息,有助于模型涨点。

分析:建议将EMA放置于YOLOv5 BackBone部分,因为BackBone是提取特征的关键,另外数据集如果有大量多尺度的目标分布,EMA很有可能起到明显的作用。另外,在EMA基础上,可以做一些微弱的创新,比如新增一个5x5的卷积分支并加入到跨分支学习中等等,这里只是提供一个思路。

3. 详细代码改进流程

3.1新建一个EMA的文件,放置源代码

特别注意:博主这里将EMA与YOLOv5中的C3模块结构融合在一起并命名为C3EMA。所以源代码中会含有C3EMA的代码,另外此代码提高了main函数的测试案例,启动测试控制台打印输入输出通道对得上就木有问题。源代码如下:

python 复制代码
import torch
from torch import nn

class EMA(nn.Module):
    def __init__(self, channels, c2=None, factor=32):
        super(EMA, self).__init__()
        self.groups = factor
        assert channels // self.groups > 0
        self.softmax = nn.Softmax(-1)
        self.agp = nn.AdaptiveAvgPool2d((1, 1))
        self.pool_h = nn.AdaptiveAvgPool2d((None, 1))
        self.pool_w = nn.AdaptiveAvgPool2d((1, None))
        self.gn = nn.GroupNorm(channels // self.groups, channels // self.groups)
        self.conv1x1 = nn.Conv2d(channels // self.groups, channels // self.groups, kernel_size=1, stride=1, padding=0)
        self.conv3x3 = nn.Conv2d(channels // self.groups, channels // self.groups, kernel_size=3, stride=1, padding=1)

    def forward(self, x):
        b, c, h, w = x.size()
        group_x = x.reshape(b * self.groups, -1, h, w)  # b*g,c//g,h,w
        x_h = self.pool_h(group_x)
        x_w = self.pool_w(group_x).permute(0, 1, 3, 2)
        hw = self.conv1x1(torch.cat([x_h, x_w], dim=2))
        x_h, x_w = torch.split(hw, [h, w], dim=2)
        x1 = self.gn(group_x * x_h.sigmoid() * x_w.permute(0, 1, 3, 2).sigmoid())
        x2 = self.conv3x3(group_x)
        x11 = self.softmax(self.agp(x1).reshape(b * self.groups, -1, 1).permute(0, 2, 1))
        x12 = x2.reshape(b * self.groups, c // self.groups, -1)  # b*g, c//g, hw
        x21 = self.softmax(self.agp(x2).reshape(b * self.groups, -1, 1).permute(0, 2, 1))
        x22 = x1.reshape(b * self.groups, c // self.groups, -1)  # b*g, c//g, hw
        weights = (torch.matmul(x11, x12) + torch.matmul(x21, x22)).reshape(b * self.groups, 1, h, w)
        return (group_x * weights.sigmoid()).reshape(b, c, h, w)
        
class C3EMA(nn.Module):
    def __init__(self, c1, c2, n=1, shortcut=True, g=1,
                 e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion #iscyy

        super(C3EMA, self).__init__()
        c_ = int(c2 * e)  # hidden channels
        self.ema = EMA(c1)
        self.cv1 = Conv(c1, c_, 1, 1)
        self.cv2 = Conv(c1, c_, 1, 1)
        self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)
        # self.m = nn.Sequential(*[CB2d(c_) for _ in range(n)])
        self.m = nn.Sequential(*[Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])

    def forward(self, x):
        out = torch.cat((self.m(self.cv1(self.ema(x))), self.cv2(x)), dim=1)
        out = self.cv3(out)
        return out
if __name__ == '__main__':
    model = C3EMA(64,64)
    inputs = torch.randn((1, 64, 64, 64))
    print(model(inputs).size())

3.2新建一个yolov5-EMA.yaml文件

注意到,这里博主直接使用C3EMA代替Backbone部分后面两个C3模块(事实上可以替换结构中的任意C3模块 ), 另外注意nc改为自己数据集的类别数

python 复制代码
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license

# Parameters
nc: 4  # 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  output_channel, kernel_size, stride, padding
   [-1, 1, Conv, [128, 3, 2]],  # 1-P2/4
   [-1, 3, C3, [128]],
   [-1, 1, Conv, [256, 3, 2]],  # 3-P3/8
   [-1, 6, C3, [256]],
   [-1, 1, Conv, [512, 3, 2]],  # 5-P4/16
   [-1, 9, C3EMA, [512]],
   [-1, 1, Conv, [1024, 3, 2]],  # 7-P5/32
   [-1, 3, C3EMA, [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, 6], 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, 4], 1, Concat, [1]],  # cat backbone P3
   [-1, 3, C3, [256, False]],  # 17 (P3/8-small)

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

   [-1, 1, Conv, [512, 3, 2]],
   [[-1, 10], 1, Concat, [1]],  # cat head P5
   [-1, 3, C3, [1024, False]],  # 23 (P5/32-large)
  
   [[17, 20, 23], 1, Detect, [nc, anchors]],  # Detect(P3, P4, P5)
  ]

3.3 将C3EMA引入到yolo.py文件中

在下图的红色圈内位置处,引入C3EMA(一共是两处地方),并手动导入相应的包即可。

3.4 修改train.py启动文件

修改配置文件为yolov5-EMA.yaml即可,如下图所示:

4. 总结

本篇博客主要介绍了高效多尺度注意力机制EMA,融合多尺度特征信息,助力YOLOv5模型涨点。另外,在修改过程中,要是有任何问题,评论区交流;如果博客对您有帮助,请帮忙点个赞,收藏一下;后续会持续更新本人实验当中觉得有用的点子,如果很感兴趣的话,可以关注一下,谢谢大家啦!

相关推荐
风象南1 天前
Claude Code这个隐藏技能,让我告别PPT焦虑
人工智能·后端
Mintopia1 天前
OpenClaw 对软件行业产生的影响
人工智能
陈广亮1 天前
构建具有长期记忆的 AI Agent:从设计模式到生产实践
人工智能
会写代码的柯基犬1 天前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia1 天前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区1 天前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两1 天前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
前端付豪1 天前
LangChain记忆:通过Memory记住上次的对话细节
人工智能·python·langchain
strayCat232551 天前
Clawdbot 源码解读 7: 扩展机制
人工智能·开源