手把手教你用fairseq训练一个NMT机器翻译系统

以构建英-中NMT为例,在linux上运行,fairseq版本为0.8.0

环境准备

Requirements:

  • fairseq:pytorch包,包括许多网络结构,https://github.com/pytorch/fairseq
  • mosesdecoder:机器翻译的标准数据处理工具, https://github.com/moses-smt/mosesdecoder
  • subword-nmt:bpe分词工具,https://github.com/rsennrich/subword-nmt
  • jieba:中文分词工具,https://github.com/fxsjy/jieba

除了jieba,其它我习惯是下载包在本地运行

Data:
准备raw双语数据,一句一行,英中各存为三个文件,分别是训练集,验证集,测试集,如下:
手把手教你用fairseq训练一个NMT机器翻译系统_第1张图片
目录结构:
手把手教你用fairseq训练一个NMT机器翻译系统_第2张图片
以下的命令都是在主目录下运行

数据预处理

1.序列化处理
用MOSES对句子进行序列化处理,说白了就是在每个句子的单词和标点符号之间插入空格:

perl requirements/mosesdecoder-master/scripts/tokenizer/tokenizer.perl \
-l en < data/en-zh/train.en-zh.en > data/en-zh/train.en-zh.tok.en

类似的,英中的剩下几个文件都作同样的处理(可以观察一下处理前后文件内容的不同之处)

2.中文分词
进行分词,只有中文数据需要进行此步骤,在这里用jieba分词工具:

python -m jieba -d " " data/en-zh/train.en-zh.tok.zh > data/en-zh/temp.txt
mv data/en-zh/temp.txt  data/en-zh/train.en-zh.tok.zh  
# 和英的文件名进行统一,方便后续操作

3.bpe分词
bpe分词是更细粒度的分词,可以减少词表大小,此外对性能也有帮助。
首先用双语数据学习bpecode(这个过程时间比较长,可以用别人学习好的):

Python requirements/subword-nmt/learn_joint_bpe_and_vocab.py \
-i data/en-zh/train.en-zh.tok.en -o data/en-zh/bpecode.en --write-vocabulary data/en-zh/voc.en

然后用bpecode对数据进行bpe分词:

python requirements/subword-nmt/apply_bpe.py \
-c data/en-zh/bpecode.en < data/en-zh/train.en-zh.tok.en > data/en-zh/train.en-zh.tok.bpe.en
# 对 valid、test进行同样操作 

类似的,对中文数据进行上述的bpe分词处理

4.生成词表以及二进制数据
用fairseq提供的数据预处理脚本进行预处理,以生成词表文件和可以直接输入模型的二进制文件:

PYTHONPATH=fairseq-0.8.0 python fairseq-0.8.0/preprocess.py  \
--source-lang en--target-lang zh --workers 4 --trainpref data/en-zh/train.en-zh.tok.bpe \
--validpref data/en-zh/valid.en-zh.tok.bpe --testpref data/en-zh/test.en-zh.tok.bpe --destdir data/en-zh/data-bin 

处理完可以看到在data/en-zh/data-bin 目录下生成了词表和许多二进制文件:
手把手教你用fairseq训练一个NMT机器翻译系统_第3张图片
以上就是数据预处理的过程,比较繁琐,建议用脚本完成,详情见 github

训练

数据处理完后,接下来就是训练,训练的参数实在太多了,github上脚本的参数是大家都通用的,下面列了几个常用的,具体看官方文档:

PYTHONPATH=fairseq-0.8.0 CUDA_VISIBLE_DEVICES=1 nohup python fairseq-0.8.0/train.py \
data/en-zh/data-bin  -a transformer --optimizer adam  -s en -t zh --dropout 0.3 --max-tokens 4096  \
--criterion label_smoothed_cross_entropy  --num-workers 8 --save-dir model/en-zh &

可以指定多卡,训练完成之后,会在model/en-zh下生成许多.pt的模型文件

解码

训练完成后就可以用模型文件来进行预测,称之为解码

PYTHONPATH=fairseq-0.8.0 CUDA_VISIBLE_DEVICES=1  python fairseq-0.8.0/generate.py \
data/en-zh/data-bin --path model/en-zh/checkpoint_best.pt --batch-size 128 --beam 5  > temp.txt

默认用测试集进行解码,解码得到的文件是这样的:
在这里插入图片描述
其中,
S 源语
T 目标语(答案)
H 预测的句子,H前的数字是这个句子的预测概率的log再除总长度
P 每个单词的预测概率的log,全部相加除句子总长度等于H

后处理

解码得到的文本中有bpe符号和许多的train过程中的输出信息,进行后处理提取预测文本。
首先得到所有的预测句子:

grep ^H temp.txt | cut -f3- > temp2.txt

在这里插入图片描述

然后去除bpe符号

sed -r 's/(@@ )| (@@ ?$)//g' < temp2.txt  > temp3.txt

在这里插入图片描述
可以计算一下bleu,答案是用tokenized后的文件,不是原生文件:

perl requirements/mosesdecoder-master/scripts/generic/multi-bleu.perl data/en-zh/test.en-zh.tok.zh < temp3.txt 

如果要提取纯预测文本,需要进行detokenizer:

perl requirements/mosesdecoder-master/scripts/tokenizer/detokenizer.perl -l zh < temp3.txt  > predict.txt

在这里插入图片描述
项目github

你可能感兴趣的:(Pytorch,NLP自然语言处理)