关系抽取概述:有监督、半监督、无监督方法

关系抽取这事儿,说白了就是从一大段文本里找出两个实体之间有什么“瓜葛”。比如“阿司匹林抑制COX-2”,这里“阿司匹林”和“COX-2”之间的“抑制”关系,就是我们要抓的东西。

我个人在多个项目中体会最深的一点是:没有万金油的方法。标注数据多,有监督是首选;标注少但领域专家有思路,半监督能救命;啥都没有,那就只能上无监督做探索。你想想看,现实中大部分场景都是缺标注的,所以搞清楚每种方法的适用边界,比背十个模型重要得多。

核心观点:选择哪种方法,不只看算法性能,更要看你的数据条件、标注成本和业务容忍度。

下面这张图我经常拿来给新同学讲。它把三种方法的核心流程放在一起对比,一看就明白各自是怎么运转的。

关系抽取三种方法核心流程对比 有监督方法 标注语料(实体+关系标签) 特征工程 / 神经网络编码 分类器(SVM / CNN / BERT) 半监督方法 少量种子规则 / 标注样本 Bootstrapping / 远程监督 迭代扩充 + 去噪过滤 无监督方法 无标注大规模语料 聚类 / 模式挖掘 / 统计共现 发现潜在关系类型 三种方法特点对比 有监督: 标注成本高,精度上限也高。适合知识库成熟、有持续标注渠道的团队。 我常用的做法:先跑小批标注, 看看一致性, 再决定是否全量标注。 半监督: 用种子拉新,但噪音是最大的敌人。迭代中必须引入筛选或置信度评估。 无监督: 发现未知关系有价值,但关系类型需要人工后验命名。适合探索性分析。

有监督学习:数据量和模型决定上限

有监督方法是最直观的。你给它一堆已经标好“头实体-关系-尾实体”的句子,它学一个分类器。我在项目里用过基于CNN和BERT的模型,前者快,后者准。

小技巧:如果你只有少量标注,别硬套CRF + BERT。可以试试冻结BERT底层,只训分类头,收敛快还省显存。

有监督的常见做法,我列个清单给你看。

  1. 流水线方法:先做NER,再做关系分类。结构简单,但会传错误差。
  2. 联合抽取:用一个模型同时做实体和关系。我用案例时发现,联合模型在小样本上更容易过拟合。
  3. 基于预训练模型: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$ 这样的。

注意:有监督方法很容易被标注不一致坑倒。我曾经遇到一个项目,两个标注员对“抑制”和“拮抗”的边界划分有分歧,结果模型F1死活上不到80。后来统一标注规范才解决。

半监督学习:用少量种子撬动大规模抽取

半监督方法的核心是“用种子引导,自动膨胀”。比如你给3个关系模板:X 抑制 Y、X 激活 Y、X 结合 Y。然后从语料里找到匹配这些模式的句子, 抽出来的新三元组再去扩展模式。

这里我重点说两种主流思路。

方法一方法二
Bootstrapping远程监督 (Distant Supervision)
从少量种子出发,交替抽取实体对和模式利用已有知识库(如DrugBank)在文本中自动标记
容易产生语义漂移,需要人工定期审查假设强:知识库中相关的一对实体在语料中一定存在对应关系——实际上很有噪音
我试过在PubMed摘要上用bootstrapping抽药物副作用,第一轮很好,三圈之后全跑偏了远程监督我一般会用多实例学习(Multi Instance Learning)来缓解噪音,而不是直接取单句
避坑指南:我曾经把远程监督结果直接用,发现近40%的标注是错的。后来加了两个过滤手段:句子置信度阈值 + 知识库对齐检查,才把精度拉到83%左右。

无监督学习:从文本中发现潜在关系

无监督方法不需要任何标注。它做的是:先找所有共现实体对,然后根据上下文句子进行聚类。同一类簇里的实体对,可能共享一种关系类型。

具体步骤通常是这样:

  1. 从语料中提取所有包含两个实体的句子。
  2. 对每个实体对,把出现该对的上下文向量化(例如用Sentence-BERT)。
  3. 对所有实体对做聚类(KMeans、DBSCAN都好用)。
  4. 每一类簇人工定义为一种关系类型。

在实际中,无监督方法很难直接上生产,但用来做关系类型探索很顺手。我有个项目,一开始不知道药物和靶点之间到底有哪些关系可抽,就是用无监督聚类发现了好几种未预料到的相互作用类型。

不过它有明显的短板:

  • 聚类数量需要预设或调参,DBSCAN对密度敏感。
  • 关系类型需要人工命名。算法告诉你哪些是一类,但不告诉你“这类叫什么”。
  • 低频实体对容易被忽略,聚类里只有少数样本。

评估与选型建议

三种方法各有优劣。我整理了一个速查表,你可以参考:

维度有监督半监督无监督
标注需求高(千条以上)低(几十条种子)无
精度上限高(BERT可达90%+)中高(70%-85%)低(依赖聚类解释)
可发现新关系否有限是
工程复杂度中高(迭代控制难)中
适用场景知识库构建、精确抽取快速冷启动、领域适应探索分析、关系发现

我个人习惯是:先做一个小规模无监督探索,看看语料里到底存在哪些关系类型;如果有条件标注,就用少量种子启动半监督迭代;等数据积累到一定规模,再切换到有监督做精炼。

给新手的建议:不要一上来就追求最复杂的有监督模型。你想想看,如果连关系类型都没摸清,堆模型只是在浪费算力。

好,这一章我们重点梳理了三种关系抽取方法的基本逻辑和适用条件。下一步你要做的,是根据自己手头的数据条件,选一条路先跑起来。哪怕只是无监督聚类出一个结果,也比空等标注强得多。