前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【深度学习入门篇 ⑪】自注意力机制

【深度学习入门篇 ⑪】自注意力机制

作者头像
@小森
发布2024-07-25 15:19:26
510
发布2024-07-25 15:19:26
举报
文章被收录于专栏:xiaosen

自注意力背景

NLP领域中, 当前的注意力机制大多数应用于seq2seq架构, 即编码器和解码器模型。

  • encoder-decoder 结构 : Encoder将输入编码成上下文向量,Decoder进行解码;解码过程顺序进行,每次仅解码出一个单词。

RNN存在一些问题:

  1. 输 入 输 出 存 在 序 列 关 系 , b 4 的 输 出 需 要 先 依 赖 于 b 3 , … , 一 次 输 出 , 无 法 进 行 并 行 化
  2. 不论输入和输出的语句长度是什么,中间的上下文向量长度都是 固定的
  3. 仅仅利用上下文向量解码,会有信息瓶颈,长度过长时候信息可 能会丢失

可以对对seq2seq结构改进,使 用 C N N 来 进 行 并 行 化。

通过堆叠多层CNN,提高感受野,使上层输出可以捕获长程时序关系。

自注意力

语言的含义是极度依赖上下文的

  • 机器人第二法则:机器人必须遵守人类给它的命令,除非该命令违背了第一法则

这句话中高亮表示了三个地方,这三处单词指代的是其它单词。除非我们知道这些词 指代的上下文联系起来,否则根本不可能理解或处理这些词语的意思。当模型处理这 句话的时候,它必须知道:

  • 「它」指代机器人
  • 「命令」指代前半句话中人类给机器人下的命令,即「人类给它的命令」
  • 「第一法则」指机器人第一法则的完整内容

自注意力机制(self-Attention):

3个人工定义的重要概念,查询向量,键向量,值向量

① 查询向量(Query向量):被用来和其它单词的键向量相乘,从而得到其它词相对于当前词的注意力得分。 ② 键向量(Key向量):序列中每个单词的标签,是我们搜索相关单词时用来匹配的对象。 ③ 值向量(Value向量):单词真正的表征,使用值向量基于注意力得分进行加权求和。

查询向量就像一张便利贴,键向量像是档案柜中文件夹上贴的标签。当找到和便利贴上所写相匹 配的文件夹时,文件夹里的东西便是值向量。

自注意力实现

q u e r y , ke y , va l u e 向 量 的 定 义

使用每一个q对每一个k做attention :

将Query和Key分别计算相似性,然后经过softmax得到相似性概率权重,即注意力,再乘以Value,最后相加即可得到包含注意力的输出 。

常见注意力机制代码

代码语言:javascript
复制
import torch
import torch.nn as nn
import torch.nn.functional as F

class Attn(nn.Module):
    def __init__(self, query_size, key_size, value_size1, value_size2, output_size):
        super(Attn, self).__init__()
        self.query_size = query_size
        self.key_size = key_size
        self.value_size1 = value_size1
        self.value_size2 = value_size2
        self.output_size = output_size

        # 第一步中需要的线性层
        self.attn = nn.Linear(self.query_size + self.key_size, value_size1)

        # 第三步中需要的线性层
        self.attn_combine = nn.Linear(self.query_size + value_size2, output_size)


    def forward(self, Q, K, V):
        attn_weights = F.softmax(self.attn(torch.cat((Q[0], K[0]), 1)), dim=1)

        attn_applied = torch.bmm(attn_weights.unsqueeze(0), V)

        output = torch.cat((Q[0], attn_applied[0]), 1)

        # 使用线性层作用在第三步的结果上做一个线性变换并扩展维度
        output = self.attn_combine(output).unsqueeze(0)
        return output, attn_weights


query_size = 32
key_size = 32
value_size1 = 32
value_size2 = 64
output_size = 64
attn = Attn(query_size, key_size, value_size1, value_size2, output_size)
Q = torch.randn(1,1,32)
K = torch.randn(1,1,32)
V = torch.randn(1,32,64)
out = attn(Q, K ,V)
print(out[0])
print(out[1])

输出:

代码语言:javascript
复制
tensor([[[-0.3390,  0.3021, -0.1952, -0.0400,  0.5597, -0.3745, -0.2216,
          -0.3438, -0.2086, -0.1554, -0.2502,  0.0486,  1.0381, -0.1030,
           0.7277,  0.0592, -0.9172, -0.3736, -0.2285, -0.0148, -0.3319,
           0.0620, -0.6006,  0.1346, -0.1530,  0.0336,  0.3269, -0.2511,
          -0.1209,  0.4153,  0.3519,  0.3344, -0.0496, -0.2759, -0.2080,
          -0.1669,  0.7263, -0.0893,  0.0298, -0.1326,  0.6898, -0.3864,
          -0.0884, -0.2329, -0.2338,  0.1920,  0.2625,  0.0396, -0.3101,
          -0.2299, -0.1226, -0.5915,  0.2620,  0.2462,  0.4123, -0.6733,
          -0.2091,  0.6727,  0.3754, -0.1620, -0.8333,  0.2066,  0.3082,
          -0.5225]]], grad_fn=<UnsqueezeBackward0>)
tensor([[0.0187, 0.0492, 0.0259, 0.0293, 0.0151, 0.0104, 0.0127, 0.0122, 0.0546,
         0.0141, 0.0170, 0.0277, 0.0284, 0.0807, 0.0228, 0.0099, 0.0327, 0.0585,
         0.0102, 0.0106, 0.0598, 0.0208, 0.0403, 0.0241, 0.0896, 0.0230, 0.0371,
         0.0316, 0.0091, 0.0242, 0.0553, 0.0447]], grad_fn=<SoftmaxBackward0>)

Self-attention就本质上是一种特殊的attention。Self-attention向对于attention的变化,就是寻找权重值的𝑤𝑖过程不同。

Self-attention和Attention使用方法
  • Attention (AT) 经常被应用在从编码器(encoder)转换到解码器(decoder)。
  • SA可以在一个模型当中被多次的、独立的使用(比如说在Transformer中,使用了18次;在Bert当中使用12次)。
  • SA比较擅长在一个序列当中,寻找不同部分之间的关系,AT却更擅长寻找两个序列之间的关系
Transformer模型

Encoder由N个相同结构的编码模块堆积而成,每一个编码模块由Multi-Head Attention, Add & Norm, Feed Forward, Add & Norm 组成的。

编码器结构

第一层的激活函数为 ReLU,第二层不使用激活函数。X是输入,全连接层的输入和输出都是512维,中间隐层维度为2048。

解码器结构

通过输入矩阵X计算得到Q, K, V 矩阵,然后计算 Q 和 KT 的乘积 QKT。

计算注意力分数,在 Softmax 之前需要使用 Mask矩阵遮挡住每一个单词之后的信息。

文本嵌入层:无论是源文本嵌入还是目标文本嵌入,都是为了将文本中词汇的数字表示转变为向量表示, 希望在这样的高维空间捕捉词汇间的关系

代码语言:javascript
复制
import torch
import torch.nn as nn
import math
from torch.autograd import Variable

class Embeddings(nn.Module):
    def __init__(self, d_model, vocab):
        
        super(Embeddings, self).__init__()
        self.lut = nn.Embedding(vocab, d_model)
        self.d_model = d_model

    def forward(self, x):
        return self.lut(x) * math.sqrt(self.d_model)

输出:

代码语言:javascript
复制
embedding = nn.Embedding(10, 3)
input = torch.LongTensor([[1,2,3,4],[6,3,2,9]])
print(embedding(input))

#
tensor([[[ 1.8450,  1.9222,  0.1577],
         [-0.7341,  0.3091,  0.7592],
         [-0.4300,  0.9030, -0.3533],
         [ 1.1873,  0.9349, -1.0567]],

        [[ 0.4812, -0.1072,  0.4980],
         [-0.4300,  0.9030, -0.3533],
         [-0.7341,  0.3091,  0.7592],
         [-2.1227, -0.3621,  0.7383]]], grad_fn=<EmbeddingBackward0>)
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 自注意力
  • 自注意力实现
  • Self-attention和Attention使用方法
  • Transformer模型
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档