关系抽取概述:有监督、半监督、无监督方法
关系抽取这事儿,说白了就是从一大段文本里找出两个实体之间有什么“瓜葛”。比如“阿司匹林抑制COX-2”,这里“阿司匹林”和“COX-2”之间的“抑制”关系,就是我们要抓的东西。
我个人在多个项目中体会最深的一点是:没有万金油的方法。标注数据多,有监督是首选;标注少但领域专家有思路,半监督能救命;啥都没有,那就只能上无监督做探索。你想想看,现实中大部分场景都是缺标注的,所以搞清楚每种方法的适用边界,比背十个模型重要得多。
下面这张图我经常拿来给新同学讲。它把三种方法的核心流程放在一起对比,一看就明白各自是怎么运转的。
有监督学习:数据量和模型决定上限
有监督方法是最直观的。你给它一堆已经标好“头实体-关系-尾实体”的句子,它学一个分类器。我在项目里用过基于CNN和BERT的模型,前者快,后者准。
有监督的常见做法,我列个清单给你看。
- 流水线方法:先做NER,再做关系分类。结构简单,但会传错误差。
- 联合抽取:用一个模型同时做实体和关系。我用案例时发现,联合模型在小样本上更容易过拟合。
- 基于预训练模型:BERT / SciBERT / BioBERT 在生物医学领域很好用,特别是加了领域语料的版本。
举个例子,如果用BioBERT做关系抽取,预处理和调用大致是这样:
from transformers import AutoTokenizer, AutoModelForSequenceClassification
model_name = "dmis-lab/biobert-base-cased-v1.1"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(
model_name, num_labels=len(relation_types)
)
text = "Aspirin [CLS] inhibits [SEP] COX-2 [SEP]"
inputs = tokenizer(text, return_tensors="pt")
outputs = model(**inputs)
pred = outputs.logits.argmax(dim=1).item()
这是简化版。真正上线时, 你还要考虑实体嵌入如何拼接到输入中。我习惯把实体起止位置用特殊标记包裹起来, 比如 @GENE$ 这样的。
半监督学习:用少量种子撬动大规模抽取
半监督方法的核心是“用种子引导,自动膨胀”。比如你给3个关系模板:X 抑制 Y、X 激活 Y、X 结合 Y。然后从语料里找到匹配这些模式的句子, 抽出来的新三元组再去扩展模式。
这里我重点说两种主流思路。
| 方法一 | 方法二 |
|---|---|
| Bootstrapping | 远程监督 (Distant Supervision) |
| 从少量种子出发,交替抽取实体对和模式 | 利用已有知识库(如DrugBank)在文本中自动标记 |
| 容易产生语义漂移,需要人工定期审查 | 假设强:知识库中相关的一对实体在语料中一定存在对应关系——实际上很有噪音 |
| 我试过在PubMed摘要上用bootstrapping抽药物副作用,第一轮很好,三圈之后全跑偏了 | 远程监督我一般会用多实例学习(Multi Instance Learning)来缓解噪音,而不是直接取单句 |
无监督学习:从文本中发现潜在关系
无监督方法不需要任何标注。它做的是:先找所有共现实体对,然后根据上下文句子进行聚类。同一类簇里的实体对,可能共享一种关系类型。
具体步骤通常是这样:
- 从语料中提取所有包含两个实体的句子。
- 对每个实体对,把出现该对的上下文向量化(例如用Sentence-BERT)。
- 对所有实体对做聚类(KMeans、DBSCAN都好用)。
- 每一类簇人工定义为一种关系类型。
在实际中,无监督方法很难直接上生产,但用来做关系类型探索很顺手。我有个项目,一开始不知道药物和靶点之间到底有哪些关系可抽,就是用无监督聚类发现了好几种未预料到的相互作用类型。
不过它有明显的短板:
- 聚类数量需要预设或调参,DBSCAN对密度敏感。
- 关系类型需要人工命名。算法告诉你哪些是一类,但不告诉你“这类叫什么”。
- 低频实体对容易被忽略,聚类里只有少数样本。
评估与选型建议
三种方法各有优劣。我整理了一个速查表,你可以参考:
| 维度 | 有监督 | 半监督 | 无监督 |
|---|---|---|---|
| 标注需求 | 高(千条以上) | 低(几十条种子) | 无 |
| 精度上限 | 高(BERT可达90%+) | 中高(70%-85%) | 低(依赖聚类解释) |
| 可发现新关系 | 否 | 有限 | 是 |
| 工程复杂度 | 中 | 高(迭代控制难) | 中 |
| 适用场景 | 知识库构建、精确抽取 | 快速冷启动、领域适应 | 探索分析、关系发现 |
我个人习惯是:先做一个小规模无监督探索,看看语料里到底存在哪些关系类型;如果有条件标注,就用少量种子启动半监督迭代;等数据积累到一定规模,再切换到有监督做精炼。
好,这一章我们重点梳理了三种关系抽取方法的基本逻辑和适用条件。下一步你要做的,是根据自己手头的数据条件,选一条路先跑起来。哪怕只是无监督聚类出一个结果,也比空等标注强得多。