在 fairseq 中复现 Scaling NMT(Ott et al., 2018):基于 unilm 仓库 IAD 子目录的 WMT'16 En-De 端到端训练与评测指南
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
本指南以 decoding/IAD/fairseq/examples/scaling_nmt/README.md 为骨架,完整讲解如何在仓库内置的 fairseq 框架中复现《Scaling Neural Machine Translation》(Ott et al., 2018)的 Transformer 大模型(Big)翻译实验:从下载 WMT'16 英德数据、预处理构建联合词典、训练 Big 模型,到使用 checkpoint 平均、束搜索生成与两种 BLEU 评测方法,并结合 fairseq/models/transformer.py 与 fairseq/scripts 下的配套脚本进行源码级印证。读完本文,你将掌握一套可复制运行的 NMT 复现流水线,并理解 fairseq 中大数据、大批量、大模型训练的关键配置技巧。
1. 背景:Scaling NMT 论文与 fairseq 的关系
《Scaling Neural Machine Translation》(Ott et al., 2018)提出了训练更大规模神经机器翻译模型的一系列实践方法,是 fairseq 早期最具代表性的工作之一。本仓库的 decoding/IAD/fairseq 目录内置了一份完整可用的 fairseq 代码库,而 examples/scaling_nmt/README.md 正是该论文结果的官方复现说明。它包含两条主线:
- 发布模型:提供
transformer.wmt14.en-fr与transformer.wmt16.en-de两个预训练模型的下载入口(模型权重与 newstest2014 测试数据); - 复现流程:给出在 WMT'16 En-De 上从零训练 Big Transformer 的完整命令序列(预处理 → 训练 → 评估)。
下文将按 README 的顺序逐条展开,并在关键步骤处引入仓库源码作为依据。
2. 预训练模型概览
README 提供了两套官方发布的模型,均基于 Scaling NMT 论文中的 Transformer 结构,可用于快速对比或直接推理:
| 模型 | 描述 | 数据集 | 下载内容 |
|---|---|---|---|
transformer.wmt14.en-fr | Transformer(Ott et al., 2018) | WMT14 English-French | 模型(.tar.bz2)与 newstest2014 测试数据 |
transformer.wmt16.en-de | Transformer(Ott et al., 2018) | WMT16 English-German | 模型(.tar.bz2)与 newstest2014 测试数据 |
下载解压后,即可用fairseq-generate配合模型权重进行推理(评估命令可参考下文第 5 节)。
3. 在 WMT'16 En-De 上训练新模型:四步流水线
3.1 第 1 步:下载并解压预处理的 WMT'16 En-De 数据
首先下载 Google 提供的预处理版 WMT'16 En-De 数据(README 中附有下载链接,数据为 BPE 分词后的格式),然后解压:
TEXT=wmt16_en_de_bpe32k mkdir -p $TEXT tar -xzvf wmt16_en_de.tar.gz -C $TEXT解压后目录中应包含train.tok.clean.bpe.32000(训练集)、newstest2013.tok.bpe.32000(验证集)与newstest2014.tok.bpe.32000(测试集)等 BPE 编码文件,BPE 词表规模为 32000。
3.2 第 2 步:使用联合词典(joined dictionary)预处理数据
fairseq-preprocess \ --source-lang en --target-lang de \ --trainpref $TEXT/train.tok.clean.bpe.32000 \ --validpref $TEXT/newstest2013.tok.bpe.32000 \ --testpref $TEXT/newstest2014.tok.bpe.32000 \ --destdir>fairseq-train \ >@register_model_architecture("transformer", "transformer_vaswani_wmt_en_de_big") def transformer_vaswani_wmt_en_de_big(args): args.encoder_embed_dim = getattr(args, "encoder_embed_dim", 1024) args.encoder_ffn_embed_dim = getattr(args, "encoder_ffn_embed_dim", 4096) args.encoder_attention_heads = getattr(args, "encoder_attention_heads", 16) args.encoder_normalize_before = getattr(args, "encoder_normalize_before", False) args.decoder_embed_dim = getattr(args, "decoder_embed_dim", 1024) args.decoder_ffn_embed_dim = getattr(args, "decoder_ffn_embed_dim", 4096) args.decoder_attention_heads = getattr(args, "decoder_attention_heads", 16) args.dropout = getattr(args, "dropout", 0.3) base_architecture(args)即:编码器/解码器各 6 层(继承自base_architecture,见 transformer.py)、嵌入维度 1024、FFN 维度 4096、注意力头数 16、dropout 默认 0.3。README 训练命令中显式给出的--dropout 0.3与该架构默认值一致。
关键超参数解读
| 参数 | 取值 | 作用 |
|---|---|---|
--share-all-embeddings | 开启 | 编码器、解码器与输出层共享词嵌入矩阵,显著减少参数量 |
--optimizer adam --adam-betas '(0.9, 0.98)' | — | Adam 优化器,beta2=0.98 是 Transformer 训练常用设置 |
--clip-norm 0.0 | 0 | 不启用梯度裁剪 |
--lr 0.0005 --lr-scheduler inverse_sqrt | — | 初始学习率 5e-4,采用逆平方根调度 |
--warmup-updates 4000 --warmup-init-lr 1e-07 | — | 前 4000 步从 1e-7 线性升温到目标学习率 |
--criterion label_smoothed_cross_entropy --label-smoothing 0.1 | — | 标签平滑交叉熵损失,平滑系数 0.1 |
--max-tokens 3584 | 3584 | 单批次最大 token 数(按 token 而非句子数计) |
--fp16 | 开启 | 半精度混合精度训练 |
关于--share-all-embeddings的约束
从源码看,共享词嵌入并非无条件可用。在 transformer.py 的模型构建逻辑中:
- 若
src_dict != tgt_dict(即没有联合词典),会抛出ValueError: --share-all-embeddings requires a joined dictionary; - 若编码器与解码器嵌入维度不一致,会抛出维度不匹配错误;
- 共享后会自动将
share_decoder_input_output_embed置为 True,即解码器输入与输出层也共享权重。
这正是第 2 步必须使用--joined-dictionary的原因所在,两个步骤在源码层面互相印证。
--fp16的硬件前提
README 明确指出:--fp16需要CUDA 9.1 及以上,且 GPU 为Volta 架构或更新(否则半精度训练无法发挥硬件优势甚至不可用)。
3.4 大批量训练的官方建议(重要)
README 特别强调:用更大的 batch 训练、同时调大学习率,可以获得更好的效果。假设机器上有 8 块 GPU:
- 添加
--update-freq 16,用梯度累积模拟在 8×16=128 个 GPU 上的训练效果(即每个更新步累积 16 个 mini-batch 的梯度); - 将学习率提升到0.001,大批量下表现良好。
这一建议在 docs/getting_started.rst 中也有对应说明:--update-freq用于累积梯度,等效于扩大 batch size,是 fairseq 在有限显存下放大有效批量的标准手段。
4. 评估技巧:复现论文 BLEU 分数的三道工序
README 提醒,原版《Attention Is All You Need》论文使用了若干技巧来获得更高的 BLEU,Scaling NMT 论文复用了这些技巧,因此在复现结果时必须一并应用。
4.1 工序一:平均最后若干轮 checkpoint
平均最近 5~10 个 checkpoint 通常效果不错,具体数量可根据训练时长调整:
python scripts/average_checkpoints \ --inputs /path/to/checkpoints \ --num-epoch-checkpoints 10 \ --output checkpoint.avg10.pt该命令由仓库内置脚本 fairseq/scripts/average_checkpoints.py 提供,其核心逻辑(average_checkpoints函数)是:将每个 checkpoint 的模型参数在 CPU 上逐项累加后除以模型个数,得到平均权重;同时校验各 checkpoint 的参数键名必须完全一致,否则抛出KeyError(见 average_checkpoints.py)。脚本还支持:
--num-epoch-checkpoints N:按checkpointN.pt命名规则取最近 N 个 epoch 的 checkpoint;--num-update-checkpoints N:按checkpoint_ee_uu.pt命名规则取最近 N 个 update 的 checkpoint(二者互斥,见 average_checkpoints.py);--checkpoint-upper-bound N:限定取数上限,例如--num-epoch-checkpoints=10 --checkpoint-upper-bound=50表示取第 41~50 个 checkpoint 求平均。
4.2 工序二:束搜索生成译文
使用束宽 4、长度惩罚 0.6 生成翻译结果:
fairseq-generate \ >bash scripts/compound_split_bleu.sh gen.out # BLEU4 = 29.29, 60.3/35.0/22.8/15.3 (BP=1.000, ratio=1.004, syslen=64763, reflen=64496)对应脚本为 fairseq/scripts/compound_split_bleu.sh:它先检查gen.out最后一行是否已包含 BLEU 统计(未生成完毕则退出),再从^H(假设译文)与^T(参考译文)行中抽取文本,用 Perl 正则s{(\S)-(\S)}{$1 ##AT##-##AT## $2}g在连字符两侧加空格,最后调用fairseq-score计算分数。例如 "Café-Liebhaber" 会被拆成 "Café - Liebhaber" 三个 token,从而普遍抬高 BLEU。README 明确警示:这种"注水"分数不能与未采用该技巧的工作直接比较,该技巧源自原版 AIAYN 代码,Scaling NMT 论文沿用了它。
方式 B:sacrebleu detokenized BLEU(推荐)
bash scripts/sacrebleu.sh wmt14/full en de gen.out # BLEU+case.mixed+lang.en-de+numrefs.1+smooth.exp+test.wmt14/full+tok.13a+version.1.4.3 = 28.6 59.3/34.3/22.1/14.9 (BP = 1.000 ratio = 1.016 hyp_len = 63666 ref_len = 62688)对应脚本为 fairseq/scripts/sacrebleu.sh:它从gen.out提取^H行并按序号排序、抽取译文列,经sacremoses detokenize还原后,交给sacrebleu计算。README 强烈建议论文报告使用sacrebleu分数,因其评测口径标准化、可复现。运行前需安装依赖:pip install sacremoses(sacrebleu 亦需另行安装)。
对比:同一模型两种口径下分别得到 29.29(compound split,不推荐)与 28.6(sacrebleu,推荐),差异正是"连字符拆词"技巧所致。
5. 使用预训练模型的推理路线
若只想复现推理效果而非重新训练,可在下载transformer.wmt16.en-de(或 en-fr)模型后,以对应测试集数据为输入执行fairseq-generate:
- 解压模型与 newstest2014 数据(.tar.bz2);
- 若使用 bpe32k 测试数据,参照第 3.2 步执行
fairseq-preprocess得到二值化数据(注意--joined-dictionary需与模型训练时的词典设置一致); - 执行第 4.2 步的
fairseq-generate,将--path指向解压后的模型权重。
6. 引用
若你的工作复用了本复现流程或模型,建议按 README 中的 BibTeX 引用论文:
@inproceedings{ott2018scaling, title = {Scaling Neural Machine Translation}, author = {Ott, Myle and Edunov, Sergey and Grangier, David and Auli, Michael}, booktitle = {Proceedings of the Third Conference on Machine Translation (WMT)}, year = 2018, }7. 复现检查清单
- 数据:解压
wmt16_en_de.tar.gz至wmt16_en_de_bpe32k目录; - 预处理:使用
--joined-dictionary,词表 32768,输出至data-bin/wmt16_en_de_bpe32k; - 训练:
transformer_vaswani_wmt_en_de_big+--share-all-embeddings+--fp16(Volta+ / CUDA 9.1+); - 大批量优化:8 卡场景可加
--update-freq 16并将--lr提到 0.001; - 评估:平均最近 5~10 个 checkpoint →
--beam 4 --lenpen 0.6生成 → 用 sacrebleu 计算 detokenized BLEU(不推荐 compound split 口径); - 对照:sacrebleu 口径下目标分数约 28.6(compound split 口径约 29.29,仅供参考)。
【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考