Transformer
Transformer是一个基于自注意力的序列到序列模型,与基于循环网络的序列到序列模型不同,其可以并行计算。
序列到序列模型
序列到序列模型输入和输出都是一个序列,输入和输出序列长度之间的关系有两种情况。第一种情况下,输入和输出的长度一样;第二种情况下,机器决定输出的长度。序列到序列模型有广泛的应用,比如常见的语音识别、机器翻译与语音翻译,TTS,聊天机器人,问答任务,句法分析、多标签分类等等。
Transformer结构
一般的序列到序列模型会分成编码器和解码器。编码器负责处理输入的序列,再把处理好的结果丢给解码器,由解码器决定要输出的序列。
Transformer编码器
Transformer编码器使用的是自注意力,输入一排向量,输出一排长度相同的向量。编码器分成很多的块,每个块不是神经网络的一层,块的结构如图所示。
先跳过残差连接与层归一化的设计,在每个块里,输入一排向量后做自注意力,考虑整个序列的信息,再将输出丢到全连接网络里,输出另外一排向量,这一排向量就是块的输出。
这时候把残差连接和层归一化加进来,如图所示,最左边的向量输入到自注意力层后得到向量,向量加上向量得到新的输出。这就是残差连接的过程。得到残差的结果后再做层归一化,得到层归一化的输出后,该输出才是全连接网络所的输入。输入到全连接网络,还有一个残差连接,把全连接网络的输入和它的输出加起来后得到新的输出,接着再把残差的结果再做一次层归一化得到的输出才是一个块的输出,这个块会重复N次。
Transformer解码器
自回归解码器
比较常见的解码器为自回归解码器。解码器把编码器的输出先读进去,要想让编码器产生输出,首先要给它一个特殊token<BOS>(Begin Of Sequence)。在机器学习里,每一个token都可以用一个独热向量表示。接下来解码器会吐出一个向量,该向量的长度和词表的长度是一样的,内容是各个字/词的概率,总和为1,概率最高的结果就是输出。接下来再把这个结果当作解码器的新的输入,解码器看到<BOS>、“结果1”后会按照相同的过程输出结果2,这个过程会反复地持续下去。
Transformer的解码器内部结构如下图所示。类似于编码器,解码器也有多头注意力、残差连接和层归一化、前馈神经网络。解码器再做一个softmax,使其输出变成一个概率。此外,由于解码器的输出是一个一个产生的,与原有的注意力不同,解码器使用了mask self-attention,该attention可以通过一个掩码来阻止每个位置选择其后面的输入信息。
以下为一般的自注意力与掩蔽自注意力的对比
要让解码器停止运作,需要另一个特殊的token<EOS>,当输出<EOS>时,整个解码器产生序列的过程就结束了
非自回归解码器
假设产生中文的句子,非自回归不是一次产生一个字,它是一次把整个句子都产生出来。非自回归的解码器可能“吃”的是一整排的<BOS>token,一次产生产生一排token。因为输出的长度是未知的,所以当做非自回归解码器输入的<BOS>的数量也是未知的,因此有如下两个做法。
-
用分类器来解决这个问题。用分类器“吃”编码器的输入,输出是一个数字,该数字代表解码器应该要输出的长度。比如分类器输出4,非自回归的解码器就会“吃”4个<BOS>的词元,产生4个中文的字。
-
给编码器一堆<BOS>的词元。假设输出的句子的长度有上限,绝对不会超过300个字。给编码器300个,就会输出300个字,输出右边的的输出就当它没有输出。
非自回归的解码器有很多优点。第一个优点是平行化。自回归的解码器输出句子的时候是一个一个字产生的,假设要输出长度一百个字的句子,就需要做一百次的解码。但是非自回归的解码器不管句子的长度如何,都是一个步骤就产生出完整的句子,所以非自回归的解码器 会跑得比自回归的解码器要快。另外一个优点是非自回归的解码器比较能够控制它输出的长度。
编码器-解码器注意力
关于编码器-解码器注意力的运作过程,如下图所示。编码器输入一排向量,输出一排向量。接下来解码器会先"吃"<BOS>,经过掩蔽自注意力得到一个向量,再把这个向量乘上一个矩阵,得到。也都产生key。把和相乘得到,再做softmax得到,通过即可得加权和,最后交给全连接网络处理。
Transformer 的训练过程
以"机器学习"为例,把<BOS>丢给解码器的时候,其第一个输出与”机”越接近越好,而编码器的输出是一个概率的分布,即这个概率分布和“机”的独热向量越接近越好。因此我们会计算标准答案与分布之间的交叉熵,希望该交叉熵的值越小越好。每一次解码器在产生一个中文字的时候做了一次类似分类的问题
序列到序列模型训练常用技巧
复制机制(copymechanism)
以聊天机器人为例,用户对机器说:“你好,我是库洛洛”。机器应该回答:“库洛洛你好,很高兴认识你”。机器其实没有必要创造“库洛洛”这 个词汇,“库洛洛”对机器来说一定会是一个非常怪异的词汇,所以它可能很难在训练数据里面出现,可能一次也没有出现过,所以它不太可能正确地产生输出。但是假设机器在学的时候, 学到的并不是它要产生“库洛洛”,它学到的是看到输入的时候说“我是某某某”,就直接把“某某某”复制出来,说“某某某你好”。这种机器的训练会比较容易,显然比较有可能得到正确的结果,所以复制对于对话任务可能是一个需要的技术。机器只要复述这一段它听不懂的话,它不需要从头去创造这一段文字,它要学的是从用户的输入去复制一些词汇当做输出。最早有从输入复制东西的能力的模型叫做指针网络(pointer network),后来还有一个变形叫做复制网络(copy network)。
引导注意力
束搜索/贪心搜索/贪心解码
加入噪声
在做语音合成的时候,解码器加噪声,这是完全违背正常的机器学习的做法。在训练的时候会加噪声,让机器看过更多不同的可能性,这会让模型比较鲁棒,比较能够对抗它在测试 的时候没有看过的状况。但从正常角度讲,在测试的时候也加一些噪声,会把测试的状况弄得更困难,结果更差。但语音合成神奇的地方是,模型训练好以后。测试的时候要加入一些噪声, 合出来的声音才会好。用正常的解码的方法产生出来的声音听不太出来是人声,产生出比较好的声音是需要一些随机性的。对于语音合成或句子完成任务,解码器找出最好的结果不一定是人类觉得最好的结果,反而是奇怪的结果,加入一些随机性的结果反而会是比较好的。
使用强化学习训练
BLEU现被广泛用于评价许 多应用输出序列的质量。解码器先产生一个完整的句子,再去跟正确的答案一整句做比较,拿两个句子之间做比较算出BLEU分数。但训练的时候,每一个词汇是分开考虑的,最小化的是交叉熵,最小化交叉熵不一定可以最大化BLEU分数。但在做验证的时候,并不是挑交叉熵最低的模型,而是挑BLEU分数最高的模型。一种可能的想法:训练的损失设置成BLEU 分数乘一个负号,最小化损失等价于最大化BLEU分数。但BLEU分数很复杂,如果要计算两个句子之间的BLEU分数,损失无法做微分。我们之所以采用交叉熵,而且把每一个中文的字分开来算,就是因为这样才有办法处理。遇到优化无法解决的问题,可以用强化学习训练。具体来讲,遇到无法优化的损失函数,把损失函数当成强化学习的奖励,把解码器当成智能体,具体可参考论文“Sequence Level Training with Recurrent Neural Networks”
计划采样
测试的时候,解码器看到的是自己的输出,因此它会看到一些错误的东西。 但是在训练的时候,解码器看到的是完全正确的,这种不一致的现象叫做曝光偏差。
假设解码器在训练的时候永远只看过正确的东西,在测试的时候,只要有一个错,就会一步错步步错。因为解码器从来没有看过错的东西,它看到错的东西会非常的惊奇,接下来它产生的结果可能都会错掉。给解码器的输入加一些错误的东西,不要给解码器都是正确的答案,偶尔给它一些错的东西,它反而会学得更好,这一技巧称为计划采样


















