文章目录
介绍
本门课程是2020年李宏毅老师新课:Deep Learning for Human Language Processing(深度学习与人类语言处理)
课程网站
B站视频
公式输入请参考:在线Latex公式
这节课是莊永松主讲,关于Non-Autoregressive这个在BERT and its family.2/2中有提到过这个名词,与之对应的是Autoregressive。所谓的Autoregressive Sequence Generation就是从左到右的一个个的生成token。Non-Autoregressive Sequence Generation则是同时生成,下面来看一下典型的Autoregressive Sequence Generation模型(inference stage):
RNN,逐个的吃token,然后生成token的时候是生成下一个token的时候要参考当前时间步的token,因此,无论是输入和输出都比较花费时间。
后来有了BERT,这个时候就可以用BERT替换输入模块,这个时候可以直接一次把所有的输入都吃进来,不用一个个的吃,输入的速度是解决了,但是输出还是和RNN一样,一个个的往外吐:
因此,就想能不能把输出也改成直接吐所有的token的模式,这个就是Non-autoregressive model的目标:
难点
图片
要实现上面提出的目标,有难度,借用之前ML课程中讲过的一个例子来说:
有一个Text-to-lmage的任务,就是给一段文字,然后模型为文字配一个图片,传统使用有监督的方式进行训练,例如下图中给出的文字是奔跑的狗子,那么模型生成的图片要和ground truth要越接近越好
假如我们给出的文字是【train】,然后由于数据库中的ground truth有很多火车的图片,那模型就犯傻了,要想和所有有火车的图片都as close as possible怎么办?只能把所有火车图片都拿过来求平均,然后计算一个相似的结果:
最后的的结果就是模糊不清的,模型又想像这张图片,又想像那张图片。
究其原因就是在模型的输出层上,各个神经元之间没有相互联系(No dependency on output structure),例如下图的第二神经元在输出ink的时候,它并不知道邻居神经元产生什么东西
解决这个问题可以用Autoregressive model,ex: PixelRNN;另外还可以用GAN,使用GAN的discriminator来判别生成的图片是否真实,使得Generator学会生成清晰,真实的图片。
另外一个原因就是没有隐变量来控制生成结果的,例如上面已经知道,ground truth有70%几率来做白灯火车,30%几率来自黑灯火车,但是在生成结果的时候输出层并没有根据这个比例来进行生成数据。
对于整个问题,Autoregressive model也是有解决方法的,因为每个时间步中,Autoregressive model都是pick当前时间步输出分布中几率最大那个;
而GAN也在输入的时候要吃一个正态分布,就是要使得输出有一个确定的方向。
文字
了解了图片的例子,再来看文字的是什么情况,假如我们使用Non-Autoregressive Sequence Generation的方式来进行translation。输入是【Hello!】,输出可以看到有好几种合理的翻译。
我们假定在groud truth中的几率分布如下:
那么对应的输出的分布就如下图所示:
可以看到输出第一个token中【哈】【你】几率都相等,都为50%,第二个token同理。那么在输出整个sequence的时候就有可能是:
明显这两个都是错误的翻译,但是都是有可能被模型sample出来的结果。
我们将这个问题称为:multi-modality problem,同一个输入,可能对应多个输出,那么Non-Autoregressive模型就会把各种可能的输出进行叠加,导致错误。
小结
generate target /methods | Image | Text |
---|---|---|
naive approach | Deconvolution layer + L2 loss,求均值,效果差 | non-autoregressive decoder,multi-modality problem本文重点要解决的问题 |
autoregressive | PixelRNN, VQVAE-2,效果好 | autoregressive decoder,成熟,缺点是一个个输出效率低 |
Generative Adversarial Networks/ non-auto model | 效果好 | 文字应用还不成熟,待研究 |
Vanilla NAT (Non-Autoregressive Translation)
这个是第一篇用在翻译上的论文这个文章提出了几个trick,来改进Non-Autoregressive模型,第一个就是:
Fertility
·Predict fertility as latent variable & Copy input words.
·Represents sentence-level “plan” before writing Y.
这个trick就是在encoder部分加入输入单词对应的翻译结果的长度,例如,下图中的2121表示【Hello】翻译后对应2个token,【,】对应一个token,以此类推:
这个做法可以使得在句子层面对翻译这个任务进行提前布局,例如:
2121和1121分别对应的结果是:
这个Fertility的训练有两种方法:
1.Labels comes from external aligner.使用外部的aligner工具,这个工具会自动给出翻译结果对应原文的哪些字
2.Observing attention weights in auto-regressive models.直接训练一个seq2seq的auto-regressive model,然后看其attention权重如何分布,就可以看出输出结果对应输入的哪个字。这个方法用在翻译上比较多。
由于Fertility模型目标和NAT模型目标不一样的,因此,需要在NAT模型训练好之后,用REINFORCE的方式对fertility classifier进行Fine-tune。
第二个trick是:
Sequence-level knowledge distillation
knowledge distillation在之前的ML课程里面有讲,就是有一个比较小的模型(绿色),这个模型训练是以另外一个大的模型(蓝色)为老师,两个模型吃相同的输入,然后大的模型已经训练好了,这个时候有一个输出,小模型的目标是输出和大模型的输出交叉熵最小化。
对于翻译任务而言:
Teacher: Autoregressive model, Student: Non-autoregressive model
Construct new corpus by autoregressive teacher model
Teacher’s greedy decode output as student’s training target
如果用autoregressive 模型做老师,那么在输出的时候,如果第一个token选择【你】,那么autoregressive 模型就会给第二个token为【好】字几率变高,那么也就是说,整个模型的输出不在有两种可能,而是只有一种,【你好】
然后Non-autoregressive model在以autoregressive model的输出做为训练集的话,就不会存在多种正确答案的情况。
第三个trick:
Noisy Parallel Decoding (NPD)
1.Sample several fertility sequences
2.Generate sequences
3.Score by a autoregressive model
首先给出不同的fertility的组合,那么这些不同的组合会使得生成的结果也不一样,然后把生成出来的不同结果丢进Autoregressive Decoder中,让Autoregressive Decoder判断哪个结果最好:
这里注意,Autoregressive Decoder判断的过程不需要一个个的token进行,全部只需要一个时间步就可以搞定。
计算出每一个token对应的几率,然后把这些几率乘起来,就得到整句话的几率。
Evolution of NAT
- Vanilla NAT
a. Gu et al., ICLR′18
在原始的NAT的算法后,基本每年都有对其进行改进的方法:
2. Iterative Refinement
a. iNAT, Lee et al, EMNLP18
b. Mask-Predict, Ghazvininejad et al., EMNLP′19
这个算法的思想是在一次性输出某句话后,再把输入拿过来,重新迭代的对输出进行修正(下图中的红箭头),但是注意,这个方法在第一次的输出之后,对其进行修正时输出的长度是不变的,而是把对应的输入进行copy,例如下图中的你好对应两个hello。
- Insertion-based
a. Insertion Transformer, Stern et al., ICML’19
b. KERMIT, Chan et al, arXiv19
这个算法针对算法2中输出长度不能变化的缺点,设定了可以对输出进行插入的设定,使得输出的长度可以变化。例如一句话是[A,B,C,D,E,F,G],这里先生成子序列[D],再插入[D]周围词,以此类推。
0→[D]→[B,D,F]→[A,B,C,D,E,F,G] - Insert+Delete
Levenshtein Transformer, Gu et al., NeurIPS’19
算法3中只对输出进行插入,如果插入了错字就没有办法进行处理,因此这个算法加入了删除功能。 - CTC-based
a. E2E NAT w/ CTC, Jindrich Libovick et al., EMNLP’20
b. NAT w/ Latent Alignments, Saharia et al., arXiv’20
NAT with Iterative Refinement
这个迭代的思想就是吃一个句子X,一步一步的调节输出
Y
L
Y_L
YL,直到最后得到结果Y:
具体模型结构如下图所示:
可以看到,第一个Encoder先预测target length,然后按照长度进行copy,经过第一个decoder_1,得到第一个输出
Y
0
Y_0
Y0,然后将
Y
0
Y_0
Y0作为输入,经过decoder_2得到第二个输出,不断重复好几次这个过程。
训练decoder_2可以将groud truth加入一些noise(将字进行重复,或者替换为随机字,或者交换顺序等),让decoder_2学习如何去噪。
Corruption Process(加入一些noise)
(1) replace
y
t
+
1
y_{t+1}
yt+1 with
y
t
y_t
yt
(2) replace
y
t
y_t
yt with a random token
(3) swap
y
t
y_t
yt and
y
t
+
1
y_{t+1}
yt+1.
这个算法效果提升不是很明显。
Mask-Predict
Conditional Masked Language Models (CMLM):这个算法是在BERT之后提出来的,借用了BERT中mask的思想,结构如下:
具体做法如下,在t=0时间步,先根据输入预测输出的长度,这里是6,那么就在Decoder(是BERT)中设置6个mask,然后BERT会得到第一版的翻译结果。
然后在t=1时间步,将第一版输出得到结果中几率比较低的字符替换为mask,再次丢入模型得到第二次输出。以此类推
每次mask的字符数量为n,计算方式如上图左下角的公式,随着时间慢慢减少。
Example: (target length is fixed)
Insertion Transformer
Partially Autoregressive Model,不是纯正的NAT,该模型会在每两个字之间做预测,是否需要插入新字。
具体做法如下,如图所示,假设的输入有6个,因此其输出(粉色)也是6个,然后将这六个输出vector两两进行concat操作(紫色)
然后把concat的结果用来预测插入词。如果不需要插入则获得【end】(end of slot),如果得到字,就把字插入到原句子中。
模型训练过程如下图所示,先将原句子打乱,然后随机给定一个数字,例如下图中是5,取前5个字,然后将前5个字还原回原句子的位置,其他去掉的字就形成了slots,然后就得到一个训练样本。
将这个训练样本丢到模型:这里两个字中间的slot对应多个字的,那么就是两个loss的allset?(这里没听清)
生成一个slot对应多个字符的情况有一个trick,这里不是为每个字符都给与相同的概率(下图中的红色),而是更加偏向生成中间的字符(下图中的蓝框),因为每次都生成中间的字符,这样整个生成过程就会按Binary tree那样效率高。
具体体现在公式中的红圈部分,中间的字权重比较大:
看一个具体例子:
Input: But on the other side of the state, that is not the impression many people have of their former governor.
Output: Aber auf der anderen Seite des Staates ist das nicht der Eindruck, den viele von ihrem ehemaligen Gouverneur haben.
用Binary tree loss(这里的计算是并行的)每次都最先Decoder的是中间的字。
Input: They want to create a post on the college’s equal opportunities committee to ensure that their opinions can be aired freely.
Output: Sie wollen einen Posten im Ausschuss fir Chancengleichheit des Kollegiums einrichten, um sicherzustellen, dass ihre Meinungen frei zur Sprache gebracht werden konnen.
使用uniform loss(这里的计算是并行的):
KERMIT
Kontextuell Encoder Representations Made by Insertion Transformations(第一个单词是上下文的德文)
这个算法对于 Insertion Transformer而言是将encoder和Decoder都合并在一起了:
这样做的好处:
做中翻英
P
(
y
∣
x
)
P(y|x)
P(y∣x),就是放完整的英文,在中文那边做插入:
做英翻中
P
(
x
∣
y
)
P(x|y)
P(x∣y),就是放完整的中文,在英文那边做插入:
中英文一起drop一些词,模型做预测
P
(
x
,
y
)
P(x,y)
P(x,y)(求联合概率):
当然可以只做中文或者英文:
也就是一个模型可以同时做5个任务结果表明任务越多,效果越差,但是最后加上finetune可以超越单个任务。
这个模型在做问答完形填空任务比较强:Zero-shot ClozeQA
这个模型还有一个改进版本:Multilingual KERMIT,专门针对多语言进行处理。
Levenshtein Transformer
这个模型是在插入的基础上加入了删除功能,模型如下图所示:
可以看到输入经过encoder之后得到初始的输出要经过三个Decoder:
第一个Decoder是一个删除分类器,判断是否需要删除当前单词;
第二个Decoder是一个插入分类器,判断是否要在当前单词与单词之间插入单词,如果插入则生成一个占位符【PLH】place holder;
第三个Decoder是token分类器,根据【PLH】的位置预测对应的单词。
这个模型训练就是采用上面提到的从另外一个模型学习的方法(knowledge distillation)。具体算法称为:Levenshtein Distance Algorithm
例子:
>>> import Levenshtein
>>> Levenshtein.distance("ABCEFGHJJ", "ABCDEFGHI")
3
>>> Levenshtein.editops("ABCEFGHJJ", "ABCDEFGHI")
[('insert', 3, 3), ('delete', 7, 8), ('replace', 8, 8)]
这个文章的算法中把最后的replace分解为删除和插入操作。
训练过程如下:
先生成一系列需要删除单词的句子
y
d
e
l
y_{del}
ydel,这个只要将正常句子中单词替换一些就可以;
再生成一系列需要插入单词的句子
y
i
n
s
y_{ins}
yins,这个只要将正常句子中单词删除一些就可以。
有了上面的数据集后,就可以按下面的模型进行训练:
例如第一个句子输入模型,根据Levenshtein Distance Algorithm看的正确答案,第三个单词要删除,其他单词保持不变;第二个句子输入模型,根据Levenshtein Distance Algorithm看的正确答案,要在第二空位插入2个单词(第一个空位是<s>和This这两个单词中间);最后一个句子就不用说了。
下面是两个例子:
针对a)这个例子,可以看到第一个iteration中刚开始啥都没有,所以不需要进行delete操作,然后插入一堆,然后在第二个iteration进行删除和插入,直到没有东西可以插入和删除结束。
下面是算法的结果比较:
当采用transformer作为teacher效果最好,然后在速度上比原来的Autoregressive Generation要明显快很多。
CTC
这个模型之前有讲过,这里只是拿过来比较一下,因为:
1.CTC也是Non-Autoregressive模型,只不过用在语音识别上;
2.语音识别没有multi-modality问题,就是一段语音对应多个结果。(特殊情况当然也有,不过加入LM可以解决,例如有人说:城市/程式还不错!)
但是这个模型有两个缺点:
1.虽然效果还不错,但是比不过seq2seq模型LAS;
2.语音经过Encoder之后得到的文字数据,不能再次经过refine操作进行修改,只能Encoder一次。例如下面红色明显是输出错误了,但是模型也无力回天。
Imputer
为了解决CTC的缺点,2020年研究人员提出了一个叫Imputer 的模型,这个模型结合了:CTC+Mask-Predict几种技术。
这个模型在t=0时刻会将一个与语音信号等长的Mask序列与语音信号丢入encoder中,得到一个初始化的输出,这个输出中可以还有Mask和确定结果(文字或者下划线)。
在t=1时刻,把上一个时间步得到序列结果在和语音信息重新进入Encoder,进行refine:
不断迭代直到输出没有变化为止。这个模型还有一个trick,叫:Block Decoding,将输入序列划分成一个个的block,并规定每个block在迭代过程,必须至少确定一个结果,下面是一个block size=3的例子:
可以看到,加入这个限制之后,迭代的次数最多为blocksize。
下面是一个blocksize=8的具体例子:
可以看到在第八个时间步结果已经出来了。
还有人把CTC和Inputer用在了翻译上,原理就是把语音信号替换为文字,然后把文字先做一个upsampling操作,然后其他操作一样。
CTC
Inputer
Knowledge Distillation in NAT
最后给出来NAT对Autoregressive模型进行Knowledge Distillation后效果提升的研究,语料中原文为英文,译文有de德文,es西班牙文,fr法文,然后Autoregressive模型翻译结果非常清楚,一句话翻译出来是三种目标文字中的一种,不会混乱(下图中第一个图每一个点代表一个句子。),但是NAT模型就不行,最后以Autoregressive模型为例进行学习后
NAT可以获得很好的效果。