多种注意力机制详解及其源码


✨✨ 欢迎大家来访Srlua的博文(づ ̄3 ̄)づ╭❤~✨✨

🌟🌟 欢迎各位亲爱的读者,感谢你们抽出宝贵的时间来阅读我的文章。

我是Srlua小谢,在这里我会分享我的知识和经验。🎥

希望在这里,我们能一起探索IT世界的奥妙,提升我们的技能。🔮

记得先点赞👍后阅读哦~ 👏👏

📘📚 所属专栏:传知代码论文复现

欢迎访问我的主页:Srlua小谢 获取更多信息和资源。✨✨🌙🌙

​​

​​

目录

概述

注意力机制的特点

捕获长距离依赖

并行化处理

重要性的加权

灵活性

解释性

减少参数

促进模型创新

Transformer Attention

Transformer Attention代码

其他注意力机制详解及代码

SENet

ELA

BAM 瓶颈注意力模块

A2Attention 双重注意力

AgentAttention


  本文所有资源均可在该地址处获取。

概述

注意力机制的发展历程体现了人工智能领域对模型表达能力和效率的不断追求。从最初在序列模型中的应用,到Transformer模型的提出,再到当前在各个领域的广泛应用,注意力机制已经成为现代人工智能模型的核心组成部分。随着研究的深入,注意力机制将继续演化,推动人工智能技术的发展。因此提出更好的注意力机制,对于模型性能的提升很有帮助。

注意力机制的特点

注意力机制在人工智能模型中的重要性体现在以下几个方面:

捕获长距离依赖

在传统的序列处理模型中,长距离的元素之间的依赖关系往往难以捕捉。注意力机制通过直接建立远程元素之间的联系,有效地解决了这一问题,这对于翻译、文本摘要等任务尤为重要。

并行化处理

尽管RNN及其变体可以处理序列数据,但它们通常是按顺序处理信息的,这限制了并行处理的能力。而注意力机制可以同时考虑序列中的所有元素,使得模型能够更高效地利用现代计算资源进行并行计算。

重要性的加权

注意力机制允许模型为输入序列的不同部分分配不同的权重,这样可以更加聚焦于对当前任务更为重要的信息,提高了模型处理信息的效率和质量。

灵活性

注意力机制能够以灵活的方式整合到各种模型结构中,不仅限于序列到序列的任务,也可以用于图像识别、语音识别等其他领域。

解释性

注意力权重可以为模型的决策提供一定的解释性,通过观察权重分布,我们可以了解模型在做出预测时关注哪些输入部分,这在某些需要模型可解释性的应用场景中非常重要。

减少参数

在处理长序列时,如果不使用注意力机制,模型可能需要大量的参数来存储长距离的信息。而注意力机制通过动态权重连接不同元素,减少了模型的参数数量。
适应不同类型的注意力:注意力机制可以根据不同的任务需求设计成多种形式,如自注意力(self-attention)、多头注意力(multi-head attention)、全局注意力和局部注意力等,这使得模型能够更好地适应不同的应用场景。

促进模型创新

注意力机制的提出推动了后续一系列研究和新模型的发展,如Transformer、BERT、GPT等,这些模型在自然语言处理、计算机视觉等领域都取得了突破性的成果。

Transformer Attention


MatMul(矩阵乘法):首先对输入数据进行两次矩阵乘法操作,分别得到Q(Query)、K(Key)和V(Value)。这一步是为了从原始数据中提取出查询、键和值向量。
Scale(缩放):由于点积可能会产生很大的数值,为了保持数值稳定性,通常会对点积进行缩放处理。在Scaled Dot-Product Attention中,缩放的因子是1dkdk​​1​,其中dkdk​​是键向量的维度。
SoftMax:经过缩放处理的点积结果会通过一个SoftMax函数转换为概率分布。SoftMax函数确保了所有输出的概率之和为1,从而可以解释为一个有效的注意力权重分布。
Mask(可选,掩码):在某些情况下,可能需要对某些位置的信息进行屏蔽,比如在序列任务中未来的信息不应该影响当前的处理。这时就会用到掩码来设置这些位置的权重为0。
第二次MatMul:最后,将得到的注意力权重与V(Value)向量进行第二次矩阵乘法,以加权求和的方式融合来自不同位置的值信息,得到最终的输出。

Transformer Attention代码

import torch
import torch.nn as nn

x=torch.rand(16,100,768)
model=nn.MultiheadAttention(embed_dim=768,num_heads=4)
print(model(x,x,x))

其他注意力机制详解及代码

SENet


SENet(Squeeze-and-Excitation Networks)通道注意力机制通过显式地建模通道之间的依赖关系来提高网络的表示能力。

class SELayer(nn.Module):
    def __init__(self, channel, reduction=16):
        super(SELayer, self).__init__()
        # 自适应平均池化层,将每个通道的空间维度(H, W)压缩到1x1
        self.avg_pool = nn.AdaptiveAvgPool2d(1)
        # 全连接层序列,包含两个线性变换和中间的ReLU激活函数
        self.fc = nn.Sequential(
            # 第一个线性层,将通道数从 'channel' 缩减到 'channel // reduction'
            nn.Linear(channel, channel // reduction, bias=False),
            # ReLU激活函数,用于引入非线性
            nn.ReLU(inplace=True),
            # 第二个线性层,将通道数从 'channel // reduction' 恢复到 'channel'
            nn.Linear(channel // reduction, channel, bias=False),
            # Sigmoid激活函数,将输出限制在(0, 1)之间
            nn.Sigmoid()
        )
    
    def forward(self, x):
        # 获取输入张量的形状
        b, c, h, w = x.size()
        # Squeeze:通过全局平均池化层,将每个通道的空间维度(H, W)压缩到1x1
        y = self.avg_pool(x).view(b, c)
        # Excitation:通过全连接层序列,对压缩后的特征进行处理
        y = self.fc(y).view(b, c, 1, 1)
        # 通过扩展后的注意力权重 y 调

ELA

import torch
import torch.nn as nn
 
class EfficientLocalizationAttention(nn.Module):
    def __init__(self, channel, kernel_size=7):
        super(EfficientLocalizationAttention, self).__init__()
        self.pad = kernel_size // 2
        self.conv = nn.Conv1d(channel, channel, kernel_size=kernel_size, padding=self.pad, groups=channel, bias=False)
        self.gn = nn.GroupNorm(16, channel)
        self.sigmoid = nn.Sigmoid()
 
    def forward(self, x):
        b, c, h, w = x.size()
 
        # 处理高度维度
        x_h = torch.mean(x, dim=3, keepdim=True).view(b, c, h)
        x_h = self.sigmoid(self.gn(self.conv(x_h))).view(b, c, h, 1)
 
        # 处理宽度维度
        x_w = torch.mean(x, dim=2, keepdim=True).view(b, c, w)
        x_w = self.sigmoid(self.gn(self.conv(x_w))).view(b, c, 1, w)
 
        print(x_h.shape, x_w.shape)
        # 在两个维度上应用注意力
        return x * x_h * x_w

BAM 瓶颈注意力模块


Bottleneck Attention Module(BAM)是一种用于计算机视觉领域的深度学习模型结构,旨在提高神经网络对图像特征提取和感受野处理的能力。BAM模块的核心在于引入了通道注意力机制和空间注意力机制,这两种机制可以自适应地调整特征通道和空间位置的重要性。

# 定义 BAMBlock 模块,结合通道和空间注意力
class BAMBlock(nn.Module):
    def __init__(self, channel=512, reduction=16, dia_val=2):
        super().__init__()
        # 初始化通道注意力和空间注意力模块
        self.ca = ChannelAttention(channel=channel, reduction=reduction)
        self.sa = SpatialAttention(channel=channel, reduction=reduction, dia_val=dia_val)
        self.sigmoid = nn.Sigmoid()  # 使用 Sigmoid 激活函数来计算注意力权重

    def forward(self, x):
        # 输入 x 的形状为 (batch_size, channels, height, width)
        b, c, _, _ = x.size()
        # 计算空间注意力输出
        sa_out = self.sa(x)
        # 计算通道注意力输出
        ca_out = self.ca(x)
        # 将空间和通道注意力相加并通过 Sigmoid 激活函数计算注意力权重
        weight = self.sigmoid(sa_out + ca_out)
        # 结合输入和注意力权重
        out = (1 + weight) * x
        return out

A2Attention 双重注意力


A2Attention模型的核心思想可以概括为两个主要步骤:
特征收集(Feature Gathering):这一步涉及从整个空间中收集关键特征到一个紧凑的集合中。这有助于捕捉输入图像或视频在整个时空空间中的全局特征。
特征分布(Feature Distribution):在收集关键特征之后,模型会自适应地将这些特征分布到每个位置。这样做即使后续的卷积层没有很大的接收域,也能感知整个空间的特征。

class DoubleAttention(nn.Module):

    def __init__(self, in_channels, c_m=128, c_n=128, reconstruct=True):
        super().__init__()
        self.in_channels = in_channels
        self.reconstruct = reconstruct
        self.c_m = c_m
        self.c_n = c_n
        # 定义三个 1x1 的卷积层
        self.convA = nn.Conv2d(in_channels, c_m, 1)  # 用于计算特征 A
        self.convB = nn.Conv2d(in_channels, c_n, 1)  # 用于计算注意力映射 B
        self.convV = nn.Conv2d(in_channels, c_n, 1)  # 用于计算注意力向量 V
        # 如果需要重新构建输出通道数,定义一个 1x1 的卷积层
        if self.reconstruct:
            self.conv_reconstruct = nn.Conv2d(c_m, in_channels, kernel_size=1)

    # 定义前向传播函数
    def forward(self, x):
        # 获取输入的形状
        b, c, h, w = x.shape
        assert c == self.in_channels  # 确保输入的通道数与定义的通道数一致
        A = self.convA(x)  # 特征 A 的形状为 (b, c_m, h, w)
        B = self.convB(x)  # 注意力映射 B 的形状为 (b, c_n, h, w)
        V = self.convV(x)  # 注意力向量 V 的形状为 (b, c_n, h, w)
        # 重塑特征 A 为 (b, c_m, h*w)
        tmpA = A.view(b, self.c_m, -1)
        # 重塑并应用 softmax 到注意力映射 B,得到注意力权重,形状为 (b, c_n, h*w)
        attention_maps = F.softmax(B.view(b, self.c_n, -1), dim=-1)
        # 重塑并应用 softmax 到注意力向量 V,得到注意力权重,形状为 (b, c_n, h*w)
        attention_vectors = F.softmax(V.view(b, self.c_n, -1), dim=-1)
        # 第一步:特征门控
        global_descriptors = torch.bmm(tmpA, attention_maps.permute(0, 2, 1))  # 计算特征 A 与注意力映射 B 的批量矩阵乘法,得到全局描述符,形状为 (b, c_m, c_n)
        # 第二步:特征分布
        tmpZ = global_descriptors.matmul(attention_vectors) # 将全局描述符与注意力向量 V 相乘,得到新的特征映射 Z,形状为 (b, c_m, h*w)
        tmpZ = tmpZ.view(b, self.c_m, h, w)  # 重塑 Z 为 (b, c_m, h, w)

        if self.reconstruct:
            tmpZ = self.conv_reconstruct(tmpZ)
        return tmpZ

AgentAttention

Agent Attention是一种由清华大学研究者提出的新的注意力模型。该模型主要针对视觉Transformer模型在处理视觉任务时遇到的挑战,如分类、分割和检测等。Agent Attention的核心创新在于它整合了Softmax注意力和线性注意力的优势,以解决传统全局自注意力计算量大和效率问题。

模型特点:
传统注意力机制的局限性:传统的Softmax注意力在视觉任务中由于特征数量多,计算复杂度为平方级别,导致计算量过大。而线性注意力虽然降低了计算复杂度到线性级别,但其效果通常不如Softmax注意力。
代理注意力(Agent Attention):为了克服上述问题,Agent Attention在标准的注意力三元组(Q, K, V)基础上引入了一组额外的代理向量A,形成了一种新的四元注意力机制(Q, A, K, V)。这些代理向量A首先作为查询向量Q的代理,从键K和值V中聚合信息,然后将这些信息广播回Q。
效率和表达能力的平衡:通过这种方式,Agent Attention既保留了全局注意力的高表达能力,又通过降低计算复杂度提高了效率。


注:附件包含的即插即用的注意力模块:A2Attention,AgentAttention,BAM,Biformer,CAA,CBAM,ECA,EMA,MCA,MLCA,SENet等

​​

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值