理解Attention机制的query key value

背景

在Attention机制引入前,自然语言处理里的深度学习模型有以下缺点:

  • 长序列的推理存在信息损失/梯度消失:输入序列越长,模型越难保存初始输入信息。
  • 运算量大并且不能并行:RNN的每一步推理都是基于上一个步的结果。

Attention的定义

Attention Is All You Need 文章中,它的定义是这样的:

An attention function can be described as mapping a query and a set of key-value pairs to an output, where the query, keys, values, and output are all vectors.

这么说有点抽象,我们用搜索引擎(信息检索)做个类比:

  1. 当你用上网查东西时,你会敲入一句关键词,这个就是query
  2. 搜索系统会根据关键词这个去查找一系列相关的keys,比如文章标题,图片标题。
  3. 最后系统会将相应的 values 比如具体的文章图片 返回给你。

Attention机制做就是根据query找出(或者将注意力集中到)相关的keys 和它们对应的 values

Attention的例子

这是Attention机制的一个实例,名字叫Scaled Dot-Product Attention。下面我们结合一个具体的应用例子来解释:

请添加图片描述

例子

请找出这个文本里跟 “计划” 这个词相关性最大的词语,及其特征向量。

今天 我 的 计划 是 买菜

预处理

  1. 先将文本切成n个词,并做Embedding,得到每个词所对应的向量。比如
  • “今天”: embedding_1 (下标 0)
  • “我”: embedding_2 (下标 1)
  • 等等
  1. 然后初始化K以及V矩阵:
  • K (keys)目的是:根据Q (query)找到文本中相关的一个或者多个词语
  • V (values)目的是:根据上述计算出来一个或多个词语的权重来对这些词语的向量进行综合加权,并得到加权向量。
  1. 然后训练模型。

Attention 推理

  1. MatMul: 将Q (query)所对应的embedding与K矩阵相乘,得到一个长度为n = 6的向量。
  2. Scale: 使这个向量的方差为1(避免训练过程中模型的太小梯度消失)
  3. Mask: 这步是可选的,因为在批量训练中,为了使不同输入数据有相同的长度,我们会加padding,而Mask这部就是想padding给去除。同时在decoder过程中,为了避免decoder作弊用未来的输入数据当作输入输入,我们会Mask掉用于接收未来信息的神经元。
  4. SoftMax: 得到一个长度为n并且 总和 为1 的向量。这n个值里面最大的数对应的下标就是我们要找的相关性词语的下标。(“买菜”: embedding_5 下标5)
  5. MatMul: 这里我们将该向量与V (values)相乘,得到最后的一个特征向量加权。

至此,Attention模块推理结束。

参考文献

  • https://stats.stackexchange.com/questions/421935/what-exactly-are-keys-queries-and-values-in-attention-mechanisms
  • https://www.jianshu.com/p/9d5706fa582d
  • https://arxiv.org/pdf/1706.03762.pdf
  • https://stats.stackexchange.com/questions/430812/why-k-and-v-are-not-the-same-in-transformer-attention
### Python中实现Attention机制 在神经网络领域,注意力(Attention机制允许模型聚焦于输入序列的不同部分。这种能力显著提升了处理长依赖性和复杂模式的能力。 #### 使用PyTorch实现简单的Self-Attention)层的例子: ```python import torch import torch.nn as nn import math class SelfAttention(nn.Module): def __init__(self, embed_size, heads): super(SelfAttention, self).__init__() self.embed_size = embed_size self.heads = heads # 定义线性变换矩阵Q,K,V self.values = nn.Linear(self.embed_size, self.embed_size, bias=False) self.keys = nn.Linear(self.embed_size, self.embed_size, bias=False) self.queries = nn.Linear(self.embed_size, self.embed_size, bias=False) # 输出后的线性变换 self.fc_out = nn.Linear(self.embed_size, self.embed_size) def forward(self, values, keys, query, mask=None): N = query.shape[0] value_len, key_len, query_len = values.shape[1], keys.shape[1], query.shape[1] # 将嵌入向量映射到多头形式下的查询、键和值张量上 queries = self.queries(query).view(N, query_len, self.heads, self.embed_size // self.heads) keys = self.keys(keys).view(N, key_len, self.heads, self.embed_size // self.heads) values = self.values(values).view(N, value_len, self.heads, self.embed_size // self.heads) # 调整维度以便计算点积相似度得分 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, query_len, self.embed_size ) return self.fc_out(out) ``` 此代码定义了一个`SelfAttention`类,它实现了自我关注的核心逻辑[^4]。通过创建多个头部(head),可以捕捉不同子空间内的特征关系;而缩放因子则有助于稳定梯度传播过程中的数值范围。 为了使上述代码更易于理解,在实际应用时还可以加入更多细节优化,比如残差连接(residual connections)、层规范化(layer normalization)等操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值