超越英语中心的M2M-100多语言机器翻译:数据管线、模型下载与推理评估实战指南
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
导读
本文以 m2m_100 使用文档 为主线,系统讲解 M2M-100(Many-to-Many Multilingual Machine Translation)这一可在任意 100 种语言对之间直接互译的多对多翻译模型:包括训练数据的挖掘来源与清洗管线、SentencePiece 编码与二值化、translation_multi_simple_epoch多语言训练任务的参数体系、418M / 1.2B / 12B 三档预训练权重的获取方式,以及基于 pipeline 模型并行的大模型生成与 sacrebleu 评估全流程。读者读完本文后,将能够在当前仓库的 fairseq 代码框架内完整复现 M2M-100 从数据到评测的整条链路,并理解其底层任务实现原理。
一、背景:什么是 M2M-100
M2M-100 是 Facebook AI 于 2020 年发布的"超越英语中心(Beyond English-Centric)"多语言机器翻译模型。与以往"以英语为中转"的翻译范式不同,它构建了真正的多对多(Many-to-Many)翻译模型,能够直接在任意一对语言(共 100 种语言,产生约 9900 个翻译方向)之间进行翻译,无需经过英语中转。
原文档给出的一组关键实验结论是:当直接在非英语语言对之间互译时,相比"源语言→英语→目标语言"的两段式翻译,M2M-100 能带来超过 10 个 BLEU 的提升,同时在 WMT 评测中与当时最优的单语向系统(single systems)表现相当。
M2M-100 的技术路线总结为四步:
- 准备评测数据(Generation Data);
- 获取训练数据(CCMatrix + CCAligned 挖掘的大规模平行语料);
- 数据预处理(去噪、去重、SPM 编码、二值化);
- 用 fairseq 的多语言翻译任务训练模型;
- 用 fairseq-generate 推理并评测。
当前仓库 decoding/IAD/fairseq 中包含实现 M2M-100 全部流程所需的代码:数据清洗脚本位于 examples/m2m_100/process_data,评测分词脚本位于 examples/m2m_100/tokenizers,多语言训练任务实现位于 fairseq/tasks/translation_multi_simple_epoch.py。
二、数据准备
2.1 评测数据(Generation Data)
评测数据用于评估翻译质量。原文档强调:所有评测数据集必须在数据预处理阶段之前先进行 detokenize(去分词化),否则 SPM 编码会引入偏差。以下数据集的获取方式(均需在引用时附上对应论文):
- WMT:可直接用 sacrebleu 导出源句与参考译文,例如:
sacrebleu -t wmt14 -l fr-en --echo src > wmt.test.fr-en.fr sacrebleu -t wmt14 -l fr-en --echo ref > wmt.test.fr-en.en- WAT(缅甸语相关评测):
wget http://lotus.kuee.kyoto-u.ac.jp/WAT/my-en-data/wat2020.my-en.zip unzip wat2020.my-en.zip- FLORES(101 种语言基准测试集):从其官方项目下载;
- TED:来自 neulab 的 word-embeddings-for-nmt 项目,注意需要用 Moses 脚本进行 detokenize:
wget http://phontron.com/data/ted_talks.tar.gz- Autshumato(南非语):需要在 SADiLaR 仓库申请下载;
- Tatoeba Challenge:来自 Helsinki-NLP 的 Tatoeba-Challenge 项目。
2.2 训练数据(Training Data)
M2M-100 的训练数据是 CCMatrix 与 CCAligned 两个大规模平行语料挖掘系统的产物:
- CCMatrix(Schwenk et al., 2019):基于多语言句向量对互联网海量网页进行平行句对挖掘;
- CCAligned(El-Kishky et al., 2019):大规模跨语言网页文档对集合。
原始挖掘数据的下载与复现说明见 LASER 项目中的 CCMatrix 任务目录。
三、数据预处理管线
训练数据在送入模型前需要经过一条严格的清洗管线。原文档特别强调:必须执行去重清洗脚本,因为它会移除挖掘语料中所有与评测数据重复的句子——这是防止评测数据泄漏(data leakage)导致 BLEU 虚高的关键环节。
3.1 去除高标点占比句子
首先移除标点占比超过 50% 的句子:
python /path/to/fairseq/examples/m2m_100/process_data/remove_too_much_punc.py对应脚本 remove_too_much_punc.py 的实现细节(源码第 8-12 行)显示:标点集合为 Python 标准库punctuation加上—|–三个字符;判定条件len_npunc < 0.5 * len_sen,即一条平行句只有同时满足源句与目标句标点占比都小于 50% 才被保留。脚本接收--input(gzip 压缩的 TSV,第 2、3 列为源/目标文本)、--bitext(输出前缀)、--src-lang与--tgt-lang参数,按语言分别写出清洗后的源、目标文件。
3.2 训练语料去重
先做句对级精确去重(用 awk 以"源句+制表符+目标句"为 key):
paste /path/to/datadir/train.$src /path/to/datadir/train.$tgt | awk '!x[$0]++' > /path/to/datadir/train.dedup echo "keeping $(wc -l /path/to/datadir/train.dedup) bitext out of $(wc -l /path/to/datadir/train.$src)" cut -f1 /path/to/datadir/train.dedup > /path/to/datadir/train.$src cut -f2 /path/to/datadir/train.dedup > /path/to/datadir/train.$tgt然后移除训练语料中所有与评测数据相同的句子(防泄漏):
python /path/to/fairseq/examples/m2m_100/process_data/dedup_data.pydedup_data.py 的实现(源码第 5-7 行)通过三个路径常量控制行为:DATADIR(按src_tgt子目录组织的训练数据)、DEDUP_FROM_DIR(存放评测数据的目录,其所有文件的行会被加载进一个 set)、OUTPUT_DIR(输出去重后的平行句对)。脚本逐语言对执行:只有当train.$src与train.$tgt中的句子都不在评测集合中时才保留(第 69-72 行),并带有"输出已存在则跳过"的断点续跑逻辑(第 45-50 行)。脚本通过--start-index与--size参数支持分片并行处理多个语言对。
3.3 频率清洗(Frequency Cleaning)
挖掘语料中常混入与训练语言无关的字符,需要按字符直方图过滤:
wget https://dl.fbaipublicfiles.com/m2m_100/histograms.tar.gz tar -xvzf histograms.tar.gz python /path/to/fairseq/examples/m2m_100/process_data/clean_histogram.py \ --src $src --tgt $tgt \ --src-file /path/to/source/file --tgt-file /path/to/output/file \ --src-output-file source_output.$src --tgt-output-file target_output.$tgt \ --histograms /path/to/histogramsclean_histogram.py 的关键参数(源码第 4-12 行):--threshold默认0.5,--threshold-character默认]。实现逻辑是:从每种语言的直方图文件中读取以]为截止的"可接受字符集",然后逐行统计源/目标句中属于该字符集的字符占比,只有当双方占比都高于阈值时才保留该平行句对(第 44 行),否则打印丢弃信息。
3.4 应用 SentencePiece 编码
M2M-100 使用一个共享的 128K 词表 SentencePiece 模型(多语言联合子词词表):
wget https://dl.fbaipublicfiles.com/m2m_100/spm.128k.model python /path/to/fairseq/scripts/spm_encode.py \ --model spm.128k.model \ --output_format=piece \ --inputs=/path/to/input/file/here \ --outputs=/path/to/output/file/here--output_format=piece表示输出子词片段(而非 id)。
3.5 长度比清洗
用 Moses 的clean-corpus-n.perl过滤源/目标长度比过大的句对(--ratio 3表示长度比超过 3 倍即丢弃,1 250为最小/最大句长约束):
perl mosesdecoder/scripts/training/clean-corpus-n.perl \ --ratio 3 /path/to/training/data/train.spm.$src-$tgt \ $src $tgt /path/to/output/directory/train.spm.$src-$tgt 1 2503.6 二值化(Binarize)
清洗、编码完成后的文本需要用 fairseq-preprocess 转成 fairseq 的二进制数据格式,并统一使用 128K 的共享词典data_dict.128k.txt:
wget https://dl.fbaipublicfiles.com/m2m_100/data_dict.128k.txt fairseq-preprocess \ --source-lang $src --target-lang $tgt \ --testpref spm.$src.$tgt \ --thresholdsrc 0 --thresholdtgt 0 \ --destdir data_bin \ --srcdict data_dict.128k.txt --tgtdict data_dict.128k.txt--thresholdsrc 0 --thresholdtgt 0表示不做词频截断(保留全部词条);--srcdict与--tgtdict指向同一个共享词典,这是多语言联合词表的关键。
四、训练:translation_multi_simple_epoch多语言任务
M2M-100 的训练复现基于 fairseq-py 的多语言翻译任务translation_multi_simple_epoch,其完整示例见 examples/multilingual 目录,官方训练脚本为 train_multilingual_model.sh:
fairseq-train $path_2_data \ --encoder-normalize-before --decoder-normalize-before \ --arch transformer --layernorm-embedding \ --task translation_multi_simple_epoch \ --sampling-method "temperature" \ --sampling-temperature 1.5 \ --encoder-langtok "src" \ --decoder-langtok \ --lang-dict "$lang_list" \ --lang-pairs "$lang_pairs" \ --criterion label_smoothed_cross_entropy --label-smoothing 0.2 \ --optimizer adam --adam-eps 1e-06 --adam-betas '(0.9, 0.98)' \ --lr-scheduler inverse_sqrt --lr 3e-05 --warmup-updates 2500 --max-update 40000 \ --dropout 0.3 --attention-dropout 0.1 --weight-decay 0.0 \ --max-tokens 1024 --update-freq 2 \ --save-interval 1 --save-interval-updates 5000 --keep-interval-updates 10 --no-epoch-checkpoints \ --seed 222 --log-format simple --log-interval 2其中$path_2_data指向包含各语言对二值化数据的目录,$lang_list是按换行分隔的语言列表文件,$lang_pairs是逗号分隔的语言对列表(如"en-fr,en-cs,fr-en,cs-en")。
4.1 核心参数解读(源码佐证)
从 translation_multi_simple_epoch.py 的add_args(第 62-78 行)及MultilingualDatasetManager的参数定义看:
| 参数 | 取值/默认 | 作用 |
|---|---|---|
--task translation_multi_simple_epoch | — | 多语言翻译任务,一个 epoch 内遍历所有语言对 |
--sampling-method | uniform/temperature/concat | 跨不平衡语向数据的采样策略(源码第 103 行通过SamplingMethod.build_sampler构建) |
--sampling-temperature | 1.5 | 温度采样:温度越高,低资源语向被采样概率越大 |
--encoder-langtok | src/tgt/ 无 | 是否在源句中加入源语言(或目标语言)token |
--decoder-langtok | 开关 | 是否在目标句开头加入目标语言 token |
--lang-dict | 文件路径 | 模型所感知的按序排列的语言列表 |
--lang-pairs | 逗号分隔 | 训练涉及的语言对集合(action=FileContentsAction,也支持文件内容展开) |
生成时-s/-t分别指定推理的源、目标语言(源码第 66-69 行);推理阶段lang_pairs会被固定为"{src}-{tgt}"(第 86-88 行)。
--encoder-langtok "src"与--decoder-langtok的组合是 M2M-100 的核心机制:编码器侧告诉模型"这句话是什么语言",解码器侧用目标语言 token 作为起始符号,从而让一个模型同时服务于上百个翻译方向。此外MultilingualDatasetManager还支持--lang-tok-replacing-bos-eos(用语言 token 替换句首/句尾符号)、--keep-inference-langtok(推理输出中保留语言 token 以便分析)等开关。
4.2 从预训练模型微调(Finetuning)
也可以在预训练多语言模型(如 mBART50)基础上微调多语言翻译模型,只需增加--finetune-from-model $pretrained_model参数,其余训练参数与上面完全一致。mBART50 系列的预训练与微调权重(many-to-one、one-to-many、many-to-many 三种形态)在 examples/multilingual/README.md 中给出,每个压缩包内含model.pt检查点、ML50_langs.txt语言列表、sentence.bpe.modelSPM 模型以及各语言的dict.{lang}.txt词典,可使用 binarize.py 工具配合sentence.bpe.model与词典完成数据二值化。
五、预训练模型下载
5.1 418M 与 1.2B 模型
这两个模型均提供最后一个 epoch 的检查点(last checkpoint):
wget https://dl.fbaipublicfiles.com/m2m_100/model_dict.128k.txt wget https://dl.fbaipublicfiles.com/m2m_100/language_pairs_small_models.txt # 418M 参数模型 wget https://dl.fbaipublicfiles.com/m2m_100/418M_last_checkpoint.pt # 1.2B 参数模型 wget https://dl.fbaipublicfiles.com/m2m_100/1.2B_last_checkpoint.pt生成命令(此时使用language_pairs_small_models语言对表):
fairseq-generate $binarized_data_path \ --batch-size 32 \ --path $path_to_model \ -s en -t fr \ --remove-bpe 'sentencepiece' \ --beam 5 \ --task translation_multi_simple_epoch \ --lang-pairs language_pairs_small_models \ --decoder-langtok --encoder-langtok src \ --gen-subset test > gen_out5.2 12B 模型
12B 模型在 100 语言的多对多训练数据上训练,提供三种检查点:最后 1 个、最后 5 个的平均、最后 10 个的平均。三者精度非常接近、没有普遍最优的选择——可以在开发集上对三者进行扫参,选最优者用于最终测试;也可以直接以 last checkpoint 作为默认选择。
检查点按"可运行的 GPU 配置"分成 4 种(2×32GB、4×16GB、6×12GB、8×8GB),因为 12B 模型必须配合 pipeline 模型并行切分才能在显存受限的卡上运行:
| 配置 | 2×32GB | 4×16GB | 6×12GB | 8×8GB |
|---|---|---|---|---|
| Last Checkpoint | 12b_last_chk_2_gpus.pt | 12b_last_chk_4_gpus.pt | 12b_last_chk_6_gpus.pt | 12b_last_chk_8_gpus.pt |
| Average of last 5 | 12b_avg5_chk_2_gpus.pt | 12b_avg5_chk_4_gpus.pt | 12b_avg5_chk_6_gpus.pt | 12b_avg5_chk_8_gpus.pt |
| Average of last 10 | 12b_avg10_chk_2_gpus.pt | 12b_avg10_chk_4_gpus.pt | 12b_avg10_chk_6_gpus.pt | 12b_avg10_chk_8_gpus.pt |
对应的 pipeline 切分参数如下(必须与检查点配置严格对应):
| 配置 | 2×32GB | 4×16GB | 6×12GB | 8×8GB |
|---|---|---|---|---|
--pipeline-encoder-balance | [26] | [1,15,10] | [1,9,9,7] | [1,6,6,6,7] |
--pipeline-encoder-devices | [0] | [0,1,0] | [0,1,2,0] | [0,4,5,1,0] |
--pipeline-decoder-balance | [3,22,1] | [3,11,11,1] | [3,7,7,8,1] | [1,6,6,6,6,1] |
--pipeline-decoder-devices | [0,1,0] | [0,2,3,0] | [0,3,4,5,0] | [0,2,6,7,3,0] |
这些 balance 数组表示将编码器/解码器的 Transformer 层按数量分配到各设备(如 4 卡配置的编码器切分为 1/15/10 层),devices 数组表示各段依次落在哪些 GPU 上(含流水线输入/输出的首尾设备)。
六、推理生成(Generation)
6.1 用 M2M-100 的 SPM 模型编码输入
先生成评测输入并用共享 SPM 模型编码(以 WMT19 de-fr 前 20 行为例):
fairseq=/path/to/fairseq cd $fairseq sacrebleu --echo src -l de-fr -t wmt19 | head -n 20 > raw_input.de-fr.de sacrebleu --echo ref -l de-fr -t wmt19 | head -n 20 > raw_input.de-fr.fr wget https://dl.fbaipublicfiles.com/m2m_100/spm.128k.model for lang in de fr ; do python scripts/spm_encode.py \ --model spm.128k.model \ --output_format=piece \ --inputs=raw_input.de-fr.${lang} \ --outputs=spm.de-fr.${lang} done6.2 二值化
wget https://dl.fbaipublicfiles.com/m2m_100/data_dict.128k.txt fairseq-preprocess \ --source-lang de --target-lang fr \ --testpref spm.de-fr \ --thresholdsrc 0 --thresholdtgt 0 \ --destdir data_bin \ --srcdict data_dict.128k.txt --tgtdict data_dict.128k.txt6.3 12B 模型生成
12B 模型当前仅支持在 GPU 上生成(2×32GB / 4×16GB / 6×12GB / 8×8GB 四种配置,检查点与 pipeline 参数见上文表格),CPU 推理将在未来版本中支持。以 4×16GB 配置为例(需同时下载model_dict.128k.txt与 100 语言完整语言对表language_pairs.txt):
wget https://dl.fbaipublicfiles.com/m2m_100/model_dict.128k.txt wget https://dl.fbaipublicfiles.com/m2m_100/language_pairs.txt wget https://dl.fbaipublicfiles.com/m2m_100/12b_last_chk_4_gpus.pt fairseq-generate \ data_bin \ --batch-size 1 \ --path 12b_last_chk_4_gpus.pt \ --fixed-dictionary model_dict.128k.txt \ -s de -t fr \ --remove-bpe 'sentencepiece' \ --beam 5 \ --task translation_multi_simple_epoch \ --lang-pairs language_pairs.txt \ --decoder-langtok --encoder-langtok src \ --gen-subset test \ --fp16 \ --dataset-impl mmap \ --distributed-world-size 1 --distributed-no-spawn \ --pipeline-model-parallel \ --pipeline-chunks 1 \ --pipeline-encoder-balance '[1,15,10]' \ --pipeline-encoder-devices '[0,1,0]' \ --pipeline-decoder-balance '[3,11,11,1]' \ --pipeline-decoder-devices '[0,2,3,0]' > gen_out参数要点:--fixed-dictionary指定 128K 的固定模型词典;--fp16以半精度推理以省显存;--dataset-impl mmap使用内存映射读取数据;--distributed-world-size 1 --distributed-no-spawn以单进程方式启动(配合 pipeline 并行在卡内切分);--pipeline-model-parallel开启流水线模型并行,balance/devices 数组按上文表格选择。输出写入gen_out供后续评测使用。
七、评测(Evaluation)
7.1 语言专属分词
M2M-100 遵循已有文献,对不同语言采用不同分词策略(见 tokenizers/README.md),并提供了开箱即用的 tok.sh 复现脚本。其语言分派逻辑(源码第 53-83 行)为:
- 中文(zh):Unicode 标点替换 → 标点归一化 → 去不可打印字符 →
tokenize_zh.py; - 泰语(th):
tokenize_thai.py(基于 pythainlp,由 install_dependecies.sh 安装); - 日语(ja):KyTea 分词(
seg_ja.sh); - 韩语(ko):mecab-ko 分词(
seg_ko.sh); - 罗马尼亚语(ro):先做 WMT16 脚本的
normalise-romanian.py规范化、remove-diacritics.py去变音符,再做 Moses 分词; - 缅甸语(my):
seg_my.py; - 阿拉伯语(ar):
tokenizer_ar.sh(需要另行安装 Arabic normalizer 工具,见 tokenizers 说明); - 印地语(hi)/尼泊尔语(ne)/僧伽罗语(si):
tokenize_indic.py(基于 indic-nlp-library); - 其余语言:Moses
tokenizer.perl标准分词。
依赖的第三方工具(Moses、wmt16-scripts、KyTea、mecab-ko、indic_nlp_resources、seg_my.py以及 pythainlp/sacrebleu/indic-nlp-library 等 Python 包)由 install_dependecies.sh 一键安装。
评测时对模型输出与参考译文分别做语言专属分词:
cd ${fairseq}/examples/m2m_100 cat ${fairseq}/gen_out | grep -P "^H" | sort -V | cut -f 3- | sh tok.sh fr > hyp cat ${fairseq}/raw_input.de-fr.fr | sh tok.sh fr > refgrep -P "^H"提取 fairseq 生成的 hypothesis 行,sort -V按序号排序,cut -f 3-去掉序号与分值前缀。
7.2 BLEU 打分
使用 sacrebleu,且不额外进行分词(因为 tok.sh 已经完成):
sacrebleu -tok 'none' ref < hypsacrebleu -tok 'none'表示按"已完成分词"处理,直接对 hyp 打分。
八、引用信息
若使用了本文涉及的任何资源,请引用以下论文(对应原文档给出的 BibTeX):
- M2M-100:Fan et al.,Beyond English-Centric Multilingual Machine Translation, 2020;
- CCMatrix:Schwenk et al.,CCMatrix: Mining Billions of High-Quality Parallel Sentences on the Web, arXiv:1911.04944;
- CCAligned:El-Kishky et al.,A Massive Collection of Cross-Lingual Web-Document Pairs, arXiv:1911.06154;
- 多语言翻译框架本身对应 Tang et al.,Multilingual Translation with Extensible Multilingual Pretraining and Finetuning, 2020(详见 examples/multilingual/README.md)。
九、FAQ 与常见问题
Q1:为什么预处理顺序如此严格?答:M2M-100 的评测必须在使用 SPM 编码前 detokenize;去重(dedup_data.py)必须放在 SPM 之前且基于未编码的原始文本,否则无法精确匹配评测句;频率清洗依赖训练语言各自的字符直方图,必须在 SPM 前基于明文执行。任意一步顺序颠倒都会引入评测偏差或产生无关字符噪声。
Q2:12B 模型为什么需要那么多 pipeline 参数?答:12B 模型无法放入单卡显存。balance 数组决定编码器/解码器各层在设备间的数量分配,devices 数组决定每段所在 GPU 编号。表中共 4 套配置,分别对应 2×32GB、4×16GB、6×12GB、8×8GB 四种显存布局,且检查点与配置必须一一对应(同一权重在不同卡数下切分方式不同,不能混用)。
Q3:能否用自己的 SPM 模型替换 spm.128k.model?答:可以,但模型输入必须使用与其训练一致的 SPM 模型与 128K 词典。若从零训练,需要先训练联合子词模型,并保证data_dict.128k.txt/model_dict.128k.txt与 SPM 词表一致;直接使用官方权重时则必须沿用spm.128k.model与配套词典。
Q4:评测时为什么-tok 'none'?答:M2M-100 的分词流程(tok.sh)已经完成了语言专属的分词/规范化,若再用 sacrebleu 默认分词会重复分词,导致 BLEU 无法与论文数字对齐。-tok 'none'即"输入已分词完毕"。
十、进一步阅读
- 数据清洗三个脚本的完整实现:remove_too_much_punc.py、dedup_data.py、clean_histogram.py;
- 多语言任务核心实现:translation_multi_simple_epoch.py;
- 多语言训练/生成/微调完整脚本:examples/multilingual;
- 分词与依赖安装:tokenizers 目录 与 install_dependecies.sh。
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考