感谢Jay Alammar,图源自他的文章[17]。
Transformer最初是在机器翻译中提出,所以我们以机器翻译为例。任何一个神经网络模型都可以认为是一个黑箱,Transformer也不例外。
再往里面一层,Transformer是一个Encoder-Decoder结构,结构如下图所示:
每一个Encoder是由self-attention+Feed Forward NN构成,如下图所示,所以我们首先要理解self-attention。
每一个Decoder是由Self-Attention+Encoder-Decoder Attention+Feed Forward NN构成,结构如下图所示:
假设我们的输入三个词,三个词通过Embedding层后,每个词变成一个向量,如下图所示:
除了最底层输入是词的Embedding,其他层的输入是上一层的输出。这三个词在Encoder中的变换是:
Self-Attention是输入的第一层NN,比较难理解,却是模型的核心组成部分。所以我们单独拿出来讲。
关于注意力机制详细可以看张俊林博士的文章[3],此处讲解self-attention,更简单易懂。
以机器翻译为例,假设我们的输入是:
“The animal didn't cross the street because it was too tired
”
在翻译的是时候我们希望将it
和The animal
联系起来,通过注意力机制可以实现这个需求。可以在Tensor2Tensor notebook 进行测试,观察每个词和其他词的对应关系(连接权重)。
刚才挖下的坑,现在来填。刚才我们提到这三个向量但是没有说如何得到的。
将我们的词向量矩阵 X X X和权重矩阵 W Q , W K , W V W_Q,W_K,W_V WQ,WK,WV相乘,即可得到 Q u e r y Query Query、 K e y Key Key、 V a l u e Value Value向量。
接下来这张图可以清晰的说明白 Q u e r y Query Query、 K e y Key Key、 V a l u e Value Value三个向量的关系。
Multi-Head Attention的优点:
Transformer模型的一大缺点是不能捕捉句子的位置信息。试想我们的句子不管如何打乱,从刚才的原理可以看出,Transformer的结果都是相同的。为了解决这个问题,论文中在编码词向量时引入了位置编码(Position Embedding),词的位置信息通过位置编码来表示。
论文中令位置嵌入的维度和词向量的维度相同,然后与词向量相加。位置嵌入,可以帮我们判断每个词的位置和词向量之间的距离。
论文中的位置嵌入公式是:
P E ( p o s , 2 i ) = s i n ( p o s 100 0 2 i / d m o d e l ) PE_{(pos,2i)} = sin(\frac{pos}{1000^{2i/d_{model}}}) PE(pos,2i)=sin(10002i/dmodelpos)
P E ( p o s , 2 i + 1 ) = c o s ( p o s 100 0 2 i / d m o d e l ) PE_{(pos,2i+1)} = cos(\frac{pos}{1000^{2i/d_{model}}}) PE(pos,2i+1)=cos(10002i/dmodelpos)
以上便是Slef-Attention的全部内容。
构成Transformer的Encoder除了上述部分还有残差网络和一层归一化,通过图可以更容易明白。
2.1中详细介绍的Self-Attention可以通过下列代码实现。忘记的可以和前面的公式去对应。
class ScaledDotProductAttention():
def __init__(self, d_model, attn_dropout=0.1):
self.temper = np.sqrt(d_model)
self.dropout = Dropout(attn_dropout)
def __call__(self, q, k, v, mask):
attn = Lambda(lambda x:K.batch_dot(x[0],x[1],axes=[2,2])/self.temper)([q, k])
if mask is not None:
mmask = Lambda(lambda x:(-1e+10)*(1-x))(mask)
attn = Add()([attn, mmask])
attn = Activation('softmax')(attn)
attn = self.dropout(attn)
output = Lambda(lambda x:K.batch_dot(x[0], x[1]))([attn, v])
return output, attn
详细公式可以见2.4,以下为keras实现:
def GetPosEncodingMatrix(max_len, d_emb):
pos_enc = np.array([
[pos / np.power(10000, 2 * (j // 2) / d_emb) for j in range(d_emb)]
if pos != 0 else np.zeros(d_emb)
for pos in range(max_len)
])
pos_enc[1:, 0::2] = np.sin(pos_enc[1:, 0::2]) # dim 2i
pos_enc[1:, 1::2] = np.cos(pos_enc[1:, 1::2]) # dim 2i+1
return pos_enc
未完待续…有空继续更新
[1]AllenNLP 使用教程
[2]从Word Embedding到Bert模型—自然语言处理中的预训练技术发展史
[3]深度学习中的注意力模型(2017版)
[4]模型汇总24 - 深度学习中Attention Mechanism详细介绍:原理、分类及应用
[5]Tensorflow源码解读(一):Attention Seq2Seq模型
[6]基于Attention Model的Aspect level文本情感分类—用Python+Keras实现
[7]完全图解RNN、RNN变体、Seq2Seq、Attention机制
[8]浅谈Attention-based Model【原理篇】
[9] 浅谈 NLP 中的 Attention 机制
[10]Deep Learning基础–理解LSTM/RNN中的Attention机制
[11]Attention? Attention!
[12]详解Transformer (Attention Is All You Need)
[13]The Annotated Transformer-Harvard出品
[14] 聊聊 Transformer
[15]Transformer Translation Model-TensorFlow官方实现
[16] BERT大火却不懂Transformer?读这一篇就够了
[17] The Illustrated Transformer
[18] Visualizing A Neural Machine Translation Model (Mechanics of Seq2seq Models With Attention)
[19] Transformer注解及PyTorch实现(上)