机器翻译引擎搭建实践

2. NMT系统搭建指导

主要对训练整体流程实现进行描述,不对算法原理进行讲解。

实验环境:
tensorflow 1.12.0 +
tensor2tensor

确保你的服务器上安装了这俩东西,而且能够跑通哈。

2.1 获取数据

搭建一个机器翻译系统最重要的是数据,机器翻译需要的数据形式就是平行语料。本质就是一句源语言,一句对应的目标语言。

举个例子:
中文:早上好。
英文:good morning.

基于神经网络的机器翻译系统训练,动辄需要几千万上亿条平行语料,我们如果自己获取或者购买成本都会很大,因此在现阶段,只能搜集更过的开源数据集用来训练。

该指导以中英文的机器翻译系统为例,我整理了几个开源的数据集供给我们进行试验。

联合国中英平行语料:
这个数据可以去WMT比赛官网上去下载,大概有几千万条数据,除此之外还可以通过参加一些比赛的方式来获取实验数据。
https://cms.unov.org/UNCorpus/zh#format
http://www.statmt.org/wmt18/translation-task.html#download
你可以仔细的挑选一下所需的平行语料。
当你下载下来数据后,需要将下载的平行语料分别放到两个文件中去,可以按照下面的方式操作一下。
在这里插入图片描述
如果没出错的话你会在自己的目录下看到数据文件。
在这里插入图片描述
如果我们仔细查看平行语料的形式,就会发现和我们想的一样。(废话。。。)

英文数据 UNv1.0.en-zh.en
在这里插入图片描述
中文数据 UNv1.0.en-zh.zh
在这里插入图片描述
所谓平行语料就是一句英文一句中文,一一对应的语料。这里我们使用的联合国平行语料共计15886041对平行数据。

2.2 数据预处理

数据预处理部分的最终目的就是对一句句话进行字词的令牌化处理,能够用对应的数字标签来进行表示。

例如:你好,我叫孙洪文,我爱吃胡萝卜

字典:{	‘你好’:0, 
‘,’:1, 
‘我’:2, 
‘叫’:3,
‘孙洪文’:4,
‘爱吃’:5,
‘胡萝卜’:6}

预处理后:012341256

对于我们的神经网络模型来说,我们要处理的直接对象就是预处理后的数据。但是往往在我们获得数据的过程中,我们不可避免的获得一些质量比较差的数据,存在一些问题。通用的一些做法尤其西方语言是参考著名的统计机器翻译工具moses的预处理流程:
机器翻译引擎搭建实践_第1张图片
normalize-punctuation
normalize-punctuation就是做一个符号或者拼写标准化的过程,例如出现的中文符号会统一的转化为英文符号,一些稀奇古怪的拼写形式会转化为标准的字母。具体的处理我们使用moses提供的方法。
首先将moses工具包下载到本地:

git clone https://github.com/moses-smt/mosesdecoder.git

然后使用moses的工具对英文平行语料做normalize-punctuation处理:

 mosesdecoder/scripts/tokenizer/normalize-punctuation.perl -l en < data/en.all > data/en.norm.all

tokenizer
该步骤就是对英文进行分词,和汉字中的结巴分词功能一样,正常情况下英文分词只需要按照空格进行就可以了,但是英文中有一些特殊的情况需要进行处理,举例说明比如标点符号和单词之间一般是没有空格的,而我们分词的时候也需要将它区分出来。
在执行此操作前,可以进入perl脚本中修改thread的数量。

mosesdecoder/scripts/tokenizer/tokenizer.perl -a -l en < data/en.norm.all > data/en.tok.all

truecase
我们观察英文语料时会发现数据中存在大量的大小写不统一的情况,有些时候大小写不同会有不同的含义,而有些时候大小写不同只是因为单词所处的语境所决定的。最简单的例子就是英文中的首字母都会进行大写处理,而一些特殊单词比如I本身就是大写的。我们通过truecase可以将单词大小写统一为他本来的形式。
第一步需要训练一个truecase的模型,这个模型包含了各个单词对应的大小写形式。

mosesdecoder/scripts/recaser/train-truecaser.perl --model en-truecase.mdl --corpus data/en.tok.al

第二步使用我们训练好的模型。

mosesdecoder/scripts/recaser/truecase.perl --model en-truecase.mdl < data/en.tok.all > data/en.tc.all

jieba
中文的分词工具有很多,在这里我们使用最基本的结巴分词,作为中文分词的工具。

python -m jieba -d < data/zh.all > data/zh.jieba.all

clean-corpus-n
清理平行语料中语句长度过长的数据,不管中文语料还是英文中出现长度超过100的平行数据都会被删除。

mv data/en.tc.all data/data.en
mv data/zh.jieba.all data/data.zh
rm -rf data/en.*
rm -rf zh.all
mosesdecoder/scripts/training/clean-corpus-n.perl data/data zh en data/clean 1 100

这样我们就获得了初步的平行语料。
可以看一下清理结果:
在这里插入图片描述
BPE
(该实验中跳过该步骤)
我们通过分词得到的字典是非常庞大的,需要将一些词语如:hello-kitty切分为更细粒度的单词:hello, -, kitty。该过程尝试使用更少的词典和更短的编码形式来表示句子。
具体的理论,这里也不进行详述了,可能会在后续的博客详细介绍。
这次实验我们不使用单独的subword工具进行训练bpe,但这里也给出实现方案。
首先需要下载subword工具包到本地。

git clone https://github.com/rsennrich/subword-nmt.gi

然后训练英文子词模型:

python subword-nmt/subword_nmt/learn_joint_bpe_and_vocab.py -i data/clean.en -o en.bpe --write-vocabulary data/vocab.en

训练中文的子词模型:

python subword-nmt/subword_nmt/learn_joint_bpe_and_vocab.py -i data/clean.zh -o zh.bpe --write-vocabulary data/vocab.zh

应用子词模型对原文进行再次分词:

python subword-nmt/subword_nmt/apply_bpe.py -c en.bpe < data/clean.en >bpe.en
python subword-nmt/subword_nmt/apply_bpe.py -c zh.bpe < data/clean.zh >bpe.zh

2.3 模型训练

我们需要训练一个基于我们处理的数据生成的英译汉翻译模型,我们这个过程也选择开源的框架来作为模型的训练工具。常见的训练工具如下:
在这里插入图片描述
我们这个实验选择tensor2tensor来训练我们的模型。
首先,需要安装tensor2tensor到服务器上,自己安装应该也不难。
但是由于我们训练模型使用的是自己生成的数据,不是默认的数据,因此我们要修改一些代码来使模型能够用我们的数据进行训练。
在此之前,先将数据取出一部分作为训练集、验证集、测试集。

paste data/clean.{zh,en} | shuf > data/clean.both

sed -n 1,5000p data/clean.both | cut -f 1 > data/test.zh
sed -n 1,5000p data/clean.both | cut -f 2 > data/test.en

sed -n 5001,10000p data/clean.both | cut -f 1 > data/dev.zh
sed -n 5001,10000p data/clean.both | cut -f 2 > data/dev.en

sed -n 10001,15721635p data/clean.both | cut -f 1 > data/train.zh
sed -n 10001,15721635p data/clean.both | cut -f 2 > data/train.en

由于需要使用自己的数据作为训练数据,tensor2tensor使用个人数据需要定制问题problem。其方法也比较简单:
新建个人问题,可以去我写好的文件中拷贝:

cp -r /home/enzh/user_dir ./

其实里面做的事情就是定义了一些使用的数据集,和生成字典的方法。我们之前不使用bpe的原因就是tensor2tensor自己集成了subword的生成,我们在新建的文件中使用默认的方法就会自动生成subword。
接下来生成训练所需的数据,我们使用t2t-datagen这个指令来生成训练需要的数据。

t2t-datagen --data_dir=data --tmp_dir=data --problem=translate_enzh_sub50k --t2t_usr_dir=user_dir

使用生成的数据进行默认参数的训练:

t2t-trainer --data_dir=data --problem=translate_enzh_sub50k --model=transformer --hparams_set=transformer_base --output_dir=t2t_train/translate_enzh_sub50k/transformer_base --train_steps=400000 --worker_gpu=2 --t2t_usr_dir=user_dir

2.4 模型的解码及bleu计算

当你开始训练你的系统的时候,你会想监测一下你的模型效果如何,如果你直接运行了上面的代码,你会看到屏幕上打印了一些能够体现模型效果的参数值。
在这里插入图片描述
Loss是通常意义下的模型的识别损失函数,我们会持续的观察loss的变化。
而每过1000个step的时候,我们就可以监测一次模型在验证集上的表现。
在这里插入图片描述
我们主要关注的参数是bleu值,不同系统采用的bleu值各有不同,因此在数值上会有大小的差异,因此不必太过纠结。

如果想评估自己的系统和别人的系统的差别,一般论文中都会给出计算bleu的具体工具,使用同样的工具就可以进行比较了。后面的章节关于bleu的计算方法,我们详细介绍。

Tensor2tensor默认的训练步骤是250k,上面的训练过程我们设置为了400k,这大概需要训练2-3天的时间,你可以吧这个过程放到后台挂着,到时候就能得到不错的结果了。

2-3天过去了。。。

当过了三天之后,你的模型训练好了,你就可以通过解码测试集并计算一下bleu得分来检测一下识别效果了。

t2t-decoder --t2t_usr_dir=user_dir --data_dir=data --problem=translate_enzh_sub50k --model=transformer --hparams_set=transformer_base --output_dir=t2t_train/translate_enzh_sub50k/transformer_base --decode_beam_size=32 --decode_from_file=data/test.en --decode_to_file=result

然后查看当前目录下的result文件,你就能得到识别结果了。
在这里插入图片描述
如果你想检查一下你训练的模型获得的bleu分是多少,你可以尝试tensor2tensor自带的计算工具。

t2t-bleu --reference=data/test.zh --translation=result

你可能感兴趣的:(NLP,深度学习,机器翻译)