PaddleNLP LUKE 实体感知模型 modeling 模块深度解析:从双塔输入到五大下游任务
2026/9/24 16:06:19 网站建设 项目流程
  • 人工智能
  • 大模型
  • 预训练
  • 微调
  • LoRA
  • RLHF
  • 强化学习
  • 分布式训练

【免费下载链接】PaddleNLP

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

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

LUKE(Language Understanding with Knowledge-based Embeddings)是一种能够同时建模词元(word)与实体(entity)的 Transformer 预训练模型,其核心创新在于将文本中的实体(如人名、地名、机构名)作为独立的"实体序列"与词序列并行编码。本文基于 PaddleNLP 仓库中的 luke/modeling.py 及其配套的 configuration.py、tokenizer.py 源码,系统讲解 LUKE 在 PaddleNLP 中的完整实现:包括LukeModel基础模型的双塔结构与实体感知注意力机制、LukeConfig的全部配置项,以及面向掩码语言建模、实体分类、实体对分类、实体片段(span)分类和问答五大任务的模型头部实现。读完本文,你将掌握 LUKE 的架构原理,并能直接使用 PaddleNLP 加载luke-base/luke-large预训练权重完成各类实体相关任务的推理与开发。

一、LUKE 在 PaddleNLP 中的定位与模块总览

LUKE 模块位于仓库的paddlenlp/transformers/luke/目录下,由四个文件组成:

文件职责
modeling.py模型结构:基础模型与五个下游任务模型
configuration.py配置类LukeConfig与预训练权重注册表
tokenizer.pyLukeTokenizer,负责文本与实体的联合编码
init.py模块导出入口

其中 modeling.py 通过 paddlenlp/transformers/init.py 中的from .luke.modeling import *被导出,因此用户可以直接从paddlenlp.transformers顶层命名空间导入全部 LUKE 模型类。

modeling.py 对外暴露的完整 API 集合(见 modeling.py 的__all__):

  • LukeModel:不带任务头的基础 Transformer 模型,输出词与实体的隐状态及池化结果;
  • LukePretrainedModel:预训练模型的抽象基类,承载权重下载与加载逻辑;
  • LukeForMaskedLM:掩码语言建模(MLM)模型,同时预测被掩码的词与实体;
  • LukeForEntityClassification:实体分类模型(如 Open Entity 任务);
  • LukeForEntityPairClassification:实体对关系分类模型(如 TACRED 任务);
  • LukeForEntitySpanClassification:实体片段分类模型(如命名实体识别 NER);
  • LukeForQuestionAnswering:抽取式问答模型。

二、LukeConfig:实体感知模型的配置体系

所有 LUKE 模型均由 LukeConfig 配置类驱动。它继承自PretrainedConfig,除常规 Transformer 配置外,还引入了两个 LUKE 特有的超参数:entity_vocab_size(实体词表大小)与entity_emb_size(实体嵌入维度)。

2.1 预训练模型注册表

configuration.py 中定义了LUKE_PRETRAINED_INIT_CONFIGURATION,注册了两个官方预训练规模:

配置项luke-baseluke-large
hidden_size7681024
num_hidden_layers1224
num_attention_heads1216
intermediate_size30724096
max_position_embeddings514514
vocab_size5026750267
hidden_actgelugelu
hidden_dropout_prob / attention_probs_dropout_prob0.10.1
type_vocab_size11
pad_token_id11
initializer_range0.020.02

同时 LUKE_PRETRAINED_RESOURCE_FILES_MAP 注册了luke-baseluke-largemodel_state.pdparams权重资源地址,LukePretrainedModel正是通过这两个注册表实现from_pretrained的自动下载与加载。

2.2 构造参数与默认值

LukeConfig.__init__的完整参数(均带默认值)如下:

参数默认值说明
vocab_size50267词元(token)词表大小,决定 token embedding 矩阵维度
hidden_size768嵌入层、编码层与池化层的隐藏维度
num_hidden_layers12Transformer 编码器层数
num_attention_heads12每层注意力头数
intermediate_size3072前馈网络中间维度(先由 hidden_size 升维、再降回)
hidden_act"gelu"前馈层激活函数,支持 gelu、relu 等 Paddle 支持的激活
hidden_dropout_prob0.1嵌入层与编码器中全连接层的 dropout 概率
attention_probs_dropout_prob0.1注意力概率矩阵的 dropout 概率
max_position_embeddings514位置编码最大长度
type_vocab_size1token_type_ids 的词表大小
entity_vocab_size500000实体词表大小,决定实体嵌入矩阵维度
entity_emb_size256实体嵌入维度(远小于 hidden_size,通过投影对齐)
initializer_range0.02权重正态初始化标准差
pad_token_id1词序列的填充 token id
entity_pad_token_id0实体序列的填充 token id
cls_token_id101分类标记 token id

从配置可以看出 LUKE 的一个关键设计:实体嵌入维度entity_emb_size=256远小于词隐藏维度hidden_size=768。这使实体词表可以做得非常大(50 万),同时保持参数量可控——实体嵌入经投影层映射到隐藏空间后再参与注意力计算,具体见下文EntityEmbeddings

三、LukeModel:双塔输入与实体感知注意力

LukeModel(modeling.py)是全部 LUKE 任务模型的基础,被@register_base_model装饰,base_model_prefix = "luke"

3.1 整体结构

LukeModel.__init__由五个子模块组成:

  • LukeEmbeddings:词元嵌入(直接复用RobertaEmbeddings);
  • EntityEmbeddings:实体嵌入(LUKE 特有);
  • LukeEncoder:堆叠num_hidden_layersLukeLayer
  • LukePooler:取[CLS](即<s>)位置的隐状态做 tanh 池化;
  • 另保存pad_token_identity_pad_token_id用于自动构造注意力掩码。

LukePretrainedModel._init_weights(modeling.py)定义了初始化钩子:nn.Linearnn.Embedding权重按initializer_range标准差做正态初始化,nn.LayerNorm的 epsilon 固定为1e-6

3.2 双塔输入:词序列与实体序列

LukeModel.forward同时接受两类输入(modeling.py):

  • 词侧input_idstoken_type_idsposition_idsattention_mask
  • 实体侧entity_idsentity_position_idsentity_token_type_idsentity_attention_mask

实体侧参数均为可选。当entity_idsNone时,模型退化为普通的 RoBERTa 风格编码器;当提供实体输入时,模型将实体序列拼接到词序列之后(paddle.concat)进行联合编码。

LukeEmbeddings(词嵌入)

LukeEmbeddings(modeling.py)直接继承RobertaEmbeddings,其 docstring 明确指出"Same as BertEmbeddings with a tiny tweak for positional embeddings indexing",即词侧嵌入与 RoBERTa 完全一致,仅保留位置嵌入索引的小调整。

EntityEmbeddings(实体嵌入)

EntityEmbeddings(modeling.py)是 LUKE 区别于普通 Transformer 的核心组件之一,其 forward 计算分为四步:

  1. 实体嵌入查找entity_embeddings(entity_ids)得到[batch, entity_len, entity_emb_size]的向量;当entity_emb_size != hidden_size时,通过无偏置的entity_embedding_dense线性层投影到hidden_size
  2. 位置嵌入:对position_ids.clip(min=0)做位置嵌入查找,随后用掩码(position_ids != -1)过滤掉值为-1(表示该实体对应的词位置为空)的嵌入,再对实体覆盖的多个词位置求平均(除以掩码和,最小值截断为1e-7)。这一步实现了 LUKE 论文中"实体位置嵌入 = 其提及(mention)覆盖的所有词位置嵌入的平均"的设计;
  3. 段嵌入token_type_embeddings(token_type_ids),未提供时默认为全 0;
  4. 融合:三者相加后经过 LayerNorm 与 dropout。

3.3 LukeSelfAttention:四类注意力查询的实体感知机制

LUKE 注意力的最大特色体现在LukeSelfAttention(modeling.py)中。当实体存在时,模型不再使用单一 Query 投影,而是使用四套独立的 Query 线性层

  • query(w2w):词对词注意力;
  • w2e_query:词对实体注意力;
  • e2w_query:实体对词注意力;
  • e2e_query:实体对实体注意力。

Key 与 Value 则共享同一投影(对词+实体拼接后的整体计算),再按位置切分为词部分与实体部分。前向过程(modeling.py)依次计算w2w_attention_scoresw2e_attention_scorese2w_attention_scorese2e_attention_scores四个分数矩阵,然后按行、列拼接成完整的注意力分数矩阵:词行由 w2w 与 w2e 拼接,实体行由 e2w 与 e2e 拼接。

随后除以sqrt(attention_head_size)缩放、叠加注意力掩码、softmax 归一化、dropout,再与共享的 Value 矩阵相乘得到上下文向量,最后按word_size位置切分回词隐状态与实体隐状态。当entity_hidden_statesNone时则退化为标准多头注意力。

3.4 层结构与编码器堆叠

  • LukeAttention(modeling.py):由LukeSelfAttentionLukeSelfOutput(dense + LayerNorm + dropout 的残差结构)组成,将词/实体输出拼接后过残差,再按word_size切分;
  • LukeIntermediate/LukeOutput(modeling.py):前馈网络,hidden_size → intermediate_size → hidden_size,中间经过get_activation(config.hidden_act)激活,外层带残差与 LayerNorm;
  • LukeLayer(modeling.py):将注意力层与前馈层串成单层,同样对词/实体输出分别切分;
  • LukeEncoder(modeling.py):nn.LayerList堆叠多层LukeLayer,逐层传递词与实体隐状态。

3.5 掩码构造与前向输出

LukeModel.forward在 modeling.py 中完成掩码与嵌入的组装:

  • 未提供attention_mask时,自动根据input_ids == pad_token_id生成-1e4的惩罚掩码并 unsqueeze 到 4 维;若提供 2 维掩码则自动unsqueeze([1,2])并转换为(1.0 - mask) * -1e4
  • 实体侧同理:未提供entity_attention_mask时按entity_ids == entity_pad_token_id生成;最终attention_maskentity_attention_mask在最后一维拼接,形成覆盖词+实体全长度的联合掩码;
  • 实体 token_type_ids 默认全 0。

返回值为三元组(sequence_output, entity_hidden_state, pooled_output)

  • word_hidden_state[batch_size, sequence_length, hidden_size]的最后一层词隐状态;
  • entity_hidden_state[batch_size, entity_length, hidden_size]的实体隐状态;
  • pooled_output:取序列第一个 token(<s>)隐状态经LukePooler(dense + tanh)池化,形状[batch_size, hidden_size]

四、五个下游任务模型

所有任务模型都复用LukeModel作为骨干,再在顶部叠加不同的任务头。

4.1 LukeForMaskedLM:词与实体的联合掩码预测

LukeForMaskedLM(modeling.py)同时预测被掩码的词与实体,包含两个头部:

  • LukeLMHead(modeling.py):词侧 MLM 头,dense → 激活 → LayerNorm 后与decoder_weight(默认复用word_embeddings.weight做权重绑定,即tied结构)做转置矩阵乘并加decoder_bias,实现权重共享的掩码词预测;
  • EntityPredictionHead(modeling.py):实体侧预测头,先由EntityPredictionHeadTransform(dense 到entity_emb_size+ 激活 + LayerNorm)变换,再由decoder线性层映射回实体词表大小entity_vocab_size

返回二元组(logits, entity_logits):词侧形状[batch_size, sequence_length, vocab_size],实体侧形状[batch_size, entity_length, entity_vocab_size]

4.2 LukeForEntityClassification:实体级分类

LukeForEntityClassification(modeling.py)面向 Open Entity 这类对单个实体分类的任务。它取实体隐状态的第一个实体 tokenoutputs[1][:, 0, :]作为特征,经 dropout 后送入nn.Linear(hidden_size, num_labels)分类器,输出[batch_size, num_labels]的 logits。

4.3 LukeForEntityPairClassification:实体对关系分类

LukeForEntityPairClassification(modeling.py)面向 TACRED 这类对实体对进行关系分类的任务。它将前两个实体 token 的隐状态outputs[1][:, 0, :]outputs[1][:, 1, :]拼接成hidden_size * 2维向量,经 dropout 后送入nn.Linear(hidden_size * 2, num_labels, bias_attr=False)(注意此处不使用偏置),输出[batch_size, num_labels]

4.4 LukeForEntitySpanClassification:实体片段分类

LukeForEntitySpanClassification(modeling.py)面向命名实体识别等实体片段分类任务。它的输入额外增加entity_start_positionsentity_end_positions两个参数,前向逻辑为:

  1. 通过paddle_gather(模块内自实现的 gather 工具函数,modeling.py,用gather_nd模拟任意维度 gather)从词隐状态中按 start/end 位置收集起始与结束词的隐状态;
  2. start_statesend_states与实体隐状态outputs[1]三者拼接成hidden_size * 3维特征;
  3. 经 dropout 后送入nn.Linear(hidden_size * 3, num_labels),输出[batch_size, num_entities, num_labels]

4.5 LukeForQuestionAnswering:抽取式问答

LukeForQuestionAnswering(modeling.py)是五类模型中唯一不直接使用实体隐状态的模型:它取词隐状态的前input_ids.shape[1]个位置,经nn.Linear(hidden_size, 2)输出 2 维 logits 后paddle.split拆分为start_logitsend_logits,两者形状均为[batch_size, sequence_length],分别表示答案跨度起始与结束位置的概率分布。

五、LukeTokenizer:实体标注的编码配套

LukeTokenizer(tokenizer.py)继承自RobertaBPETokenizer(RoBERTa 风格的 byte-level BPE),并额外引入了实体词表entity_fileentity_vocab.json)。它加载三类资源文件:vocab.jsonmerges.txtentity_vocab.json,特殊 token 与 RoBERTa 一致(<s></s><pad><unk><mask>)。

__call__方法(tokenizer.py)在标准词编码参数之外,新增了以下 LUKE 专有参数:

参数说明
entity_spans/entity_spans_pair字符级别的实体跨度列表,如[(0, 7)]表示第 0~7 个字符是实体
entities/entities_pair实体的字符串表示(如 Wikipedia 实体标题"Los Angeles"或特殊实体[MASK]);若只给entity_spans不给定实体,则自动用[MASK]实体填充
max_mention_length实体提及覆盖的最大词位置数,默认 30,决定entity_position_ids的长度
task构造器中的任务类型参数,可选"entity_classification""entity_pair_classification"等,用于约束实体数量

返回的字典除input_idsattention_mask等常规字段外,还会在传入entity_spans时额外包含entity_idsentity_position_idsentity_segment_idsentity_attention_mask等实体侧字段(tokenizer.py)。tokenizer 的 docstring 给出了一个直观示例:对"Beyoncé lives in Los Angeles"并指定两个实体跨度,会输出input_idsentity_ids两组 id。

六、快速上手:完整可运行的推理示例

综合 modeling.py 中各个类的 docstring 示例,加载luke-base的完整流程如下:

import paddle from paddlenlp.transformers import LukeModel, LukeTokenizer # 1. 加载预训练模型与配套 tokenizer(首次运行自动下载权重) tokenizer = LukeTokenizer.from_pretrained('luke-base') model = LukeModel.from_pretrained('luke-base') # 2. 构造文本与实体跨度(字符级别的 start/end 位置) text = "Beyoncé lives in Los Angeles." entity_spans = [(0, 7)] # "Beyoncé" 为实体 inputs = tokenizer(text, entity_spans=entity_spans, add_prefix_space=True) # 3. 转换为 Tensor 并前向 inputs = {k: paddle.to_tensor([v]) for (k, v) in inputs.items()} word_hidden_state, entity_hidden_state, pooled_output = model(**inputs) print(word_hidden_state.shape, entity_hidden_state.shape, pooled_output.shape)

五个任务模型的使用方式与之完全一致,仅需替换模型类与输出处理:

from paddlenlp.transformers import LukeForMaskedLM model = LukeForMaskedLM.from_pretrained('luke-base') logits, entity_logits = model(**inputs) # 词 MLM logits + 实体 MLM logits
from paddlenlp.transformers import LukeForEntityClassification model = LukeForEntityClassification.from_pretrained('luke-base', num_labels=2) logits = model(**inputs) # [batch_size, num_labels]
from paddlenlp.transformers import LukeForEntityPairClassification model = LukeForEntityPairClassification.from_pretrained('luke-base', num_labels=2) # 实体对任务需提供两个实体跨度 inputs = tokenizer(text, entity_spans=[(0, 7), (17, 28)], add_prefix_space=True) inputs = {k: paddle.to_tensor([v]) for (k, v) in inputs.items()} logits = model(**inputs) # [batch_size, num_labels]
from paddlenlp.transformers import LukeForEntitySpanClassification model = LukeForEntitySpanClassification.from_pretrained('luke-base', num_labels=2) inputs = tokenizer(text, entity_spans=[(0, 7)], add_prefix_space=True) inputs = {k: paddle.to_tensor([v]) for (k, v) in inputs.items()} inputs['entity_start_positions'] = paddle.to_tensor([[1]], dtype='int64') inputs['entity_end_positions'] = paddle.to_tensor([[2]], dtype='int64') logits = model(**inputs) # [batch_size, num_entities, num_labels]
from paddlenlp.transformers import LukeForQuestionAnswering model = LukeForQuestionAnswering.from_pretrained('luke-base') start_logits, end_logits = model(**inputs) # 均为 [batch_size, sequence_length]

需要说明的适用前提:所有示例的默认entity_spans均为单实体,实体对分类等任务请按上文所示提供相应数量的跨度;add_prefix_space=True与 RoBERTa 系列 tokenizer 的惯例一致,用于在句首补充空格标记。

七、测试与验证

仓库在 tests/transformers/luke/test_modeling.py 中提供了完整的模型测试,可用于验证上述 API 的正确性:

  • LukeModelTester(test_modeling.py)构造小规模随机配置的模型与输入;
  • 测试断言覆盖了LukeModel输出的[batch_size, seq_length, hidden_size][batch_size, hidden_size]形状(对应前向三元组中的词隐状态与池化输出);
  • 五个任务模型的输出形状均被逐一验证:LukeForMaskedLM的词/实体 logits、LukeForQuestionAnswering的 start/end logits、LukeForEntityClassification[batch_size, num_labels]LukeForEntityPairClassification[batch_size, num_labels]LukeForEntitySpanClassification[batch_size, 2, num_labels]
  • test_forward_signaturetest_model_from_pretrained则分别检查前向方法参数签名与预训练权重加载。

配套的 tests/transformers/luke/test_tokenizer.py 覆盖 tokenizer 的实体编码逻辑。若需在本地复现测试,可参照仓库 tests/README.md 的测试环境说明运行对应用例。

八、小结:从源码理解 LUKE 的设计要点

纵观 modeling.py,LUKE 在 PaddleNLP 中的实现有四个值得记住的设计要点:

  1. 双序列输入:词序列与实体序列并行编码,实体序列经EntityEmbeddings(含平均化的位置嵌入)映射到与词相同的隐藏空间;
  2. 实体感知注意力LukeSelfAttention使用 w2w / w2e / e2w / e2e 四套 Query 投影,Key/Value 共享,将实体信息显式注入每一层的注意力计算;
  3. 大实体词表 + 低维实体嵌入entity_vocab_size达 50 万而entity_emb_size仅 256,通过投影层与隐藏维度对齐,兼顾表示能力与参数量;
  4. 任务头多样化:同一骨干之上,通过取实体首 token(实体分类)、实体对拼接(实体对分类)、词隐状态按 span 收集拼接(实体片段分类)、词隐状态投影(问答)、双头联合预测(MLM),覆盖了实体相关的典型 NLP 任务。

如需进一步了解 LUKE 与 PaddleNLP 其他预训练模型的差异,可参考 paddlenlp/transformers/README.md 与 docs/zh/source/paddlenlp.transformers.luke.configuration.rst 对应的配置类文档;各任务模型的完整参数与返回类型说明,可直接阅读 modeling.py 中各类的 docstring。

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

【免费下载链接】PaddleNLP

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

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

相关推荐

上一篇:微信AI助手快速搭建:20 分钟跑通微信群机器人,免费本地模型也能接
下一篇:5分钟快速上手:Obsidian-i18n终极汉化插件完整指南

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询