以构建英-中NMT为例,在linux上运行,fairseq版本为0.8.0
Requirements:
除了jieba,其它我习惯是下载包在本地运行
Data:
准备raw双语数据,一句一行,英中各存为三个文件,分别是训练集,验证集,测试集,如下:
目录结构:
以下的命令都是在主目录下运行
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 目录下生成了词表和许多二进制文件:
以上就是数据预处理的过程,比较繁琐,建议用脚本完成,详情见 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