通俗易懂:Attention中的Q、K、V是什么?怎么得到Q、K、V?

说一下Attention中的QKV是什么,再举点例子说明QKV怎么得到。还是结合例子明白的快。

Attention中Q、K、V是什么?

首先Attention的任务是获取局部关注的信息。Attention的引入让我们知道输入数据中,哪些地方更值得关注。
对于Q(uery)、K(ey)、V(alue)的解释,知其然而知其所以然。
首先Q、K、V都源于输入特征本身,是根据输入特征产生的向量,但目前我们现在无需关注是如何产生这组向量的。
V可以看做表示单个输入特征的向量。当我们直接把一组V输入到网络中进行训练,那这个网络就是没有引入Attention的网络。但如果引入Attention,需要将这组V分别乘以一组权重W(Q,K),那么就可以做到关注局部的输入特征。
W(Q,K)是什么?W(Q,K)是计算Q、K之间的相似度。常见的方式有dot-product attention和additive attention,前者是点积运算,后者是通过一个hidden layer的网络计算。
即:V是表示输入特征的向量,Q、K是计算Attention权重的特征向量。它们都是由输入特征得到的。Attention(Q,K,V)是根据关注程度对V乘以相应权重。
Attention机制中的Q,K,V即是,我们对当前的Query和所有的Key计算相似度,将这个相似度值通过Softmax层进行得到一组权重,根据这组权重与对应Value的乘积求和得到Attention下的Value值。
在这里插入图片描述

和这个图表现出的一样。QKV这种可以算作Attention机制中最基本的思想。

示例1 Self-Attention之打野捉上单被反杀了怎么办

大部分人在讲Attention时都会讲到Self-Attention,毕竟这也是经典了。
而当我们打游戏出现打野来上被他反杀这种现象时,我们的第一反应是:在NLP中,我们能否通过语言理解去做到,这个他指的是上单还是打野?
在这里插入图片描述

那么在Self-Attention中的做法是:
1、根据这个句子得到打野、上、他的embedding,在下图表示为 e 1 、 e 2 、 e 3 e_{1}、e_{2}、e_{3} e1e2e3
2、将e通过不同的线性变换Q、K、V。(注意理解:所有的e到Q或K或V都采取相同的线性变换,而e到Q和K和V采取不同的线性变换。)实际上这里把Q、K、V都看做与e一样的话可能更好理解。
3、根据 Q 3 Q_{3} Q3分别与 K 1 、 K 2 K_{1}、K_{2} K1K2计算相似程度即Attention值,得到 A 1 , 3 、 A 2 , 3 A_{1,3}、A_{2,3} A1,3A2,3
4、 A t t e n t i o n V 3 = ( A 1 , 3 + A 2 , 3 + 1 ) ⋅ V 3 Attention V_{3}=(A_{1,3}+A_{2,3}+1)\cdot V _{3} AttentionV3=(A1,3+A2,3+1)V3
A t t e n t i o n V 3 Attention V_{3} AttentionV3向量中包括了这样的信息:他更可能指代上单,而不是打野。
总结:这里的Q、K、V是根据单词embedding的线性变换得到的。
图有点丑抱歉!

示例2 推荐系统之NASR——我们更关注哪些用户历史数据

用电影这个事例来解释:在一个人的观影生涯中,观看影片的顺序是比较重要的。当推荐系统对某人推荐电影时,这一点就很重要了:我们有这个人观影数据,该怎么判断他看过的哪些电影对他当前的偏好影响最大?
下图是NASR的模型,但我们只需要关注到Attention的部分(红色方框)。
在这里插入图片描述

红色方框所做到的是,通过一个Attention网络,得到用户对哪些观看过的电影更感兴趣。我们取出红色方块的下半部分(Local encoder),这部分是该模型中Attention的核心。
在这里插入图片描述

我们知道RNN网络可以对序列进行建模。这里的Attention即是:通过RNN网络获得整个序列的建模ht,然后计算ht与hi(i=1,2,3…)的相似度,再而计算相应Attention权重。
这里的Q:整个序列向量ht。K:部分序列(1~i)向量hi 。V:部分序列(1~i)向量hi。
如果hi与ht相似度高,代表序列(1~i)在整个序列建模中起到了重要的作用。
得到的Attention V 向量则包括了用户对哪些观看过的电影更感兴趣的信息。
在这里插入图片描述

结果可以理解为最近的观看的电影通常很重要,以前观看的电影也偶尔会很重要。

以下是一个使用PyTorch实现Transformer模型的标准示例,并附有逐行注释和通俗易懂的说明: ```python import torch import torch.nn as nn # 定义一个多头自注意力机制的模块 class MultiheadAttention(nn.Module): def __init__(self, hidden_dim, num_heads): super(MultiheadAttention, self).__init__() self.hidden_dim = hidden_dim self.num_heads = num_heads self.head_dim = hidden_dim // num_heads self.query_fc = nn.Linear(hidden_dim, hidden_dim) self.key_fc = nn.Linear(hidden_dim, hidden_dim) self.value_fc = nn.Linear(hidden_dim, hidden_dim) self.fc_out = nn.Linear(hidden_dim, hidden_dim) def forward(self, query, key, value, mask=None): batch_size = query.size(0) # 将query、key和value分别通过线性映射层得到Q、K和V Q = self.query_fc(query) K = self.key_fc(key) V = self.value_fc(value) # 将Q、K和V按照num_heads维度进行切分 Q = Q.view(batch_size, -1, self.num_heads, self.head_dim).transpose(1, 2) K = K.view(batch_size, -1, self.num_heads, self.head_dim).transpose(1, 2) V = V.view(batch_size, -1, self.num_heads, self.head_dim).transpose(1, 2) # 计算注意力权重 scores = torch.matmul(Q, K.transpose(-2, -1)) / torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)) if mask is not None: scores = scores.masked_fill(mask == 0, -1e9) attention_weights = torch.softmax(scores, dim=-1) # 根据注意力权重对V进行加权求和 attention_output = torch.matmul(attention_weights, V) # 将多个头的输出拼接在一起,并通过线性映射层得到最终输出 attention_output = attention_output.transpose(1, 2).contiguous().view(batch_size, -1, self.hidden_dim) attention_output = self.fc_out(attention_output) return attention_output # 定义Transformer模型 class Transformer(nn.Module): def __init__(self, hidden_dim, num_heads, num_layers): super(Transformer, self).__init__() self.hidden_dim = hidden_dim self.num_heads = num_heads self.num_layers = num_layers self.embedding = nn.Embedding(vocab_size, hidden_dim) self.encoder = nn.ModuleList([nn.TransformerEncoderLayer(hidden_dim, num_heads) for _ in range(num_layers)]) self.decoder = nn.ModuleList([nn.TransformerDecoderLayer(hidden_dim, num_heads) for _ in range(num_layers)]) self.fc_out = nn.Linear(hidden_dim, output_dim) def forward(self, src, tgt): src_mask = (src != pad_token).unsqueeze(-2) tgt_mask = (tgt != pad_token).unsqueeze(-2) src_embedded = self.embedding(src) tgt_embedded = self.embedding(tgt) src_encoded = src_embedded.permute(1, 0, 2) tgt_encoded = tgt_embedded.permute(1, 0, 2) for layer in self.encoder: src_encoded = layer(src_encoded, src_mask) for layer in self.decoder: tgt_encoded = layer(tgt_encoded, src_encoded, tgt_mask) output = self.fc_out(tgt_encoded.permute(1, 0, 2)) return output # 定义词汇表大小、隐藏状态维度、输出维度、头数和层数 vocab_size = 10000 hidden_dim = 512 output_dim = 1000 num_heads = 8 num_layers = 6 # 初始化Transformer模型 model = Transformer(hidden_dim, num_heads, num_layers) # 定义输入源和目标序列 src = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8]]) # 假设输入源是[[1, 2, 3, 4], [5, 6, 7, 8]] tgt = torch.tensor([[9, 10, 11, 12], [13, 14, 15, 16]]) # 假设目标序列是[[9, 10, 11, 12], [13, 14, 15, 16]] # 使用Transformer模型进行训练 output = model(src, tgt) print(output) ``` 模型解释和原理技术说明: 1. Transformer是一种基于自注意力机制的序列到序列模型,用于处理序列任务,如机器翻译、文本生成等。 2. 在上述代码中,首先导入了PyTorch库中的`nn.Module`模块。 3. 定义了一个MultiheadAttention模块,用于实现多头自注意力机制。 4. MultiheadAttention模块接收查询(query)、键(key)和值(value)作为输入,并通过线性映射层将输入映射到不同的子空间。 5. 在MultiheadAttention模块中,将查询、键和值分别进行线性映射,并按照头数进行切分。 6. 计算注意力权重时,使用查询和键的点积作为得分,并进行归一化处理。 7. 根据注意力权重对值进行加权求和,并将多个头的输出拼接在一起,通过线性映射层得到最终输出。 8. 定义了一个Transformer模型,包括嵌入层(Embedding)、编码器(Encoder)和解码器(Decoder)。 9. Transformer模型中的编码器由多个TransformerEncoderLayer组成,解码器由多个TransformerDecoderLayer组成。 10. 在前向传播方法中,首先通过嵌入层将输入源和目标序列转换为嵌入表示。 11. 然后,分别将输入源和目标序列转置,并通过编码器和解码器进行处理。 12. 在编码器中,通过多个TransformerEncoderLayer对输入源进行编码。 13. 在解码器中,通过多个TransformerDecoderLayer对目标序列进行解码,并传入编码器的输出作为额外的上下文信息。 14. 最后,通过线性映射层将解码器的输出转换为最终的预测结果。 15. 初始化Transformer模型实例,并定义词汇表大小、隐藏状态维度、输出维度、头数和层数。 16. 定义输入源和目标序列。 17. 使用Transformer模型进行训练,得到输出结果。 通过以上代码和解释,一个NLP新手可以了解到: - Transformer是一种基于自注意力机制的序列到序列模型,常用于机器翻译、文本生成等任务。 - 在使用PyTorch实现Transformer模型时,需要定义多头自注意力机制模块(MultiheadAttention)和Transformer模型。 - 多头自注意力机制模块中,通过线性映射层将输入映射到不同的子空间,并计算注意力权重对值进行加权求和。 - Transformer模型中的编码器由多个TransformerEncoderLayer组成,解码器由多个TransformerDecoderLayer组成。 - 在前向传播方法中,首先通过嵌入层将输入源和目标序列转换为嵌入表示。 - 然后,分别将输入源和目标序列转置,并通过编码器和解码器进行处理。 - 在编码器中,通过多个TransformerEncoderLayer对输入源进行编码。 - 在解码器中,通过多个TransformerDecoderLayer对目标序列进行解码,并传入编码器的输出作为额外的上下文信息。 - 最后,通过线性映射层将解码器的输出转换为最终的预测结果。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值