• YOLOv9改进策略 | 添加注意力篇 | TripletAttention三重注意力机制(附代码+机制原理+添加教程)


     一、本文介绍

    本文给大家带来的改进是Triplet Attention三重注意力机制。这个机制,它通过三个不同的视角来分析输入的数据,就好比三个人从不同的角度来观察同一幅画,然后共同决定哪些部分最值得注意。三重注意力机制的主要思想是在网络中引入了一种新的注意力模块,这个模块包含三个分支,分别关注图像的不同维度。比如说,一个分支可能专注于图像的宽度,另一个分支专注于高度,第三个分支则聚焦于图像的深度,即色彩和纹理等特征。这样一来,网络就能够更全面地理解图像内容,就像是得到了一副三维眼镜,能够看到图片的立体效果一样。

    专栏地址:YOLOv9有效涨点专栏-持续复现各种顶会内容-有效涨点-全网改进最全的专栏 

    目录

     一、本文介绍

    二、Triplet Attention机制原理

    2.1 Triplet Attention的基本原理 

    2.2 Triplet Attention和其它简单注意力机制的对比 

    2.3 Triplet Attention的实现流程

    三、Triplet Attention的核心代码

    四、手把手教你添加Triplet Attention

    4.1 细节修改教程

    4.1.1 修改一

    ​4.1.2 修改二

    4.1.3 修改三 

    4.1.4 修改四

    4.2 Triplet Attention的yaml文件

    4.2.1 Triplet Attention的yaml文件一

    4.2.2 Triplet Attention的yaml文件二

    4.3 Triplet Attention运行成功截图

    五、本文总结 


    二、Triplet Attention机制原理

    论文地址:官方论文地址

    代码地址:官方代码地址


    2.1 Triplet Attention的基本原理 

    三重注意力(Triplet Attention)的基本原理是利用三支结构捕获输入数据的跨维度交互,从而计算注意力权重。这个方法能够构建输入通道或空间位置之间的相互依赖性,而且计算代价小。三重注意力由三个分支组成,每个分支负责捕获空间维度H或W与通道维度C之间的交互特征。通过对每个分支中的输入张量进行排列变换,然后通过Z池操作和一个大小为k×k的卷积层,生成注意力权重。这些权重是通过一个S形激活层生成的,然后应用于排列变换后的输入张量,再变换回原来的输入形状 

    三重注意力(Triplet Attention)的主要改进点包括:

    1. 跨维度的注意力权重计算: 通过一个创新的三支结构捕获通道、高度、宽度三个维度之间的交互关系来计算注意力权重。

    2. 旋转操作和残差变换: 通过旋转输入张量和应用残差变换来建立不同维度间的依赖,这是三重注意力机制中的关键步骤。

    3. 维度间依赖性的重要性: 强调在计算注意力权重时,捕获跨维度依赖性的重要性,这是三重注意力的核心直觉和设计理念。

    下面的图片是三重注意力的一个抽象表示图,展示了三个分支如何捕获跨维度交互。图中的每个子图表示三重注意力中的一个分支: 

    1. 分支(a): 这个分支直接处理输入张量,没有进行旋转,然后通过残差变换来提取特征。

    2. 分支(b): 这个分支首先沿着宽度(W)和通道(C)的维度旋转输入张量,然后进行残差变换。

    3. 分支(c): 这个分支沿着高度(H)和通道(C)的维度旋转输入张量,之后同样进行残差变换。

    总结:通过这样的设计,三重注意力模型能够有效地捕获输入张量中的空间和通道维度之间的交互关系。这种方法使模型能够构建通道与空间位置之间的相互依赖性,提高模型对特征的理解能力。


    2.2 Triplet Attention和其它简单注意力机制的对比 

    下面的图片是论文中三重注意力机制和其它注意力机制的一个对比大家有兴趣可以看看,横向扩展以下自己的知识库。

    这张图片是一幅对比不同注意力模块的图示,其中包括:

    1.Squeeze Excitation (SE) Module:
    这个模块使用全局平均池化 (Global Avg Pool) 生成通道描述符,接着通过两个全连接层(1x1 Conv),中间使用ReLU激活函数,最后通过Sigmoid函数生成每个通道的权重。

    2. Convolutional Block Attention Module (CBAM):
    首先使用全局平均池化和全局最大池化(GAP + GMP)结合,再通过一个卷积层和ReLU激活函数,最后经过另一个卷积层和Sigmoid函数生成注意力权重。

    3. Global Context (GC) Module:
    从一个1x1卷积层开始,经过Softmax函数进行归一化,接着进行另一个1x1卷积,然后使用LayerNorm和最终的1x1卷积,通过广播加法结合原始特征图。

    4. Triplet Attention (我们的方法):
    分为三个分支,每个分支进行不同的处理:通道池化后的7x7卷积,Z池化,再接一个7x7卷积,然后是批量归一化和Sigmoid函数。每个分支都有一个Permute操作来调整维度。最后,三个分支的结果通过平均池化聚合起来生成最终的注意力权重。

    每种模块都设计用于处理特征图(C x H x W),其中C是通道数,H是高度,W是宽度。这些模块通过不同方式计算注意力权重,增强网络对特征的重要部分的关注度,从而在各种视觉任务中提高性能。图片中的符号⊗代表矩阵乘法,⊕代表广播元素级加法。


    2.3 Triplet Attention的实现流程

    下面的图片是三重注意力(Triplet Attention)的具体实现流程图。图中详细展示了三个分支如何处理输入张量,并最终合成三重注意力。下面是对这个过程的描述: 

    1. 上部分支: 负责计算通道维度C和空间维度W的注意力权重。这个分支对输入张量进行Z池化(Z-Pool)操作,然后通过一个卷积层(Conv),接着用Sigmoid函数生成注意力权重。

    2. 中部分支: 负责捕获通道维度C与空间维度H和W之间的依赖性。这个分支首先进行相同的Z池化和卷积操作,然后同样通过Sigmoid函数生成注意力权重。

    3. 下部分支: 用于捕获空间维度之间的依赖性。这个分支保持输入的身份(Identity,即不改变输入),执行Z池化和卷积操作,之后也通过Sigmoid函数生成注意力权重。

    每个分支在生成注意力权重后,会对输入进行排列(Permutation),然后将三个分支的输出进行平均聚合(Avg),最终得到三重注意力输出。

    这种结构通过不同的旋转和排列操作,能够综合不同维度上的信息,更好地捕获数据的内在特征,同时这种方法在计算上是高效的,并且可以作为一个模块加入到现有的网络架构中,增强网络对复杂数据结构的理解和处理能力。


    三、Triplet Attention的核心代码

    使用方式看章节四!

    1. import torch
    2. import torch.nn as nn
    3. __all__ = ['TripletAttention']
    4. def autopad(k, p=None, d=1): # kernel, padding, dilation
    5. # Pad to 'same' shape outputs
    6. if d > 1:
    7. k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size
    8. if p is None:
    9. p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
    10. return p
    11. class Conv(nn.Module):
    12. # Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)
    13. default_act = nn.SiLU() # default activation
    14. def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
    15. super().__init__()
    16. self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
    17. self.bn = nn.BatchNorm2d(c2)
    18. self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
    19. def forward(self, x):
    20. return self.act(self.bn(self.conv(x)))
    21. def forward_fuse(self, x):
    22. return self.act(self.conv(x))
    23. class BasicConv(nn.Module):
    24. def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1, relu=True,
    25. bn=True, bias=False):
    26. super(BasicConv, self).__init__()
    27. self.out_channels = out_planes
    28. self.conv = nn.Conv2d(in_planes, out_planes, kernel_size=kernel_size, stride=stride, padding=padding,
    29. dilation=dilation, groups=groups, bias=bias)
    30. self.bn = nn.BatchNorm2d(out_planes, eps=1e-5, momentum=0.01, affine=True) if bn else None
    31. self.relu = nn.ReLU() if relu else None
    32. def forward(self, x):
    33. x = self.conv(x)
    34. if self.bn is not None:
    35. x = self.bn(x)
    36. if self.relu is not None:
    37. x = self.relu(x)
    38. return x
    39. class ZPool(nn.Module):
    40. def forward(self, x):
    41. return torch.cat((torch.max(x, 1)[0].unsqueeze(1), torch.mean(x, 1).unsqueeze(1)), dim=1)
    42. class AttentionGate(nn.Module):
    43. def __init__(self):
    44. super(AttentionGate, self).__init__()
    45. kernel_size = 7
    46. self.compress = ZPool()
    47. self.conv = BasicConv(2, 1, kernel_size, stride=1, padding=(kernel_size - 1) // 2, relu=False)
    48. def forward(self, x):
    49. x_compress = self.compress(x)
    50. x_out = self.conv(x_compress)
    51. scale = torch.sigmoid_(x_out)
    52. return x * scale
    53. class TripletAttention(nn.Module):
    54. def __init__(self, no_spatial=False):
    55. super(TripletAttention, self).__init__()
    56. self.cw = AttentionGate()
    57. self.hc = AttentionGate()
    58. self.no_spatial = no_spatial
    59. if not no_spatial:
    60. self.hw = AttentionGate()
    61. def forward(self, x):
    62. x_perm1 = x.permute(0, 2, 1, 3).contiguous()
    63. x_out1 = self.cw(x_perm1)
    64. x_out11 = x_out1.permute(0, 2, 1, 3).contiguous()
    65. x_perm2 = x.permute(0, 3, 2, 1).contiguous()
    66. x_out2 = self.hc(x_perm2)
    67. x_out21 = x_out2.permute(0, 3, 2, 1).contiguous()
    68. if not self.no_spatial:
    69. x_out = self.hw(x)
    70. x_out = 1 / 3 * (x_out + x_out11 + x_out21)
    71. else:
    72. x_out = 1 / 2 * (x_out11 + x_out21)
    73. return x_out


    四、手把手教你添加Triplet Attention

    4.1 细节修改教程

    4.1.1 修改一

    我们找到如下的目录'yolov9-main/models'在这个目录下创建一个文件目录(注意是目录,因为我这个专栏会出很多的更新,这里用一种一劳永逸的方法)文件目录起名modules,然后在下面新建一个文件,将我们的代码复制粘贴进去。


    ​4.1.2 修改二

    然后新建一个__init__.py文件,然后我们在里面添加一行代码。注意标记一个'.'其作用是标记当前目录。


    4.1.3 修改三 

    然后我们找到如下文件''models/yolo.py''在开头的地方导入我们的模块按照如下修改->

    (如果你看了我多个改进机制此处只需要添加一个即可,无需重复添加)

    ​​​​


    4.1.4 修改四

    然后我们找到parse_model方法,按照如下修改->

    1. elif m in {TripletAttention}:
    2. c2 = ch[f]
    3. args = [c2, *args]

    到此就修改完成了,复制下面的ymal文件即可运行。


    4.2 Triplet Attention的yaml文件

    4.2.1 Triplet Attention的yaml文件一

    下面的配置文件为我修改的Triplet Attention的位置,参数的位置里面什么都不用添加空着就行,大家复制粘贴我的就可以运行,同时我提供多个版本给大家,根据我的经验可能涨点的位置。

    1. # YOLOv9
    2. # parameters
    3. nc: 80 # number of classes
    4. depth_multiple: 1 # model depth multiple
    5. width_multiple: 1 # layer channel multiple
    6. #activation: nn.LeakyReLU(0.1)
    7. #activation: nn.ReLU()
    8. # anchors
    9. anchors: 3
    10. # YOLOv9 backbone
    11. backbone:
    12. [
    13. [-1, 1, Silence, []],
    14. # conv down
    15. [-1, 1, Conv, [64, 3, 2]], # 1-P1/2
    16. # conv down
    17. [-1, 1, Conv, [128, 3, 2]], # 2-P2/4
    18. # elan-1 block
    19. [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 3
    20. # conv down
    21. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
    22. # elan-2 block
    23. [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 5
    24. # conv down
    25. [-1, 1, Conv, [512, 3, 2]], # 6-P4/16
    26. # elan-2 block
    27. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 7
    28. # conv down
    29. [-1, 1, Conv, [512, 3, 2]], # 8-P5/32
    30. # elan-2 block
    31. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 9
    32. ]
    33. # YOLOv9 head
    34. head:
    35. [
    36. [-1, 1, TripletAttention, []], # 添加一行我们的改进机制
    37. # elan-spp block
    38. [-1, 1, SPPELAN, [512, 256]], # 11
    39. # up-concat merge
    40. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
    41. [[-1, 7], 1, Concat, [1]], # cat backbone P4
    42. # elan-2 block
    43. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 14
    44. # up-concat merge
    45. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
    46. [[-1, 5], 1, Concat, [1]], # cat backbone P3
    47. # elan-2 block
    48. [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 17 (P3/8-small)
    49. # conv-down merge
    50. [-1, 1, Conv, [256, 3, 2]],
    51. [[-1, 14], 1, Concat, [1]], # cat head P4
    52. # elan-2 block
    53. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 20 (P4/16-medium)
    54. # conv-down merge
    55. [-1, 1, Conv, [512, 3, 2]],
    56. [[-1, 11], 1, Concat, [1]], # cat head P5
    57. # elan-2 block
    58. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 23 (P5/32-large)
    59. # routing
    60. [5, 1, CBLinear, [[256]]], # 24
    61. [7, 1, CBLinear, [[256, 512]]], # 25
    62. [9, 1, CBLinear, [[256, 512, 512]]], # 26
    63. # conv down
    64. [0, 1, Conv, [64, 3, 2]], # 27-P1/2
    65. # conv down
    66. [-1, 1, Conv, [128, 3, 2]], # 28-P2/4
    67. # elan-1 block
    68. [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 29
    69. # conv down fuse
    70. [-1, 1, Conv, [256, 3, 2]], # 30-P3/8
    71. [[24, 25, 26, -1], 1, CBFuse, [[0, 0, 0]]], # 31
    72. # elan-2 block
    73. [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 32
    74. # conv down fuse
    75. [-1, 1, Conv, [512, 3, 2]], # 33-P4/16
    76. [[25, 26, -1], 1, CBFuse, [[1, 1]]], # 34
    77. # elan-2 block
    78. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 35
    79. # conv down fuse
    80. [-1, 1, Conv, [512, 3, 2]], # 36-P5/32
    81. [[26, -1], 1, CBFuse, [[2]]], # 37
    82. # elan-2 block
    83. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 38
    84. # detect
    85. [[32, 35, 38, 17, 20, 23], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5)
    86. ]


    4.2.2 Triplet Attention的yaml文件二

    1. # YOLOv9
    2. # parameters
    3. nc: 80 # number of classes
    4. depth_multiple: 1 # model depth multiple
    5. width_multiple: 1 # layer channel multiple
    6. #activation: nn.LeakyReLU(0.1)
    7. #activation: nn.ReLU()
    8. # anchors
    9. anchors: 3
    10. # YOLOv9 backbone
    11. backbone:
    12. [
    13. [-1, 1, Silence, []],
    14. # conv down
    15. [-1, 1, Conv, [64, 3, 2]], # 1-P1/2
    16. # conv down
    17. [-1, 1, Conv, [128, 3, 2]], # 2-P2/4
    18. # elan-1 block
    19. [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 3
    20. # conv down
    21. [-1, 1, Conv, [256, 3, 2]], # 4-P3/8
    22. # elan-2 block
    23. [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 5
    24. # conv down
    25. [-1, 1, Conv, [512, 3, 2]], # 6-P4/16
    26. # elan-2 block
    27. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 7
    28. # conv down
    29. [-1, 1, Conv, [512, 3, 2]], # 8-P5/32
    30. # elan-2 block
    31. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 9
    32. ]
    33. # YOLOv9 head
    34. head:
    35. [
    36. # elan-spp block
    37. [-1, 1, SPPELAN, [512, 256]], # 10
    38. # up-concat merge
    39. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
    40. [[-1, 7], 1, Concat, [1]], # cat backbone P4
    41. # elan-2 block
    42. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 13
    43. # up-concat merge
    44. [-1, 1, nn.Upsample, [None, 2, 'nearest']],
    45. [[-1, 5], 1, Concat, [1]], # cat backbone P3
    46. # elan-2 block
    47. [-1, 1, RepNCSPELAN4, [256, 256, 128, 1]], # 16 (P3/8-small)
    48. [-1, 1, TripletAttention, []], # 17 添加一行我们的改进机制
    49. # conv-down merge
    50. [-1, 1, Conv, [256, 3, 2]],
    51. [[-1, 13], 1, Concat, [1]], # cat head P4
    52. # elan-2 block
    53. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 20 (P4/16-medium)
    54. [-1, 1, TripletAttention, []], # 21 添加一行我们的改进机制
    55. # conv-down merge
    56. [-1, 1, Conv, [512, 3, 2]],
    57. [[-1, 10], 1, Concat, [1]], # cat head P5
    58. # elan-2 block
    59. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 24 (P5/32-large)
    60. [-1, 1, TripletAttention, []], # 25 添加一行我们的改进机制
    61. # routing
    62. [5, 1, CBLinear, [[256]]], # 26
    63. [7, 1, CBLinear, [[256, 512]]], # 27
    64. [9, 1, CBLinear, [[256, 512, 512]]], # 28
    65. # conv down
    66. [0, 1, Conv, [64, 3, 2]], # 29-P1/2
    67. # conv down
    68. [-1, 1, Conv, [128, 3, 2]], # 30-P2/4
    69. # elan-1 block
    70. [-1, 1, RepNCSPELAN4, [256, 128, 64, 1]], # 31
    71. # conv down fuse
    72. [-1, 1, Conv, [256, 3, 2]], # 32-P3/8
    73. [[26, 27, 28, -1], 1, CBFuse, [[0, 0, 0]]], # 33
    74. # elan-2 block
    75. [-1, 1, RepNCSPELAN4, [512, 256, 128, 1]], # 34
    76. [-1, 1, TripletAttention, []], # 35 添加一行我们的改进机制
    77. # conv down fuse
    78. [-1, 1, Conv, [512, 3, 2]], # 36-P4/16
    79. [[27, 28, -1], 1, CBFuse, [[1, 1]]], # 37
    80. # elan-2 block
    81. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 38
    82. [-1, 1, TripletAttention, []], # 39 添加一行我们的改进机制
    83. # conv down fuse
    84. [-1, 1, Conv, [512, 3, 2]], # 40-P5/32
    85. [[28, -1], 1, CBFuse, [[2]]], # 41
    86. # elan-2 block
    87. [-1, 1, RepNCSPELAN4, [512, 512, 256, 1]], # 42
    88. [-1, 1, TripletAttention, []], # 43 添加一行我们的改进机制
    89. # detect
    90. [[35, 39, 43, 17, 21, 25], 1, DualDDetect, [nc]], # DualDDetect(A3, A4, A5, P3, P4, P5)
    91. ]

    4.3 Triplet Attention运行成功截图

    附上我的运行记录确保我的教程是可用的。 


    五、本文总结 

    到此本文的正式分享内容就结束了,在这里给大家推荐我的YOLOv9改进有效涨点专栏,本专栏目前为新开的平均质量分98分,后期我会根据各种最新的前沿顶会进行论文复现,也会对一些老的改进机制进行补充,目前本专栏免费阅读(暂时,大家尽早关注不迷路~),如果大家觉得本文帮助到你了,订阅本专栏,关注后续更多的更新~

    专栏地址:YOLOv9有效涨点专栏-持续复现各种顶会内容-有效涨点-全网改进最全的专栏 

  • 相关阅读:
    LLM学习之自然语言处理简单叙述
    Echarts社区开源地址
    【计算机网络微课堂】5.6 TCP超时重传时间的选择
    《深入浅出.NET框架设计与实现》笔记6.4——ASP.NET Core应用程序多种运行模式之四——服务承载
    修改switch Nand无线区码 以支持高频5G 信道
    Ubuntu 20.04编译GPMP2过程记录
    【ACM程序设计】动态规划 第二篇 LCS&LIS问题
    六零导航页(LyLme Spage)导航网站源码
    C++ Qt 学习(十):Qt 其他技巧
    Instagram 为何从内容共享平台变成营销工具?独立站卖家如何利用该工具?
  • 原文地址:https://blog.csdn.net/java1314777/article/details/138169566