目录
attention is all you need的解读可以参考
https://daiwk.github.io/posts/platform-tensor-to-tensor.html
各种attention model可以参考:
https://daiwk.github.io/posts/dl-attention-models.html
本文参考自然语言处理中的自注意力机制(Self-Attention Mechanism)
论文作者之一Lukasz Kaiser的ppt:https://daiwk.github.io/assets/attention-is-all-you-need-lkaiser.pdf
https://www.jianshu.com/p/48e71b72ca67
Adam 优化器可以说是目前使用最广泛、收敛速度较快且收敛过程较稳定的优化器。Adam 的计算公式如图所示。可以看到公式中梯度的计算使用了动量原理,每一轮用于梯度下降的梯度是当前计算的真实梯度与上一轮用于梯度下降的梯度的加权和。这样动量的引入可以防止训练时产生震荡。Adam 优化器的学习率对于不同参数也是不同的,由该参数历史每一轮的真实梯度的大小决定。好处是对于 NLP 这种输入极度稀疏且输入特征极度不平衡(例如整个预料库中“我”这样的词经常出现,而“拉姆塞”这样的词只出现几次)的任务,学习率是自适应的,一些在一次训练 epoch 中只更新几次的 embedding,在训练后期还是会有较大的学习率。
NLP 输入稀疏的特点与 Adam 使用动量计算梯度的特点相结合就引入了麻烦。每一轮更新参数时,只有极少数 embedding 的梯度是非 0 的,大部分 embedding 的梯度是 0 即上图公式中的 gt 是 0。但是,计算了动量之后,这些原本梯度都应该是 0 的 embedding 有了非零梯度 mt 用于梯度下降更新。想象一个极端的例子,“拉姆塞”这个词在一个 epoch 中只在第一个 batch 出现了,于是第一个 batch 计算了“拉姆塞”这个 embedding 的真实梯度 g0 用于更新参数,在以后的每个 batch 中虽然“拉姆塞”这个词没有出现过,Adam 都会计算它的动量梯度 mt,并用于更新“拉姆塞”这个 embedding,实际上方向与 g0 完全相同,只是每一轮做一次 β1 倍的衰减。这样的做法就相当于对这些出现次数较少的低频词的 embedding,每次梯度下降的等效学习率是非常大的,容易引起类似过拟合的问题。
每轮迭代只更新这个 batch 中出现过的词的 embedding 即可。TensorFlow 中可以使用 tf.contrib.opt.LazyAdamOptimizer
。
参考https://www.zhihu.com/question/265357659/answer/580469438
和图像等领域不同,对 NLU 之类的任务,每个 batch 采样到的词有限,每次更新对 Embedding 的梯度估计都是稀疏的。非 momentum-based 的 Optimizer 每步只会更新采样到的词,而对于 momentum-based 的 Optimizer,现在所有框架的实现都会用当前的 momentum 去更新所有的词,即使这些词在连续的几十步更新里都没有被采样到。这可能会使 Embedding 过拟合。
Attention函数的本质可以被描述为一个查询(query)与一系列(键key-值value)对一起映射成一个输出。分为以下3步:
\[
attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt {d_k}})V
\]
目前在NLP研究中,key和value常常都是同一个,即 key=value(如下例中的源语言的编码器输出)。
对比https://daiwk.github.io/posts/nlp-nmt.html#4-%E6%B3%A8%E6%84%8F%E5%8A%9B%E6%9C%BA%E5%88%B6以及https://daiwk.github.io/posts/platform-tensor-to-tensor.html#422-attention可以发现:
\(h_j\)
就是\(V\)
\(h_j\)
同样是\(K\)
\(z_i\)
就是\(Q\)
\(e_{ij}\)
就是\(\frac{QK^T}{\sqrt {d_k}}\)
\(a_{ij}\)
就是\(softmax(\frac{QK^T}{\sqrt {d_k}})\)
\(c_i\)
就是最终的\(attention(Q,K,V)\)
所以说,机器翻译的attention,本质就是想给源语言的encoder输出的每一个元素\(h_j\)
(即V) 搞一个权重,然后加权求和。而这个权重是通\(h_j\)
它自己 (即K=V) 与目标语言的隐层状态\(z_i\)
(即Q) 进行变换得到的。所以:
k=v=源语言的encoder输出,q=目标语言的隐层状态。
再理解回nmt里(不理那个\(\sqrt{d_k}\)
)。假设emb是d维,那么 Q是mxd,K是nxd,i=1->m,j=1->n,\(e_{ij}=QK^T\)
是一个m行目标语言,n列源语言的矩阵,那么\(a_{ij}\)
是对\(e_{ij}\)
求softmax,分母就是第i行每个元素(即这第i个目标语言的词,对应的所有源语言词)的exp之和,分子就是第i行第j列(第i个目标语言词对应的第j个源语言词)的exp,即\(a_{ij}=\frac {exp(e_{ij})}{\sum _{k=1}^Texp(e_{ik})}\)
看分母,是固定i,遍历j,也就是固定第i行,求这行每一列的和。
再强调一次,一定要记得i、Q、m是目标语言的,j、K、n是源语言的,所以是\(QK^T\)
,我们要拿attention来对源语言也就是V=K来做加权。做加权这步,就是一个mxn的矩阵,乘一个nxd的矩阵,得到最后mxd矩阵。就是第i行和nxd的一列对应相乘相加,得到一个元素,最后总共得到m个元素。相当于对于目标语言的第i个词来讲,他和源语言的每个词(共n个词)分别有个相关性(mxn矩阵的一行),然后作为这次输入的n个词的权重,求个和,当做这第i个目标语言的词的表示,即最终mxd的第i行的一个元素。而可以看到这个权重,对d维的emb的每一维的作用都是一样的(emb的第1维,即nxd的第1列和mxn的第i行相乘相加得到一个元素;emb的第2维,即nxd的第2列,和mxn的第i行相乘相加得到一个元素,这次运算和上一次运算,对于这一列的每一行来讲,它乘的mxn里的那一行是一样的,也就是说对一个给定的目标语言的词语,即mxn的第i行来讲,他对每一个源语言的词的影响权重在每一维源语言的emb(例如nxd的第1列和第2列)上都是一样的)。
另外,得到的context只是作为产出下一个目标语言词的输入之一,还有前一个目标语言的词,及前一个目标语言的隐层状态。
再来理解一下其中的softmax那步:
类比一个分类任务,m行n列,m个样本,n个类别,每一行就是对这个样本而言,他在这个分类的概率,所以分子是这个类别,分母是所有类别(这一行求和)
类似地,对于这个attention矩阵,m行n列,m个目标语言,n个源语言,一行就是一个目标语言的词,表示这个词和源语言每个词的相关程度,所以分母是所有源语言的词(这一行求和)。
某个时候整理了个ppt:
注意:输出的attention维度和Q一样,都是mxn
\(d_{model}\)
维,各自通过h个线性变换(即每个\(W^Q,W^K,W^V\)
)拆成h部分,每一部分的大小是\(d_k\)
,\(d_k\)
和\(d_v\)
(\(d_k=d_v=d_{model}/h\)
)。不同之处在于进行了h次计算而不仅仅算一次,论文中说到这样的好处是可以允许模型在不同的表示子空间里学习到相关的信息。
Self-Attention即K=V=Q,例如输入一个句子,那么里面的每个词都要和该句子中的所有词进行Attention计算。目的是学习句子内部的词依赖关系,捕获句子的内部结构。
使用self-attention的原因:
decoder中的masked att:
参考https://zhuanlan.zhihu.com/p/79872507
每个词只能看到他前面的词,后面的要mask掉
在gpt-2中,就是把要mask的乘以负无穷。qk如下:
乘以mask矩阵后如下:
计算softmax后如下:
当然,在讲t2t的时候,就讲到了https://daiwk.github.io/posts/platform-tensor-to-tensor.html#426-why-self-attention
不过,我们可以参考放弃幻想,全面拥抱Transformer:自然语言处理三大特征抽取器(CNN/RNN/TF)比较再来对比一下~
nlp问题的特点:
主要的nlp任务:
基本原理不再赘述,看看rnn并行化的两个主要套路
Simple Recurrent Units for Highly Parallelizable Recurrence
在nmt上,transformer+sru比单纯transformer的bleu提升约0.7个点。
SRU的核心思想就是仍然保留任意连续时间步(T-1和T)之间的隐层连接,然后在网络结构上做了一些改变,可以参考知乎的讨论:如何评价新提出的RNN变种SRU?
先看下原始的gru:https://daiwk.github.io/posts/nlp-nmt.html#12-gru
\[
\\ z_t=\sigma(W_zx_t+U_zh_{t-1}+b_z)
\\ r_t=\sigma(W_rx_t+U_rh_{t-1}+b_r)
\\ h_t=z_t \circ h_{t-1}+(1-z_t) \circ tanh(W_hx_t+ U_h(r_t \circ h_{t-1}) + b_h)
\]
然后从知乎偷个图:
在gru的基础上进行修改,将各个时间步的gate和transformed input的计算只依赖于当前时间步的输入,然后在recurrent layers之间添加了skip connections(严格来说是highway connections)
所以,
因此这个RNN单元现在的计算瓶颈就在三个矩阵乘法了,最后将这三个矩阵乘法可以归并成一个矩阵乘法。
作者为了进一步的加速,将上面的各个时间步之间的element-wise的操作优化实现成了CUDA kernel functions。
翻译模型把原文句子整体读进去以后形成了一个向量,然后再对这个向量进行解码。翻译模型认为有些词不应该产生,从而漏掉了译文。
Addressing the Under-translation Problem from the Entropy Perspective这篇就发现漏译与词语的熵成正相关关系,这个词的熵越大,漏译的可能性越大。它所对应的目标语言词越多,概率越分散(熵越大),越有可能被漏译。
例如源语言的一个词s1
对应3种不同的翻译,(s1,t1),(s1,t2),(s1,t3 t4)
,它的熵就比较大。我们把所有对应的翻译统一替换为一个特殊词stoken4s1
,以降低词语翻译的熵值。然后文章提出了pre-training, multitask learning, two-pass decoding三种方法,来改善翻译结果。
相比于统计机器翻译,这个问题对神经网络翻译而言更严重。实验表明,神经网络对于数据量更敏感。
Multi-Task Learning for Multiple Language Translation在进行多语言翻译的时候,源语言共享编码器,在解码端,不同的语言,使用不同的解码器。这样在源语言端就会共享编码器的信息,从而缓解数据稀疏问题。
Phrase-Based & Neural Unsupervised Machine Translation是EMNLP’18的best paper,提出了一个统一的框架,通过两种单语言,来构建翻译系统。
我们引入了几种知识,
但这样还可能有歧义问题,因为比如中巴关系,可以是中国和巴基斯坦,中国和巴西,中国和巴勒斯坦等的缩写,如果限定了『金砖框架』下的,那就只能是巴西了,所以这还是有挑战的。
Visualizing and Understanding Neural Machine Translation
左边的例子,出现了一个UNK,它虽然没有被翻译出来,但是出现在正确的位置,占了一个位置。通过Attention对应关系,可以看到这个UNK对应到『债务国』。
右边例子是一个重复翻译的现象。神经网络机器翻译除了经常漏翻译之外,还会经常重复翻译。比如说出现了两个“history”。那么通过这个对应关系我们就可以看到,第6个位置上的“history”是重复出现的,它的出现不仅跟第一个位置“美国人”和第二个位置“历史”相关,还跟第5个位置“the”相关。因为产生了一个定冠词“the”,模型认为这个地方应该出现一个“history”。
Modeling Coherence for Discourse Neural Machine Translation提出了一个两步解码的方法。在第一轮解码中单独生成每个句子的初步翻译结果,在第二轮解码中利用第一轮翻译的结果进行翻译内容润色,并且提出使用增强式学习模型来奖励模型产生更流畅的译文。
参考清华刘洋《基于深度学习的机器翻译》,突破知识整合、可解释和鲁棒性三大难关
Prior Knowledge Integration for Neural Machine Translation using Posterior Regularization
在这项工作中,建议使用后验正则化来提供一个将先验知识整合到神经机器翻译中的通用框架。将先验知识来源表示为一个对数线性模型的特征,该模型指导神经翻译模型的学习过程。汉英翻译实验表明,该方法取得了显著的改进。
Visualizing and Understanding Neural Machine Translation
这项工作主要的贡献包括:
输入中的小扰动会严重扭曲中间表示,从而影响神经机器翻译(NMT)模型的翻译质量。
机器翻译里,假设emb是d维,正常机器翻译里,源语言K=V是nxd,目标语言Q是mxd
softmax(QK^T)是mxn,第i行第j列是源语言的第j个词在所有源语言的词里,对第i个目标语言词的重要程度
假设有一个rank问题,m个队列,n个位置,每个队列有n条结果,每条结果是一个d维向量
Q是(mxd)xn,姑且把mxd这个向量看成一维的,即d=1,
K是nxn,表示每个位置间两两的关系
QK^T是(mxd)xn,第i行第j列是第j个位置在所有位置里,对第i个队列的重要程度
。。真绕
从我自己的角度,yy了一下:
m个队列,n个位置,每个队列有k条结果,每个结果是一个d维向量
Q: (mxd)xk,m行表示m个队列,k列表示k条结果
K: nxk,n行表示n个位置,k列表示k条结果,也就是每个位置与每一条结果间的权重
V: nxk,同K
softmax(QK^T):(mxd)xn维,第i行第j列表示,第j个位置在所有位置里,对第i个队列的重要程度
softmax(QK^T)V:(mxd)xk维,
有点奇怪。。如果把k和n互换呢。。。
再想想。。