用自有数据预训练 RoBERTa:基于 fairseq 的完整实战指南(数据处理 · 训练 · 加载)
用自有数据预训练 RoBERTa基于 fairseq 的完整实战指南数据处理 · 训练 · 加载【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm导读本文以 decoding/IAD/fairseq/examples/roberta/README.pretraining.md 为核心骨架系统讲解如何在 fairseq 框架下使用你自己的语料从零预训练一个 RoBERTa 模型从原始文本的清洗与 GPT-2 BPE 编码、fairseq-preprocess二值化到fairseq-train启动掩码语言模型masked LM训练再到用RobertaModel.from_pretrained加载训练产物。读完本文你将掌握一套可直接套用的自定义语料预训练流水线并理解其中每个关键参数在源码层面的真实作用能够根据自有 GPU 资源灵活调整批量大小与学习率。说明本文所述内容对应 unilm 仓库中decoding/IAD/fairseq子项目内嵌的 fairseq 代码其结构与官方 fairseq 一致。所有命令行、参数均以该仓库实际代码为准。1. 总体流程一览用自有数据预训练 RoBERTa 共分三步预处理数据将原始文本按语言模型LM格式整理用 GPT-2 BPE 编码再用fairseq-preprocess二值化为 fairseq 索引数据集训练以--task masked_lm --criterion masked_lm --arch roberta_base启动预训练加载通过RobertaModel.from_pretrained加载 checkpoint 并继续微调或提取特征。下面按此顺序逐步展开。2. 数据预处理原始文本 → LM 格式2.1 语言模型数据格式数据必须按照语言模型的格式组织具体规范见 decoding/IAD/fairseq/examples/language_model/README.md。核心要求是每个文档之间用空行分隔——这一约定只在启用--sample-break-mode complete_doc时生效用于在采样时尊重文档边界训练时所有行会被拼接成一条一维的文本流1D text stream也就是说文档内部的换行在训练阶段并不保留只是作为采样的边界标记。在 masked_lm.py 的--sample-break-mode参数说明中四种取值的行为如下取值行为none缺省值之一每个样本填满tokens-per-sample个 token无视句子边界complete只在句子结尾处切断一个样本可包含多个句子complete_doc与complete类似但额外尊重文档空行边界eos每个样本只包含一个句子原教程在训练阶段使用的是complete即允许样本跨文档边界、但尽量在句子结尾截断这与 RoBERTa 原文“训练更长序列、打乱文档顺序”的思路一致。2.2 下载示例数据集WikiText-103教程以 WikiText-103 作为演示数据注意该数据集规模很小训练出的模型效果有限仅用于演示完整流程wget https://s3.amazonaws.com/research.metamind.io/wikitext/wikitext-103-raw-v1.zip unzip wikitext-103-raw-v1.zip解压后得到wikitext-103-raw/目录内含wiki.train.raw、wiki.valid.raw、wiki.test.raw三个原始文本文件。仓库还提供了脚本化的数据准备方式可参考 prepare-wikitext-103.sh该脚本下载并解压 WikiText-103并在完成后cd ..回到仓库根目录。3. 使用 GPT-2 BPE 编码文本3.1 获取 BPE 词表文件fairseq 的 RoBERTa 使用与 GPT-2 相同的 BPEByte-Pair Encoding子词切分需要两个文件mkdir -p gpt2_bpe wget -O gpt2_bpe/encoder.json https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/encoder.json wget -O gpt2_bpe/vocab.bpe https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/vocab.bpe这两个文件分别保存了 token 到 id 的映射encoder.json以及 BPE 合并规则vocab.bpe。其默认路径在 gpt2_bpe.py 中以DEFAULT_ENCODER_JSON/DEFAULT_VOCAB_BPE常量声明即使用--bpe gpt2时若未显式指定文件fairseq 会通过cached_path自动下载缓存。3.2 用多进程 BPE 编码器逐 split 处理对train / valid / test三个 split 分别执行编码for SPLIT in train valid test; do \ python -m examples.roberta.multiprocessing_bpe_encoder \ --encoder-json gpt2_bpe/encoder.json \ --vocab-bpe gpt2_bpe/vocab.bpe \ --inputs wikitext-103-raw/wiki.${SPLIT}.raw \ --outputs wikitext-103-raw/wiki.${SPLIT}.bpe \ --keep-empty \ --workers 60; \ done该脚本的源码位于 multiprocessing_bpe_encoder.py其工作原理值得展开它通过 Pythonmultiprocessing.Pool创建--workers个工作进程每个进程用get_encoder(encoder_json, vocab_bpe)加载一次 GPT-2 编码器initializer中把编码器放入进程级全局变量bpe再以pool.imap(..., 100)以 100 行为一批进行并行编码encode_lines会先strip每一行空行默认会被过滤返回EMPTY并整组丢弃传入--keep-empty后空行得以保留——这正是第 2.1 节所说“空行分隔文档”约定能被保留到编码后文本的关键每行编码结果是一串以空格分隔的 token id如hello world→31373 995因此输出文件里空行仍然代表文档边界脚本会对输入/输出文件数量做断言assert len(args.inputs) len(args.outputs)并支持-表示标准输入/输出便于管道化使用。编码完成后每个原始行都被替换为对应的 BPE token id 序列得到wiki.train.bpe、wiki.valid.bpe、wiki.test.bpe。4. 构建 fairseq 词典并二值化4.1 获取 GPT-2 词典wget -O gpt2_bpe/dict.txt https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/dict.txtdict.txt是 GPT-2 词表对应的 fairseqDictionary格式文件每行一个 token 及频率计数。它决定了后续模型词表大小GPT-2 词表为 50265含特殊符号。4.2 运行 fairseq-preprocessfairseq-preprocess \ --only-source \ --srcdict gpt2_bpe/dict.txt \ --trainpref wikitext-103-raw/wiki.train.bpe \ --validpref wikitext-103-raw/wiki.valid.bpe \ --testpref wikitext-103-raw/wiki.test.bpe \ --destdir>TOTAL_UPDATES125000 # Total number of training steps WARMUP_UPDATES10000 # Warmup the learning rate over this many updates PEAK_LR0.0005 # Peak learning rate, adjust as needed TOKENS_PER_SAMPLE512 # Max sequence length MAX_POSITIONS512 # Num. positional embeddings (usually same as above) MAX_SENTENCES16 # Number of sequences per batch (batch size) UPDATE_FREQ16 # Increase the batch size 16x DATA_DIRdata-bin/wikitext-103 fairseq-train --fp16 $DATA_DIR \ --task masked_lm --criterion masked_lm \ --arch roberta_base --sample-break-mode complete --tokens-per-sample $TOKENS_PER_SAMPLE \ --optimizer adam --adam-betas (0.9,0.98) --adam-eps 1e-6 --clip-norm 0.0 \ --lr-scheduler polynomial_decay --lr $PEAK_LR --warmup-updates $WARMUP_UPDATES --total-num-update $TOTAL_UPDATES \ --dropout 0.1 --attention-dropout 0.1 --weight-decay 0.01 \ --batch-size $MAX_SENTENCES --update-freq $UPDATE_FREQ \ --max-update $TOTAL_UPDATES --log-format simple --log-interval 1各参数在源码中的对应关系如下--task masked_lm/--criterion masked_lm任务注册于 masked_lm.py。该任务在初始化时通过dictionary.add_symbol(mask)向词典追加掩码符号并动态生成掩码样本见第 6 节--arch roberta_base模型架构注册于 model.py。roberta_base与roberta均使用base_architecture的默认值12 层 encoder、768 维 embedding、3072 维 FFN、12 个注意力头、GELU 激活、dropout/attention-dropout 默认 0.1、pre-normencoder_normalize_beforeTrue、BERT 风格初始化apply_bert_initTrue参数量约 1.25 亿若资源充足可换--arch roberta_large24 层 / 1024 / 4096 / 16 头约 3.55 亿参数见 model.py--fp16混合精度训练显著降低显存占用是官方预训练标配--optimizer adam --adam-betas (0.9,0.98) --adam-eps 1e-6 --clip-norm 0.0Adam 优化器与 RoBERTa 原文一致的 beta 配置clip-norm 0.0表示不裁剪梯度--lr-scheduler polynomial_decay多项式衰减调度器学习率从--warmup-updates预热阶段线性上升至PEAK_LR再按多项式衰减至 0--total-num-update给出总步数--tokens-per-sample 512每个样本的最大序列长度MAX_POSITIONS决定位置嵌入数量通常与前者一致。若未显式设置build_model会用args.tokens_per_sample兜底见 model.py--batch-size 16 --update-freq 16单卡每步 16 个序列梯度累积 16 次后更新一次参数等效把批量放大了 16 倍--max-update训练总步数此例 125000 步。5.2 批量大小与学习率的配套调整原教程明确给出三点实战提醒硬件前提上述命令假设使用 8×32GB V100 GPU。每张卡批量 16 个序列$MAX_SENTENCES经$UPDATE_FREQ16的梯度累积放大全局等效批量为 2048 个序列8 × 16 × 16 2048显存不足怎么办GPU 数量更少或显存更小时应调小$MAX_SENTENCES、调大$UPDATE_FREQ来补偿GPU 更多时则可相应减小$UPDATE_FREQ以提升训练速度学习率与批量强耦合学习率应随批量增大而调高原文档给出的参考对照表如下注意具体数值依赖数据集不可盲从批量大小峰值学习率2560.000120480.000581920.0007本教程示例取批量 2048、峰值学习率 0.0005正好与表中第二行吻合。5.3 从官方 checkpoint 恢复训练可选# 添加此参数即可从已发布的 RoBERTa base 权重继续训练 --restore-file /path/to/roberta.base/model.pt官方roberta.base/roberta.large权重的下载入口在RobertaModel.hub_models()中声明见 model.py。注意恢复训练时需保证词典与架构一致。6. 源码视角masked_lm 任务与动态掩码预训练的核心在于 masked_lm.py 的MaskedLMTask.load_dataset数据流水线它完整复现了 RoBERTa“动态掩码”的做法分块加载二值化数据集后用TokenBlockDataset按tokens-per-sample - 1为s留位切成连续 token 块break_mode由--sample-break-mode控制见 2.1 节加句首符PrependTokenDataset在每个样本前追加s等价于 BERT 的[CLS]动态掩码调用MaskTokensDataset.apply_mask在每个 epoch 重新采样掩码位置——这正是 RoBERTa 与 BERT静态掩码的关键区别之一。相关可调参数及默认值参数默认值含义--mask-prob0.15将 token 替换为mask的概率--leave-unmasked-prob0.1被选中 token 中“保持原样”的比例--random-token-prob0.1被选中 token 中替换为随机 token 的比例--mask-whole-wordsFalse是否按整词掩码开启时建议配合--bpe--mask-multiple-length1掩码 span 长度倍数--mask-stdev0.0掩码 span 长度的标准差被掩码的 token 组成 target与掩码后的输入一起打包成NestedDictionaryDataset并按随机序 长度排序后送入训练。注意这里的掩码概率与 BERT 论文一致15% 选中、其中 80%/10%/10% 分别替换为mask/随机词/原词且每个 epoch 重新采样避免了静态掩码带来的“同一句反复见到同一掩码”问题。7. 加载你的预训练模型训练完成后checkpoint 保存在 fairseq 默认的checkpoints/目录。用 Python 加载from fairseq.models.roberta import RobertaModel roberta RobertaModel.from_pretrained(checkpoints, checkpoint_best.pt, path/to/data) assert isinstance(roberta.model, torch.nn.Module)from_pretrained的实现见 model.py它会读取 checkpoint 与数据目录用于加载词典和 BPE 配置默认bpegpt2最终返回一个封装好的RobertaHubInterface见 hub_interface.py支持encode/decode/extract_features/register_classification_head/predict/fill_mask等开箱即用的接口可直接进入下游微调或特征提取阶段。8. 从预训练到下游任务预训练只是第一步。仓库在 examples/roberta 下提供了完整的后续配套文档与脚本README.mdRoBERTa 整体介绍、官方预训练模型与 GLUE/SuperGLUE/SQuAD 等基准结果、torch.hub加载与特征提取示例README.glue.mdGLUE 任务微调指南配套 preprocess_GLUE_tasks.sh 数据预处理脚本README.custom_classification.md自定义分类任务微调README.race.md 与 preprocess_RACE.shRACE 阅读理解数据集处理wsc/README.md、commonsense_qa/README.mdWSC、Commonsense QA 专项微调。9. 常见问题与要点小结空行语义只有使用--sample-break-mode complete_doc时数据中的空行文档边界才被采样逻辑尊重编码阶段务必用--keep-empty保留空行批量与显存的权衡优先固定全局批量如 2048通过MAX_SENTENCES × UPDATE_FREQ × GPU 数三者互相调配学习率必须随批量联动批量翻倍时学习率也应上调可参考第 5.2 节的对照表起步再按验证集损失微调动态掩码是 RoBERTa 的核心特性--task masked_lm在每个 epoch 重新采样掩码位置相关概率参数--mask-prob等可在训练命令中覆盖默认值验证训练流程WikiText-103 规模较小适合跑通整条流水线但训练出的模型效果有限正式预训练应使用更大规模语料并考虑从官方权重--restore-file续训或作为初始化。至此一条“自有语料 → BPE 编码 → 二值化 → masked_lm 预训练 → 加载使用”的完整 RoBERTa 预训练链路已经打通你可以将其中的数据集、批量、学习率替换为适合自身场景的配置后直接复用。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考