
基于 fairseq 微调 RoBERTa 完成 GLUE 全任务数据预处理、超参配置与推理实战指南【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm本指南完整讲解如何在 fairseq 框架中将预训练 RoBERTa 模型微调至 GLUE 全部 8 个任务QQP、MNLI、QNLI、MRPC、RTE、STS-B、SST-2、CoLA覆盖原始数据下载、BPE 与二进制预处理、sentence_prediction任务微调命令逐参数解析、各任务推荐超参表以及微调后的模型加载与推理验证。阅读本文后你将能够复现 RoBERTa 在 GLUE 基准上的单任务微调流程并理解 fairseq 中句子分类任务从数据管线到分类头的完整实现链路。GLUE 基准与 RoBERTa 微调概览GLUEGeneral Language Understanding Evaluation是包含 8 个句子级理解任务的基准涵盖单句分类SST-2、CoLA、句子对分类MNLI、QQP、QNLI、RTE、MRPC与句子对回归STS-B。RoBERTaA Robustly Optimized BERT Pretraining Approach在 BERT 预训练流程上做了多项改进更长时间训练、更大 batch、更多数据、去除 NSP 目标、动态掩码等本仓库 examples/roberta/README.md 给出了其在 GLUE dev 集上的单模型单任务微调结果roberta.base125M 参数与roberta.large355M 参数分别达到 MNLI 87.6/90.2、QNLI 92.8/94.7、QQP 91.9/92.2、RTE 78.7/86.6、SST-2 94.8/96.4、MRPC 90.2/90.9、CoLA 63.6/68.0、STS-B 91.2/92.4dev 集准确率 / Spearman 相关。微调的核心思路是复用预训练好的 RoBERTa 编码器权重在[CLS]即 RoBERTa 的s位置之上挂载一个随机初始化的分类头用目标任务数据做全参数微调。fairseq 通过--task sentence_prediction统一驱动这一流程本文全部操作均以仓库 decoding/IAD/fairseq 内代码为准。第一步下载 GLUE 原始数据GLUE 官方数据需通过其下载脚本获取。本仓库 README.glue.md 给出的标准做法如下wget https://gist.githubusercontent.com/W4ngatang/60c2bdb54d156a41194446737ce03e2e/raw/17b8dd0d724281ed7c3b2aeeda662b92809aadd5/download_glue_data.py python download_glue_data.py --data_dir glue_data --tasks all执行后会在glue_data/目录下生成各任务子目录每个任务内含train.tsv、dev.tsv、test.tsv等原始 TSV 文件MNLI 额外包含dev_matched.tsv、dev_mismatched.tsv、test_matched.tsv、test_mismatched.tsv。这些 TSV 的列结构与任务相关后续预处理脚本正是按固定列号抽取文本与标签因此下载版本与脚本中的列号约定必须一致。第二步预处理 GLUE 任务数据一键预处理脚本原始 TSV 不能直接送入 fairseq需要经过「去表头 → 按列抽取输入/标签 → BPE 编码 → fairseq-preprocess 二进制化」四步。仓库提供了封装脚本 preprocess_GLUE_tasks.sh./examples/roberta/preprocess_GLUE_tasks.sh glue_data glue_task_nameglue_task_name取值为{ALL, QQP, MNLI, QNLI, MRPC, RTE, STS-B, SST-2, CoLA}传ALL会按QQP MNLI QNLI MRPC RTE STS-B SST-2 CoLA的顺序依次处理全部任务见脚本第 24-27 行。脚本内部首先下载三份 BPE 所需文件第 18-20 行wget -N https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/encoder.json wget -N https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/vocab.bpe wget -N https://dl.fbaipublicfiles.com/fairseq/gpt2_bpe/dict.txt各任务 TSV 列映射脚本源码细节预处理的核心难点在于不同任务 TSV 的列布局不同。脚本第 33-83 行以硬编码方式为每个任务声明了输入列、标签列与数据集划分任务输入列train/dev输入列test标签列输入句数特殊划分QQP4, 52, 362过滤非 6 字段行MNLI9, 109, 1012dev 用 162dev/test 含 matched 与 mismatchedQNLI2, 32, 342-MRPC4, 54, 512-RTE2, 32, 342-STS-B8, 98, 9102标签需归一化到 [0,1]SST-21221单句-CoLA4221单句train/dev 无表头脚本随后的处理逻辑第 85-144 行去表头除 CoLA 的 train/dev本身无表头外其余一律用tail -n 2去掉首行格式过滤QQP 的 train/dev 用awk -F \t -v NUM_FIELDS6 NFNUM_FIELDS{print}{}仅保留恰有 6 个字段的行剔除脏数据按列抽取用cut -f列号将每个 split 拆成split.raw.input0、split.raw.input1单句任务只有 input0与split.labelBPE 编码调用 multiprocessing_bpe_encoder.pypython -m examples.roberta.multiprocessing_bpe_encoder--workers 60 --keep-empty对每个输入列做 GPT-2 风格 BPE 切词。二进制化fairseq-preprocess编码完成后脚本第 158-184 行对 input0/input1 分别执行fairseq-preprocess \ --only-source \ --trainpref $TASK_DATA_FOLDER/processed/train.$LANG \ --validpref ${DEVPREF//LANG/$LANG} \ --testpref ${TESTPREF//LANG/$LANG} \ --destdir $TASK-bin/$LANG \ --workers 60 \ --srcdict dict.txt;MNLI 的 valid/test 前缀被替换为dev_matched.LANG,dev_mismatched.LANG第 152-156 行使一个*_matched-bin目录同时包含 matched/mismatched 两个验证集。标签列也以--only-source方式二进制化为$TASK-bin/label。STS-B 是回归任务标签不经过fairseq-preprocess而是直接把原始分值除以 5.0 归一化到[0.0, 1.0]第 179-184 行awk {print $1 / 5.0 }因为其原始标签是 0~5 的相似度打分。预处理完成后每个任务会生成类似RTE-bin/的目录内含input0/、input1/、label/三个子目录及各自的dict.txt这就是微调阶段的输入。第三步微调配置逐参数解析RTE 任务微调命令预处理完成后即可微调。以 RTE 为例README.glue.md 给出的完整命令如下TOTAL_NUM_UPDATES2036 # 10 epochs through RTE for bsz 16 WARMUP_UPDATES122 # 6 percent of the number of updates LR2e-05 # Peak LR for polynomial LR scheduler. NUM_CLASSES2 MAX_SENTENCES16 # Batch size. ROBERTA_PATH/path/to/roberta/model.pt CUDA_VISIBLE_DEVICES0 fairseq-train RTE-bin/ \ --restore-file $ROBERTA_PATH \ --max-positions 512 \ --batch-size $MAX_SENTENCES \ --max-tokens 4400 \ --task sentence_prediction \ --reset-optimizer --reset-dataloader --reset-meters \ --required-batch-size-multiple 1 \ --init-token 0 --separator-token 2 \ --arch roberta_large \ --criterion sentence_prediction \ --num-classes $NUM_CLASSES \ --dropout 0.1 --attention-dropout 0.1 \ --weight-decay 0.1 --optimizer adam --adam-betas (0.9, 0.98) --adam-eps 1e-06 \ --clip-norm 0.0 \ --lr-scheduler polynomial_decay --lr $LR --total-num-update $TOTAL_NUM_UPDATES --warmup-updates $WARMUP_UPDATES \ --fp16 --fp16-init-scale 4 --threshold-loss-scale 1 --fp16-scale-window 128 \ --max-epoch 10 \ --find-unused-parameters \ --best-checkpoint-metric accuracy --maximize-best-checkpoint-metric;关键参数的含义与底层依据--task sentence_prediction核心任务入口对应 fairseq/tasks/sentence_prediction.py 中的SentencePredictionTaskregister_task(sentence_prediction)第 34-35 行。它负责加载data/input0/dict.txt作为源词典加载data/label/dict.txt作为标签词典第 115-130 行并断言--num-classes必须大于 0第 112 行。--num-classes分类类别数回归任务传 1。训练时任务会为模型注册一个对应维度输出的分类头第 260-263 行。--init-token 0 --separator-token 2分别对应s与/s的 token id。在load_dataset中input0 前会PrependTokenDataset(input0, init_token)加上sinput1 前会加上/s作为分隔符再通过ConcatSentencesDataset(input0, input1)拼接成句子对sentence_prediction.py 第 158-167 行。--criterion sentence_prediction对应 fairseq/criterions/sentence_prediction.py 中的SentencePredictionCriterion。分类任务计算F.nll_loss(F.log_softmax(logits))回归任务计算F.mse_loss第 50-56 行分类模式下会累计ncorrect并最终输出accuracy指标第 64-66、86-90 行这正是 checkpoint 选择依据。--reset-optimizer --reset-dataloader --reset-meters微调时丢弃预训练 checkpoint 中携带的优化器状态与数据加载状态从零开始训练。--arch roberta_large模型结构为 RoBERTa-large也可换成roberta_base以节省显存。--lr-scheduler polynomial_decay --lr ... --total-num-update ... --warmup-updates ...多项式衰减学习率调度器。--total-num-update是衰减总步数需根据任务大小与 batch 推算详见下节--warmup-updates为预热步数推荐取总步数的 6%。--fp16 ...混合精度训练参数初始 scale 4、阈值 1、scale window 128在 V100 等 GPU 上显著降低显存占用并加速。--max-epoch 10最多训练 10 个 epoch。--best-checkpoint-metric accuracy --maximize-best-checkpoint-metric以验证集 accuracy 为选择 best checkpoint 的指标越大越好。--find-unused-parametersRoBERTa 微调时部分参数不参与梯度更新此参数避免 DDP 报错。分类头的源码级原理从 fairseq/models/roberta/model.py 可以看到微调时SentencePredictionTask.build_model调用model.register_classification_head(...)第 204-227 行将RobertaClassificationHead第 353 行起注册进模型的classification_heads字典。该分类头的结构非常精简第 381-387 行def forward(self, features, **kwargs): x features[:, 0, :] # take s token (equiv. to [CLS]) x self.dropout(x) x self.dense(x) # input_dim - inner_dim x self.activation_fn(x) x self.dropout(x) x self.out_proj(x) # inner_dim - num_classes即取序列首位置s的隐向量等价于 BERT 的[CLS]经「线性层 激活 dropout 输出层」投影为类别 logits。分类头默认名为sentence_classification_head可通过 criterion 的--classification-head-name自定义见 criterions/sentence_prediction.py 第 24-26 行。各 GLUE 任务的推荐超参表除 RTE 外其余任务只需调整下列几个命令行参数README.glue.md 表格原文完整继承如下参数MNLIQNLIQQPRTESST-2MRPCCoLASTS-B--num-classes32222221--lr1e-51e-51e-52e-51e-51e-51e-52e-5--batch-size3232321632161616--total-num-update12387333112113272203620935229653363598--warmup-updates74321986283181221256137320214几点说明MNLI 是 3 分类contradiction / neutral / entailmentSTS-B 是 1 输出的回归任务其余均为 2 分类--total-num-update由多项式衰减调度器使用其数值是按--max-epoch10与上表--batch-size16/32计算得到的总更新步数STS-B 需要额外添加--regression-target --best-checkpoint-metric loss并移除--maximize-best-checkpoint-metric——回归任务以 MSE loss 为 checkpoint 选择依据越小越好。--regression-target会让任务走回归分支不再加载 label 词典标签按RawLabelDataset以浮点形式读取sentence_prediction.py 第 215-234 行criterion 切换为 MSE 损失。训练资源与超参调整建议原文对超参使用给出了三条重要提示直接关系到复现成败上表所有命令与超参均在单张 32GB 显存的 NVIDIA V100上测试通过。如果 GPU 显存不足可以减小--batch-size并等比增大--update-freq来保持有效 batch 不变例如--batch-size 8 --update-freq 4等效于 batch 32。--update-freq通过累积多个 mini-batch 的梯度再更新参数是显存受限场景下微调 RoBERTa-large 的标配手段自定义分类任务的同类示例可参考 README.custom_classification.md其中 IMDB 示例即采用--batch-size 8 --update-freq 4实现有效 batch 32。表中数值是在固定搜索空间内做超参搜索后给出的建议值目的是保证不同模型之间公平可比。若自行扩大搜索范围很可能找到指标更高的配置。--total-num-update依赖 batch 与 epoch 数若改动--batch-size、--update-freq或--max-epoch需要同步重算该值否则多项式调度器会过早/过晚衰减到零。微调后推理加载 checkpoint 并评估训练完成后checkpoint 保存在checkpoints/目录checkpoint_best.pt为验证指标最优的模型。使用 fairseq/models/roberta 提供的 hub 接口即可加载模型并评估。以 RTE 为例README.glue.md 原文代码from fairseq.models.roberta import RobertaModel roberta RobertaModel.from_pretrained( checkpoints/, checkpoint_filecheckpoint_best.pt, data_name_or_pathRTE-bin ) label_fn lambda label: roberta.task.label_dictionary.string( [label roberta.task.label_dictionary.nspecial] ) ncorrect, nsamples 0, 0 roberta.cuda() roberta.eval() with open(glue_data/RTE/dev.tsv) as fin: fin.readline() for index, line in enumerate(fin): tokens line.strip().split(\t) sent1, sent2, target tokens[1], tokens[2], tokens[3] tokens roberta.encode(sent1, sent2) prediction roberta.predict(sentence_classification_head, tokens).argmax().item() prediction_label label_fn(prediction) ncorrect int(prediction_label target) nsamples 1 print(| Accuracy: , float(ncorrect)/float(nsamples))关键点解析RobertaModel.from_pretrained(model_name_or_path, checkpoint_file, data_name_or_path)从本地目录加载模型权重并绑定预处理后的二进制数据目录data_name_or_pathRTE-bin从而复用训练时的词典与 BPE 设置对应 model.py 第 233-244 行的from_pretrained实现roberta.encode(sent1, sent2)对句子对做 BPE 编码并拼上s//sroberta.predict(sentence_classification_head, tokens)调用训练时注册的sentence_classification_head分类头得到 logitsargmax取类别label_fn将预测出的标签索引还原为字符串如 RTE 的 entailment / not_entailment与 dev.tsv 中的真实标签比对累计准确率。注意 STS-B 的评估方式不同其标签为 0~5 的连续相似度分值应使用 Spearman 相关系数而非准确率这也解释了为何回归任务要以loss作为 checkpoint 选择指标。扩展阅读与完整生态本文聚焦 GLUE 微调但 fairseq 的 RoBERTa 示例目录decoding/IAD/fairseq/examples/roberta还包含一系列一脉相承的实战指南可作为延伸学习Finetuning on custom classification tasks (IMDB)自定义单句分类任务的全流程含数据格式化、BPE 编码、微调与 hub 加载Finetuning on Winograd Schema Challenge (WSC)代词消歧任务微调Finetuning on Commonsense QA多选题任务微调Pretraining RoBERTa using your own data从零预训练 RoBERTa 的教程。需要说明的是本文所有命令、超参与源码分析均以当前仓库 decoding/IAD/fairseq 为准数据下载与 BPE 文件来自 GLUE 官网脚本及 fairseq 官方发布站点微调硬件环境假设为单卡 V100 32GB若环境不同请按前文提示等比调整--batch-size与--update-freq并同步重算--total-num-update与--warmup-updates。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考