介绍
摘要
我们介绍了BoTNet,这是一个概念简单但功能强大的骨干架构,将自注意力引入多个计算机视觉任务,包括图像分类、物体检测和实例分割。通过仅在ResNet的最后三个瓶颈块中用全局自注意力替换空间卷积,而不进行其他更改,我们的方法在实例分割和物体检测任务上显著提升了基线性能,同时减少了参数,延迟方面的开销也极小。通过设计BoTNet,我们还指出了带自注意力的ResNet瓶颈块可以视为Transformer块。在不增添任何复杂元素的情况下,BoTNet在COCO实例分割基准上使用Mask R-CNN框架实现了44.4%的Mask AP和49.7%的Box AP,超过了以前在COCO验证集上评估的ResNeSt [67]单模型和单尺度结果的最佳水平。最后,我们展示了将BoTNet设计简单地适应图像分类的方法,结果显示模型在ImageNet基准上达到了84.7%的top-1准确率,而在TPU-v3硬件上的“计算”时间比流行的EfficientNet模型快高达1.64倍。我们希望我们简单而有效的方法能成为未来视觉自注意力模型研究的强有力基准。
YOLOv11目标检测创新改进与实战案例专栏
点击查看文章目录: YOLOv11创新改进系列及项目实战目录 包含卷积,主干 注意力,检测头等创新机制 以及 各种目标检测分割项目实战案例
点击查看专栏链接: YOLOv11目标检测创新改进与实战案例
文章链接
论文地址:论文地址
代码地址: 代码地址
基本原理
多头自注意力(Multi-Head Self-Attention)是一种在神经网络,尤其是Transformer架构中常用的机制,它在自然语言处理、计算机视觉等领域取得了显著的效果。多头自注意力的核心思想是通过多个注意力头(attention heads)来捕捉输入数据中不同部分之间的关系,从而提升模型的表示能力。
自注意力机制(Self-Attention)
在解释多头自注意力之前,先了解自注意力机制。自注意力机制的主要步骤如下:
输入向量:假设输入是一组向量,表示为$\mathbf{X} = [x_1, x_2, ..., x_n]$,其中每个$x_i$是一个$d$维向量。
线性变换:对每个输入向量$x_i$进行三个线性变换,生成查询(query)、键(key)和值(value)向量:
$$ q_i = W_q x_i, \quad k_i = W_k x_i, \quad v_i = W_v x_i $$
其中,$W_q, W_k, W_v$是可训练的权重矩阵。计算注意力得分:通过点积来计算查询向量和键向量之间的相似性得分,然后通过softmax函数归一化:
$$ \text{score}_{ij} = \frac{q_i \cdot k_j}{\sqrt{d_k}} $$
其中,$d_k$是键向量的维度。加权求和:使用归一化后的得分对值向量进行加权求和,得到每个输入向量的输出表示:
$$ \text{Attention}(x_i) = \sum_{j=1}^n \text{softmax}(\text{score}_{ij}) v_j $$
多头自注意力(Multi-Head Self-Attention)
多头自注意力机制通过多个注意力头来增强模型的表现力。每个注意力头独立地执行上述的自注意力机制,并最终将这些头的输出进行拼接和线性变换。具体步骤如下:
多头计算:假设有$h$个注意力头,每个头都有独立的查询、键和值的线性变换:
$$ q_i^h = W_q^h x_i, \quad k_i^h = W_k^h x_i, \quad v_i^h = W_v^h x_i $$
每个头都执行自注意力机制,得到输出:
$$ \text{head}_h = \sum_{j=1}^n \text{softmax}\left(\frac{q_i^h \cdot k_j^h}{\sqrt{d_k}}\right) v_j^h $$拼接和线性变换:将所有头的输出拼接在一起,并进行线性变换,得到最终的输出:
$$ \text{MultiHead}(x_i) = W_o [\text{head}_1, \text{head}_2, ..., \text{head}_h] $$
其中,$W_o$是用于将拼接结果映射到输出维度的线性变换矩阵。
核心代码
class MHSA(nn.Module):
def __init__(self, n_dims, width=14, height=14, heads=4):
super(MHSA, self).__init__()
self.heads = heads
self.query = nn.Conv2d(n_dims, n_dims, kernel_size=1)
self.key = nn.Conv2d(n_dims, n_dims, kernel_size=1)
self.value = nn.Conv2d(n_dims, n_dims, kernel_size=1)
self.rel_h = nn.Parameter(torch.randn([1, heads, n_dims // heads, 1, height]), requires_grad=True)
self.rel_w = nn.Parameter(torch.randn([1, heads, n_dims // heads, width, 1]), requires_grad=True)
self.softmax = nn.Softmax(dim=-1)
task与yaml配置
详见:https://blog.csdn.net/shangyanaf/article/details/143107350