【YOLOv8改进】ACmix(Mixed Self-Attention and Convolution) (论文笔记+引入代码)
YOLO目标检测创新改进与实战案例专栏
专栏目录: YOLO有效改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
专栏链接: YOLO基础解析+创新改进+实战案例
摘要
卷积和自注意力是两个强大的表示学习技术,通常被认为是彼此独立的两种同级方法。在本文中,我们展示了它们之间存在一种强有力的内在联系,从计算的角度来看,这两种范式的主要计算实际上是通过相同的操作完成的。具体来说,我们首先展示了传统的k×k卷积可以分解为k^2个1×1卷积,再加上位移和求和操作。然后,我们将自注意力模块中查询、键和值的投影解释为多个1×1卷积,再计算注意力权重并聚合值。因此,这两个模块的第一阶段包含了相似的操作。更重要的是,与第二阶段相比,第一阶段在计算复杂度上占据主导地位(通道数的平方)。这一观察自然引出了这两种看似不同的范式的优雅整合,即一种混合模型,它同时享有自注意力和卷积的优势(ACmix),并且相比纯卷积或自注意力方法具有最低的计算开销。大量实验表明,我们的模型在图像识别和下游任务中相较于竞争性基线始终取得了更好的结果。代码和预训练模型将发布在 https://github.com/Panxuran/ACmix 和 https://gitee.com/mindspore/models。
创新点
-
发现共同操作:ACmix揭示了自注意力和卷积之间存在强烈的基础关系,指出它们的大部分计算实际上使用相同的操作。通过将传统卷积分解为多个1×1卷积,并将自注意力模块中的查询、键和值的投影解释为多个1×1卷积,ACmix发现了这两种技术之间的共同操作。
-
阶段性计算复杂度:ACmix强调了自注意力和卷积模块中第一阶段的计算复杂度较高,这一观察自然地导致了这两种看似不同范式的优雅整合。通过最小化计算开销,ACmix实现了自注意力和卷积的有效融合。
-
轻量级移位和聚合:为了提高效率,ACmix采用深度卷积替代低效的张量移位操作,实现了轻量级的移位操作。这种创新的方法改善了模型的实际效率,同时保持了数据的局部性。
-
模块化设计:ACmix采用了模块化的设计,将自注意力和卷积技术结合在一起,同时保持了模块之间的独立性。这种设计使得ACmix能够充分利用两种技术的优势,同时避免了昂贵的重复投影操作。
yolov8 引入
class ACmix(nn.Module):
def __init__(self, in_planes, out_planes, kernel_att=7, head=4, kernel_conv=3, stride=1, dilation=1):
super(ACmix, self).__init__()
self.in_planes = in_planes
self.out_planes = out_planes
self.head = head
self.kernel_att = kernel_att
self.kernel_conv = kernel_conv
self.stride = stride
self.dilation = dilation
self.rate1 = torch.nn.Parameter(torch.Tensor(1))
self.rate2 = torch.nn.Parameter(torch.Tensor(1))
self.head_dim = self.out_planes // self.head
# 定义三个 1x1 卷积层,用于生成查询、键、值
self.conv1 = nn.Conv2d(in_planes, out_planes, kernel_size=1)
self.conv2 = nn.Conv2d(in_planes, out_planes, kernel_size=1)
self.conv3 = nn.Conv2d(in_planes, out_planes, kernel_size=1)
self.conv_p = nn.Conv2d(2, self.head_dim, kernel_size=1)
self.padding_att = (self.dilation * (self.kernel_att - 1) + 1) // 2
self.pad_att = torch.nn.ReflectionPad2d(self.padding_att)
self.unfold = nn.Unfold(kernel_size=self.kernel_att, padding=0, stride=self.stride)
self.softmax = torch.nn.Softmax(dim=1)
# 定义全连接层和深度卷积层
self.fc = nn.Conv2d(3*self.head, self.kernel_conv * self.kernel_conv, kernel_size=1, bias=False)
self.dep_conv = nn.Conv2d(self.kernel_conv * self.kernel_conv * self.head_dim, out_planes, kernel_size=self.kernel_conv, bias=True, groups=self.head_dim, padding=1, stride=stride)
self.reset_parameters()
def reset_parameters(self):
# 初始化参数
init_rate_half(self.rate1)
init_rate_half(self.rate2)
kernel = torch.zeros(self.kernel_conv * self.kernel_conv, self.kernel_conv, self.kernel_conv)
for i in range(self.kernel_conv * self.kernel_conv):
kernel[i, i//self.kernel_conv, i%self.kernel_conv] = 1.
kernel = kernel.squeeze(0).repeat(self.out_planes, 1, 1, 1)
self.dep_conv.weight = nn.Parameter(data=kernel, requires_grad=True)
self.dep_conv.bias = init_rate_0(self.dep_conv.bias)
task与yaml配置
详见:https://blog.csdn.net/shangyanaf/article/details/139167656