Unsupervised NMT
概述
神经机器翻译系统取得了很好的翻译水平,但非常依赖于平行语料。目前已经有利用大量单语数据训练模型的研究,这其中包括:
- 仅仅由两份单语语料(不平行)训练出双语词典。这个的核心是学习一个旋转矩阵W,使得两份语料的词向量空间对齐,再进行一些调整更好的对齐两词向量空间,最后进行单词到单词的翻译,即生成了双语词典。
- 对偶学习的思想。有些研究里也提出迭代后向翻译,但思想是类似的,即通过翻译模型生成假的平行语料,再利用该平行语料训练模型,迭代此过程。
- 利用第三种语言。翻译模型依赖于大量的语料数据,但有些语言对的可用数据是很少的。这时,可以利用第三种语言如英语,训练A和英语翻译、B和英语翻译,从而实现A和B的翻译。值得注意的是,Google’s Multilingual Neural Machine Translation System实现了一对多和多对一翻译。
- 翻译系统多采用seq2seq结构,encoder将各种语言编码到特征空间,将其训练成“世界通用语言”,再由decoder翻译到指定语言。上面的Google’s Multilingual Neural Machine Translation System即根据添加一个标记“en-fr”指定系统是将en翻译到fr。类似的还有许多人研究了共享编码器、解码器参数的影响,发现效果不错。
- 去噪自编码器的使用,即将添加噪声的句子通过auto-encoding恢复自身。
- 用强的语言模型来优化翻译模型,语言模型衡量一个句子自然程度。
- 使用bpe而不是word,发现效果不错。
- 相关的研究还包括利用少量双语数据来优化/启动训练。
Facebook的UNMT研究
在Facebook的论文Phrase-Based & Neural Unsupervised Machine Translation中对无监督机器翻译做了总结,他们将前人的无监督机器翻译系统的成功总结为以下三点:
- 初始化。通过近似翻译,对翻译系统认真初始化。例如有人通过双语词典,词到词的翻译初始化整个翻译系统,双语词典可以来自自己的学习,也可以利用一个已有的词典。
- 语言模型。利用语言模型提高翻译模型的质量,通过对句子加入噪声应用语言模型,衡量句子的自然程度,来提高翻译模型的质量。
- 迭代后向翻译。对S近似翻译生成T,将T后向翻译成S‘,S与S’的差异作为损失,训练T->S的翻译系统,反之亦然,迭代。
之后,Facebook提出了自己的无监督NMT系统,这项工作主要来源于两项前人工作,分别是:
- Unsupervised neural machine translation.
- Unsupervised machine translation us- ing monolingual corpora only.
在解释Facebook的模型之前,首先对这两篇论文的模型加以论述。
学习双语词典的过程示意图
Unsupervised neural machine translation的研究
这个研究可以概括为下面这张图,解释的也很清楚。
Unsupervised machine translation us- ing monolingual corpora only的研究
下面提到的discriminator就是借鉴这里的,其作用描述为:
对抗学习。我们说了,我们就是要让中间语真正的成为一种“世界语言都通用的中间语言”,那么对于任何一个中间语词向量(就是encoder编码出的潜在共享表示),系统不该分辨出原输入到底是L1还是L2。这里采用了对抗学习的策略,引入一个discriminator,该辨别器(在该系统中就是一个二分类)就是用来辨别出中间语词向量来自于L1 or L2,那么,系统不断学习,通过”欺骗“这个discriminator,让discriminator越来越无法辨别,就达到了目的。因此,只要在此处也定义一个损失,该损失是discriminator辨别成功概率的负值,学习时考虑该损失,此问题也就得到了解决。
Facebook的研究
下面说明Facebook的模型
Facebook提出的UNMT主要结构类似于Unsupervised machine translation us- ing monolingual corpora only,但是:
有以下几点不同:
- 不采用word,而采用bpe,即首先对语料bpe处理,以得到的每一个token为单位进行处理,最后得到token的词向量。
- 之前的工作大都对两份语料分别训练词向量,这样就不得不再去学习双语词典。然而在本系统中,做法是将两份预料混合于同一份文件中,打乱,再bpe处理,直接得到双语embeddings,但这样做有个前提,两语言必须相近,如欧洲语系,否则就不得不学习双语词典。另外,值得注意的是,这样做时,用bpe比用word效果更好。
- 共享所有。在两种语言中,前面已经对embeddings共享了,在论文Unsupervised neural machine translation中共享了encoder,但decoder没有共享,但在这里,包括encoder、decoder,不管是auto-encoding还是S->T/T->S翻译系统汇总,都完全共享,当然这样做了相应的也要进行一些额外的处理。实验发现,共享之后效果很好。
- 上面提到有额外的处理,为了解释清楚,首先看下源码,我加了中文注释:
# initialize experiment / load data / build model
logger = initialize_exp(params)
data = load_data(params)
#建立一个encoder、一个decoder、一个discriminator和一个lm(语言模型)
encoder, decoder, discriminator, lm = build_mt_model(params, data)
# initialize trainer / reload checkpoint / initialize evaluator
#初始化训练器,用上面建立的模型
trainer = TrainerMT(encoder, decoder, discriminator, lm, data, params)
trainer.reload_checkpoint()
trainer.test_sharing() # check parameters sharing
evaluator = EvaluatorMT(trainer, data, params)
# evaluation mode
if params.eval_only:
evaluator.run_all_evals(0)
exit()
# language model pretraining
# 语言模型预训练,语言模型使用过降噪自编码器实现的
if params.lm_before > 0:
logger.info("Pretraining language model for %i iterations ..." % params.lm_before)
trainer.n_sentences = 0
for _ in range(params.lm_before):
for lang in params.langs:
trainer.lm_step(lang)
trainer.iter()
# define epoch size
if params.epoch_size == -1:
params.epoch_size = params.n_para
assert params.epoch_size > 0
# start training
# 迭代训练
for _ in range(trainer.epoch, params.max_epoch):
logger.info("====================== Starting epoch %i ... ======================" % trainer.epoch)
trainer.n_sentences = 0
while trainer.n_sentences < params.epoch_size:
# 训练discriminator
for _ in range(params.n_dis):
trainer.discriminator_step()
# 训练语言模型
# lambda_lm是语言模型产生的loss作为总loss的系数,如果为0,则表明不训练语言模型了
if params.lambda_lm > 0:
for _ in range(params.lm_after):
for lang in params.langs:
trainer.lm_step(lang)
# MT training (parallel data)
# 平行语料模型训练,这是个可选项,可以用来加入一些双语预料训练模型,
# 也可以直接用来训练双语语料
if params.lambda_xe_para > 0:
for lang1, lang2 in params.para_directions:
trainer.enc_dec_step(lang1, lang2, params.lambda_xe_para)
# MT training (back-parallel data)
# 反向训练,双面是正向,这个是训练反向
if params.lambda_xe_back > 0:
for lang1, lang2 in params.back_directions:
trainer.enc_dec_step(lang1, lang2, params.lambda_xe_back, back=True)
# autoencoder training (monolingual data)
# 对每一个语言训练自编码,loss系数是lambda_xe_mono
# 值得注意的是,lambda_xe_mono是衰减的,
# 也即训练到最后,自编码的损失已经不考虑了,变成了完全训练翻译系统
if params.lambda_xe_mono > 0:
for lang in params.mono_directions:
trainer.enc_dec_step(lang, lang, params.lambda_xe_mono)
# AE - MT training (on the fly back-translation)
# 动态反向翻译
if params.lambda_xe_otfd > 0 or params.lambda_xe_otfa > 0:
# start on-the-fly batch generations
# 生成假的平行语料
if not getattr(params, ‘started_otf_batch_gen‘, False):
otf_iterator = trainer.otf_bt_gen_async()
params.started_otf_batch_gen = True
# update model parameters on subprocesses
# 在subprocess上更新模型参数,上面生成了平行语料
if trainer.n_iter % params.otf_sync_params_every == 0:
trainer.otf_sync_params()
# get training batch from CPU
# 得到训练的batch
before_gen = time.time()
batches = next(otf_iterator)
trainer.gen_time += time.time() - before_gen
# training
# 最重要的训练
for batch in batches:
lang1, lang2, lang3 = batch[‘lang1‘], batch[‘lang2‘], batch[‘lang3‘]
# 2-lang back-translation - autoencoding
if lang1 != lang2 == lang3:
trainer.otf_bt(batch, params.lambda_xe_otfa, params.otf_backprop_temperature)
# 2-lang back-translation - parallel data
elif lang1 == lang3 != lang2:
trainer.otf_bt(batch, params.lambda_xe_otfd, params.otf_backprop_temperature)
# 3-lang back-translation - parallel data
elif lang1 != lang2 and lang2 != lang3 and lang1 != lang3:
trainer.otf_bt(batch, params.lambda_xe_otfd, params.otf_backprop_temperature)
trainer.iter()
- 可以看到,模型的初始化是实现一个语言模型来实现的,这个语言模型和之前的语言模型是有差异的,具体 来说,它是最小化下面这个函数再加一个score层实现的:
下面说明训练过程。
模型的初始化,实现一个语言模型来初始化encoder-decoder参数。
之后,模型进入迭代训练,每一步,都先训练discriminator,这个的作用就不说了,他实际上只更新了encoder参数,之后,再训练一次语言模型,更新参数,这是个可选项,默认不训练。然后训练auto-encoding,更新encoder和decoder参数,由于我们最后的目的是训练语言模型,这一步对整个encoder-decoder系统的作用其实是衰减的,由它产生的loss更新参数的影响越来越弱,直到最后只训练翻译模型。这里,对auto-encoding的loss的影响是通过参数--lambda_xe_mono实现的,它的默认值是lambda_xe_mono ‘0:1,100000:0.1,300000:0‘ ,表示迭代从0到100000,参数从1线性衰减到0.1,从100000到300000,参数从0.1线性衰减到0。
其他的过程就是不断生成伪双语数据和迭代后向翻译的过程,通过不断更新参数,最后训练的encoder-decoder既可以将S->T,又可以将T->S。很神奇,amazing。前面提到的Google’s Multilingual Neural Machine Translation System也是一个encoder-decoder,但他们的工作中至少添加了一个标记“en-fr”指示目标语言是什么,而Facebook竟然忽略了,最后效果还很好。
一开始我真不敢相信竟然只有一个encoder和decoder,于是我发邮件问了原作者,得到的回应是:
其他细节:
- 模型的词向量是通过fastText实现的。
- 模型既用了LSTM,结构和Unsupervised machine translation us- ing monolingual corpora only相同,也用了transformer结构,这个我不清楚,但transformer效果更好。
原文地址:https://www.cnblogs.com/duye/p/9800969.html