目录
一、Bleu评价(Bilingual Evaluation Understudy)
1、N-gram
2、召回率
3.公式总结
4.BLEU算法代码实现
sentence_bleu语句级的bleu值
corpus_bleu语句级的bleu值
二、WMT数据集
1. 多模态NMT的数据集:
2. IWSLT(国际口语研讨会)数据集:
三、seq2seq
Encoder部分
Decoder部分
seq2seq模型举例
四、Attention机制
Attention整体流程
Step1 计算Encoder的隐藏状态和Decoder的隐藏状态
Step2 获取每个编码器隐藏状态对应的分数
Step3 通过softmax归一化分数
Step4 用每个编码器的隐藏状态乘以其softmax得分
Step5 把所有对齐的向量加起来
Step6 将上下文向量输入到Decoder中
Step7 反向传播
机器翻译的结果越接近人工参考译文就认定它的质量越高。
N-gram 准确率(N-gram Precision)
n-gram是指n 个连续单词组成的单元,称为n 元语法单元。n 越大表示评价时考虑的匹配片段越大BLEU的计算首先考虑待评价译文中n-gram在参考答案中的匹配率,称为n-gram 准确率(n-gram Precision)。其计算方法如下:
例如:原文:今天天气不错
机器译文:It is a nice day today
人工译文:Today is a nice day
如果用1-gram匹配的话:
可以看到机器译文一共6个词,有5个词语都命中的了参考译文,那么它1-gram的匹配度为 5/6我们再以3-gram举例:
可以看到机器译文一共可以分为四个3-gram的词组,其中有两个可以命中参考译文,那么它3-gram的匹配度为 2/4
依次类推,我们可以很容易实现一个程序来遍历计算N-gram的一个匹配度。一般来说1-gram的结果代表了文中有多少个词被单独翻译出来了,因此它反映的是这篇译文的忠实度;而当我们计算2-gram以上时,更多时候结果反映的是译文的流畅度,值越高文章的可读性就越好
上面所说的方法比较好理解,也比较好实现,但是没有考虑到召回率,举一个非常简单的例子说明:原文:猫站在地上
机器译文:the the the the
人工译文:The cat is standing on the ground
在计算1-gram的时候,the 都出现在译文中,因此匹配度为4/4 ,但是很明显 the 在人工译文中最多出现的次数只有2次,因此BLEU算法修正了这个值的算法,首先会计算该n-gram在译文中可能出现的最大次数:
Count是N-gram在机器翻译译文中的出现次数,Max_Ref_Count是该N-gram在一个参考译文中最大的出现次数,最终统计结果取两者中的较小值。然后在把这个匹配结果除以机器翻译译文的N-gram个数。因此对于上面的例子来说,修正后的1-gram的统计结果就是2/4。
译文整体的准确率等于各n-gram 的加权平均:
这里解释一下这个公式,N代表的总共的单词元组,例如,n=1时就是1-gram,一元组。wn是指当前单词元组下所占有的权重比,所有的权重比相加应当为1。从公式可以看出BLEU的取值范围是(0,1],0最差,1最好。这里值得注意的是,当所有的权重值是均分的时候,这里所有元组的平均值就是算术平均值。短句惩罚因子(Brevity Penalty, BP)
上面的算法已经足够可以有效的翻译评估了,然而N-gram的匹配度可能会随着句子长度的变短而变好,因此会存在这样一个问题:一个翻译引擎只翻译出了句子中部分句子且翻译的比较准确,那么它的匹配度依然会很高。为了避免这种评分的偏向性,BLEU在最后的评分结果中引入了长度惩罚因子(Brevity Penalty)c: 表示译文的句子长度,
r :表示参考译文的句子长度这个公式表示当译文小于参考译文(也就是翻译的句子过短是短句的时候)会得到一个BP值,并且最后的结果会乘上这个BP值来惩罚我们的短句翻译。这里放在指数上是为了扩大这种”惩罚“。
最终BLEU 的计算公式为:
总结一下:BLEU值其实也就是“改进版的n-gram”加上“过短惩罚因子”。
通过上面BLEU算法理论的学习,我们知道BLEU算法的原理。
接着要运用到一个nltk工具包里面定义好的BLEU算法。
anslate.bleu_score import sentence_bleu
reference = ['this', 'is', 'a', 'test']
candidate = ['this', 'is', 'a', 'test']
score = sentence_bleu(reference, candidate)
print(score)
anslate.bleu_score import corpus_bleu
references = [['this', 'is', 'a', 'test']]
candidates = [['this', 'is', 'a', 'test']]
score = corpus_bleu(references, candidates)
print(score)
score = corpus_bleu(references, candidates,weights,SmoothingFunction)
这里说明一下两个方法的一些参数介绍:
属性名 说明
references 参考语句也就是人工翻译的目标语句
candidates 候选语句也就是机器翻译得到的语句
weights 分配每个元组的权重值,这个权重指的是1-gram,2-gram, 3-gram等等的权重
累积
N-Gram
得分指的是为各个gram对应的权重加权, 来计算得到一个加权几何平均(weighted geometric mean). 默认情况下,sentence_bleu()
和corpus_bleu()
都是计算累积的4-gram BLEU分数的, 也称之为BLEU-4.
BLEU-4的加权策略如下: 1/4 (25%) 或者 0.25 对 1-gram, 2-gram, 3-gram and 4-gram 的得分.
# 4-gram cumulative BLEU
>>> anslate.bleu_score import sentence_bleu
>>> reference = [['this', 'is', 'small', 'test']]
>>> candidate = ['this', 'is', 'a', 'test']
>>> score = sentence_bleu(reference, candidate)
>>> score
1.0547686614863434e-154
>>> score = sentence_bleu(reference, candidate, weights=(0.25, 0.25, 0.25, 0.25))
>>> score
1.0547686614863434e-154
SmoothingFunction SmoothingFunction是用来平滑log函数的结果的,防止fn=0(也就是某个元组匹配数为0)时,取对数为负无穷
主要来源于WMT16,WMT17,WMT18的共享任务(Multi30k EN-DE,EN-Fr,EN-CS):
.html
.html
.html
IWSLT2011~IWSLT2020:;
如IWSLT2015:
train和dev:
:
test.de:
总数据集下载: .tgz
2. WMT(国际机器翻译研讨会)数据集:
3. OPUS:/
3. 中文机器翻译数据集:
4. 大规模中文自然语言处理语料:
5. 中文自然语言处理机器翻译语料库:.md
seq2seq模型虽然简单,但是特别经典,它的出现可以说给整个NLP带来个翻天覆地的变化。网上已经有很多人做了相关的总结,但是翻看起来还是感觉有点乱,于是想自己总结一个版本,方便自己回忆,也希望所写的内容能给大家带来帮助。由于平时都是直接拿来用,不需要在原理方面做推敲,所以公式部分就不详细介绍了,感兴趣的可以自己去阅读论文,下面只介绍相关原理及应用。
Seq2Seq,全称Sequence to Sequence。它是一种通用的Encoder——Decoder框架,可用于机器翻译、文本摘要、会话建模、图像字幕等场景中。其中Decoder部分的输出通常是不定长的,以机器翻译为例:将一句中文翻译成英文,那么这句英文的长度有可能会比中文短,也有可能会比中文长,所以输出的长度就不确定了。
如下图所示,输入的中文长度为4,输出的英文长度为2。下面的所有内容都以机器翻译为例。
Encoder负责将输入序列压缩成指定长度的向量,这个向量就可以看成是这个序列的语义,这个过程称为编码。
如下图,获取语义向量最简单的方式就是直接将最后一个输出的隐状态作为语义向量c。也可以对最后一个隐含状态做一个变换得到语义向量,还可以将输入序列的所有隐含状态做一个变换得到语义变量。
下图c代表生成的语义向量,q函数代表相应的变换(线性变换等)
Decoder部分就是根据Encoder部分输出的语义向量c来做解码工作。以翻译为例,就是生成相应的译文。
注意生成的序列是不定长的。而且上一时刻的输出通常要作为下一时刻的输入,如下图所示,预测y2时y1要作为输入。
得到语义向量c后,通常的做法是将c当做初始状态h0输入到Decoder中:
还有一种做法是将c当做每一步的输入:
一般而言在Decoder阶段上一步的输出会作为下一步的输入,如下所示:
邮箱对话
下面是一个收发邮件的例子,根据发来的消息生成相应的回复。
左右两边各有四个LSTM单元(黄色蓝色方块,每个方块代表一个LSTM单元),得到的语义向量c当做初始状态h0输入到Decoder中:
Attention机制是为了解决当翻译文本过长时,比如:
这里的用are而不用is是因为很久之前有一个pigs,当文本过长的时候,如果用一个和上边seq2seq一样的语义向量,关联性就被减弱了。所以提出了Attention机制
通过这种方法,模型能够有选择地关注输入序列的有用部分,从而了解它们之间的对齐关系,有助于模型更好地处理输入较长的句子。
模型结构如下:
此模型中语义编码c1、c2、c3各不相同,y1、y2、y3的生成方法为:
下面的内容会详细介绍Attention的整个流程:
通过为每个单词分配一个权重,注意力机制能够保证当前翻译的单词对原文各个单词的关注点不同(就是对照着原文翻译)。由于这个权重可能大于1,为了方便我们使用softmax进行归一化,得到归一化权重,然后计算Encoder隐藏状态和其对应归一化权重的加权和,得上下文向量c(语义编码)。
注意力层的实现可以分为6个步骤。
首先计算第一个解码器隐藏状态(红色)和所有可用的编码器隐藏状态(绿色)。下图中有4个编码器隐藏状态和当前解码器的隐藏状态。要想输出Decoder的第一个隐藏的状态,需要给Decoder一个初始状态和一个输入,例如采用Encoder的最后一个状态作为Decoder的初始状态,输入为0。
计算Decoder的第一个隐藏状态和Encoder所有的隐藏状态的相关性,这里采用点积的方式(默认两个向量长度一样)。后面是一个计算示例。
decoder_hidden = [10, 5, 10]
encoder_hidden score
---------------------
[0, 1, 1] 15 (= 10×0 + 5×1 + 10×1, the dot product)
[5, 0, 1] 60
[1, 1, 0] 15
[0, 5, 1] 35
在上面的例子中,对于编码器的隐藏状态[5, 0, 1],我们获得了较高的注意分值60。这意味着下一个要翻译的单词与此编码器的隐藏状态相关性很大。
我们把得到的分数输入到softmax层进行归一化,归一化之后的分数(标量)加起来等于1,归一化后的分数代表注意力分配的权重 。
encoder_hidden score score^
-----------------------------
[0, 1, 1] 15 0
[5, 0, 1] 60 1
[1, 1, 0] 15 0
[0, 5, 1] 35 0
注意,经过softmax之后的分数score^,注意力的分配仅按预期放在了[5, 0, 1]上。实际上,这些数字不是二进制的,而是0到1之间的一个浮点数。
通过将每个编码器的隐藏状态与其softmax之后的分数(标量)相乘,我们得到对齐向量 或标注向量。这正是对齐产生的机制。
encoder_hidden score score^ alignment
-----------------------------------------
[0, 1, 1] 15 0 [0, 0, 0]
[5, 0, 1] 60 1 [5, 0, 1]
[1, 1, 0] 15 0 [0, 0, 0]
[0, 5, 1] 35 0 [0, 0, 0]
在这里,我们看到除了[5, 0, 1]外,所有编码器隐藏状态的对齐都被降低到0,这是因为注意力得分较低。这意味着我们可以期望第一个被翻译的单词应该与输入单词中使用[5, 0, 1]嵌入所表示的单词匹配。
对齐向量进行求和,生成上下文向量(语义编码)。上下文向量是前一步对齐向量的聚合信息。
encoder_hidden score score^ alignment
-------------------------------------------
[0, 1, 1] 15 0 [0, 0, 0]
[5, 0, 1] 60 1 [5, 0, 1]
[1, 1, 0] 15 0 [0, 0, 0]
[0, 5, 1] 35 0 [0, 0, 0]
context = [0+5+0+0, 0+0+0+0, 0+1+0+0] = [5, 0, 1]
输入的方式和模型有关。我们会在后面的例子中看到不同的模型是如何利用Encoder的上下文向量的。
引用:Attention原理详解_小小鸟要高飞-CSDN博客_attention原理
《Attention is All You Need》浅读(简介+代码) - 科学空间|Scientific Spaces2017年中,有两篇类似同时也是笔者非常欣赏的论文,分别是FaceBook的《Convolutional Sequence to Sequence Learning》和Google的《
首页 信息时代 《Attention is All You Need》浅读(简介+代码) 6Jan2017年中,有两篇类似同时也是笔者非常欣赏的论文,分别是FaceBook的《Convolutional Sequence to Sequence Learning》和Google的《Attention is All You Need》,它们都算是Seq2Seq上的创新,本质上来说,都是抛弃了RNN结构来做Seq2Seq任务。
这篇博文中,笔者对《Attention is All You Need》做一点简单的分析。当然,这两篇论文本身就比较火,因此网上已经有很多解读了(不过很多解读都是直接翻译论文的,鲜有自己的理解),因此这里尽可能多自己的文字,尽量不重复网上各位大佬已经说过的内容。
深度学习做NLP的方法,基本上都是先将句子分词,然后每个词转化为对应的词向量序列。这样一来,每个句子都对应的是一个矩阵X=(x1,x2,…,xt)X=(x1,x2,…,xt),其中xixi都代表着第ii个词的词向量(行向量),维度为dd维,故X∈Rn×dX∈Rn×d。这样的话,问题就变成了编码这些序列了。
第一个基本的思路是RNN层,RNN的方案很简单,递归式进行:
yt=f(yt−1,xt)(1)(1)yt=f(yt−1,xt)第二个思路是CNN层,其实CNN的方案也是很自然的,窗口式遍历,比如尺寸为3的卷积,就是
yt=f(xt−1,xt,xt+1)(2)(2)yt=f(xt−1,xt,xt+1)Google的大作提供了第三个思路:纯Attention!单靠注意力就可以!RNN要逐步递归才能获得全局信息,因此一般要双向RNN才比较好;CNN事实上只能获取局部信息,是通过层叠来增大感受野;Attention的思路最为粗暴,它一步到位获取了全局信息!它的解决方案是:
yt=f(xt,A,B)(3)(3)yt=f(xt,A,B)Attention
Google的一般化Attention思路也是一个编码序列的方案,因此我们也可以认为它跟RNN、CNN一样,都是一个序列编码的层。
前面给出的是一般化的框架形式的描述,事实上Google给出的方案是很具体的。首先,它先把Attention的定义给了出来:
Attention(Q,K,V)=softmax(QK⊤dk−−√)V(4)(4)Attention(Q,K,V)=softmax(QK⊤dk)V那怎么理解这种结构呢?我们不妨逐个向量来看。
Attention(qt,K,V)=∑s=1m1Zexp(〈qt,ks〉dk−−√)vs(5)(5)Attention(qt,K,V)=∑s=1m1Zexp(〈qt,ks〉dk)vs事实上这种Attention的定义并不新鲜,但由于Google的影响力,我们可以认为现在是更加正式地提出了这个定义,并将其视为一个层地看待;此外这个定义只是注意力的一种形式,还有一些其他选择,比如queryquery跟keykey的运算方式不一定是点乘(还可以是拼接后再内积一个参数向量),甚至权重都不一定要归一化,等等。
Multi-Head Attention
这个是Google提出的新概念,是Attention机制的完善。不过从形式上看,它其实就再简单不过了,就是把Q,K,VQ,K,V通过参数矩阵映射一下,然后再做Attention,把这个过程重复做hh次,结果拼接起来就行了,可谓“大道至简”了。具体来说
headi=Attention(QWQi,KWKi,VWVi)(6)(6)headi=Attention(QWiQ,KWiK,VWiV)到目前为止,对Attention层的描述都是一般化的,我们可以落实一些应用。比如,如果做阅读理解的话,QQ可以是篇章的向量序列,取K=VK=V为问题的向量序列,那么输出就是所谓的Aligned Question Embedding。
而在Google的论文中,大部分的Attention都是Self Attention,即“自注意力”,或者叫内部注意力。
所谓Self Attention,其实就是Attention(X,X,X)Attention(X,X,X),XX就是前面说的输入序列。也就是说,在序列内部做Attention,寻找序列内部的联系。Google论文的主要贡献之一是它表明了内部注意力在机器翻译(甚至是一般的Seq2Seq任务)的序列编码上是相当重要的,而之前关于Seq2Seq的研究基本都只是把注意力机制用在解码端。类似的事情是,目前SQUAD阅读理解的榜首模型R-Net也加入了自注意力机制,这也使得它的模型有所提升。
当然,更准确来说,Google所用的是Self Multi-Head Attention:
Y=MultiHead(X,X,X)(8)(8)Y=MultiHead(X,X,X)然而,只要稍微思考一下就会发现,这样的模型并不能捕捉序列的顺序!换句话说,如果将K,VK,V按行打乱顺序(相当于句子中的词序打乱),那么Attention的结果还是一样的。这就表明了,到目前为止,Attention模型顶多是一个非常精妙的“词袋模型”而已。
这问题就比较严重了,大家知道,对于时间序列来说,尤其是对于NLP中的任务来说,顺序是很重要的信息,它代表着局部甚至是全局的结构,学习不到顺序信息,那么效果将会大打折扣(比如机器翻译中,有可能只把每个词都翻译出来了,但是不能组织成合理的句子)。
于是Google再祭出了一招——Position Embedding,也就是“位置向量”,将每个位置编号,然后每个编号对应一个向量,通过结合位置向量和词向量,就给每个词都引入了一定的位置信息,这样Attention就可以分辨出不同位置的词了。
Position Embedding并不算新鲜的玩意,在FaceBook的《Convolutional Sequence to Sequence Learning》也用到了这个东西。但在Google的这个作品中,它的Position Embedding有几点区别:
1、以前在RNN、CNN模型中其实都出现过Position Embedding,但在那些模型中,Position Embedding是锦上添花的辅助手段,也就是“有它会更好、没它也就差一点点”的情况,因为RNN、CNN本身就能捕捉到位置信息。但是在这个纯Attention模型中,Position Embedding是位置信息的唯一来源,因此它是模型的核心成分之一,并非仅仅是简单的辅助手段。
2、在以往的Position Embedding中,基本都是根据任务训练出来的向量。而Google直接给出了一个构造Position Embedding的公式:
⎧⎩⎨⎪⎪PE2i(p)=sin(p/100002i/dpos)PE2i+1(p)=cos(p/100002i/dpos)(9)(9){PE2i(p)=sin(p/100002i/dpos)PE2i+1(p)=cos(p/100002i/dpos)
这里的意思是将id为pp的位置映射为一个dposdpos维的位置向量,这个向量的第ii个元素的数值就是PEi(p)PEi(p)。Google在论文中说到他们比较过直接训练出来的位置向量和上述公式计算出来的位置向量,效果是接近的。因此显然我们更乐意使用公式构造的Position Embedding了,我们称之为Sinusoidal形式的Position Embedding。3、Position Embedding本身是一个绝对位置的信息,但在语言中,相对位置也很重要,Google选择前述的位置向量公式的一个重要原因是:由于我们有sin(α+β)=sinαcosβ+cosαsinβsin(α+β)=sinαcosβ+cosαsinβ以及cos(α+β)=cosαcosβ−sinαsinβcos(α+β)=cosαcosβ−sinαsinβ,这表明位置p+kp+k的向量可以表示成位置pp的向量的线性变换,这提供了表达相对位置信息的可能性。
结合位置向量和词向量有几个可选方案,可以把它们拼接起来作为一个新向量,也可以把位置向量定义为跟词向量一样大小,然后两者加起来。FaceBook的论文和Google论文中用的都是后者。直觉上相加会导致信息损失,似乎不可取,但Google的成果说明相加也是很好的方案。看来我理解还不够深刻。
还有,尽管论文给出的Position Embedding是sin,cossin,cos交错的形式,但其实这个交错形式没有特别的意义,你可以按照任意的方式重排它(比如前sinsin后coscos地拼接),原因如下:
1、假如你的Position_Embedding是拼接到原来的词向量中,那么将coscos和sinsin前后连接还是交叉连接,都是没区别的,因为你下一步都是接一个变换矩阵而已;
2、如果你的Position_Embedding是加到原来的词向量中,那么两种方式貌似是有点区别的,但是要注意的是,词向量本身没有局部结构,也就是说,50维的词向量,将每一维打乱重新排个序(当然整体要按同样的顺序来重新排序),它还是等价于原来的词向量。既然相加的对象(词向量)都没有局部结构,我们也没必要强调被加的对象(Position_Embedding)的局部结构(也就是交叉连接)了。
本文发布于:2024-02-05 04:34:37,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170724274663081.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |