news 2026/9/26 10:14:07

PaddleNLP 中 RemBERT 多语言模型的原理与 XTREME 任务微调实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PaddleNLP 中 RemBERT 多语言模型的原理与 XTREME 任务微调实战
  • 人工智能
  • 大模型
  • 预训练
  • 微调
  • LoRA
  • RLHF
  • 强化学习
  • 分布式训练

【免费下载链接】PaddleNLP

Easy-to-use and powerful LLM and SLM library with awesome model zoo.

项目地址:https://gitcode.com/gh_mirrors/pa/PaddleNLP
点击查看免费下载

RemBERT(Rethinking embedding coupling in pre-trained language models)是 Google Research 提出的一类基于"解耦词嵌入"思想的多语言预训练模型,其论文发表于 arXiv 2010.12821。本文以 RemBERT 使用文档 为主体,结合 PaddleNLP 仓库中 RemBERT 的模型实现(modeling.py)、配置(configuration.py)、分词器(tokenizer.py)以及 XTREME 微调示例(slm/model_zoo/rembert),系统讲解 RemBERT 的核心设计动机,并给出在 XTREME-XNLI 与 XTREME-PAWS-X 两个多语言下游任务上完整可复现的训练、评估流程。读完本文,你将掌握:RemBERT 架构与标准 BERT 式模型的差异、PaddleNLP 中 RemBERT 的源码级结构,以及如何用一条命令完成多语言文本分类模型的微调与精度复现。

RemBERT 核心思想:解耦词嵌入带来的参数效率

标准预训练语言模型通常让输入词嵌入与输出词嵌入共享同一份参数(即"词嵌入耦合")。RemBERT 的作者指出,分离词嵌入为语言模型建模提供了更好的灵活性,能够显著提高多语言模型中输入词嵌入参数的分配效率。具体来说,通过把原本"喂"给输入词嵌入的部分参数重新分配进 Transformer 编码器层,在参数量完全相同的情况下,RemBERT 在多语言自然语言理解任务上取得了优于同规模模型的性能。

文档还总结了作者的两个关键发现:

  • 增大输出词嵌入维度可以提升模型性能:即使预训练结束后输出词嵌入被丢弃,这一收益在微调阶段依然能够保持;
  • 更大的输出词嵌入具有正则化效果:可以防止模型在预训练数据集上过拟合,并增强模型在其他 NLP 数据集上的泛化能力。

这两点带来的实际收益是:可以训练出性能更强的模型,而无需在微调阶段增加任何参数。这正是"解耦嵌入"在参数效率上的核心价值——把参数花在真正影响建模能力的地方。

PaddleNLP 中的 RemBERT:配置与源码结构解读

预训练模型配置一览

PaddleNLP 通过RemBertConfig与REMBERT_PRETRAINED_INIT_CONFIGURATION定义了官方rembert预训练模型的全部超参数(见 configuration.py):

配置项取值说明
vocab_size250300词表大小(SentencePiece 词表)
input_embedding_size256输入嵌入维度(核心特征,远小于 hidden_size)
hidden_size1152编码器隐藏层维度
num_hidden_layers32Transformer 编码器层数
num_attention_heads18每层注意力头数
intermediate_size4608FFN 中间层维度(4 × hidden_size)
hidden_actgeluFFN 激活函数
hidden_dropout_prob0全连接层 dropout 概率
attention_probs_dropout_prob0注意力概率 dropout
max_position_embeddings512最大序列长度
type_vocab_size2token_type 数量(句子 A/B)
initializer_range0.02参数初始化标准差
pad_token_id0padding token 的 id
layer_norm_eps1e-12LayerNorm epsilon

注意到一个关键细节:input_embedding_size = 256远小于hidden_size = 1152。这正是 RemBERT "参数重新分配"思想的直接体现——输入嵌入只保留较小的维度,省下的参数被分配到更深更宽的 Transformer 编码器中。

网络结构源码解读

RemBERT 的模型主体定义在 paddlenlp/transformers/rembert/modeling.py,整体结构与 BERT 式模型一致,但嵌入层有本质区别:

  1. RemBertEmbeddings(modeling.py#L64-L103):词嵌入、位置嵌入、token_type 嵌入的维度均为config.input_embedding_size(256),而非hidden_size;
  2. 维度映射层:RemBertEncoder在进入 32 层 Transformer 之前,先用一个nn.Linear(config.input_embedding_size, config.hidden_size)的embedding_hidden_mapping_in将 256 维映射到 1152 维(modeling.py#L256-L260);
  3. 标准编码器:随后是 32 层由自注意力(query/key/value 线性层 + softmax + dropout)、FFN(gelu 激活)与残差连接 + LayerNorm 构成的RemBertLayer;
  4. Pooler:取序列首 token([CLS])的隐藏状态,经过一层 Linear + Tanh 得到池化输出(modeling.py#L106-L118)。

围绕RemBertModel基座,仓库提供了 5 种下游任务头(全部定义在 modeling.py 的__all__中):

  • RemBertForSequenceClassification:文本分类(本文微调示例所用),在[CLS]池化输出上加 dropout 与Linear(hidden_size, num_classes);
  • RemBertForQuestionAnswering:阅读理解,输出 span 的 start/end logits;
  • RemBertForMaskedLM:掩码语言模型;
  • RemBertForTokenClassification:序列标注(如 NER);
  • RemBertForMultipleChoice:多选题型分类。

此外,RemBertLMPredictionHead的 decoder 被实现为Linear(config.hidden_size, config.hidden_size)(modeling.py#L527-L548),即 LM 预测头不再与输入嵌入矩阵共享权重,从源码层面印证了"解耦嵌入"的设计理念。

分词器

RemBertTokenizer(tokenizer.py)基于SentencePiece(词表文件sentencepiece.model),do_lower_case=False,特殊 token 为[CLS]、[UNK]、[SEP]、[PAD]、[MASK],最大输入长度 512。句子对编码格式为[CLS] A [SEP] B [SEP],句子 A 的 token_type 为 0、句子 B 为 1。该分词器对应的测试用例位于 tests/transformers/rembert/test_tokenizer.py。

快速开始:自动下载模型与分词器

在运行微调脚本前,需要先安装 PaddlePaddle 与 PaddleNLP。PaddleNLP 的from_pretrained("rembert")会自动完成预训练权重与分词器资源的下载:

  • 模型权重:model_state.pdparams,资源地址配置在 configuration.py#L44-L48 的REMBERT_PRETRAINED_RESOURCE_FILES_MAP中;
  • 分词器:sentencepiece.model,资源地址配置在 tokenizer.py#L74-L79。

可以先用下面这段代码快速验证模型能否正确加载并前向推理(源自 modeling.py 中的使用示例):

import paddle from paddlenlp.transformers import RemBertModel, RemBertTokenizer tokenizer = RemBertTokenizer.from_pretrained("rembert") model = RemBertModel.from_pretrained("rembert") inputs = tokenizer("欢迎使用百度飞桨!") inputs = {k: paddle.to_tensor([v]) for (k, v) in inputs.items()} output = model(**inputs)

数据集准备:XTREME-XNLI 与 XTREME-PAWS-X

RemBERT 微调示例使用 XTREME 基准中的两个多语言自然语言理解任务,数据文件的读取逻辑由 data_processor.py 中的XNLIProcessor与MrpcProcessor实现。

XTREME-XNLI

  • 训练集:来自XNLI-MT-1.0.zip,解压后位于XNLI-MT-1.0/multinli/multinli.train.en.tsv;
  • 测试集:来自XNLI-1.0.zip,文件为xnli.test.tsv。

对应到代码中(data_processor.py#L75-L112),XNLIProcessor的训练、验证、测试文件分别为multinli.train.en.tsv、xnli.dev.tsv、xnli.test.tsv,标签空间为["neutral", "entailment", "contradictory"](共 3 类)。训练样本从 tsv 的第 1、2 列读取句子对、第 3 列读取标签;测试样本从第 7、8 列读取句子对、第 2 列读取标签(并将contradiction统一映射为contradictory)。

XTREME-PAWS-X

  • 解压后每种语言包含train、dev、test开头的 tsv 文件;
  • 由于该任务需要在多语言上进行测试,请将全部语言的测试集合并到一个文件。

对应到代码中(data_processor.py#L37-L62),MrpcProcessor读取的合并后文件为train.tsv(训练)、dev_2k.tsv(验证)、test_2k.tsv(测试),标签为二分类["0", "1"]。

两个数据处理器都会使用RemBertTokenizer将文本逐条 token 化,并交由 main.py 中的DataGenerator封装成 PaddleDataset。

下游任务微调:XTREME-XNLI

在slm/model_zoo/rembert目录下,以 XTREME-XNLI 为例,运行以下命令即可训练并评估 RemBert 在 XNLI 数据集上的精度(文档原文命令中--device gpu一行缺少续行符,此处已修正):

python -m paddle.distributed.launch main.py \ --model_type rembert \ --data_dir data/ \ --output_dir output/ \ --device gpu \ --learning_rate 1e-5 \ --num_train_epochs 3 \ --train_batch_size 16 \ --do_train \ --do_eval \ --task xnli \ --eval_step 500

说明:README 中给出的示例路径为examples/language_model/rembert/main.py,在本仓库中的实际位置为 slm/model_zoo/rembert/main.py,运行时请以实际路径为准。

训练过程中会周期性地在测试集上评估模型,并保存当前最优精度对应的 checkpoint。训练结束后将看到如下结果:

Accuracy 0.8089

XTREME-XNLI 数据集内部处理细节

从 main.py 的load_example与collate_fn可以看到数据流水线的关键步骤:

  • 根据--task选择处理器:xnli→XNLIProcessor,paws→MrpcProcessor;
  • 训练集使用DistributedBatchSampler(按--train_batch_size分片、shuffle),验证/测试集使用普通DataLoader(按--eval_batch_size);
  • collate_fn将 batch 内文本按最长序列动态 padding:句子 A 的 token_type 补 0,句子 B 补 1;
  • 拼接text_a与text_b后统一截断到--max_seq_length(默认 512);
  • 每个 epoch 的步数按len(dataloader) // gradient_accumulation_steps计算(main.py#L144)。

下游任务微调:XTREME-PAWS-X

在 PAWS-X 数据集上训练使用如下命令(学习率改为 8e-6,任务切换为paws):

python -m paddle.distributed.launch main.py \ --model_type rembert \ --data_dir data/ \ --output_dir output/ \ --device gpu \ --learning_rate 8e-6 \ --num_train_epochs 3 \ --train_batch_size 16 \ --do_train \ --do_eval \ --task paws \ --eval_step 500

训练结束后模型会在测试集上完成评估,你将看到如下结果:

Accuracy 0.8778

命令行参数详解

以下参数定义均可从 main.py#L32-L73 的 argparse 中逐一对应:

参数说明默认值
model_type预训练模型类型,当前支持rembertrembert
data_dir数据集路径(包含上述 tsv 文件)无(需指定)
task训练任务:xnli或paws无(必填)
output_dir模型预测结果与 checkpoint 保存路径outputs
device设备类型,脚本支持cpu、gpu(README 亦提及 XPU 场景,当前脚本的 choices 限定为 cpu/gpu)gpu
learning_rate基础学习率,与 scheduler 输出相乘得到实际学习率(XNLI 用 1e-5,PAWS-X 用 8e-6)8e-6
num_train_epochs训练 epoch 数3
train_batch_size每次迭代每张卡上的样本数目16
eval_batch_size评估时每张卡上的 batch size16
max_seq_lengthtoken 化后输入最大长度,超长截断、不足 padding512
gradient_accumulation_steps梯度累积步数(loss 会除以该值再反传)2
warmup_proportion线性学习率 warmup 所占训练步数比例0.02
weight_decayAdamW 权重衰减系数0.01
seed随机种子(同时设置 paddle / random / numpy)42
eval_step每训练多少步在测试集上评估一次模型2000
do_train是否开启训练关闭
do_eval是否开启评估(加载output_dir中模型在测试集评估)关闭

其中两点值得注意:

  • 多 GPU 训练:--device gpu配合python -m paddle.distributed.launch即可分布式启动;main.py#L140-L142 中当nranks > 1时会初始化并行环境并用paddle.DataParallel包装模型;可通过环境变量CUDA_VISIBLE_DEVICES指定使用的 GPU id;
  • 类数自动推导:RemBertForSequenceClassification.from_pretrained(args.model_type, num_classes=num_label)中的num_label取自processor.get_labels()的长度(XNLI 为 3,PAWS-X 为 2),无需手动指定。

训练器源码视角:优化器、混合精度与评估逻辑

微调脚本的训练逻辑封装在 trainer.py,几个关键实现细节如下:

  • 优化器:AdamW,beta1=0.9、beta2=0.99,梯度裁剪ClipGradByNorm(clip_norm=1.0);权重衰减只作用于非 bias、非 LayerNorm 的参数(trainer.py#L85-L99);
  • 学习率调度:LinearDecayWithWarmup(线性 warmup + 线性衰减),warmup 比例默认 0.02;
  • 混合精度:paddle.amp.decorate(level="O2")开启 AMP O2 训练,配合GradScaler(init_loss_scaling=1024)与paddle.amp.auto_cast完成前向与梯度缩放(trainer.py#L47-L66);
  • 评估与保存策略:每eval_step步在测试集上计算一次Accuracy,只有当精度超过历史最优值时才model.save_pretrained(output_dir)保存模型,训练结束时output_dir中保留的即是最优 checkpoint(trainer.py#L71-L77)。

参考资料

RemBERT 原论文的 BibTeX 引用如下(源自 README 的 Reference 部分):

@article{chung2020rethinking, title={Rethinking embedding coupling in pre-trained language models}, author={Chung, Hyung Won and Fevry, Thibault and Tsai, Henry and Johnson, Melvin and Ruder, Sebastian}, journal={arXiv preprint arXiv:2010.12821}, year={2020} }

如需进一步深入,可以继续阅读仓库中的以下文件:微调入口 main.py、数据与分词处理 data_processor.py、训练器 trainer.py、模型实现 modeling.py、配置 configuration.py、分词器 tokenizer.py 以及分词器测试 test_tokenizer.py。

  • 人工智能
  • 大模型
  • 预训练
  • 微调
  • LoRA
  • RLHF
  • 强化学习
  • 分布式训练

【免费下载链接】PaddleNLP

Easy-to-use and powerful LLM and SLM library with awesome model zoo.

项目地址:https://gitcode.com/gh_mirrors/pa/PaddleNLP
点击查看免费下载

相关推荐

上一篇:3步打造专业音效:Equalizer APO免费调音全指南
下一篇:如何在ComfyUI中部署Florence2?从安装到运行的5分钟快速入门

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 10:12:00

RANSAC之opencv和C++实现:TaoToken统一Key接入与config.toml骨架

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 10:09:25

Java 开发里的埋点是什么

目录 埋点采集什么信息 Java 里常见的埋点实现方式 1. 代码硬编码埋点(最基础) 2. AOP 切面埋点(Java 项目最常用!) 3. 中间件 / 异步埋点 4. 字节码埋点(探针,如 SkyWalking)…

作者头像 李华