Transformer简介

Transformer是第一个完全依靠Self-attention而不使用序列对齐的RNN或卷积的方式来计算输入输出表示的转换模型。

Self-attention有时候也被称为Intra-attention,是在单个句子不同位置上做的Attention,并得到序列的一个表示。它能够很好地应用到很多任务中,包括阅读理解、摘要、文本蕴涵,以及独立于任务的句子表示。端到端的网络一般都是基于循环注意力机制而不是序列对齐循环,并且已经有证据表明在简单语言问答和语言建模任务上表现很好。

1 概览

在这里插入图片描述

2 框架

在这里插入图片描述

模型框架如下

  • Encoder 部分
    6个block 每个block 有两层。他们分别是Multi-head self attenton 和 position-wise feed forward。
  1. Multi-head self attention - 多组 self attention 的连接。首先 encoder 的初始输入为 sentence embedding + position embedding,其中 position embedding 的三角函数表示挺有意思。Attention(Q,K,V)=softmax(QK^T/sqrt(d_k))V,其中 Q 与 K 均为输入,(V 为 learned value?此处存疑)。输入 size 为 [sequence_length, d_model],输出 size 不变。然后是 residual connection,即 LayerNorm(x+Sublayer(x)),输出 size 不变。
  2. Position-wise feed forward network,其实就是一个 MLP 网络,1 的输出中,每个 d_model 维向量 x 在此先由 xW1+b1 变为 d_ff 维的 x’,再经过 max(0, x’)W2+b2 回归 d_model 维。之后再是一个 residual connection。输出 size 仍是 [sequence_length, d_model]。
  • Decoder 部分
    每个block中有3层 他们分别是 Multi-head self attention(with mask), Multi-head attention(with encoder), Postion-wise feed forward。
  1. Multi-head self attention (with mask) 与 encoder 部分相同,只是采用 0-1 mask 消除右侧单词对当前单词 attention 的影响。
  2. Multi-head attention(with encoder)引入encoder 部分的输出在此处作为multi-head 的其中几个head。
  3. Position-wise feed forward network与encoder 部分相同。

attention mechanism

RNN 中使用的注意力机制

在这里插入图片描述
在这里插入图片描述

Transformer中的注意力机制

在论文中,谷歌将注意力机制一般化了,一个注意力函数描述为将Query与一组健值对(Key-Value)映射到输出,其中这三者均为向量形势。

对于翻译任务,Query 可以认为是源词语向量序列,而 Key 和 Value 可以认为为目标词向量序列。即注意力通过计算 Query 和 Key 之间的相似性,并通过相似性来确定 Query 和 Value 之间的注意力关系。
在这里插入图片描述

  1. 点积attention

我们来介绍一下attention的具体计算方式。attention可以有很多种计算方式:

在这里插入图片描述

下图中令A=QK^T, Q(m * d), K(N * d)分别是Query和Key,其中,Query可以看作M个维度为d的向量(长度为M的sequence的向量表达)拼接而成,Key可以看作N个维度为d的向量(长度为N的sequence的向量表达)拼接而成.
在这里插入图片描述

扫描二维码关注公众号,回复: 12493779 查看本文章

(Attention中Q*(K^T)矩阵计算示意图,Query和Key的维度要保持一致)

【一个小问题】为什么有缩放因子?

  • 先一句话回答这个问题: 缩放因子的作用是归一化。
    假设Q(m * d), K(N * d)里的元素的均值为0,方差为1,那么A{T}=Q{T} K中元素的均值为0,方差为d. 当d变得很大时, A 中的元素的方差也会变得很大,如果 A 中的元素方差很大,那么 softmax(A)的分布会趋于陡峭(分布的方差大,分布集中在绝对值大的区域)。总结一下就是softmax(A)的分布会和d有关。因此 A中每一个元素乘上 缩放因子 后,方差又变为1。这使得softmax(A) 的分布“陡峭”程度与d解耦,从而使得训练过程中梯度值保持稳定。
  1. Attention机制涉及到的参数

在这里插入图片描述

3.Query, Key, Value在这里插入图片描述
在这里插入图片描述

而每一层线性映射参数矩阵都是独立的,所以经过映射后的Q, K, V各不相同,模型参数优化的目标在于将q, k, v被映射到新的高维空间,使得每层的Q, K, V在不同抽象层面上捕获到q, k, v之间的关系。一般来说,底层layer捕获到的更多是lexical-level的关系,而高层layer捕获到的更多是semantic-level的关系。

multi-head attention

Attention是将Query和Key映射到同一高维空间中去计算相似度,而对应的multi-head attention把Query和Key映射到高维空间a的不同子空间{a1,a2,a3,a4,a5}中去计算相似度。
为什么要做multi-head attention? 论文原文里面是这么说的:

Multi-head attention allows the model to jointly attend to information from different representation subspaces
at different positions. With a single attention head, averaging inhibits this.

也就是说,这样可以在不改变参数量的情况下增强每一层attention的表现力。

Multi-head Attention的本质是,在参数总量保持不变的情况下,将同样的Query, Key, Value映射到原来的高维空间的不同子空间中进行attention的计算,在最后一步再合并不同子空间中的attention信息。这样降低了计算每个head的attention时每个向量的维度,在某种意义上防止了过拟合;由于Attention在不同子空间中有不同的分布,Multi-head Attention实际上是寻找了序列之间不同角度的关联关系,并在最后concat这一步骤中,将不同子空间中捕获到的关联关系再综合起来。

在这里插入图片描述

从上图可以看出,qi 和 kj 之间的attention score从1个变成了h个,这就对应了h个子空间中它们的关联度。

transformer mask

  1. padding mask: 处理非定长序列,区分 padding 和非 padding 部分,如在 RNN 等模型和 Attention 机制中的应用等;
  2. sequence mask: 防止标签泄漏 如: Transformer decoder 中的mask 矩阵,bert中的【Mask】位,XLNet中的mask矩阵等。
    Transformer 是包括 Encoder和 Decoder的,Encoder中 self-attention 的 padding mask就是用于处理非定长序列,而 Decoder 还需要防止标签泄露,即在t时刻不能看到t时刻之后的信息,因此在上述 padding mask的基础上,还要加上 sequence mask。

Encoder mask篇

在NLP中,文本一般是不定长的,所以在进行 batch训练之前,要先进行长度的统一,过长的句子可以通过truncating 截断到固定的长度,过短的句子可以通过 padding 增加到固定的长度,但是 padding 对应的字符只是为了统一长度,并没有实际的价值,因此希望在之后的计算中屏蔽它们,这时候就需要 Mask。

在 Attention 机制中,同样需要忽略 padding 部分的影响,这里以Transformer encoder中的self-attention为例:self-attention中,Q和K在点积之后,需要先经过mask再进行softmax,因此,对于要屏蔽的部分,mask之后的输出需要为负无穷,这样softmax之后输出才为0。

def attention(query, key, value, mask=None, dropout=None):
    "Compute 'Scaled Dot Product Attention'"
    d_k = query.size(-1)
    scores = torch.matmul(query, key.transpose(-2, -1)) \
             / math.sqrt(d_k)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, -1e9) # mask步骤,用 -1e9 代表负无穷
    p_attn = F.softmax(scores, dim = -1)
    if dropout is not None:
        p_attn = dropout(p_attn)
    return torch.matmul(p_attn, value), p_attn

Decoder mask篇

在语言模型中,常常需要从上一个词预测下一个词,但如果要在LM中应用 self attention 或者是同时使用上下文的信息,要想不泄露要预测的标签信息,就需要 mask 来“遮盖”它。

sequence mask 一般是通过生成一个上三角矩阵来实现的,上三角区域对应要mask的部分。

在Transformer 的 Decoder中,先不考虑 padding mask,一个包括四个词的句子[A,B,C,D]在计算了相似度scores之后,得到下面第一幅图,将scores的上三角区域mask掉,即替换为负无穷,再做softmax得到第三幅图。这样,比如输入 B 在self-attention之后,也只和A,B有关,而与后序信息无关。

因为在softmax之后的加权平均中: B’ = 0.48A+0.52B,而 C,D 对 B’不做贡献。

对于 decoder 的 self-attention,里面使用到的 scaled dot-product attention,同时需要padding mask 和 sequence mask 作为 attn_mask,具体实现就是两个mask相加作为attn_mask。
其他情况,attn_mask 一律等于 padding mask。

import torch
 
def padding_mask(seq, pad_idx):
    return (seq != pad_idx).unsqueeze(-2)   # [B, 1, L]
 
def sequence_mask(seq):
    batch_size, seq_len = seq.size()
    mask = 1- torch.triu(torch.ones((seq_len, seq_len), dtype=torch.uint8),diagonal=1)
    mask = mask.unsqueeze(0).expand(batch_size, -1, -1)  # [B, L, L]
    return mask
 
def test():
    # 以最简化的形式测试Transformer的两种mask
    seq = torch.LongTensor([[1,2,0]]) # batch_size=1, seq_len=3,padding_idx=0
    embedding = torch.nn.Embedding(num_embeddings=3, embedding_dim=10, padding_idx=0)
    query, key = embedding(seq), embedding(seq)
    scores = torch.matmul(query, key.transpose(-2, -1))
 
    mask_p = padding_mask(seq, 0)
    mask_s = sequence_mask(seq)
    mask_decoder = mask_p & mask_s # 结合 padding mask 和 sequence mask
 
    scores_encoder = scores.masked_fill(mask_p==0, -1e9) # 对于scores,在mask==0的位置填充
    scores_decoder = scores.masked_fill(mask_decoder==0, -1e9)
 
test()

# mask_p
[[[1 1 0]]]
# mask_s
[[[1 0 0]
  [1 1 0]
  [1 1 1]]]
# mask_decoder
[[[1 0 0]
  [1 1 0]
  [1 1 0]]]

在这里插入图片描述

FFN(Feed forward network) 层

每一层经过attention之后,还会有一个FFN,这个FFN的作用就是空间变换。FFN包含了2层linear transformation层,中间的激活函数是ReLu。

曾经我在这里有一个百思不得其解的问题:attention层的output最后会和W相乘,为什么这里又要增加一个2层的FFN网络?

其实,FFN的加入引入了非线性(ReLu激活函数),变换了attention output的空间, 从而增加了模型的表现能力。把FFN去掉模型也是可以用的,但是效果差了很多。

架构图

在这里插入图片描述

reference

  1. 动图图解Transformer及其工程领域应用
  2. illustrated-transformer
  3. Transformer学习笔记
  4. Transformer模型原理详解
  5. (Transformer 详解)[https://wmathor.com/index.php/archives/1438/]

猜你喜欢

转载自blog.csdn.net/kingiscoming/article/details/113706784