首页 > 编程语言 >【AI中数学-线代-综合实例-包括python实现】 聚焦注意力:解析GPT等大模型中的注意力机制

【AI中数学-线代-综合实例-包括python实现】 聚焦注意力:解析GPT等大模型中的注意力机制

时间:2025-01-12 21:32:42浏览次数:3  
标签:dim AI self torch python hidden 注意力 size

第三章 线性代数--综合实例

第11节 聚焦注意力:解析GPT等大模型中的注意力机制

在人工智能的众多技术中,注意力机制(Attention Mechanism)无疑是推动大规模模型如GPT(Generative Pre-trained Transformer)取得突破性进展的关键因素之一。本节将通过五个实际应用案例,深入解析注意力机制在不同AI任务中的应用与实现,涵盖案例描述、分析、算法步骤以及配套的Python代码示例。


案例一:机器翻译中的自注意力机制

1. 案例描述

机器翻译是自然语言处理(NLP)中的核心任务之一,旨在将一种语言的文本自动翻译为另一种语言。传统的序列到序列(Seq2Seq)模型在翻译过程中容易遇到长距离依赖问题,难以有效捕捉源语言与目标语言之间复杂的对应关系。自注意力机制的引入显著提升了翻译质量,使得模型能够在翻译过程中更好地理解上下文。

2. 案例分析

自注意力机制允许模型在处理每个词时,关注输入序列中所有位置的词,从而捕捉全局依赖关系。以Transformer模型为代表的架构,通过多头自注意力(Multi-Head Self-Attention)实现了这一点,极大地提高了翻译的准确性和效率。

3. 案例算法步骤
  1. 输入编码:将源语言句子转换为词向量表示。
  2. 位置编码:加入位置信息以保留词序。
  3. 多头自注意力计算
    • 计算查询(Q)、键(K)、值(V)向量。
    • 计算注意力权重:Attention(Q, K, V) = softmax(QK^T / √d_k) VAttention(Q, K, V) = Softmax(\frac{QK^\top}{\sqrt{d_{k}}})V
    • 多头并行计算并拼接结果。
  4. 前馈神经网络:对注意力输出进行非线性变换。
  5. 输出生成:通过解码器生成目标语言句子。
4. 案例对应Python代码及详解

以下示例展示了如何使用PyTorch实现一个简化的自注意力机制,用于机器翻译任务。

import torch
import torch.nn as nn
import torch.nn.functional as F

class SelfAttention(nn.Module):
    def __init__(self, embed_size, heads):
        super(SelfAttention, self).__init__()
        self.embed_size = embed_size
        self.heads = heads
        self.head_dim = embed_size // heads

        assert (
            self.head_dim * heads == embed_size
        ), "Embedding size needs to be divisible by heads"

        # 定义线性变换层
        self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.fc_out = nn.Linear(heads * self.head_dim, embed_size)

    def forward(self, values, keys, queries, mask):
        N, seq_length, embed_size = queries.shape

        # 将嵌入分成多头
        values = values.reshape(N, seq_length, self.heads, self.head_dim)
        keys = keys.reshape(N, seq_length, self.heads, self.head_dim)
        queries = queries.reshape(N, seq_length, self.heads, self.head_dim)

        # 线性变换
        values = self.values(values)
        keys = self.keys(keys)
        queries = self.queries(queries)

        # 计算注意力分数
        energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys])

        if mask is not None:
            energy = energy.masked_fill(mask == 0, float("-1e20"))

        attention = torch.softmax(energy / (self.embed_size ** (1 / 2)), dim=3)

        out = torch.einsum("nhql,nlhd->nqhd", [attention, values]).reshape(
            N, seq_length, self.heads * self.head_dim
        )

        # 最终线性变换
        out = self.fc_out(out)
        return out

# 示例用法
embed_size = 256
heads = 8
self_attention = SelfAttention(embed_size, heads)

# 假设输入序列长度为10,批大小为2
queries = torch.rand((2, 10, embed_size))
keys = torch.rand((2, 10, embed_size))
values = torch.rand((2, 10, embed_size))
mask = None  # 这里不使用掩码

output = self_attention(values, keys, queries, mask)
print(output.shape)  # 输出: torch.Size([2, 10, 256])

代码详解

  • SelfAttention类:实现了多头自注意力机制。

    • __init__方法中定义了线性变换层,用于生成查询、键、值向量。
    • forward方法中:
      • 将输入的嵌入向量分成多个头。
      • 对每个头进行线性变换。
      • 计算注意力权重,并应用于值向量。
      • 将所有头的输出拼接,并通过最终的线性层生成输出。
  • 示例用法:创建一个SelfAttention实例,并对随机生成的查询、键、值进行前向传播,输出结果的形状为[批大小, 序列长度, 嵌入维度]


案例二:文本摘要中的注意力机制

1. 案例描述

文本摘要任务旨在从长文本中提取关键信息,生成简明扼要的摘要。注意力机制在文本摘要中帮助模型聚焦于输入文本的关键部分,提高摘要的质量和相关性。

2. 案例分析

在文本摘要中,注意力机制使得解码器能够在生成每个摘要词时,动态地关注源文本的不同部分。这种动态聚焦能力有效地捕捉了源文本中的关键信息,从而生成连贯且信息丰富的摘要。

3. 案例算法步骤
  1. 输入编码:将源文本转换为词向量,并通过编码器生成上下文表示。
  2. 位置编码:为词向量加入位置信息。
  3. 注意力机制
    • 解码器在生成每个词时,计算对编码器输出的注意力权重。
    • 根据注意力权重加权汇总编码器输出,作为当前生成词的上下文向量。
  4. 词生成:通过解码器的前馈网络和softmax层生成摘要词。
4. 案例对应Python代码及详解

以下示例展示了如何使用PyTorch实现一个简化的注意力机制,用于文本摘要任务。

import torch
import torch.nn as nn
import torch.nn.functional as F

class Attention(nn.Module):
    def __init__(self, encoder_hidden_dim, decoder_hidden_dim):
        super(Attention, self).__init__()
        self.attn = nn.Linear((encoder_hidden_dim + decoder_hidden_dim), decoder_hidden_dim)
        self.v = nn.Linear(decoder_hidden_dim, 1, bias=False)

    def forward(self, hidden, encoder_outputs, mask):
        # hidden: [batch_size, decoder_hidden_dim]
        # encoder_outputs: [batch_size, src_len, encoder_hidden_dim]
        
        batch_size = encoder_outputs.shape[0]
        src_len = encoder_outputs.shape[1]
        
        # 重复隐藏状态以匹配源序列长度
        hidden = hidden.unsqueeze(1).repeat(1, src_len, 1)  # [batch_size, src_len, decoder_hidden_dim]
        
        # 连接隐藏状态与编码器输出
        energy = torch.tanh(self.attn(torch.cat((hidden, encoder_outputs), dim=2)))  # [batch_size, src_len, decoder_hidden_dim]
        
        # 计算注意力得分
        attention = self.v(energy).squeeze(2)  # [batch_size, src_len]
        
        # 应用掩码
        if mask is not None:
            attention = attention.masked_fill(mask == 0, -1e10)
        
        return F.softmax(attention, dim=1)  # [batch_size, src_len]

# 示例用法
batch_size = 2
src_len = 10
encoder_hidden_dim = 256
decoder_hidden_dim = 256

attention = Attention(encoder_hidden_dim, decoder_hidden_dim)
hidden = torch.rand((batch_size, decoder_hidden_dim))
encoder_outputs = torch.rand((batch_size, src_len, encoder_hidden_dim))
mask = torch.ones((batch_size, src_len))  # 假设没有填充

attn_weights = attention(hidden, encoder_outputs, mask)
print(attn_weights.shape)  # 输出: torch.Size([2, 10])

代码详解

  • Attention类:实现了一个基于加性注意力的机制。

    • __init__方法中定义了用于计算注意力得分的线性层。
    • forward方法中:
      • 将解码器的隐藏状态与编码器的输出进行拼接。
      • 通过非线性激活函数(tanh)生成能量分数。
      • 计算注意力权重,并应用掩码防止关注填充部分。
  • 示例用法:创建一个Attention实例,并对随机生成的隐藏状态和编码器输出进行前向传播,输出注意力权重的形状为[批大小, 源序列长度]


案例三:问答系统中的双向注意力

1. 案例描述

问答系统旨在根据用户提出的问题,从给定的文本中找到准确的答案。双向注意力机制(Bi-Attention)在此任务中起到了关键作用,通过同时关注问题和上下文,提高了系统的理解和回答能力。

2. 案例分析

双向注意力机制使得模型能够在问题和上下文之间建立相互关联,增强了对相关信息的捕捉能力。在问答系统中,模型需要理解问题的意图,并在上下文中找到对应的答案,双向注意力提供了有效的方式来实现这一目标。

3. 案例算法步骤
  1. 输入编码:将问题和上下文分别编码为词向量表示。
  2. 位置编码:为问题和上下文词向量加入位置信息。
  3. 双向注意力计算
    • 问题对上下文的注意力:计算上下文中每个词对问题的关注程度。
    • 上下文对问题的注意力:计算问题中每个词对上下文的关注程度。
  4. 特征融合:结合双向注意力的输出,生成更丰富的特征表示。
  5. 答案预测:通过前馈网络和softmax层预测答案的位置或内容。
4. 案例对应Python代码及详解

以下示例展示了如何使用PyTorch实现一个简化的双向注意力机制,用于问答系统任务。

import torch
import torch.nn as nn
import torch.nn.functional as F

class BiAttention(nn.Module):
    def __init__(self, hidden_dim):
        super(BiAttention, self).__init__()
        self.hidden_dim = hidden_dim

    def forward(self, context, question, mask_context=None, mask_question=None):
        # context: [batch_size, context_len, hidden_dim]
        # question: [batch_size, question_len, hidden_dim]
        
        # 计算相似度矩阵
        similarity = torch.bmm(context, question.transpose(1, 2))  # [batch_size, context_len, question_len]
        
        # 问题对上下文的注意力
        if mask_question is not None:
            similarity = similarity.masked_fill(mask_question.unsqueeze(1).expand(-1, context.size(1), -1) == 0, -1e10)
        attention_context_to_question = F.softmax(similarity, dim=2)  # [batch_size, context_len, question_len]
        
        # 上下文对问题的注意力
        similarity_transposed = similarity.transpose(1, 2)  # [batch_size, question_len, context_len]
        if mask_context is not None:
            similarity_transposed = similarity_transposed.masked_fill(mask_context.unsqueeze(1).expand(-1, question.size(1), -1) == 0, -1e10)
        attention_question_to_context = F.softmax(similarity_transposed, dim=2)  # [batch_size, question_len, context_len]
        
        # 加权求和
        attended_question = torch.bmm(attention_context_to_question, question)  # [batch_size, context_len, hidden_dim]
        attended_context = torch.bmm(attention_question_to_context, context)  # [batch_size, question_len, hidden_dim]
        
        return attended_question, attended_context

# 示例用法
batch_size = 2
context_len = 15
question_len = 5
hidden_dim = 256

bi_attention = BiAttention(hidden_dim)
context = torch.rand((batch_size, context_len, hidden_dim))
question = torch.rand((batch_size, question_len, hidden_dim))
mask_context = torch.ones((batch_size, context_len))
mask_question = torch.ones((batch_size, question_len))

attended_question, attended_context = bi_attention(context, question, mask_context, mask_question)
print(attended_question.shape)  # 输出: torch.Size([2, 15, 256])
print(attended_context.shape)  # 输出: torch.Size([2, 5, 256])

代码详解

  • BiAttention类:实现了双向注意力机制。

    • forward方法中:
      • 通过批量矩阵乘法计算上下文与问题之间的相似度矩阵。
      • 计算问题对上下文的注意力权重,并进行加权求和生成attended_question
      • 计算上下文对问题的注意力权重,并进行加权求和生成attended_context
  • 示例用法:创建一个BiAttention实例,并对随机生成的上下文和问题进行前向传播,输出attended_questionattended_context的形状分别为[批大小, 上下文长度, 隐藏维度][批大小, 问题长度, 隐藏维度]


案例四:情感分析中的注意力机制

1. 案例描述

情感分析旨在识别文本中表达的情感倾向,如积极、消极或中立。引入注意力机制后,模型能够重点关注对情感分类最具影响力的词语,从而提升分类的准确性。

2. 案例分析

在情感分析任务中,并非所有词语对情感判断都有同等的重要性。注意力机制帮助模型自动识别并聚焦于关键情感词,如“优秀”、“糟糕”等,提高了模型对情感的敏感度和判别能力。

3. 案例算法步骤
  1. 输入编码:将输入文本转换为词向量表示。
  2. 位置编码:为词向量加入位置信息。
  3. 注意力机制
    • 计算每个词对整体情感的注意力权重。
    • 根据注意力权重加权汇总词向量,生成全局情感表示。
  4. 分类层:通过全连接层和softmax进行情感分类。
4. 案例对应Python代码及详解

以下示例展示了如何使用PyTorch实现一个简化的注意力机制,用于情感分析任务。

import torch
import torch.nn as nn
import torch.nn.functional as F

class SentimentAttention(nn.Module):
    def __init__(self, embed_size, hidden_dim, num_classes):
        super(SentimentAttention, self).__init__()
        self.embedding = nn.Embedding(num_embeddings=5000, embedding_dim=embed_size)
        self.lstm = nn.LSTM(embed_size, hidden_dim, batch_first=True, bidirectional=True)
        self.attention = nn.Linear(hidden_dim * 2, 1)
        self.fc = nn.Linear(hidden_dim * 2, num_classes)

    def forward(self, x, mask=None):
        # x: [batch_size, seq_len]
        embedded = self.embedding(x)  # [batch_size, seq_len, embed_size]
        lstm_out, _ = self.lstm(embedded)  # [batch_size, seq_len, hidden_dim*2]
        
        # 计算注意力权重
        attn_weights = self.attention(lstm_out).squeeze(2)  # [batch_size, seq_len]
        if mask is not None:
            attn_weights = attn_weights.masked_fill(mask == 0, -1e10)
        attn_weights = F.softmax(attn_weights, dim=1)  # [batch_size, seq_len]
        
        # 加权求和
        weighted = torch.bmm(attn_weights.unsqueeze(1), lstm_out).squeeze(1)  # [batch_size, hidden_dim*2]
        
        # 分类
        out = self.fc(weighted)  # [batch_size, num_classes]
        return out

# 示例用法
batch_size = 2
seq_len = 10
embed_size = 128
hidden_dim = 64
num_classes = 3  # 积极、消极、中立

model = SentimentAttention(embed_size, hidden_dim, num_classes)
input_ids = torch.randint(0, 5000, (batch_size, seq_len))  # 随机生成输入
mask = torch.ones((batch_size, seq_len))  # 假设没有填充

logits = model(input_ids, mask)
print(logits.shape)  # 输出: torch.Size([2, 3])

代码详解

  • SentimentAttention类:实现了一个基于注意力机制的情感分析模型。

    • __init__方法中定义了嵌入层、双向LSTM、注意力层和全连接分类层。
    • forward方法中:
      • 将输入序列转换为嵌入向量,并通过双向LSTM提取上下文特征。
      • 计算每个时间步的注意力权重,并进行加权求和生成全局表示。
      • 通过全连接层和softmax进行情感分类。
  • 示例用法:创建一个SentimentAttention实例,并对随机生成的输入进行前向传播,输出情感分类的logits,其形状为[批大小, 类别数]


案例五:文本生成中的多头注意力机制

1. 案例描述

文本生成任务旨在根据给定的上下文生成连贯且符合语法的文本,如对话系统、自动写作等。多头注意力机制在文本生成中发挥了重要作用,使模型能够从多个子空间同时关注不同的信息,提高生成文本的多样性和质量。

2. 案例分析

多头注意力机制通过并行计算多个注意力头,每个头学习不同的表示,从而捕捉到不同层次和不同类型的依赖关系。在文本生成中,这种机制使得模型能够更全面地理解上下文,提高生成文本的相关性和流畅度。

3. 案例算法步骤
  1. 输入编码:将上下文文本转换为词向量表示。
  2. 位置编码:为词向量加入位置信息。
  3. 多头注意力机制
    • 生成多个注意力头,分别计算查询、键、值向量。
    • 计算每个头的注意力输出,并将其拼接。
  4. 前馈神经网络:对多头注意力的输出进行非线性变换。
  5. 文本生成:通过解码器逐词生成文本。
4. 案例对应Python代码及详解

以下示例展示了如何使用PyTorch实现一个简化的多头注意力机制,用于文本生成任务。

import torch
import torch.nn as nn
import torch.nn.functional as F

class MultiHeadAttention(nn.Module):
    def __init__(self, embed_size, heads):
        super(MultiHeadAttention, self).__init__()
        self.embed_size = embed_size
        self.heads = heads
        self.head_dim = embed_size // heads

        assert (
            self.head_dim * heads == embed_size
        ), "Embedding size must be divisible by heads"

        # 定义线性变换层
        self.values = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.keys = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.queries = nn.Linear(self.head_dim, self.head_dim, bias=False)
        self.fc_out = nn.Linear(heads * self.head_dim, embed_size)

    def forward(self, values, keys, queries, mask=None):
        N, seq_length, embed_size = queries.shape

        # 分头
        values = values.reshape(N, seq_length, self.heads, self.head_dim)
        keys = keys.reshape(N, seq_length, self.heads, self.head_dim)
        queries = queries.reshape(N, seq_length, self.heads, self.head_dim)

        # 线性变换
        values = self.values(values)
        keys = self.keys(keys)
        queries = self.queries(queries)

        # 计算注意力分数
        energy = torch.einsum("nqhd,nkhd->nhqk", [queries, keys])

        if mask is not None:
            energy = energy.masked_fill(mask == 0, float("-1e20"))

        attention = torch.softmax(energy / (self.head_dim ** 0.5), dim=3)

        out = torch.einsum("nhql,nlhd->nqhd", [attention, values]).reshape(
            N, seq_length, self.heads * self.head_dim
        )

        # 最终线性变换
        out = self.fc_out(out)
        return out

# 示例用法
embed_size = 256
heads = 8
multi_head_attention = MultiHeadAttention(embed_size, heads)

# 假设输入序列长度为10,批大小为2
queries = torch.rand((2, 10, embed_size))
keys = torch.rand((2, 10, embed_size))
values = torch.rand((2, 10, embed_size))
mask = None  # 这里不使用掩码

output = multi_head_attention(values, keys, queries, mask)
print(output.shape)  # 输出: torch.Size([2, 10, 256])

代码详解

  • MultiHeadAttention类:实现了多头注意力机制。

    • __init__方法中定义了用于生成查询、键、值向量的线性层,以及最终的线性输出层。
    • forward方法中:
      • 将输入的嵌入向量分成多个头。
      • 对每个头进行线性变换。
      • 计算注意力权重,并应用于值向量。
      • 将所有头的输出拼接,并通过最终的线性层生成输出。
  • 示例用法:创建一个MultiHeadAttention实例,并对随机生成的查询、键、值进行前向传播,输出结果的形状为[批大小, 序列长度, 嵌入维度]


总结

通过以上五个案例,我们深入探讨了注意力机制在不同AI应用中的具体实现和作用。无论是机器翻译、文本摘要、问答系统、情感分析还是文本生成,注意力机制都展示了其强大的能力,帮助模型更好地理解和处理复杂的语言信息。理解和掌握这些注意力机制,不仅有助于提升模型的性能,也为进一步的创新提供了坚实的基础。

标签:dim,AI,self,torch,python,hidden,注意力,size
From: https://blog.csdn.net/l35633/article/details/145087832

相关文章

  • Python函数
    在Python编程中,函数是构建程序的关键模块,它允许将复杂的任务分解为可管理、可重复使用的代码片段,极大地提高了代码的可读性、可维护性和可扩展性。以下为函数的详细内容:函数的定义与基本结构定义方式使用def关键字来定义函数,其基本语法结构为:deffunction_name(parame......
  • 2025 年 1 月 TIOBE 指数,一月头条:Python 是 TIOBE 2024 年度编程语言!
    2025年1月TIOBE指数一月头条:Python是TIOBE2024年度编程语言!编程语言Python赢得了“TIOBE2024年度编程语言”称号。该奖项授予一年内评级增幅最高的编程语言。Python在2024年增长了9.3%。这远远领先于其竞争对手:Java+2.3%、JavaScript+1.4%和Go+1.2%。......
  • containerd版本升级影响调查
    这边测试环境的containerd版本是1.5.7,生产环境的会是1.6.28,排查版本不同的影响。调研1.更新影响containerd版本1.5.7升级到1.6.28,是软件本身的优化和修复,对业务暂时没有排查到明显的影响。数据来源:https://github.com/containerd/containerd/releases/tag/v1.6.0https://g......
  • Python AI教程之十八:监督学习之决策树(9) 决策树模型中的过度拟合
    决策树模型中的过度拟合在机器学习中,决策树是一种常用的预测工具。然而,使用这些模型时遇到的一个常见问题是过度拟合。在这里,我们探讨决策树中的过度拟合以及应对这一挑战的方法。决策树为什么会出现过度拟合?决策树模型中的过度拟合是指决策树变得过于复杂,并捕获训练数......
  • AI项目依赖安全分析评估
    场景自动化漏洞检测与分析代码扫描与漏洞识别:AI可以快速扫描项目依赖的代码库,利用机器学习算法识别潜在的安全漏洞。通过对大量已知漏洞代码模式的学习,AI能够准确地检测出类似的安全问题,提高漏洞检测的效率和准确性。漏洞优先级排序:在检测到多个漏洞时,AI可以根据漏洞的严重程度、......
  • python脚本实现经纬度和大地高与ECEF坐标互转
    importmath#地心地固坐标系(ECEF)转经纬度和大地高defecef2lla(x,y,z):#初始近似d=0for_inrange(32):#最大迭代次数设为32,可根据实际情况调整#计算临时变量R_prime=math.sqrt(x**2+y**2+(z-d)**2)......
  • python语言daifanyedeshipin爬虫程序代码QZQ
    importrequestsimportosimportsubprocessurl=‘https://api.bilibili.com/x/space/wbi/arc/search?mid=3493140394674396&pn=1&ps=25&index=1&order=pubdate&order_avoided=true&platform=web&web_location=1550101&dm_img_list=[]&am......
  • Python 基础知识 之 选择(分支)结构 + 模式匹配结构(match)
    选择结构按照条件选择执行不同的代码段1.单分支结构if语法结构执行流程:如果表达式的值为True,就执行语句块,如果表达式的值为False,就跳过语句块,继续执行下面的语句⭐注意:⭐⭐⭐表达式后面的冒号;缩进,python中通过缩进来控制程序逻辑示例;#1.判断是否中奖nu......
  • Python库房管理系统开发指南
    在现代仓储管理中,高效、准确的信息系统是提高运营效率的关键。Python作为一种强大且易于学习的编程语言,非常适合用来开发简易而功能齐全的库房管理系统。本文将详细介绍如何使用Python编写一个基本的库房管理系统,包括商品入库、出库、查询库存及生成报表等功能。通过本文,读者不仅......
  • Python 魔法学院 - 第18篇:Python 多线程 ⭐⭐⭐
    目录引言1.多线程编程基础1.1什么是多线程?1.2为什么需要多线程?1.3Python中的多线程模块2.创建和启动线程2.1使用`threading.Thread`创建线程2.2使用`target`参数创建线程3.线程同步3.1为什么需要线程同步?3.2使用`Lock`实现线程同步3.3使用`RLock`......