以“我喜欢吃苹果“为例,配合代码、参数,解释self-attention机制

学习资料来源:

GPT-Universal Primer

Transformer_哔哩哔哩_bilibili(李宏毅2020机器学习深度学习)

在讨论自注意力(self-attention)机制之前,需要先对序列数据处理有基本认识

什么是序列数据:

序列数据处理指的是处理一系列有序数据的过程。这类数据通常是时间相关的,如文本、音频或时间序列数据。比如在自然语言处理中,句子就是一个序列,每个词都是序列中的一个元素。处理这些数据时,模型需要考虑元素之间的顺序和上下文关系。

在图像处理中,序列数据处理的概念可以扩展到图像的像素或特征图的序列。虽然图像是二维数据(宽度和高度),但处理图像时,可以将每一行像素视为一个序列,或者将图像的特征图(由卷积层生成)视为多个序列:

  1. 像素序列:

    每个图像由许多像素组成,每个像素可以看作是图像中的一个元素。当我们处理图像时,模型可能需要考虑像素的空间位置关系。
  2. 特征图序列:

    在卷积神经网络(CNN)中,特征图是通过卷积层提取的。这些特征图可以看作是图像中不同特征的表示。例如,边缘、纹理或颜色等。
  3. 时序图像:

    在视频处理中,图像序列(帧)可以看作是一个时间序列,每一帧都与前一帧和后一帧相关联。

自注意力在图像中的应用

自注意力机制允许模型在处理图像时,关注不同位置的像素或特征。例如,在计算某个像素的表示时,可以考虑图像中所有其他像素的信息,从而捕获全局上下文。

这在处理复杂图像时非常有效,因为它能够理解长距离依赖关系,比如在理解一个场景时,前景和背景的关系。

先了解自注意力的简单框架:

  1. 输入表示

    将输入数据(如词嵌入或特征图)转换为查询(Query)、键(Key)和值(Value)的表示。下面再结合例子分析这三个是什么东东。
  2. 计算注意力分数

    通过点积计算查询和键的相似度,生成一个注意力分数矩阵。
  3. 归一化注意力分数

    使用Softmax函数将注意力分数转换为权重,使它们总和为1。
  4. 加权求和

    将权重应用于值(Value),得到加权求和的输出。

那么假设我们已经写好了 self_attention函数,它的输入和输出分别是:(下面结合例子具体说明)

# 示例输入
inputs = torch.rand(2, 5, 64)  # (batch_size, seq_len, d_model)
output, attention_weights = self_attention(inputs)

print("Output shape:", output.shape)  #Output形状为 (2, 5, 64)
print("Attention weights shape:", attention_weights.shape)  # Attention weights形状为(2, 5, 5)

以"我喜欢吃苹果"为例解释:

输入解析

句子“我喜欢吃苹果”包含四个词:我、喜欢、吃、苹果。

在代码中输入的则是一个张量(这里省去了从数据库读取的步骤,是随机生成的张量),输入的形状为 (2, 5, 64),这意味着:

  • 2:批次大小(batch size),表示同时处理两个独立的序列。(与举的例子无关,是训练参数)
  • 5:序列长度(sequence length),表示每个序列包含5个元素(例如在这里是5个词)。
  • 64:每个元素的特征维度(d_model),表示每个词或特征由64个数值表示。这些数值通常是通过嵌入层(embedding layer)或卷积层等获得的,捕获了该词的语义信息(即从各个不同的语义角度解释这个词的归属)

这个输入进入函数中会得到什么QKV:

1. 查询(Query)

  • 词:我

  • 目的:希望从句子中获取与“我”相关的信息。可以理解为“我”在句子中所代表的主体。

2. 键(Key)

  • 词:喜欢、吃、苹果

  • 作用:每个词作为键,表示其特征。

3. 值(Value)

  • 词:喜欢、吃、苹果的具体含义

  • 作用:值携带了每个词的信息内容。

当“我”作为查询时,注意力计算过程如下

  1. 相似度计算

    计算“我”与每个键(喜欢、吃、苹果)之间的相似度。(这是通过计算'我'与每个键的64维·64维/根号计算得到的):
    • “我”和“苹果”之间的相关性更低,因为“苹果”是行为的对象。
    • “我”和“吃”之间的相关性可能较低,因为“吃”是描述行为的动词。
    • “我”和“喜欢”之间可能有较高的相关性,因为“我”表达了主体的情感状态。
  2. 归一化权重

    • 通过Softmax函数将相似度分数转换为权重,决定“我”需要关注哪些信息。假设经过计算,“我”与“喜欢”的权重最高,其次是“吃”,最后是“苹果”。
  3. 加权求和

    • 根据权重,将每个词的值进行加权求和。最终得到一个综合表示,强调了与“我”相关的重要信息。这个输出可以理解为一个新的表示,表示“我”在这个句子中的状态和意图。
    • 这个计算得到的就是b1
    • 以句子“我喜欢吃苹果”为例:
  • 如果“我”的原始特征向量是 [0.1, 0.2, ...](64维),经过自注意力机制的处理后,输出可能变成 [0.3, 0.4, ...]
  • 这里的 [0.3, 0.4, ...] 是基于“我”与“喜欢”、“吃”、“苹果”的关系调整后的结果,可能强调了“我”与“喜欢”的情感关联。

实际上,这些计算都是使用矩阵计算,同步进行,最终每个词的64维向量都会被调整 

结果

在代码中的输出(output)依然是一个张量:输出的形状与输入相同,为(2, 5, 64)。其中每个元素的向量都被调整。

同时还输出了attention_weights

  • 这是一个注意力权重矩阵,形状为 (2, 5, 5),表示每个元素(查询)与所有其他元素(键)之间的相似度(归一化后)。

  • 例如,attention_weights[0] 将展示第一个句子中每个词相对于其他词的注意力权重

补充,self-attention与其他机器学习算法的关系:

1. 与传统注意力机制的关系:

  • 传统注意力:通常用于序列到序列模型(如RNN或LSTM),自注意力是其扩展形式,允许模型在输入序列的每个位置直接关注其他位置。
  • 优势:自注意力可以并行处理整个序列,而传统注意力往往依赖于序列的顺序处理,效率较低。

2. 与卷积神经网络(CNN):

  • 特征捕捉:CNN通常用于处理图像,利用局部特征提取。然而,自注意力可以捕捉全局信息,更适合长序列或需要全局上下文的任务。
  • 结合使用:近年来,一些模型结合了自注意力与CNN,以同时获得局部和全局特征。

3. 与循环神经网络(RNN):

  • 序列处理:RNN在处理时间序列或序列数据时表现良好,但在长序列中容易出现梯度消失问题。自注意力通过并行计算和全局依赖性解决了这一问题。
  • 替代方案:在许多现代架构(如Transformer)中,自注意力逐渐取代了RNN。

4. 与生成模型的关系:

  • 生成对抗网络(GAN):自注意力也可以集成到生成模型中,帮助生成更复杂和高质量的样本,例如在图像生成领域。
  • 应用于文本生成:在语言模型(如GPT系列)中,自注意力是核心组成部分,用于生成上下文相关的文本。

5. 与强化学习的关系:

  • 决策过程:自注意力可以用于表示状态的特征,使得智能体在做决策时能够更好地考虑不同因素之间的关系。
  • 增强模型能力:通过自注意力机制,强化学习模型可以更有效地捕捉环境状态之间的依赖。

最终代码:

import torch
import torch.nn.functional as F

class SelfAttention(torch.nn.Module):
    def __init__(self, d_model):
        super(SelfAttention, self).__init__()
        self.d_model = d_model
        self.query_linear = torch.nn.Linear(d_model, d_model)
        self.key_linear = torch.nn.Linear(d_model, d_model)
        self.value_linear = torch.nn.Linear(d_model, d_model)

    def forward(self, x):
        # 计算查询、键和值
        Q = self.query_linear(x)  # (batch_size, seq_len, d_model)
        K = self.key_linear(x)     # (batch_size, seq_len, d_model)
        V = self.value_linear(x)   # (batch_size, seq_len, d_model)

        # 计算相似度
        scores = torch.matmul(Q, K.transpose(-2, -1)) / (self.d_model ** 0.5)  # (batch_size, seq_len, seq_len)

        # 归一化权重
        attention_weights = F.softmax(scores, dim=-1)  # (batch_size, seq_len, seq_len)

        # 加权求和
        output = torch.matmul(attention_weights, V)  # (batch_size, seq_len, d_model)

        return output, attention_weights

# 示例输入
inputs = torch.rand(2, 5, 64)  # (batch_size, seq_len, d_model)

# 创建自注意力模型
self_attention = SelfAttention(d_model=64)

# 计算输出和注意力权重
output, attention_weights = self_attention(inputs)

# 输出结果
print("Output shape:", output.shape)  # 应该是 (2, 5, 64)
print("Attention weights shape:", attention_weights.shape)  # 应该是 (2, 5, 5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值