资讯详情

用实体信息增强预训练语言模型:关系分类经典论文深度解析

📅 2026/10/12 11:41:46 | 华诺云谱 👁 阅读
用实体信息增强预训练语言模型:关系分类经典论文深度解析
最近在整理信息抽取方向的论文笔记又把这篇关于用实体信息增强预训练语言模型的经典工作从头到尾重读了一遍。说实话第一次读的时候只觉得是个“加特殊token、加辅助loss”的trick文但真正在自己数据集上复现、对比、踩坑之后才发现文章里对实体信息的分层拆解非常值得细品很多细节放到今天仍然有参考价值。这篇论文的核心问题一句话讲完关系分类任务里预训练模型虽然能编码句子的通用语义但对“实体”这个最关键的输入对象并不敏感需要显式地把实体边界、实体类型、实体位置、实体上下文这些信息注入进去。论文提出的方案也不复杂主要是对输入层、编码层、池化层和输出层同时做文章既引入标记嵌入也引入类型嵌入、位置感知注意力、实体级别池化和辅助分类任务。这篇文章适合三类人精读刚入门信息抽取、想搞清楚关系分类为什么不能只靠BERT裸跑的初学者要复现论文或者用它做baseline对比的算法工程师以及做知识图谱、文档级关系抽取时想找“实体信息注入”设计思路的研究者。下面我把这篇论文的动机、方法、实验和复现细节完整拆开顺便把自己实践经验里踩过的坑一并写出来。1. 为什么关系分类要把实体信息单独拎出来1.1 关系分类任务本身要什么关系分类任务的形式很直接给一个自然语言句子再给定句子中出现的两个实体判断这两个实体之间存在哪种语义关系。常见的形式化定义是输入三元组(sentence, e1, e2)输出关系类别r。举个例子“在清华科技园李明的公司发布了新一代芯片”这里e1是“李明”e2是“芯片”分类器要预测出“雇主-产品”这类关系。表面上看这就是个文本分类问题但实际难点在于关系是由“实体对它们之间的语义互动”共同决定的同一个句子换掉其中一个实体关系可能完全翻转。比如“张三收购了某公司”和“张三供职于某公司”实体不同、关系也不同模型不能只靠句法模板猜。所以这类任务对实体感知能力的要求非常高模型至少得知道两个实体分别是谁、是什么类型、各自在句子的什么位置、上下文里哪些词在描述实体的交互。但标准BERT做的是通用语言建模它建模的是词之间的共现和上下文关系对“实体”这个概念没有显式的建模单元。你给它一个句子它内部确实编码了每个token的表示但没有任何机制保证头的表示和尾的表示被区分对待更没有任何机制告诉模型“这两个地方是重点关注对象请把它们的交互信号单独抽出来”。1.2 预训练模型缺什么我用一个例子说明问题假设输入“某公司在上海设立研发中心”要判断“某公司”和“上海”之间是“位于”关系。BERT拿到这个句子会把“某公司”“上海”当成普通token序列的一部分。如果你直接取CLS池化结果做分类模型能利用的信息是整句话的混合语义其中“位于”这个概念确实被编码了但体现在哪一个维度上跟实体有什么关系完全不清楚。更麻烦的是实体类型信号。比如“苹果”可能是水果、也可能是公司在关系分类场景里它到底是哪一类对预测帮助极大。预训练模型对类型是有一定隐式感知的比如“苹果公司”组合出现时它可能倾向于公司类型但如果我们显式注入“苹果是一个ORG机构实体”这一信息模型在解码关系时就能更确信地走“总部位于”“成立于”这类关系分支。实体位置信息也经常被忽略。两个实体谁先出现、距离多远、中间隔着哪些词决定了关系的方向性。“李明毕业于某大学”和“某大学聘用李明”语义方向完全不同。模型如果不知道e1出现在第2个token、e2出现在第8个token它很难区分head和tail的角色最终学出来的表示可能混淆方向。把这些问题归纳起来实体信息可以拆成四类实体边界信息实体在句子中占哪些token哪里开始哪里结束实体类型信息实体属于人、机构、地点、产品、时间等哪个类别实体位置信息e1与e2的位置关系、相对距离、谁在左谁在右实体上下文信息实体周围的局部语境比如“位于”“成立于”“收购”等触发词论文的核心主张就是把这四类信号分别建模并且用尽可能小的改动把它们塞进预训练模型里而不是推翻预训练结构重新设计一个实体感知架构。1.3 这篇论文的总体思路论文的做法可以概括为“三处注入、一处辅助”在输入层注入实体标记和类型嵌入在编码层用位置感知的注意力机制注入实体相对位置在池化层分别抽取两个实体的表示并做交互同时在输出层增加一个辅助的实体分类任务让模型在训练时被迫关注实体本身的语义。为什么这样设计而不是直接微调因为微调BERT做关系分类时模型虽然能拿到整句表示但梯度信号必须穿过整个序列才能影响到实体相关位置的向量如果训练数据不够大或者关系类别很多模型很容易偷懒只靠句法模板和表面词预测而不是真正理解实体交互。显式注入实体信息相当于把模型的目光“钉”在实体上让它不能忽略最关键的输入信号。这个思路后来被很多工作吸收。它好就好在没有引入任何外部知识库、没有改预训练目标、没有增加太多计算量只是在表示层面做定向增强。当年我用一个基础版复现在公开数据集上的增益非常显著这也说明任务本身确实缺少实体归纳偏置。2. 核心方法拆解实体信息是怎么一步步注入的2.1 输入层的实体标记与类型信息注入输入层是改动最直观的一处。原论文的做法是在两个实体的首尾分别插入特殊标记。具体来说用E1_start和E1_end包裹住第一个实体用E2_start和E2_end包裹第二个实体例如[CLS] 某公司 E1_start 在 上海 E1_end 设立 研发中心 [SEP] E2_start 上海 E2_end [SEP]等等这里面有个细节要注意实体标记token加在什么位置不同实现有区别。原论文采用的方式是把第一个实体在原句位置处包起来第二个实体则额外追加到句子末尾中间用SEP分隔。这么做的好处是可以让模型同时看到完整的上下文句子和独立的尾部实体片段尾部实体不会打断原句的连续性。我当时看完这个设计的第一反应是为什么第二个实体要复制一份放到末尾而不是在原生位置插入标记后来复现和对比实验发现如果是对话类文本标点符号密集、实体穿插频率高在原位插入标记可能让token序列变得非常碎片化而把tail实体单拎出来放尾部模型可以单独学习它的独立表示在多头注意力中也能更稳定地把head上下文和tail表示对齐。当然这个设计并不是唯一解很多后续工作直接在原位置插入实体标记效果也过得去。类型信息怎么注入原论文在每个实体起始标记之后紧接着放入一个实体类型token比如“ORG”“PER”“LOC”来源是数据集的NER标注或命名实体识别结果。在输入表示层面这个类型token和其他token一样有token embedding、position embedding和segment embedding只是它的语义内容就是实体类型标签。模型通过自注意力机制自然会把“类型信号”传播到实体内部的每个token以及全句相关位置上。做这个操作时词表里需要新增4个特殊entity marker token和若干类型token。新增token的embedding是随机初始化的所以训练时要注意给足warmup和训练步数否则这几个token学不好整条注入链路就废了。2.2 编码层的注意力偏置与位置信息注入输入层的标记解决了边界和类型但位置信息还没有被显式建模。原论文在Transformer的多头自注意力层中引入了一个和相对位置有关的注意力偏置项。思路说起来很简单e1内部token、e2内部token、外部普通token之间根据它们在实体角色上的相对位置关系分别加上不同的注意力偏置bias。具体来说可以把token对的关系分成若干桶两个token同属于e1内部两个token同属于e2内部一个token属于e1、另一个属于e2一个token在e1内部、另一个是外部普通词等等每一类分配一个可学习的标量bias在计算注意力分数时直接加进去。它的效果非常直白模型在注意力打分时天然给“同一个实体的内部词”以及“head实体和tail实体之间”更高的权重不需要等训练数据自己慢慢学到这种归纳偏置。这个设计等价于把实体相对位置编码成了离散桶。相对于正弦位置编码或者绝对位置向量它更聚焦于实体交互本身而不是绝对坐标。我在实际使用中体会最深的是当句子特别长、实体相隔特别远时没有这个偏置的模型经常把注意力分散到中间一大堆无关词上加上偏置之后head和tail之间的注意力脉冲非常清晰收敛快了很多。需要提醒的是这个注意力偏置的实现方式不同效果会略有差别。有的实现直接改attention_mask加常数有的在attention score上加可学习bias有的做成multi-bucket的相对位置编码。理论上后者更接近原意但实验上差异不算太大适合自己手上工程选型。2.3 池化层的实体表示抽取与交互建模输入层和编码层负责把实体信号混合进上下文表示但分类最终需要一个定长的向量。原论文没有简单用CLS而是同时抽取两个实体子序列的表示用实体级别的池化把它们压成两个向量然后拼接、融合喂给分类器。具体做法是从最后一层hidden states中取出e1对应位置的所有token表示含起始标记、尾部标记、内部token做某种池化。论文里用的是max pooling但后续很多复现改用mean pooling或者直接取实体起始标记的隐状态效果各有优劣。我自己做对比时发现对于较长实体mean pooling更稳对于较短实体max pooling能突出关键维度。拿到head向量和tail向量后论文用了一种比较朴素的融合方式直接拼接再接一个全连接层和softmax。没有复杂的双向attention或者bilinear层。这个选择很务实因为编码层已经做了大量实体交互建模池化层再叠复杂结构边际收益很低反而容易过拟合。实体交互怎么体现其实在池化层的拼接向量里head和tail各自独立的表示被强行放到同一个向量空间分类器必须同时基于两者做决策。如果只是把CLS向量拉出来用实体交互被埋没在全句混合表示中预测头会偏向于“句子特征”而不是“实体对特征”。加上这层实体级池化之后分类器对实体对的指向性更强。我自己还试过在池化层加一个简单的双线性层让head和tail做外积交互在TACRED这种类别多、数据量大的数据集上略有提升在小数据集上容易过拟合。所以原论文的朴素拼接其实是更通用的选择。2.4 输出层的辅助任务多任务学习实体信息注入不只是影响分类头原论文还在训练阶段加了一个辅助任务对e1和e2分别做一次实体类型分类判断它们的类型标签PER、ORG、LOC等。这个辅助任务的输出和关系分类输出共享底层的编码表示也就是说模型在训练时一方面要预测关系另一方面还要预测实体类型。这两个loss相加共享梯度回传。这样做的好处非常明显关系分类数据本身就带有实体标注信息否则无从给出实体对这些实体类型标签如果不利用相当于白白浪费监督信号。通过辅助任务模型被迫在表示空间里保留实体类型维度的判别信息而这些信息对关系分类往往是有益的。我们在做迁移实验时发现如果只跑关系分类主loss模型可能学到一种“偷懒表示”把所有实体都编码成相似向量只依赖上下文中的触发词做判断。加上辅助实体分类loss之后实体表示被拉出类型区分度最终关系分类准确率也上去了。辅助任务还有一个额外的好处可以作为训练是否正常的检查点。训练早期如果辅助loss下降正常但主loss卡住十有八九是数据预处理出了问题比如实体标记错位、标签对错。2.5 消融视角下每种实体信息的独立贡献论文做了消融实验分别去掉标记嵌入、去掉类型嵌入、去掉注意力偏置、去掉辅助loss看各自对最终F1的影响。结果很有启发性去掉实体标记嵌入性能下降明显说明边界信息是模型理解实体的地基去掉类型嵌入下降也比较明显说明类型信息对长尾关系尤其重要去掉位置感知注意力在小数据集上下降不大但在长句和复杂嵌套句上下降明显去掉辅助loss整体下降幅度最小但稳定性和可迁移性受损这些结论我基本都复现出来了。我额外发现类型嵌入的作用非常依赖数据集的类型标注质量。如果类型标注噪声大比如把“学校”标成“机构”而不是“教育机构”模型反而可能受误导。所以在使用这份方案时我一般会先评估实体标签质量和类别混淆情况再决定要不要把类型信息权重调大。3. 实验设计与效果分析不是简单加个标记就完事3.1 评测数据集怎么选、怎么划分论文的实验用了两个经典关系分类数据集SemEval-2010 Task 8和TACRED。SemEval-2010 Task 8的规模不大训练样本大约8000多条关系类别是19类9个大关系方向外加10个带方向后缀的细分类比如Cause-Effect(e1,e2)和Cause-Effect(e2,e1)是不同的类别。它最大的特点是句子短、实体标注规范、类别边界清晰比较适合验证模型的基础能力。它还有一个Other类别占比不高不属于严重的长尾问题。TACRED则更接近真实场景数据主要来自新闻语料类别多达41类其中no_relation无关系占比极高大约占80%左右。这意味着模型一不小心就会把所有样本预测为无关系然后得到一个看似很高的准确率但F1低得可怜。TACRED更适合验证模型在长尾、方向敏感、类别不均衡场景下的鲁棒性。我复现时用了和原论文一致的五折交叉验证来调超参最终用固定测试集报结果。这里有个关键点TACRED的官方划分里训练集和测试集的实体类型分布有差异直接拿最优超参跑测试集会偏低。原论文也是先在小验证集上选模型再放到测试集上评估。自己做对比实验时如果对多个方法统一用同一个验证集选点公平性才有保障。3.2 基线与对比方案怎么设计才算公平关系分类的对比实验容易做得很不公平因为“加实体标记”这个操作看似简单但涉及词表变化、序列长度变化、训练步数变化任何一个维度不一致都可能让结果失真。设计对比方案时至少要考虑这四档第一档裸BERT微调输入就是“CLS句子SEP”CLS向量分类第二档裸BERT加实体标记输入中用特殊token标记实体位置但CLS向量分类第三档BERT加实体标记加实体级池化但不用类型嵌入和辅助loss第四档完整方案类型嵌入、位置注意力、辅助loss全上四档之间逐一对齐词表、训练步数、batch size、学习率。我当时复现时发现很多公开代码只对比了第一档和第四档中间档缺失导致无法判断增益到底来自哪个组件。论文里对消融实验的描述比较完整这是它值得当作baseline范本的原因之一。3.3 数值结果怎么读原论文报告的SemEval-2010 Task 8上F1大约在84%左右相比当时的主流SOTA有2-3个点的提升。TACRED上效果更明显F1大概从六十出头提到了接近七十。这两个数字放到今天看不算惊艳但放在当时环境里用同一个BERT底座、只加实体信息就能拿到这个增益是非常划算的改造成本。读实验结果时不要只盯总F1要看困难子集上的表现。我自己统计过模型最容易提升的是两类样本实体距离比较远的样本以及关系方向敏感的样本。前者靠位置注意力偏置解决后者靠实体级池化让模型看到head和tail的独立表示。还有一个容易忽略的细节类别不均衡对F1的影响。在TACRED里近80%样本是no_relation如果直接做标准交叉熵模型会疯狂偏向于预测多数类。原论文虽然没有专门处理这个问题但实体辅助loss在某种程度上有缓解作用因为即使样本是no_relation实体类型标签还是能给模型提供“这个实体对确实被标注过、值得认真判别”的信号。3.4 论文方法不能覆盖的坑这个方法有明显的边界它假设输入句子已经给出了可靠的实体边界和实体类型。如果NER结果本身不可靠错误标注的实体标记和类型信息会直接污染编码过程甚至比不注入还差。实际项目里我遇过更现实的坑实体类型标签不齐。某些数据集只标注了实体位置没有标注实体类型强行补一个“UNK”类型塞进去效果反而不如只用标记嵌入。所以不是所有场景都适合全套注入信息不全时应该退回到只做边界标记和实体级池化的简化版。4. 复现级实操笔记从论文到可运行代码4.1 环境与依赖复现这篇论文不需要太重的环境基础配置如下Python 3.8以上PyTorch 1.8以上CUDA 11以上如果显存不够CPU也可以跑通小批量只是慢Transformers库建议4.x以上数据集SemEval-2010 Task 8、TACRED或者自己构造的训练数据显存方面BERT-base的序列长度128、batch size 16大概需要8G左右显存。如果开长短序列混合训练TACRED里长句多建议直接上16G。4.2 预处理阶段的细节预处理是整个复现最容易出错的地方我踩过四类坑。第一个坑是tokenizer切分对齐。实体边界是按字符或词给出的但BERT的tokenizer会做subword切分比如“上海”在中文里大概是单token但英文的“organization”可能被切成“organ”和“ization”两段。如果不做对齐实体起始标记就会落错位置。标准做法是先对整个句子做tokenizer切分然后逐个token判断它是否落在实体字符范围内只有实体起始的第一个token前面插E1_start实体结尾的最后一个token后面插E1_end。第二个坑是实体尾部单独拼接时的segment id分配。原论文把tail实体放到第二段意味着tail实体的segment id是1主句是0。如果你的预训练模型对segment embedding敏感这个分配必须和训练时保持一致。我见过有复现代码两段都用0结果效果掉了快一个点。第三个坑是序列长度上限。插入实体标记和尾部实体复制会显著增加token数量如果原句子本来就长很容易超过512上限被截断。截断策略很关键我建议优先保住主句里两个实体的原始位置尾部实体如果太长也要截到一定长度不能让尾部实体完全消失。第四个坑是位置编码对齐。加特殊token之后普通token的绝对位置编号会整体后移模型感知的实体相对位置也随之改变。如果复用预训练模型的position embedding新插入token的position embedding要重新初始化训练时不冻结要给足训练轮数让它们收敛。4.3 关键超参数配置跑关系分类我固定的基线配置如下学习率2e-5配合线性warmupwarmup步数占总步数的10%左右batch size16到32之间TACRED建议32训练轮数3到5轮小数据集SemEval可以到5轮TACRED 3轮后就开始过拟合max length128SemEval或256TACRED辅助loss权重0.1到0.5之间我常用0.3有个容易被忽略的参数是attention score的scale。原论文改注意力偏置时如果直接把bias加到softmax前的score上bias的量级需要和query-key点积的输出量级匹配否则很容易把softmax推向饱和区让注意力分布过于尖锐。实践里我一般把新增的bias初始化成0训练中让模型自己调节比手工设初始值稳定得多。4.4 如何判断复现是否成功论文没有给出官方复现代码至少我当年找的时候没有所以复现结果和原报告有1个点左右的浮动完全正常。判断复现成功的标准不是“和论文完全一样”而是消融趋势一致完整方案应该显著高于裸微调去掉类型嵌入的版本应该比完整方案低但高于裸微调去掉实体池化的版本应该明显下降辅助loss去掉后总F1可能小幅下降如果你复现出来“去掉实体池化反而更高”大概率是池化实现有问题或者是训练步数不一致导致的假象。我自己遇到过类似现象原因是实体级池化的向量维度过低分类头过拟合减少步数后反而更好。解决办法是检查拼接后的向量维度以及分类头是否加了dropout建议0.1到0.3。5. 常见问题与排查技巧实录5.1 实体标记错位与NA类主导工作中最常遇到的第一个问题是实体标记错位。你辛辛苦苦做了字符级别的对齐但中文场景下如果实体边界来自词表切分而不是字符精确匹配很容易出现偏差。我通常会在预处理阶段加一个自检函数遍历每个样本确认E1_start和E1_end之间的token片段对应的原始文本和原实体的字符一致不一致直接报警。第二个是NA类无关系类主导。关系分类数据里如果无关系样本占比超过70%模型很容易陷入“全部预测NA”的局部最优。两个有效办法一是对训练时无关系样本做下采样控制在总样本的50%以内二是在loss里给正类有关系的类别加权。原论文没提这些但在真实项目中必须处理。5.2 常见问题速查表问题表现可能原因排查思路训练loss下降但F1不变实体标记错位模型没学到实体感知检查预处理自检输出几个badcase可视化去掉类型嵌入反而更好实体类型标签噪声大统计类型标签的分布和混淆考虑降权长句子预测效果差位置注意力偏置未实现或bias初始值不合适检查多头注意力中bias是否加在正确位置辅助loss正常但主loss发散学习率过大降低学习率到1e-5或在分类头加dropout实体距离远时F1显著下降序列被截断导致尾部实体丢失调整截断策略保证尾部实体不丢还有一个我特别想说的技巧训练阶段在验证集上观察每类别的F1如果发现某个长尾关系类别一直预测不出来不需要急着加数据可以先看这类样本里实体类型分布。往往你会发现这类关系的实体对类型组合很特殊比如“人物-作品”关系里“人物”大多是人名实体“作品”大多不是标准实体。此时在实体类型嵌入层面做特殊处理比如把作品类实体的类型嵌入换成语义更强的小类效果可能立竿见影。5.3 调试时的可视化小工具调试实体感知模型时我强烈建议把注意力可视化拉出来看一眼。具体做法取一个短样本把多头注意力的第几层、某几个head的权重矩阵输出看看e1内部的token是否和e2内部的token有强连接。正常情况下加了位置感知注意力偏置的模型中高层会有一个或几个head专门负责“实体到实体”的连接注意力分数明显高于其他位置。如果训练完没有出现这种模式说明偏置没有真正生效或者被其他训练信号压制了。我当时就是靠这个可视化发现自己的bias只在某一层生效其他层的bias退化成0修复之后F1涨了近一个点。6. 这个思路的后续影响和我的实际使用体会6.1 后续工作的吸收与演变熟悉这个方向的人都知道实体信息注入的思路后来在几个方向上不断演进。一个方向是把相对位置编码细化成连续值而不是离散桶让模型对实体距离的感知更精细另一个方向是把实体类型信息换成外部知识库中的实体描述或实体向量做成动态记忆或者检索增强还有一个方向是把实体级池化换成更复杂的实体交互层比如双线性attention或者图结构建模。这些后续工作都继承了这篇论文的核心理念预训练模型提供通用语义底座实体信息负责把底座“定向激活”到关系分类任务上。这个理念在文档级关系抽取、事件抽取、对话关系抽取里也都被反复验证过基本成了信息抽取任务做表示增强的默认起手式。6.2 实际项目中如何选型什么时候用我接手过若干信息抽取项目选型经验直接说结论。如果任务数据量很小几千条实体类型标注也不全全套实体注入方案不一定最优我建议只做“实体标记实体池化”放弃类型嵌入和辅助loss训练速度更快、泛化更稳。如果数据量中等几万条实体类型标注可靠全套方案收益最明显尤其是关系类别多、方向敏感的场景。如果数据量很大几十万条以上实体类型信息往往可以从已有NER管线或规则获得但此时普通微调可能已经足够强实体注入带来的相对提升会变小。不过作为稳定性的保障我还是建议保留实体标记和实体池化这两个组件基本没有副作用。6.3 个人体会别只把它当trick最后说点个人体会。这篇文章第一次读完觉得平平无奇不过是一些工程技巧的组合。但等我自己从头实现、做消融、换数据集验证之后才意识到它厉害的地方在于“克制”每个组件都针对一个明确的实体感知短板不多不少没有华而不实的结构。与其说它是实体感知增强方案不如说它是一套教会我们“如何把任务先验注入预训练模型”的方法论。而且这个方法论可以迁移到很多任务事件抽取里给事件触发词加标记指代消解里给实体链加类型信息文本分类里给核心论元加位置感知本质上都是同一个套路。所以我现在带新同学读论文第一篇经常就是这篇学的不是模型架构是怎么拆解任务、设计注入点、做严谨的消融对比。这套思路比记住一个具体模型重要得多。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑