BART 详解:基于去噪自编码的序列到序列预训练模型在 unilm/IAD 仓库中的完整实践指南

发布时间:2026/9/13 17:55:10
BART 详解:基于去噪自编码的序列到序列预训练模型在 unilm/IAD 仓库中的完整实践指南 BART 详解基于去噪自编码的序列到序列预训练模型在 unilm/IAD 仓库中的完整实践指南【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilmBART 是由 Facebook AI 提出的序列到序列seq2seq预训练模型以去噪denoising作为预训练目标在文本生成、翻译与理解任务上均表现出色。本指南以 decoding/IAD/fairseq/examples/bart/README.md 为核心结合本仓库unilm/IAD中 fairseq 源码级的 BART 实现系统讲解 BART 的模型架构、预训练范式、预训练权重加载、特征提取、掩码填充、句子对分类、以及 GLUE 与 CNN-DM 摘要任务的微调全流程。读完本文你将掌握如何在本仓库的 fairseq 环境中完成 BART 的加载、推理、评估与微调并理解其底层实现原理。一、BART 是什么去噪自编码器式的预训练目标BARTBidirectional and Auto-Regressive Transformer是一个标准的序列到序列 Transformer 模型其核心创新在于预训练目标对文本施加多种噪声扰动如 token 掩码、删除、打乱顺序、旋转等再训练模型将损坏的文本还原为原始文本。这种去噪自编码器式目标比单纯的 MLM掩码语言模型如 BERT或自回归 LM如 GPT更为通用。官方 README 指出使用该预训练目标后BART 在SQuAD 与 GLUE上可以匹配 RoBERTa 的表现并在摘要XSum、CNN 数据集、长文本生成式问答ELI5和对话响应生成ConvAI2任务上取得当时的 state-of-the-art 结果。在本仓库中BART 还被用作了实际业务落地的基座decoding/IAD/README.md介绍的Input-guided Aggressive DecodingIAD输入引导的激进解码即采用了122 BART-Init架构12 层编码器 2 层解码器的 BART 初始化模型用于语法纠错GEC任务在 CoNLL-14 与 BEA-19 上取得了 P/R/F0.5 分别为 71.0/52.8/66.4 与 74.7/66.4/72.9beam1的成绩并带来约 9.6x10.3x 的推理加速。这说明 BART 不仅是理论研究模型也是本仓库解码加速方案的重要组件。二、预训练模型列表与关键差异官方发布了一系列预训练权重下表完整收录自 README 模型描述参数量下载bart.base6 层编码器 6 层解码器140Mbart.base.tar.gzbart.large12 层编码器 12 层解码器400Mbart.large.tar.gzbart.large.mnlibart.large在MNLI上微调400Mbart.large.mnli.tar.gzbart.large.cnnbart.large在CNN-DM上微调400Mbart.large.cnn.tar.gzbart.large.xsumbart.large在Xsum上微调400Mbart.large.xsum.tar.gz从源码看架构差异在 model.py 中两种架构的差异被完整定义bart_largeencoder_embed_dim1024、encoder_ffn_embed_dim4*1024、12 层编码器与解码器、16 个注意力头、max_source_positions/max_target_positions1024、激活函数gelu、启用layernorm_embedding与share_all_embeddings默认dropout0.1bart_base仅将encoder_embed_dim降为 768、层数降为 6、注意力头降为 12其余继承 large 的配置。同时模型遵循 BERT 的随机初始化方案self.apply(init_bert_params)并使用绝对位置嵌入encoder_learned_posTrue。值得注意的是bart.large在微调进翻译任务时会自动删除词表中对应masktoken 的嵌入行相关逻辑见 model.py。三、快速上手加载 BART 模型3.1 通过 torch.hub 加载PyTorch 1.1import torch bart torch.hub.load(pytorch/fairseq, bart.large) bart.eval() # 关闭 dropout训练模式可保留以进行微调3.2 手动下载权重后加载适用于 PyTorch 1.0 或自定义模型wget https://dl.fbaipublicfiles.com/fairseq/models/bart.large.tar.gz tar -xzvf bart.large.tar.gzfrom fairseq.models.bart import BARTModel bart BARTModel.from_pretrained(/path/to/bart.large, checkpoint_filemodel.pt) bart.eval()从源码看BARTModel.from_pretrained 最终会调用fairseq.hub_utils.from_pretrained并通过 BARTHubInterface 对外提供统一的编码、解码、生成与预测接口预训练权重映射表hub_models()同时被 torch.hub 与from_pretrained使用见 model.py。3.3 BPE 编码与解码BART 使用 GPT-2 的 BPE 编码每条输入序列以s开头、/s结尾tokens bart.encode(Hello world!) assert tokens.tolist() [0, 31414, 232, 328, 2] bart.decode(tokens) # Hello world!源码 hub_interface.py 揭示了一个易踩坑的细节GPT-2 BPE 要求单词前有空格。例如bart.encode(Hello world)得到[0, 31414, 232, 2]而bart.encode(world)得到[0, 8331, 2]由于缺少前导空格分词结果完全不同。多句输入时每增加一个句子会追加/s分隔符例如句子对编码为s d e f /s 1 2 3 /s的形式。四、特征提取与分类头把 BART 当作编码器使用4.1 提取特征# 提取最后一层特征 last_layer_features bart.extract_features(tokens) assert last_layer_features.size() torch.Size([1, 5, 1024]) # 提取解码器所有层特征第 0 层为嵌入层 all_layers bart.extract_features(tokens, return_all_hiddensTrue) assert len(all_layers) 13 assert torch.all(all_layers[-1] last_layer_features)extract_features的实现位于 hub_interface.py它通过右移一位 首位置为最后一个非 pad token的方式构造prev_output_tokens以前缀式解码一次性得到解码器各层T x B x C转置为B x T x C的隐藏状态。4.2 句子对分类以 MNLI 为例# 加载已在 MNLI 上微调好的 BART bart torch.hub.load(pytorch/fairseq, bart.large.mnli) bart.eval() tokens bart.encode(BART is a seq2seq model., BART is not sequence to sequence.) bart.predict(mnli, tokens).argmax() # 0: contradiction矛盾 tokens bart.encode(BART is denoising autoencoder., BART is version of autoencoder.) bart.predict(mnli, tokens).argmax() # 2: entailment蕴含4.3 注册一个新的随机初始化的分类头bart.register_classification_head(new_task, num_classes3) logprobs bart.predict(new_task, tokens)从源码看分类头对应 BARTClassificationHead结构为Dense - 激活函数(tanh) - Dropout - OutProj并支持可选的谱归一化--spectral-norm-classification-head。句级表征取自最后一个eos位置的隐藏状态见 hub_interface.py 与 model.py。若 checkpoint 中带有新分类头且设置了load_checkpoint_headsTruefrom_pretrained会自动恢复否则会删除状态字典中与当前模型维度不匹配的分类头见 model.py。4.4 批量预测import torch from fairseq.data.data_utils import collate_tokens bart torch.hub.load(pytorch/fairseq, bart.large.mnli) bart.eval() batch_of_pairs [ [BART is a seq2seq model., BART is not sequence to sequence.], [BART is denoising autoencoder., BART is version of autoencoder.], ] batch collate_tokens( [bart.encode(pair[0], pair[1]) for pair in batch_of_pairs], pad_idx1 ) logprobs bart.predict(mnli, batch) print(logprobs.argmax(dim1)) # tensor([0, 2])4.5 使用 GPUbart.cuda() bart.predict(new_task, tokens)五、掩码填充Fill MaskBART 的多 token 生成能力BART 可以一次性填充输入中的多个masktoken这是它与 BERT只能预测单个[MASK]的本质区别bart torch.hub.load(pytorch/fairseq, bart.base) bart.eval() bart.fill_mask([The cat mask on the mask.], topk3, beam10) # [[(The cat was on the ground., tensor(-0.6183)), (The cat was on the floor., tensor(-0.6798)), (The cat sleeps on the couch., tensor(-0.6830))]]默认情况下模型会强制生成结果与输入长度一致可通过match_source_lenFalse关闭bart.fill_mask([The cat mask on the mask.], topk3, beam10, match_source_lenFalse) # [[(The cat was on the ground., tensor(-0.6185)), (The cat was asleep on the couch., tensor(-0.6276)), (The cat was on the floor., tensor(-0.6800))]]GPU 批量掩码填充示例bart.cuda() bart.fill_mask([The cat mask on the mask., The dog mask on the mask.], topk3, beam10) # [[(The cat was on the ground., ...), (The cat was on the floor., ...), (The cat sleeps on the couch., ...)], # [(The dog was on the ground., ...), (The dog lay on the ground., ...), (The dog was asleep on the couch, ...)]]底层实现见 fill_mask它要求输入中必须包含masktoken将句子按mask切分为片段后分别做 BPE并保证beam 大小不小于 topkbeam max(topk, beam)最终返回(解码文本, 得分)的列表。六、去噪预训练任务噪声从何而来BART 预训练阶段的去噪由 fairseq 的denoising任务实现其参数解析在 denoising.py 中可在预训练脚本中通过命令行覆盖构成完整的噪声工具箱参数默认值作用--mask0.0被掩码的词/子词比例--mask-random0.0不用mask而替换为随机 token 的比例--insert0.0额外插入随机 token 的百分比--permute0.0打乱该比例的子词顺序--rotate0.5旋转该比例的输入--poisson-lambda3.0泊松分布的 lambda用于 span 掩码长度采样--permute-sentences0.0打乱该比例的句子顺序--mask-lengthsubword掩码粒度subword/word/span-poisson--replace-length-1掩码 N 个 token 时替换为 0、1 或 N 个 token-1 表示 N--tokens-per-sample512每个样本的最大 token 数--sample-break-modecomplete_doc句子切分模式--max-source-positions/--max-target-positions1024源/目标序列最大长度任务初始化时会向词典追加mask符号self.mask_idx self.dictionary.add_symbol(mask)见 denoising.py数据管线则按去尾 EOS → 连续 token 分块 → 前插s→ 后补/s→ 套用DenoisingDataset的流程构造样本见 denoising.py。mask相关逻辑正是上一节fill_mask能工作的前提。七、评估预训练模型7.1 评估bart.large.mnliMNLI dev_matched 集label_map {0: contradiction, 1: neutral, 2: entailment} ncorrect, nsamples 0, 0 bart.cuda() bart.eval() with open(glue_data/MNLI/dev_matched.tsv) as fin: fin.readline() for index, line in enumerate(fin): tokens line.strip().split(\t) sent1, sent2, target tokens[8], tokens[9], tokens[-1] tokens bart.encode(sent1, sent2) prediction bart.predict(mnli, tokens).argmax().item() prediction_label label_map[prediction] ncorrect int(prediction_label target) nsamples 1 print(| Accuracy: , float(ncorrect)/float(nsamples)) # 预期输出: 0.90107.2 评估bart.large.cnnCNN-DM 摘要首先将 CNN-DM 数据预处理为test.source与test.target每行一个未分词的样本然后bart torch.hub.load(pytorch/fairseq, bart.large.cnn) bart.cuda() bart.eval() bart.half() count 1 bsz 32 with open(test.source) as source, open(test.hypo, w) as fout: sline source.readline().strip() slines [sline] for sline in source: if count % bsz 0: with torch.no_grad(): hypotheses_batch bart.sample(slines, beam4, lenpen2.0, max_len_b140, min_len55, no_repeat_ngram_size3) for hypothesis in hypotheses_batch: fout.write(hypothesis \n) fout.flush() slines [] slines.append(sline.strip()) count 1 if slines ! []: hypotheses_batch bart.sample(slines, beam4, lenpen2.0, max_len_b140, min_len55, no_repeat_ngram_size3) for hypothesis in hypotheses_batch: fout.write(hypothesis \n) fout.flush()然后使用files2rouge计算 ROUGE 分数先用 Stanford PTB Tokenizer 对假设与参考分别做分词export CLASSPATH/path/to/stanford-corenlp-full-2016-10-31/stanford-corenlp-3.7.0.jar # 对 hypothesis 和 target 文件分词 cat test.hypo | java edu.stanford.nlp.process.PTBTokenizer -ioFileList -preserveLines test.hypo.tokenized cat test.target | java edu.stanford.nlp.process.PTBTokenizer -ioFileList -preserveLines test.hypo.target files2rouge test.hypo.tokenized test.hypo.target # 预期输出: (ROUGE-2 Average_F: 0.21238)八、BART 在 GLUE 上的微调实战8.1 数据准备wget https://gist.githubusercontent.com/W4ngatang/60c2bdb54d156a41194446737ce03e2e/raw/17b8dd0d724281ed7c3b2aeeda662b92809aadd5/download_glue_data.py python download_glue_data.py --data_dir glue_data --tasks all8.2 数据预处理与 RoBERTa 相同./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可一次性预处理全部任务。该脚本与 BPE 编码器multiprocessing_bpe_encoder.py均位于本仓库 examples/roberta 目录下可直接复用。8.3 微调命令以 RTE 为例TOTAL_NUM_UPDATES2036 # RTE 数据集 bsz16 下 10 个 epoch WARMUP_UPDATES61 # 更新总数的 6% LR1e-05 # 多项式学习率调度器的峰值 LR NUM_CLASSES2 MAX_SENTENCES16 # 批大小 BART_PATH/path/to/bart/model.pt CUDA_VISIBLE_DEVICES0,1 fairseq-train RTE-bin/ \ --restore-file $BART_PATH \ --batch-size $MAX_SENTENCES \ --max-tokens 4400 \ --task sentence_prediction \ --add-prev-output-tokens \ --layernorm-embedding \ --share-all-embeddings \ --share-decoder-input-output-embed \ --reset-optimizer --reset-dataloader --reset-meters \ --required-batch-size-multiple 1 \ --init-token 0 \ --arch bart_large \ --criterion sentence_prediction \ --num-classes $NUM_CLASSES \ --dropout 0.1 --attention-dropout 0.1 \ --weight-decay 0.01 --optimizer adam --adam-betas (0.9, 0.98) --adam-eps 1e-08 \ --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;8.4 各 GLUE 任务的推荐超参数各任务需要不同的--num-classes、--lr、--batch-size、--total-num-update与--warmup-updates模型参数MNLIQNLIQQPRTESST-2MRPCCoLASTS-B--num-classes32222221--lr5e-61e-51e-51e-55e-62e-52e-52e-5bsz128323232128646432--total-num-update309683311211327210185233114813341799--warmup-updates185819866796613146880107针对STS-B回归任务需额外添加--regression-target --best-checkpoint-metric loss并移除--maximize-best-checkpoint-metric。注意事项 a)--total-num-updates供polynomial_decay调度器使用按--max-epoch10与--batch-size32/64/128视任务而定计算 b) 上述参数在 NvidiaV100 32GBGPU 上验证通过显存不足时可提高--update-freq并降低--batch-size。8.5 GLUE 推理from fairseq.models.bart import BARTModel bart BARTModel.from_pretrained( checkpoints/, checkpoint_filecheckpoint_best.pt, data_name_or_pathRTE-bin ) label_fn lambda label: bart.task.label_dictionary.string( [label bart.task.label_dictionary.nspecial] ) ncorrect, nsamples 0, 0 bart.cuda() bart.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 bart.encode(sent1, sent2) prediction bart.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))九、BART 在 CNN-DM 摘要任务上的微调实战9.1 数据下载与预处理CNN/Daily Mail 原始数据及 XSum 数据按官方说明下载并整理为每行一个未分词、未做 BPE 的样本。9.2 BPE 预处理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 TASKcnn_dm for SPLIT in train val do for LANG in source target do python -m examples.roberta.multiprocessing_bpe_encoder \ --encoder-json encoder.json \ --vocab-bpe vocab.bpe \ --inputs $TASK/$SPLIT.$LANG \ --outputs $TASK/$SPLIT.bpe.$LANG \ --workers 60 \ --keep-empty; done done9.3 二值化binarize数据集fairseq-preprocess \ --source-lang source \ --target-lang target \ --trainpref ${TASK}/train.bpe \ --validpref ${TASK}/val.bpe \ --destdir ${TASK}-bin/ \ --workers 60 \ --srcdict dict.txt \ --tgtdict dict.txt;9.4 CNN-DM 微调命令TOTAL_NUM_UPDATES20000 WARMUP_UPDATES500 LR3e-05 MAX_TOKENS2048 UPDATE_FREQ4 BART_PATH/path/to/bart/model.pt CUDA_VISIBLE_DEVICES0,1,2,3,4,5,6,7 fairseq-train cnn_dm-bin \ --restore-file $BART_PATH \ --max-tokens $MAX_TOKENS \ --task translation \ --source-lang source --target-lang target \ --truncate-source \ --layernorm-embedding \ --share-all-embeddings \ --share-decoder-input-output-embed \ --reset-optimizer --reset-dataloader --reset-meters \ --required-batch-size-multiple 1 \ --arch bart_large \ --criterion label_smoothed_cross_entropy \ --label-smoothing 0.1 \ --dropout 0.1 --attention-dropout 0.1 \ --weight-decay 0.01 --optimizer adam --adam-betas (0.9, 0.999) --adam-eps 1e-08 \ --clip-norm 0.1 \ --lr-scheduler polynomial_decay --lr $LR --total-num-update $TOTAL_NUM_UPDATES --warmup-updates $WARMUP_UPDATES \ --fp16 --update-freq $UPDATE_FREQ \ --skip-invalid-size-inputs-valid-test \ --find-unused-parameters;以上命令预期在1 个节点、8 张 32GB V100上运行训练时间约5 小时改用 4 节点分布式训练并设--update-freq 1可进一步缩短。XSum 任务使用TOTAL_NUM_UPDATES15000、UPDATE_FREQ2。9.5 摘要推理与参数差异import torch from fairseq.models.bart import BARTModel bart BARTModel.from_pretrained( checkpoints/, checkpoint_filecheckpoint_best.pt, data_name_or_pathcnn_dm-bin ) bart.cuda() bart.eval() bart.half() count 1 bsz 32 with open(cnn_dm/test.source) as source, open(cnn_dm/test.hypo, w) as fout: sline source.readline().strip() slines [sline] for sline in source: if count % bsz 0: with torch.no_grad(): hypotheses_batch bart.sample(slines, beam4, lenpen2.0, max_len_b140, min_len55, no_repeat_ngram_size3) for hypothesis in hypotheses_batch: fout.write(hypothesis \n) fout.flush() slines [] slines.append(sline.strip()) count 1 if slines ! []: hypotheses_batch bart.sample(slines, beam4, lenpen2.0, max_len_b140, min_len55, no_repeat_ngram_size3) for hypothesis in hypotheses_batch: fout.write(hypothesis \n) fout.flush()XSum 生成请改用beam6, lenpen1.0, max_len_b60, min_len10——不同数据集的摘要长度分布不同解码参数需相应调整。十、官方基准结果以下是 README 收录的官方评估数据均来自原论文与官方复现用于横向参考GLUEdev 集单模型、单任务微调模型MNLIQNLIQQPRTESST-2MRPCCoLASTS-Broberta.large90.294.792.286.696.490.968.092.4bart.large89.994.992.587.096.690.462.891.2SQuADdev 集未使用额外数据模型SQuAD 1.1 EM/F1SQuAD 2.0 EM/F1roberta.large88.9/94.686.5/89.4bart.large88.8/94.686.1/89.2CNN/Daily Mailtest 集未使用额外数据模型R1R2RLBERTSUMEXTABS42.1319.6039.18bart.large44.1621.2840.90十一、与本仓库 IAD 解码加速的衔接回到本仓库的主题decoding/IAD项目在语法纠错任务中直接以 BART 权重初始化模型并在此基础上实现了输入引导的激进解码IAD。其推理入口 inference.py 提供了三种解码模式可通过--batch、--baseline、--aggressive开关切换其中paper_aggressive_generateinference.py利用 BART 解码器的增量状态incremental state与源文本 n-gram 哈希匹配construct_hash_sets/find_hash_sets见 inference.py在生成过程中当预测片段与源文一致时直接跳跃式复制源 token从而避免逐 token 解码显著提升在线推理速度。这也解释了为何理解 BART 的解码器结构与 fairseq 增量解码机制是使用本仓库 IAD 能力的前提。十二、引用如果本文帮助你完成了相关工作请引用 BART 原始论文article{lewis2019bart, title {BART: Denoising Sequence-to-Sequence Pre-training for Natural Language Generation, Translation, and Comprehension}, author {Mike Lewis and Yinhan Liu and Naman Goyal and Marjan Ghazvininejad and Abdelrahman Mohamed and Omer Levy and Veselin Stoyanov and Luke Zettlemoyer }, journal{arXiv preprint arXiv:1910.13461}, year {2019}, }延伸阅读本仓库内GLUE 微调完整文档见 README.glue.mdCNN-DM/XSum 摘要微调完整文档见 README.summarization.mdBART 模型核心实现见 fairseq/models/bart/model.pyHub 推理接口见 fairseq/models/bart/hub_interface.py去噪预训练任务见 fairseq/tasks/denoising.py。【免费下载链接】unilmLarge-scale Self-supervised Pre-training Across Tasks, Languages, and Modalities项目地址: https://gitcode.com/GitHub_Trending/un/unilm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询