PaddleNLP 单塔文本匹配实战:基于 ERNIE-Gram 的 Point-wise 与 Pair-wise 训练范式
人工智能大模型预训练微调LoRARLHF强化学习分布式训练【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址https://gitcode.com/gh_mirrors/pa/PaddleNLP点击查看免费下载本文是 PaddleNLP 仓库中slm/examples/text_matching/ernie_matching示例的完整技术指南讲解如何基于预训练模型 ERNIE-Gram 搭建单塔Siamese/Unified文本匹配模型覆盖 Point-wise逐样本二分类与 Pair-wise样本对排序两种训练范式。读完本文你将掌握单塔匹配模型的数据组织、组网结构、训练调参与评估指标选择并能完成从动态图训练、预测到静态图导出的完整落地链路。一、单塔文本匹配与两种训练范式概述文本匹配Text Matching是自然语言理解中的基础任务常见于语义相似度判断、检索排序、FAQ 问答等场景。本示例采用单塔结构将一对文本query与title拼接后送入同一个预训练模型编码再基于[CLS]位置的句级向量完成分类或打分。与双塔结构相比单塔模型能够充分利用两个文本之间的交叉注意力信息匹配精度通常更高但推理时需要将文本对拼接输入适合候选集较小的场景。项目提供了两种训练范式分别适配不同业务需求范式模型结构损失函数输出适用场景Point-wise预训练模型 Dropout 2 分类线性层交叉熵CrossEntropyLoss相似 / 不相似二分类概率直接判断两个文本是否语义相似Pair-wise预训练模型 Dropout 打分线性层Margin Ranking Loss文本对相似度打分0~1将相似度作为特征喂给上层排序模块完整代码位于 slm/examples/text_matching/ernie_matching 目录核心文件包括ernie_matching/ ├── deploy/ │ └── python/ │ └── predict.py # 静态图 Python 预测部署示例 ├── export_model.py # 动态图参数导出静态图参数脚本 ├── model.py # Point-wise Pair-wise 匹配模型组网 ├── data.py # 训练样本转换逻辑、Pair-wise 随机负例生成逻辑 ├── train_pointwise.py # Point-wise 单塔匹配模型训练脚本 ├── train_pairwise.py # Pair-wise 单塔匹配模型训练脚本 ├── predict_pointwise.py # Point-wise 预测脚本输出 0/1 相似性标签 └── predict_pairwise.py # Pair-wise 预测脚本输出相似度打分二、模型下载开箱即用的 Point-wise 中文语义匹配模型项目使用中文语义匹配公开数据集 LCQMC 作为训练集基于 ERNIE 系列预训练模型热启训练并开源了单塔 Point-wise 语义匹配模型可直接用于文本对语义匹配二分类任务模型dev accERNIE-1.0-Base Point-wise 匹配模型89.43ERNIE-Gram-Base Point-wise 匹配模型90.60下载模型后将其作为--params_path传入 predict_pointwise.py 即可直接做二分类预测无需自行训练。三、数据组织与样本转换3.1 LCQMC 数据集训练与评估使用paddlenlp.datasets.load_dataset(lcqmc, ...)加载。数据集读取逻辑定义在 paddlenlp/datasets/lcqmc.py提供train、dev、test三个切分train.tsv / dev.tsv / test.tsv每条样本由query、title、label三列组成label 为 0不相似或 1相似。3.2 文本对读取与转换data.py 中定义了三条关键逻辑read_text_pair(data_path)读取预测用的 TSV 文件两列query、title按\t切分跳过格式异常行以字典形式逐行产出{query: ..., title: ...}。convert_pointwise_example(example, tokenizer, max_seq_length512, is_testFalse)将query与title通过tokenizer(textquery, text_pairtitle, max_seq_lenmax_seq_length)编码为input_ids、token_type_ids训练/评估时额外返回label预测时is_testTrue只返回两个 id 序列。convert_pairwise_example(example, tokenizer, max_seq_length512, phasetrain)训练阶段分别对(query, pos_title)与(query, neg_title)编码返回正负两组input_ids与token_type_ids评估与预测阶段则与 Point-wise 类似返回单对文本的编码结果评估额外带 label。数据加载统一由create_dataloader完成训练模式使用paddle.io.DistributedBatchSampler支持分布式采样其他模式使用paddle.io.BatchSampler样本先经dataset.map(trans_fn)转换再经collate_fnpaddlenlp.data.Pad/Stack/Tuple补齐为 batch。3.3 Pair-wise 随机负例生成Pair-wise 训练需要三元组(query, pos_title, neg_title)。gen_pair(dataset, pool_size100)实现了随机负例生成遍历数据集时过滤掉 label 为 0 的正样本此处指不相似样本将正样本的title累积进一个大小为pool_size的池子凑满后随机打乱把池中的标题作为各样本的负例neg_title。当数据集不足pool_size时自动缩小池子大小。这一逻辑从实现上保证了正负样本均来自数据集内部标题的随机组合。四、单塔模型组网原理model.py 定义了两种单塔匹配模型二者共享同一主干预训练模型编码 Dropout 线性映射差异仅在输出头和损失构造上。4.1 PointwiseMatching二分类匹配模型class PointwiseMatching(nn.Layer): def __init__(self, pretrained_model, dropoutNone): super().__init__() self.ptm pretrained_model self.dropout nn.Dropout(dropout if dropout is not None else 0.1) # num_labels 2 (similar or dissimilar) self.classifier nn.Linear(self.ptm.config[hidden_size], 2) def forward(self, input_ids, token_type_idsNone, position_idsNone, attention_maskNone): _, cls_embedding self.ptm(input_ids, token_type_ids, position_ids, attention_mask) cls_embedding self.dropout(cls_embedding) logits self.classifier(cls_embedding) return logits取预训练模型输出的[CLS]句级向量代码中_, cls_embedding即model_output与pooled返回值中的后者经 Dropout默认 0.1后送入nn.Linear(hidden_size, 2)输出维度为 2 的 logits训练时配合paddle.nn.loss.CrossEntropyLoss预测时对 logits 取np.argmax(axis1)得到 0/1 标签。4.2 PairwiseMatching排序打分模型class PairwiseMatching(nn.Layer): def __init__(self, pretrained_model, dropoutNone, margin0.1): super().__init__() self.ptm pretrained_model self.dropout nn.Dropout(dropout if dropout is not None else 0.1) self.margin margin # hidden_size - 1, calculate similarity self.similarity nn.Linear(self.ptm.config[hidden_size], 1) def predict(self, input_ids, token_type_idsNone, position_idsNone, attention_maskNone): _, cls_embedding self.ptm(input_ids, token_type_ids, position_ids, attention_mask) cls_embedding self.dropout(cls_embedding) sim_score self.similarity(cls_embedding) sim_score F.sigmoid(sim_score) return sim_score def forward(self, pos_input_ids, neg_input_ids, pos_token_type_idsNone, neg_token_type_idsNone, pos_position_idsNone, neg_position_idsNone, pos_attention_maskNone, neg_attention_maskNone): _, pos_cls_embedding self.ptm(pos_input_ids, pos_token_type_ids, pos_position_ids, pos_attention_mask) _, neg_cls_embedding self.ptm(neg_input_ids, neg_token_type_ids, neg_position_ids, neg_attention_mask) pos_embedding self.dropout(pos_cls_embedding) neg_embedding self.dropout(neg_cls_embedding) pos_sim self.similarity(pos_embedding) neg_sim self.similarity(neg_embedding) pos_sim F.sigmoid(pos_sim) neg_sim F.sigmoid(neg_sim) labels paddle.full(shape[pos_cls_embedding.shape[0]], fill_value1.0, dtypefloat32) loss F.margin_ranking_loss(pos_sim, neg_sim, labels, marginself.margin) return loss要点说明训练前向同一预训练模型分别编码正样本对与负样本对得到各自[CLS]向量经 Dropout 后过同一个打分线性层nn.Linear(hidden_size, 1)再经F.sigmoid压缩到 0~1 区间作为相似度打分。损失函数使用F.margin_ranking_loss(pos_sim, neg_sim, labels, margin...)其中labels全为 1.0含义是正样本打分应比负样本打分至少高出 marginmargin 越大模型被要求区分的差距越大默认 0.1训练脚本可通过--margin调整。预测前向predict方法只对单个文本对编码打分供 predict_pairwise.py 与训练时的评估逻辑调用。五、模型训练5.1 Point-wise 训练以 LCQMC 为示例数据集在训练集train.tsv上训练单塔 Point-wise 模型并在开发集dev.tsv验证$ unset CUDA_VISIBLE_DEVICES python -u -m paddle.distributed.launch --gpus 0 train_pointwise.py \ --device gpu \ --save_dir ./checkpoints \ --batch_size 32 \ --learning_rate 2E-5训练脚本 train_pointwise.py 的核心训练循环为取 batch → 前向得到 logits → CrossEntropyLoss 计算损失 → 反向传播 →optimizer.step()与lr_scheduler.step()每 10 步打印一次 loss/accu 与吞吐每--eval_step默认 100步在 dev 集上评估一次每--save_step默认 10000步保存一次 checkpoint达到--max_step默认 10000提前终止训练。评估函数evaluate使用paddle.metric.Accuracy输出 acc。5.2 Pair-wise 训练Pair-wise 匹配模型只需换用train_pairwise.py脚本python -u -m paddle.distributed.launch --gpus 0 train_pairwise.py \ --device gpu \ --save_dir ./checkpoints \ --batch_size 32 \ --learning_rate 2E-5训练脚本 train_pairwise.py 与 Point-wise 版本的主要差异加载训练集后先执行train_ds gen_pair(train_ds)生成随机负例三元组训练 batch 由 4 个张量组成正样本 input_ids / token_type_ids、负样本 input_ids / token_type_ids前向时直接调用model(pos_input_ids..., neg_input_ids...)得到 margin ranking loss评估指标改用paddle.metric.Auc评估时以pos_probs与1 - pos_probs拼接成二分类概率矩阵更新 AUC——因为 Pair-wise 模型关注排序能力而非绝对分类阈值AUC 更适合衡量正样本打分高于负样本的排序质量多出--margin参数默认 0.2用于调节正负打分的间隔要求。5.3 训练参数说明两个训练脚本均基于 argparse 解析参数可配置项如下参数说明默认值save_dir保存训练模型的目录./checkpointmax_seq_length输入序列最大长度不能超过 512显存不足时调低128batch_size批处理大小结合显存调整显存不足时调低32learning_rateFine-tune 最大学习率5e-5weight_decay正则项力度防止过拟合仅对非 bias/norm 参数生效见下方源码细节0.0epochs训练轮次3eval_step评估间隔步数100save_step保存 checkpoint 间隔步数10000max_step训练最大步数上限10000warmup_proportionwarmup 比例如 0.1 表示学习率在前 10% 的训练 step 内从 0 线性增至learning_rate再缓慢衰减0.0init_from_ckpt热启动模型参数路径Noneseed随机种子1000device训练设备可选 cpu、gpuPair-wise 脚本还支持 npugpumargin仅 Pair-wise正负打分间隔0.2关于weight_decay的实现细节脚本通过decay_params [p.name for n, p in model.named_parameters() if not any(nd in n for nd in [bias, norm])]排除所有 bias 与 LayerNorm 参数再以apply_decay_param_fun传入paddle.optimizer.AdamW即仅对权重矩阵施加权重衰减。关于学习率调度脚本使用paddlenlp.transformers.LinearDecayWithWarmup定义于 paddlenlp/transformers/optimization.py它基于 LambdaDecay 实现warmup 后线性衰减策略调度周期为len(train_data_loader) * epochs配合--warmup_proportion控制前段爬坡比例。5.4 更换预训练模型示例代码中默认使用 ERNIE-Gramernie-gram-zh训练脚本中实际使用ernie-3.0-medium-zh。如需换用其他预训练模型ERNIE、BERT、RoBERTa、Electra 等只需同时更换model与tokenizer# 使用 ERNIE-3.0-medium-zh 预训练模型 model AutoModel.from_pretrained(ernie-3.0-medium-zh) tokenizer AutoTokenizer.from_pretrained(ernie-3.0-medium-zh) # 使用 ERNIE-Gram 预训练模型 model AutoModel.from_pretrained(ernie-gram-zh) tokenizer AutoTokenizer.from_pretrained(ernie-gram-zh) # 使用 ERNIE 预训练模型 # ernie-1.0 # model AutoModel.from_pretrained(ernie-1.0-base-zh) # tokenizer AutoTokenizer.from_pretrained(ernie-1.0-base-zh) # ernie-tiny需先 pip install sentencepiece # model AutoModel.from_pretrained(ernie-tiny) # tokenizer AutoTokenizer.from_pretrained(ernie-tiny) # 使用 BERT 预训练模型 # bert-base-chinese # model AutoModel.from_pretrained(bert-base-chinese) # tokenizer AutoTokenizer.from_pretrained(bert-base-chinese) # bert-wwm-chinese # model AutoModel.from_pretrained(bert-wwm-chinese) # tokenizer AutoTokenizer.from_pretrained(bert-wwm-chinese) # bert-wwm-ext-chinese # model AutoModel.from_pretrained(bert-wwm-ext-chinese) # tokenizer AutoTokenizer.from_pretrained(bert-wwm-ext-chinese) # 使用 RoBERTa 预训练模型 # roberta-wwm-ext # model AutoModel.from_pretrained(roberta-wwm-ext) # tokenizer AutoTokenizer.from_pretrained(roberta-wwm-ext) # roberta-wwm-ext-large # model AutoModel.from_pretrained(roberta-wwm-ext-large) # tokenizer AutoTokenizer.from_pretrained(roberta-wwm-ext-large)注意ERNIE-Gram 模型的具体实现可进一步阅读 paddlenlp/transformers/ernie_gram/其核心思想是显式 N-gram 掩码语言建模通过[CLS]向量与 N-gram 信息的融合提升自然语言理解能力。更多可用的预训练模型可参考仓库内 transformers 模型列表。5.5 训练产物与断点恢复程序运行时自动进行训练与评估并按照save_step间隔在save_dir中保存 checkpoint。目录结构如下checkpoints/ ├── model_100 │ ├── model_state.pdparams │ ├── tokenizer_config.json │ └── vocab.txt └── ...恢复训练设置init_from_ckptcheckpoints/model_100/model_state.pdparams即可从指定 checkpoint 热启动继续训练。ernie-tiny 依赖如需使用 ernie-tiny 模型需先安装 sentencepiece 依赖pip install sentencepiece。六、动态图模型预测6.1 Point-wise 预测输出 0/1 标签用 LCQMC 测试集作为预测数据测试数据示例如下每行两列\t分隔谁有狂三这张高清的 这张高清图谁有 英雄联盟什么英雄最好 英雄联盟最好英雄是什么 这是什么意思被蹭网吗 我也是醉了这是什么意思 现在有什么动画片好看呢 现在有什么好看的动画片吗 请问晶达电子厂现在的工资待遇怎么样要求有哪些 三星电子厂工资待遇怎么样啊启动预测$ unset CUDA_VISIBLE_DEVICES python -u -m paddle.distributed.launch --gpus 0 \ predict_pointwise.py \ --device gpu \ --params_path ./checkpoints/model_4400/model_state.pdparams \ --batch_size 128 \ --max_seq_length 64 \ --input_file test.tsvpredict_pointwise.py加载--params_path指定的模型参数后对输入 TSV 逐对编码推理输出每条样本的pred_label{query: 谁有狂三这张高清的, title: 这张高清图谁有, pred_label: 1} {query: 英雄联盟什么英雄最好, title: 英雄联盟最好英雄是什么, pred_label: 1} {query: 这是什么意思被蹭网吗, title: 我也是醉了这是什么意思, pred_label: 1} {query: 现在有什么动画片好看呢, title: 现在有什么好看的动画片吗, pred_label: 1} {query: 请问晶达电子厂现在的工资待遇怎么样要求有哪些, title: 三星电子厂工资待遇怎么样啊, pred_label: 0}6.2 Pair-wise 预测输出相似度打分python -u -m paddle.distributed.launch --gpus 0 \ predict_pairwise.py \ --device gpu \ --params_path ./checkpoints/model_4400/model_state.pdparams \ --batch_size 128 \ --max_seq_length 64 \ --input_file test.tsvpredict_pairwise.py 调用模型的predict方法输出每条文本对的相似度概率pred_prob0~1可直接作为排序特征。两个预测脚本均要求--input_file与--params_path为必填参数max_seq_length默认 64batch_size默认 32device支持 cpu、gpuPoint-wise 脚本额外支持 npu。七、静态图导出与部署预测7.1 动态图参数导出静态图动态图训练结束后用export_model.py将动态图参数导出为静态图推理模型python export_model.py --params_path checkpoints/model_300/model_state.pdparams --output_path./outputparams_path动态图训练保存的参数路径output_path静态图参数导出路径默认./output。其内部实现位于 export_model.py加载ernie-3.0-medium-zh预训练模型与PointwiseMatching组网model.set_dict(state_dict)载入训练权重后通过paddle.jit.to_static指定两个InputSpec(shape[None, None], dtypeint64)即 input_ids 与 segment_ids 的动态维度输入描述最终以paddle.jit.save(model, os.path.join(output_path, inference))保存静态图模型。7.2 静态图预测部署导出静态图模型后使用deploy/python/predict.py提供的静态图预测示例进行部署python deploy/python/predict.py --model_dir ./output部署脚本 deploy/python/predict.py 的关键能力基于paddle.inference.Config与paddle.inference.create_predictor加载inference.pdmodel/inference.pdiparams文件名由PADDLE_INFERENCE_MODEL_SUFFIX与PADDLE_INFERENCE_WEIGHTS_SUFFIX拼接得到GPU 推理config.enable_use_gpu(100, 0)初始化显存可选--use_tensorrt开启 TensorRT 加速--precision支持 fp32 / fp16 / int8 三种精度CPU 推理config.disable_gpu()后可选--enable_mkldnn开启 MKL-DNN 加速并通过--cpu_threads设置线程数MKL-DNN 会缓存 10 种不同 shape 以避免内存泄漏XPU 推理config.enable_xpu(100)支持--benchmark开启 auto_log 性能日志输出预/推理/后处理各阶段耗时并保存到--save_log_path加载数据源为load_dataset(lcqmc, splits[test])按--batch_size分批预测label_map {0: dissimilar, 1: similar}将预测 id 映射为语义标签。八、总结与实践建议本示例以一套代码覆盖了单塔文本匹配的两条主流技术路线可归纳为以下实践要点任务选型纯二分类相似/不相似选 Point-wise输出 0/1 标签需要相似度打分并接入上层排序的场景选 Pair-wise输出 0~1 连续分。数据组织Point-wise 直接使用带标签的文本对Pair-wise 需通过gen_pair生成随机负例三元组负例质量与pool_size直接相关。训练细节统一使用LinearDecayWithWarmup学习率调度、AdamW权重衰减仅作用于非 bias/norm 参数Point-wise 关注 AccuracyPair-wise 关注 AUC。落地部署动态图训练 →export_model.py导出静态图 →deploy/python/predict.py完成推理并可按设备选择 TensorRT / MKL-DNN / XPU 加速。该示例的完整实现、训练脚本与部署代码均可在仓库的 slm/examples/text_matching/ernie_matching 目录中查看与复现。Reference[1] Xin Liu, Qingcai Chen, Chong Deng, Huajun Zeng, Jing Chen, Dongfang Li, Buzhou Tang. LCQMC: A Large-scale Chinese Question Matching Corpus. COLING 2018.[2] Xiao, Dongling, Yu-Kun Li, Han Zhang, Yu Sun, Hao Tian, Hua Wu, Haifeng Wang. ERNIE-Gram: Pre-Training with Explicitly N-gram Masked Language Modeling for Natural Language Understanding. arXiv:2010.12148.赞分享人工智能大模型预训练微调LoRARLHF强化学习分布式训练【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址https://gitcode.com/gh_mirrors/pa/PaddleNLP点击查看免费下载相关推荐基于 ERNIE-Gram 的 Pair-wise 语义排序模型实战从 margin_ranking_loss 训练到 Paddle Serving 部署基于 ERNIE Gram 的 Pair wise 语义排序模型实战从 margin_ranking_loss 训练到 Paddle Serving 部署 本人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLPPaddleNLP 文本匹配实战指南单塔、双塔与 SimNet 方案从 LCQMC 训练到静态图部署PaddleNLP 文本匹配实战指南单塔、双塔与 SimNet 方案从 LCQMC 训练到静态图部署 文本匹配是研究两段文本之间关系的基础 NLP 任务信人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP基于 PaddleHub 的 Transformer 预训练模型文本匹配 Fine-tune 实战ERNIE Sentence Transformer 双塔方案基于 PaddleHub 的 Transformer 预训练模型文本匹配 Fine tune 实战ERNIE Sentence Transformer 双塔方人工智能大模型微调模型推理服务创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考