PaddleNLP ERNIE-CTM 模型详解:基于 content summary 的多任务中文预训练模型实现与使用指南
【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP
ERNIE-CTM(ERNIE for Chinese Token-level Modeling)是 PaddleNLP 中针对中文词级/字级细粒度语言建模设计的预训练模型系列,通过引入多个[CLS]摘要占位符(content summary token)机制,让模型在序列标注类任务(如命名实体识别 NER、词边界标注 wordtag、命名短语标注 nptag)上同时兼顾全局语义与局部词法信息。本文以 docs/zh/source/paddlenlp.transformers.ernie_ctm.rst 所定义的 API 文档结构为骨架,结合 paddlenlp/transformers/ernie_ctm 模块的完整源码与 tests/transformers/ernie_ctm/test_modeling.py 测试用例,系统讲解其配置类、基础模型、三类下游任务模型与专用分词器的实现原理和调用方式,读完即可在 PaddleNLP 中完成 ERNIE-CTM 的加载、推理与微调。
一、ERNIE-CTM 模块总览与文件布局
该 RST 文档是 PaddleNLP 中文 API 文档体系中的标准 autodoc 页面,它定义了paddlenlp.transformers.ernie_ctm这一顶层模块的公开文档结构,并通过toctree将内容划分为两个子页面:
- paddlenlp.transformers.ernie_ctm.modeling:模型结构(modeling)
- paddlenlp.transformers.ernie_ctm.tokenizer:分词器(tokenizer)
对应的实际源码位于 paddlenlp/transformers/ernie_ctm 目录,包含四个文件:
| 文件 | 职责 |
|---|---|
| configuration.py | 定义ErnieCtmConfig配置类、默认超参与预训练模型资源映射 |
| modeling.py | 实现ErnieCtmEmbeddings、ErnieCtmPooler、ErnieCtmModel以及三类任务模型 |
| tokenizer.py | 实现ErnieCtmTokenizer,支持多个[CLS]占位符的输入构造 |
| init.py | 模块包声明 |
modeling.py的__all__导出五个公开类(modeling.py 第 43-49 行):
ErnieCtmPretrainedModel ErnieCtmModel ErnieCtmWordtagModel ErnieCtmNptagModel ErnieCtmForTokenClassificationtokenizer.py仅导出ErnieCtmTokenizer(tokenizer.py 第 20 行)。整个模块同时被 paddlenlp/transformers/auto 的自动加载机制登记,可通过模型名直接from_pretrained加载。
二、ErnieCtmConfig:架构配置与预训练资源
ErnieCtmConfig继承自PretrainedConfig(位于 paddlenlp/transformers/configuration_utils.py),model_type为"ernie-ctm"。其默认配置定义在模块级常量ERNIE_CTM_CONFIG(configuration.py 第 27-44 行):
| 配置项 | 默认值 | 说明 |
|---|---|---|
vocab_size | 23000 | 词表大小,决定 token embedding 矩阵规模 |
embedding_size | 128 | 词嵌入维度(区别于hidden_size,后续通过线性映射升维) |
hidden_size | 768 | Encoder 层与 Pooler 层维度 |
num_hidden_layers | 12 | Transformer Encoder 层数 |
num_attention_heads | 12 | 每层注意力头数 |
intermediate_size | 3072 | FFN 中间层维度 |
hidden_dropout_prob | 0.1 | Embedding 与 Encoder 全连接层 dropout |
attention_probs_dropout_prob | 0.1 | 注意力概率 dropout |
max_position_embeddings | 512 | 最大序列长度 |
type_vocab_size | 2 | segment id 词表大小 |
layer_norm_eps | 1e-12 | LayerNorm 的 epsilon |
initializer_range | 0.02 | 权重初始化标准差 |
pad_token_id | 0 | padding token 的 id |
use_content_summary | True | 是否启用 content summary token 机制 |
content_summary_index | 1 | content summary token 在序列中的位置(即第二个[CLS],索引 1) |
cls_num | 2 | 模型使用的[CLS]占位符数量 |
num_prompt_placeholders | 5 | 解码阶段 prompt 答案的最大长度 |
prompt_vocab_ids | None | 解码过程的 prompt 词表集合 |
其中embedding_size与hidden_size分离是 ERNIE-CTM 的显著特点:Embedding 层只有 128 维,送入 Encoder 前先经embedding_hidden_mapping_in线性层映射到 768 维,从而在不牺牲模型容量的前提下显著压缩嵌入参数量。
此外配置类还提供了attribute_map(num_tag → num_labels、dropout → classifier_dropout等),保证与 PaddleNLP 通用任务头接口的兼容性(configuration.py 第 109 行)。
预训练资源映射ERNIE_CTM_PRETRAINED_RESOURCE_FILES_MAP(configuration.py 第 53-59 行)与分词器侧(tokenizer.py 第 76-88 行)共同定义了三个可加载的预训练模型名:
ernie-ctm:通用基础模型(ernie_ctm_v3.pdparams)wordtag:词边界/词性标注任务模型(wordtag_v3.pdparams)nptag:命名短语标注任务模型(nptag_v3.pdparams)
三者共享同一份ERNIE_CTM_CONFIG默认架构与同一个vocab.txt词表,最大输入长度均为 512(PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES)。
三、ErnieCtmModel:带 content summary 的基础编码器
3.1 类继承与初始化
ErnieCtmModel继承自ErnieCtmPretrainedModel,后者通过类属性声明了资源文件命名与预训练配置(modeling.py 第 146-162 行):
model_config_file = "model_config.json",resource_files_names = {"model_state": "model_state.pdparams"}base_model_prefix = "ernie_ctm"- 权重初始化
_init_weights对 Linear/Embedding 使用initializer_range标准差的高斯初始化,对 LayerNorm 将 epsilon 设为 1e-12
模型内部结构(modeling.py 第 245-275 行)由四部分组成:
ErnieCtmEmbeddings:word / position / token_type 三类 embedding 相加后过 LayerNorm 与 Dropout;embedding_hidden_mapping_in:把 128 维嵌入映射到 768 维隐藏层;nn.TransformerEncoder:12 层标准 Transformer,激活函数为GELU(approximate=True);ErnieCtmPooler:取序列第一个 token([CLS0])的隐藏状态,经 Linear + Tanh 得到句级表示。
3.2 特殊的 position ids 构造
ErnieCtmEmbeddings.forward(modeling.py 第 100-126 行)体现了多个[CLS]占位符的定位策略:当未显式传入position_ids时,前cls_num个位置(即所有[CLS]占位符)位置编码为 0,正文 token 则从 1 开始用linspace连续编号,保证摘要位与正文位的相对距离明确。
3.3 content summary 机制与输出
这是 ERNIE-CTM 的核心设计。在forward中(modeling.py 第 428-452 行):
content_output = sequence_output[:, self.content_summary_index],即取content_summary_index=1位置(第二个[CLS],对应[CLS1])的隐藏状态作为全局内容摘要;- 将
content_output沿序列维扩展,与原sequence_output在最后一维拼接,得到hidden_size * 2维; - 依次通过
feature_fuse(Linear:hidden_size*2 → intermediate_size)与feature_output(Linear:intermediate_size → hidden_size)完成特征融合,把全局摘要信息逐 token 地注入序列表示。
该机制同时支持content_clone参数:置为 True 时直接用序列表示克隆内容摘要,用于避免分类任务对序列标注任务产生干扰。返回值(return_dict=True时)为ErnieCtmModelOutput(modeling.py 第 52-83 行):
last_hidden_state:融合了 content summary 的最后一层序列输出,形状[batch, seq_len, hidden_size];pooler_output:[CLS0]经 Pooler 的句级表示,形状[batch, hidden_size];content_output:[CLS1]的内容摘要表示,形状[batch, hidden_size];- 可选
hidden_states与attentions。
attention_mask缺省时自动以pad_token_id位置填充-1e4构建掩码(modeling.py 第 397-400 行),2D 掩码也会被自动扩展为 4D。
四、三类下游任务模型
基于ErnieCtmModel,模块提供了三种任务头,分别面向词法级与序列标注场景。
4.1 ErnieCtmWordtagModel:CRF 词边界/词性标注
ErnieCtmWordtagModel(modeling.py 第 470-600 行)在基础模型之上叠加:
tag_classifier:Linear(hidden_size, num_tag)生成逐 token 标签 logits;LinearChainCrf与LinearChainCrfLoss:来自 paddlenlp/layers/crf.py 的线性链 CRF,with_start_stop_tag=False;ViterbiDecoder:Paddle 2.2.0 及以上使用paddle.text.ViterbiDecoder,否则回退到paddlenlp.layers.crf.ViterbiDecoder(modeling.py 第 35-39 行)。
训练与推理路径(forward,modeling.py 第 583-593 行):
- 训练:传入
tag_labels时,loss = CRF loss + token 级交叉熵之和; - 推理:不传标签时,使用
viterbi_decoder输出全局最优标签序列,返回seq_logits; lengths缺省时按input_ids != pad_token_id自动统计各样本有效长度,供 CRF 处理变长序列。
4.2 ErnieCtmNptagModel:MLM 头命名短语标注
ErnieCtmNptagModel(modeling.py 第 626-723 行)由基础模型加ErnieCtmMLMHead构成,用于命名短语标注(nptag)任务。ErnieCtmMLMHead(modeling.py 第 603-623 行)的结构为:
Linear(hidden_size → embedding_size) → GELU → LayerNorm → Linear(embedding_size → vocab_size)即先降回 128 维嵌入空间再映射到 23000 维词表,输出形状[batch, seq_len, vocab_size],等价于对每个 token 做掩码词预测(MLM),从而支持在[MASK]位“填空”式地预测命名短语。传入labels时返回交叉熵 loss。
4.3 ErnieCtmForTokenClassification:通用 token 分类
ErnieCtmForTokenClassification(modeling.py 第 726-830 行)提供了与 HuggingFace 风格一致的通用 token 分类接口:基础模型输出先过Dropout(默认复用hidden_dropout_prob,支持classifier_dropout覆盖),再经Linear(hidden_size, num_labels)分类器,返回TokenClassifierOutput。适用于 NER 等需要逐 token 多分类、但不依赖 CRF 约束的场景。
五、ErnieCtmTokenizer:多 [CLS] 占位符分词器
ErnieCtmTokenizer继承自PretrainedTokenizer(paddlenlp/transformers/tokenizer_utils.py),构造函数的关键参数(tokenizer.py 第 90-112 行):
| 参数 | 默认值 | 说明 |
|---|---|---|
vocab_file | 必填 | 词表文件路径 |
do_lower_case | True | 是否小写化输入 |
do_basic_tokenize | True | 是否先做基础分词再做 WordPiece |
cls_token_template | "[CLS{}]" | 多摘要占位符的 token 模板 |
cls_num | 1 | [CLS]占位符数量(预训练配置中为 2) |
unk_token/sep_token/pad_token/mask_token | [UNK]/[SEP]/[PAD]/[MASK] | 标准特殊 token |
其分词逻辑_tokenize(tokenizer.py 第 266-282 行)面向中文按单字切分(字符级),可配置小写化——这与中文词法任务的字级建模方式一致。
5.1 多 [CLS] 的输入构造
build_inputs_with_special_tokens(tokenizer.py 第 150-174 行)定义了 ERNIE-CTM 的序列格式:
单句: [CLS0][CLS1]... X [SEP] 句对: [CLS0][CLS1]... X [SEP] X [SEP]其中cls_token_ids通过cls_token_template.format(sid)(即[CLS0]、[CLS1]…)逐个生成,数量等于cls_num。相应地,num_special_tokens_to_add在单句时为cls_num + 1、句对时为cls_num + 2(tokenizer.py 第 245-264 行)。
create_token_type_ids_from_sequences(tokenizer.py 第 206-243 行)把前cls_num个[CLS]与第一段都标记为 segment 0,第二段标记为 segment 1。由于ErnieCtmEmbeddings的默认position_ids将前cls_num位置编码为 0,分词器与模型在占位符数量上必须保持cls_num一致,加载ernie-ctm/wordtag/nptag时默认即为 2。
5.2 反序列化与转换
convert_tokens_to_string(tokenizer.py 第 124-148 行)在拼接字符串时移除 WordPiece 的##前缀(中文场景主要用于处理词表内可能出现的子词),get_special_tokens_mask则为[CLS]与[SEP]返回 1、正文 token 返回 0。
六、端到端使用示例
6.1 加载基础模型并获取三路输出
import paddle from paddlenlp.transformers import ErnieCtmModel, ErnieCtmTokenizer tokenizer = ErnieCtmTokenizer.from_pretrained("ernie-ctm") model = ErnieCtmModel.from_pretrained("ernie-ctm") inputs = tokenizer("Welcome to use PaddlePaddle and PaddleNLP!") inputs = {k: paddle.to_tensor([v]) for k, v in inputs.items()} sequence_output, pooled_output, content_output = model(**inputs) # sequence_output: [1, seq_len, 768] # pooled_output: [1, 768] (来自 [CLS0]) # content_output: [1, 768] (来自 [CLS1])6.2 词边界标注(wordtag)
from paddlenlp.transformers import ErnieCtmWordtagModel, ErnieCtmTokenizer tokenizer = ErnieCtmTokenizer.from_pretrained("wordtag") model = ErnieCtmWordtagModel.from_pretrained("wordtag", num_tag=2) inputs = tokenizer("Welcome to use PaddlePaddle and PaddleNLP!") inputs = {k: paddle.to_tensor([v]) for k, v in inputs.items()} logits = model(**inputs) # 推理时内部走 Viterbi 解码,返回标签序列6.3 命名短语标注(nptag)
from paddlenlp.transformers import ErnieCtmNptagModel, ErnieCtmTokenizer tokenizer = ErnieCtmTokenizer.from_pretrained("nptag") model = ErnieCtmNptagModel.from_pretrained("nptag") inputs = tokenizer("Welcome to use PaddlePaddle and PaddleNLP!") inputs = {k: paddle.to_tensor([v]) for k, v in inputs.items()} logits = model(**inputs) print(logits.shape) # [1, seq_len, 23000],逐 token 在词表上打分6.4 通用 token 分类微调接口
from paddlenlp.transformers import ErnieCtmForTokenClassification, ErnieCtmTokenizer tokenizer = ErnieCtmTokenizer.from_pretrained("ernie-ctm") model = ErnieCtmForTokenClassification.from_pretrained("ernie-ctm", num_labels=7) inputs = tokenizer("Welcome to use PaddlePaddle and PaddleNLP!") inputs = {k: paddle.to_tensor([v]) for k, v in inputs.items()} logits = model(**inputs) # [1, seq_len, 7]七、测试验证与工程细节
仓库为 ERNIE-CTM 提供了完整的单元测试 tests/transformers/ernie_ctm/test_modeling.py(共 385 行)。ErnieCtmModelTester使用小规模配置(vocab_size=100、hidden_size=16、num_hidden_layers=2等)覆盖ErnieCtmConfig的全部超参,并通过ModelTesterMixin验证ErnieCtmModel、ErnieCtmWordtagModel、ErnieCtmNptagModel、ErnieCtmForTokenClassification四个模型的前向、反向与输出形状;同时通过ConfigTester校验配置对象的序列化、属性映射与默认值。
工程实现上还有两点值得注意:
- Paddle 版本兼容:
paddle.text.ViterbiDecoder需要 Paddle 2.2.0 及以上,旧版本自动回退到paddlenlp.layers.crf.ViterbiDecoder(modeling.py 第 35-39 行); - 标签参数兼容:
ErnieCtmWordtagModel.forward同时接受tag_labels与labels两种命名(modeling.py 第 560-561 行),便于与 Trainer 等高层 API 对齐。
八、总结
ERNIE-CTM 在 PaddleNLP 中的实现围绕"多[CLS]摘要占位符 + content summary 特征融合"这一核心机制展开:ErnieCtmTokenizer负责构造[CLS0][CLS1]... X [SEP]形式的输入,ErnieCtmModel将第二个[CLS]的全局表示逐 token 注入序列输出,而ErnieCtmWordtagModel(CRF 词边界)、ErnieCtmNptagModel(MLM 短语填空)、ErnieCtmForTokenClassification(通用序列标注)三个任务头则把该表示应用于具体的中文词法任务。开发者可通过ernie-ctm、wordtag、nptag三个预训练模型名直接体验,或基于ErnieCtmForTokenClassification在自有数据集上微调,实现词级细粒度语义建模。
【免费下载链接】PaddleNLPEasy-to-use and powerful LLM and SLM library with awesome model zoo.项目地址: https://gitcode.com/gh_mirrors/pa/PaddleNLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考