十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

fairseq 字节级子词神经机器翻译:基于 IWSLT17 法英任务的 BBPE 完整实践指南

fairseq 字节级子词神经机器翻译:基于 IWSLT17 法英任务的 BBPE 完整实践指南 fairseq 字节级子词神经机器翻译基于 IWSLT17 法英任务的 BBPE 完整实践指南【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm导读本文以 fairseq 官方示例byte_level_bpe为骨架系统讲解字节级子词Byte-Level Subwords / BBPE技术在神经机器翻译中的完整落地路径从 IWSLT 2017 Fr-En 数据集的获取与多套词表bytes / chars / BPE / BBPE的构建到使用带 Bi-GRU 嵌入上下文化的 Transformer 模型gru_transformer完成训练、生成与交互式推理并给出各词表方案的 BLEU 对比结果。读完本文你将掌握 BBPE 的原理、fairseq 中对应的编码器/解码器实现bytes、characters、byte_bpe、sentencepiece以及一套可直接复现的端到端命令流程。一、背景为什么要做字节级子词BBPE传统基于词或子词的翻译系统面临两大痛点词表爆炸与 OOV未登录词问题按词切分需要覆盖海量词汇且难以处理新词、专有名词、拼写变体跨语言符号不一致不同语言使用不同字符集联合词表往往需要很大的词汇量才能覆盖。Byte-Level BPEBBPE的思路是先把文本按 UTF-8 编码转成字节序列再对字节序列学习 BPE 合并规则。由于所有语言共用同一套 UTF-8 字节空间256 个字节BBPE 天然具备多语言友好、词表紧凑、理论上无 OOV 的特性。本示例参考论文Neural Machine Translation with Byte-Level SubwordsWang, Cho Gu, 2019arXiv:1909.03341在 fairseq 中给出了完整实现并以 IWSLT 2017 Fr-En 为基准任务。在当前的 unilm 仓库中该示例位于 decoding/IAD/fairseq/examples/byte_level_bpe包含三个核心文件文件作用get_data.sh一键下载 IWSLT17 数据、构建各词表并生成 fairseq 二进数据集get_bitext.py双语语料的清洗、Moses 预分词、各词表切分与 SentencePiece 模型训练gru_transformer.py注册gru_transformer模型在 Transformer 编码器中加入 Bi-GRU 对嵌入做上下文化二、数据准备构建 6 套词表的完整流水线2.1 一键脚本 get_data.sh原文档给出的数据获取方式非常简洁bash ./get_data.sh但脚本内部实际完成了五步工作见 get_data.sh安装依赖pip install sentencepiece sacremoses下载 IWSLT 2017 Fr-En 语料从wit3.fbk.eu下载fr-en.tgz并解压到data/调用 get_bitext.py 构建多套词表数据${PY_BIN_ROOT}python get_bitext.py --bpe-vocab 16384 --byte-vocab --char-vocab for VOCAB_SIZE in 2048 4096; do ${PY_BIN_ROOT}python get_bitext.py --bpe-vocab ${VOCAB_SIZE} --bbpe-vocab ${VOCAB_SIZE} done这一步会生成 BPE 16k、BPE 2k/4k、BBPE 2k/4k、bytes、chars 共 6 类切分文本清理原始文件rm -r data/fr-en data/fr-en.tgz对每类词表分别执行fairseq-preprocess生成二进制数据集目标目录分别为data/bin_bpe16384、data/bin_bytes、data/bin_chars、data/bin_bbpe2048、data/bin_bpe2048、data/bin_bbpe4096、data/bin_bpe4096。其中fairseq-preprocess统一使用--joined-dictionary法英共享联合词典与--workers $(nproc)按机器核数并行fairseq-preprocess --source-lang fr --target-lang en --destdir data/bin_bpe16384 --joined-dictionary \ --workers $(nproc) --trainpref data/train.moses.bpe16384 --validpref data/valid.moses.bpe16384 \ --testpref data/test.moses.bpe163842.2 词表构建细节get_bitext.pyget_bitext.py 是数据流水线的核心其处理链路可拆解为Step 1 — 语料清洗从train.tags.fr-en.fr/en提取正文跳过...标签行从IWSLT17.TED.dev2010验证集与IWSLT17.TED.tst2015测试集的 XML 中抽取seg段内容。Step 2 — Moses 预分词调用 fairseq 内置的MosesTokenizer实现在 moses_tokenizer.py对法英两侧做常规化切分输出*.moses.*文件。Step 3 — 按词表类型切分对应脚本中的 4 个分支BPE--bpe-vocab K将法英训练语料拼接成train.all用sp.SentencePieceTrainer.Train以--model_typebpe、--character_coverage1.0、--normalization_rule_nameidentity训练spm_bpeK.model再通过SentencepieceBPEsentencepiece_bpe.py应用到 train/valid/testBBPE--bbpe-vocab K先把训练语料逐行做字节编码得到train.bchar调用byte_encode再在字节序列上训练spm_bbpeK.model应用时使用ByteBPEbyte_bpe.pyBytes--byte-vocab直接对每行调用Bytes.encode将文本转成逐字节 tokenChars--char-vocab调用Characters.encode按字符切分空格转义为▁。命令行参数一览python get_bitext.py --help语义参数类型说明--rootstr默认data数据根目录--bpe-vocab Kint生成 BPE 词表大小为 K 的切分语料默认禁用--bbpe-vocab Kint生成 BBPE 词表大小为 K 的切分语料默认禁用--byte-vocabflag生成逐字节词表的切分语料--char-vocabflag生成逐字符词表的切分语料2.3 底层字节编解码原理BBPE 的字节层完全由 byte_utils.py 承担核心是双射字节映射表PRINTABLE_LATIN set(list(range(32, 1261)) list(range(161, 1721)) list(range(174, 2551))) BYTE_TO_BCHAR {b: chr(b) if b in PRINTABLE_LATIN else chr(256 b) for b in range(256)} BCHAR_TO_BYTE {bc: b for b, bc in BYTE_TO_BCHAR.items()}编码byte_encode(x)先做空白归一化连续空白折叠为单个空格再utf-8编码后把每个字节映射为一个字符可打印拉丁字节保留原样其余映射到chr(256b)的不可打印区从而得到一个无空格冲突的单字符序列便于送入 SentencePiece解码byte_decode(x)按映射表逆变换回字节并decode(utf-8)容错解码smart_byte_decode(x)当字节序列因切分导致 UTF-8 断裂decode抛ValueError时采用动态规划代码中f[i]/pt[i]数组在 14 字节窗口内寻找有效字符数最多的最优恢复路径避免输出乱码。Bytes与Characters两个注册 BPE 类bytes.py、characters.py均以▁chr(9601)转义空格后按 token 用空格拼接输出保证序列化格式与 fairseq 分词器接口一致。ByteBPE.encode则是先byte_encode再 SentencePiece 切分的完整 BBPE 前向路径。三、模型训练Transformer Bi-GRU 嵌入上下文化3.1 训练命令原文档给出的训练命令通过环境变量切换词表类型# VOCABbytes # VOCABchars VOCABbbpe2048 # VOCABbpe2048 # VOCABbbpe4096 # VOCABbpe4096 # VOCABbpe16384fairseq-train data/bin_${VOCAB} --task translation --user-dir examples/byte_level_bpe/gru_transformer \ --arch gru_transformer --encoder-layers 2 --decoder-layers 2 --dropout 0.3 --share-all-embeddings \ --optimizer adam --adam-betas (0.9, 0.98) \ --lr 5e-4 --lr-scheduler inverse_sqrt --warmup-updates 4000 \ --criterion label_smoothed_cross_entropy --label-smoothing 0.1 \ --log-format simple --log-interval 100 --save-dir checkpoints/${VOCAB} \ --batch-size 100 --max-update 100000 --update-freq 2各超参数的作用如下参数取值说明--task translation—标准翻译任务--user-direxamples/byte_level_bpe/gru_transformer加载自定义模型注册gru_transformer--arch gru_transformer—使用 Bi-GRU 上下文化的 Transformer--encoder-layers / --decoder-layers2 / 2编码器、解码器均为 2 层base 配置为 6 层此处显式覆盖为 2 层--dropout 0.30.3全连接/注意力 dropout--share-all-embeddings—共享源/目标/输出嵌入--optimizer adam --adam-betas (0.9, 0.98)—Adambetas 对齐 Transformer 论文--lr 5e-4 --lr-scheduler inverse_sqrt --warmup-updates 4000—逆平方根学习率衰减 4000 步预热--criterion label_smoothed_cross_entropy --label-smoothing 0.1—标签平滑交叉熵平滑系数 0.1--batch-size 100 --update-freq 2—单步 batch 100每 2 步累积一次更新等效 batch 200--max-update 100000—最多 10 万次参数更新3.2 模型结构源码解读gru_transformer.py的关键设计见 gru_transformer.pyGRUTransformerModel继承TransformerModel仅重写build_encoder返回GRUTransformerEncoderGRUTransformerEncoder在TransformerEncoder之上增加一个单层双向 GRUnn.GRUinput_sizeembed_dimhidden_sizeembed_dim//2bidirectionalTrue作为嵌入上下文化网络forward_embedding的执行顺序词嵌入 ×embed_scale→ 叠加位置嵌入 → 转置为 (T, B, E) 送入 GRU → 转置回来 → 可选 LayerNorm → dropout同时把原始embed返回给 decoder 复用如 cross-attention 键架构注册函数gru_transformer_base_architecture给出默认值encoder_embed_dim512、encoder_ffn_embed_dim2048、6 层、8 头等并额外提供gru_transformer_big变体1024 维、16 头、FFN 4096、dropout 0.3。引入 Bi-GRU 的动机当词表变成字节/字符粒度时单个 token 缺乏语义信息编码器首先用双向 GRU 在局部窗口内融合相邻字节/字符的上下文等价于在 Transformer 之前做一层软合并从而缓解细粒度子词带来的语义碎片化。四、生成与交互式推理解码器与字节还原4.1 fairseq-generate必须配对正确的 BPE 解码器由于模型输出的是字节/字符/BPE 片段fairseq-generate需要对应的--bpe解码器把输出还原成自然语言。原文档通过BPE变量按词表切换# BPE--bpe bytes # BPE--bpe characters BPE--bpe byte_bpe --sentencepiece-model-path data/spm_bbpe2048.model # BPE--bpe sentencepiece --sentencepiece-model data/spm_bpe2048.model # BPE--bpe byte_bpe --sentencepiece-model-path data/spm_bbpe4096.model # BPE--bpe sentencepiece --sentencepiece-model data/spm_bpe4096.model # BPE--bpe sentencepiece --sentencepiece-model data/spm_bpe16384.modelfairseq-generate data/bin_${VOCAB} --task translation --user-dir examples/byte_level_bpe/gru_transformer \ --source-lang fr --gen-subset test --sacrebleu --path checkpoints/${VOCAB}/checkpoint_last.pt \ --tokenizer moses --moses-target-lang en ${BPE}要点说明--bpe bytes对应Bytes.decode空格转义还原 smart_byte_decode容错解码--bpe characters对应Characters.decode去掉 token 间空格并还原▁为空格--bpe byte_bpe对应ByteBPE.decodebyte_bpe.pyx.replace(SPACE, ).replace(SPACE_ESCAPE, SPACE)后交给smart_byte_decode--bpe sentencepiece对应SentencepieceBPE.decode用同一个 SentencePiece 模型做 detokenize--tokenizer moses --moses-target-lang en负责对解码输出做 Moses 去分词使其与官方 BLEU 计算口径一致--sacrebleu让 fairseq 直接输出 sacreBLEU。4.2 fairseq-interactive编码与解码双向闭环交互式推理时输入侧也要经过字节编码输出侧要还原因此必须同时指定编码器和解码器fairseq-interactive data/bin_${VOCAB} --task translation --user-dir examples/byte_level_bpe/gru_transformer \ --path checkpoints/${VOCAB}/checkpoint_last.pt --input data/test.fr --tokenizer moses --moses-source-lang fr \ --moses-target-lang en ${BPE} --buffer-size 1000 --max-tokens 10000--input data/test.fr按行读入源句也可省略该参数改为 stdin 逐行输入--moses-source-lang fr源侧先做 Moses 预分词--buffer-size 1000 --max-tokens 10000限制输入缓冲与单次前向的最大 token 数控制显存占用。至此BBPE 的完整闭环文本 → byte_encode → SentencePiece 切分 → 模型 → 字节片段 → smart_byte_decode → 自然语言全部打通。五、实验结果不同词表方案的 BLEU 对比原文档给出的 IWSLT17 Fr-Entst2015结果如下括号内为加入 ensemble 的 BLEU词表方案模型BLEUJoint BPE 16kKudo, 2018512d LSTM 2233.81Joint BPE 16kTransformer base 22w/ GRU36.64 (36.72)Joint BPE 4kTransformer base 22w/ GRU35.49 (36.10)Joint BBPE 4kTransformer base 22w/ GRU35.61 (35.82)Joint BPE 2kTransformer base 22w/ GRU34.87 (36.13)Joint BBPE 2kTransformer base 22w/ GRU34.98 (35.43)CharactersTransformer base 22w/ GRU31.78 (33.30)BytesTransformer base 22w/ GRU31.57 (33.62)从表格可以读出三个可复现的结论在相同 Transformer 结构下BPE/BBPE 明显优于纯 Bytes/Chars 方案字节/字符粒度的序列更长、语义碎片化更严重即使有 Bi-GRU 上下文化仍损失约 2.43.5 个 BLEUBBPE 与同规模 BPE 基本持平BBPE 2k34.98vs BPE 2k34.87BBPE 4k35.61vs BPE 4k35.49说明在法英这种字符集可被常规词表覆盖的场景下字节级子词不损失质量同时换来更强的跨语言泛化能力词表越大质量越好16k 联合 BPE 达到最高 36.64但 2k 小词表约 2 万级参数开销更小仅低约 1.8 个点工程上可用小词表换取更低的内存与嵌入参数。六、复现注意事项与适用前提运行目录上述fairseq-*命令与bash ./get_data.sh需在 decoding/IAD/fairseq 根目录下执行该示例属于 IAD 解码框架内置的 fairseq 分支目录内含完整 fairseq 实现依赖需要sentencepiece、sacremoses脚本中已通过pip install自动安装wget需网络可达模型路径--user-dir examples/byte_level_bpe/gru_transformer指向示例目录使 fairseq 能发现GRUTransformerModel的注册register_model(gru_transformer)解码器与词表必须严格对应bytes → --bpe bytes、chars → --bpe characters、bbpeK → --bpe byte_bpe --sentencepiece-model-path data/spm_bbpeK.model、bpeK → --bpe sentencepiece --sentencepiece-model data/spm_bpeK.model混用会导致输出无法还原结果口径BLEU 数值仅对应当前仓库该示例的实验配置Transformer 22、dropout 0.3、inverse_sqrt 4000 warmup 等更换数据或超参后需重新评估。七、引用与致谢该实现对应的论文引用信息同样记录在原文档中misc{wang2019neural, title{Neural Machine Translation with Byte-Level Subwords}, author{Changhan Wang and Kyunghyun Cho and Jiatao Gu}, year{2019}, eprint{1909.03341}, archivePrefix{arXiv}, primaryClass{cs.CL} }如需深入源码推荐按以下顺序阅读数据流水线get_data.sh → get_bitext.py字节编解码核心byte_utils.py双射映射与 DP 容错解码三个注册分词器bytes.py、characters.py、byte_bpe.py模型实现gru_transformer.pyBi-GRU 嵌入上下文化。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表