人工智能之语言领域
第八章 关系抽取
文章目录
- 人工智能之语言领域
- [前言 关系抽取](#前言 关系抽取)
- [8.1 关系抽取概述](#8.1 关系抽取概述)
- [8.1.1 关系类型](#8.1.1 关系类型)
- [8.1.2 任务类型](#8.1.2 任务类型)
- [8.2 传统关系抽取方法](#8.2 传统关系抽取方法)
- [8.2.1 基于特征工程的方法](#8.2.1 基于特征工程的方法)
- [8.2.2 基于核函数的方法](#8.2.2 基于核函数的方法)
- [8.3 深度学习关系抽取方法](#8.3 深度学习关系抽取方法)
- [8.3.1 基于CNN的关系抽取:局部特征匹配](#8.3.1 基于CNN的关系抽取:局部特征匹配)
- [8.3.2 基于注意力机制的关系抽取](#8.3.2 基于注意力机制的关系抽取)
- [8.3.3 预训练模型在关系抽取中的微调](#8.3.3 预训练模型在关系抽取中的微调)
- [8.4 联合抽取技术](#8.4 联合抽取技术)
- [8.5 实战案例:金融领域"公司-产品-合作"关系抽取](#8.5 实战案例:金融领域“公司-产品-合作”关系抽取)
- 关系抽取挑战与前沿
- 小结
- 资料关注
前言 关系抽取
关系抽取(Relation Extraction, RE)属于自然语言处理中信息抽取 范畴,可以从非结构化文本中自动识别两个或多个实体之间的语义关系 。它是构建知识图谱、智能问答、风险控制等系统的基石。如果说命名实体识别(NER)回答"谁/什么 ",那么关系抽取回答"它们之间是什么关系"。本章将系统介绍关系抽取的任务形式、传统与深度学习方法、联合抽取技术,并通过金融领域实战案例完整演示端到端流程。
8.1 关系抽取概述
8.1.1 关系类型
关系抽取关注两类主要关系:
| 类型 | 说明 | 示例 |
|---|---|---|
| 语义关系 | 语言学定义的通用关系 | "位于"、"出生于"、"创始人是" |
| 实体间关联关系 | 领域特定业务关系 | "公司A 与 公司B 合作开发 产品X" |
常见标准关系集:
- ACE 2005 :
PER-SOC(社会关系)、ORG-AFF(组织隶属) - SemEval-2010 Task 8 :
Cause-Effect、Component-Whole - 中文金融关系 :
合作、投资、控股、供应
🌰 示例句子:
"阿里巴巴 (ORG)投资 了小鹏汽车 (ORG)。"
→ 抽取三元组:(阿里巴巴, 投资, 小鹏汽车)
原始文本
实体识别
(阿里巴巴, ORG)
(小鹏汽车, ORG)
关系分类
投资
阿里巴巴, 投资, 小鹏汽车
8.1.2 任务类型
| 类型 | 说明 | 数据来源 | 挑战 |
|---|---|---|---|
| 有监督关系抽取 | 使用人工标注的句子-关系对训练 | 专家标注数据集 | 标注成本高 |
| 远程监督关系抽取 | 利用知识库(如 Freebase)自动标注 | 知识库 + 文本语料 | 噪声标签(错误对齐) |
🔍 远程监督假设 :
若两个实体在知识库中有关系,则包含这两个实体的所有句子 都表达该关系。
❌ 问题:句子"马云创立了阿里巴巴"和"马云访问了阿里巴巴总部"都被标为
(马云, 创始人, 阿里巴巴),但后者不表达该关系。
8.2 传统关系抽取方法
8.2.1 基于特征工程的方法
核心思想:人工设计特征,输入分类器(如 SVM)。
常用特征:
- 词法特征:实体类型、词性、依存路径
- 句法特征:最短依存路径(Shortest Dependency Path, SDP)
- 上下文特征:实体前后窗口词
📐 示例:
句子:"马云 创立 了 阿里巴巴"
SDP:
马云 ← nsubj ← 创立 → dobj → 阿里巴巴特征向量:
[nsubj, dobj, "创立", PER, ORG]
python
# 伪代码:特征提取
def extract_features(sentence, e1, e2):
features = {
'e1_type': get_entity_type(e1),
'e2_type': get_entity_type(e2),
'between_words': get_words_between(e1, e2),
'dependency_path': get_dependency_path(e1, e2)
}
return features
✅ 优点:可解释性强
❌ 缺点:依赖 NLP 工具(分词、句法分析),泛化能力弱
8.2.2 基于核函数的方法
思想:通过核函数(Kernel)直接计算句子相似度,避免显式特征工程。
- 子树核(Subtree Kernel):比较句法树子结构
- 卷积核(Convolution Kernel):组合多源特征
📊 在 SemEval 等早期竞赛中表现优异,但实现复杂,已被深度学习取代。
8.3 深度学习关系抽取方法
8.3.1 基于CNN的关系抽取:局部特征匹配
原理:将句子视为词向量序列,用 CNN 提取局部 n-gram 特征。
关键技巧 :位置嵌入(Position Embedding)
- 为每个词添加相对于两个实体的相对距离
- 帮助模型聚焦实体附近信息
词序列 + 实体位置
Word + Position Embedding
Multi-size CNN
Max Pooling
全连接+Softmax
关系类别
python
import torch
import torch.nn as nn
class CNNRelationExtractor(nn.Module):
def __init__(self, vocab_size, embed_dim=128, pos_embed_dim=16, num_relations=10, kernel_sizes=[2,3,4]):
super().__init__()
self.word_embed = nn.Embedding(vocab_size, embed_dim)
self.pos1_embed = nn.Embedding(2*MAX_LEN, pos_embed_dim) # 相对位置范围 [-L, L]
self.pos2_embed = nn.Embedding(2*MAX_LEN, pos_embed_dim)
self.convs = nn.ModuleList([
nn.Conv2d(1, 100, (k, embed_dim + 2*pos_embed_dim)) for k in kernel_sizes
])
self.dropout = nn.Dropout(0.5)
self.fc = nn.Linear(100 * len(kernel_sizes), num_relations)
def forward(self, words, pos1, pos2):
# words: [B, L], pos1/pos2: [B, L]
w_emb = self.word_embed(words) # [B, L, D]
p1_emb = self.pos1_embed(pos1) # [B, L, P]
p2_emb = self.pos2_embed(pos2) # [B, L, P]
x = torch.cat([w_emb, p1_emb, p2_emb], dim=2) # [B, L, D+2P]
x = x.unsqueeze(1) # [B, 1, L, D+2P]
xs = []
for conv in self.convs:
c = torch.relu(conv(x)).squeeze(3) # [B, F, L-k+1]
p = torch.max_pool1d(c, c.size(2)).squeeze(2) # [B, F]
xs.append(p)
x = torch.cat(xs, 1)
x = self.dropout(x)
return self.fc(x)
✅ 优势:并行计算快,擅长捕捉关键词组合
❌ 劣势:忽略长距离依赖和全局结构
8.3.2 基于注意力机制的关系抽取
思想:让模型自动关注对关系判断最重要的词。
- 自注意力(Self-Attention):计算词间相关性
- 实体为中心的注意力:以两个实体为查询,加权句子其他部分
python
class AttentionRE(nn.Module):
def __init__(self, hidden_dim, num_relations):
super().__init__()
self.attn = nn.MultiheadAttention(hidden_dim, num_heads=8, batch_first=True)
self.fc = nn.Linear(hidden_dim, num_relations)
def forward(self, h, e1_idx, e2_idx):
# h: [B, L, H] (e.g., from BiLSTM)
# 以 e1 和 e2 的表示作为 Query
query = torch.stack([h[torch.arange(h.size(0)), e1_idx],
h[torch.arange(h.size(0)), e2_idx]], dim=1) # [B, 2, H]
attn_out, _ = self.attn(query, h, h) # [B, 2, H]
sentence_rep = attn_out.mean(dim=1) # [B, H]
return self.fc(sentence_rep)
💡 注意力权重可可视化,提升模型可解释性。
8.3.3 预训练模型在关系抽取中的微调
主流方案:BERT + 分类头
输入格式(标记实体位置):
[CLS] 马云 [E1] 创立 [/E1] 了 [E2] 阿里巴巴 [/E2]。[SEP]
或使用实体类型标记:
[CLS] 马云 (PER) 创立 了 阿里巴巴 (ORG)。[SEP]
python
from transformers import AutoTokenizer, AutoModel
import torch.nn as nn
class BertForRE(nn.Module):
def __init__(self, model_name, num_relations):
super().__init__()
self.bert = AutoModel.from_pretrained(model_name)
self.dropout = nn.Dropout(0.1)
self.classifier = nn.Linear(self.bert.config.hidden_size, num_relations)
def forward(self, input_ids, attention_mask):
outputs = self.bert(input_ids=input_ids, attention_mask=attention_mask)
cls_output = outputs.last_hidden_state[:, 0] # [CLS] 向量
logits = self.classifier(self.dropout(cls_output))
return logits
# Tokenizer 处理带标记的句子
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
text = "马云 [E1] 创立 [/E1] 了 [E2] 阿里巴巴 [/E2]。"
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
🌐 中文推荐:
hfl/chinese-roberta-wwm-ext(性能优于原生 BERT)
8.4 联合抽取技术
传统流水线(先 NER 再 RE)存在错误传播 问题:NER 错 → RE 必错。
联合模型同时优化两个任务,提升整体性能。
8.4.1 实体识别与关系抽取联合模型
主流架构:
- 共享编码器 + 多任务头
- BERT 编码 → NER 头(CRF) + RE 头(分类)
- 基于指针网络(Pointer Network)
- 直接预测实体起止位置和关系
- 基于表格填充(Table Filling)
- 构建 token-token 矩阵,每个单元格预测关系
输入文本
BERT Encoder
NER Head: CRF
RE Head: 分类器
实体列表
关系列表
三元组
开源实现推荐:
- CasRel(2020):基于关系的指针网络
- TPLinker(2020):统一处理重叠关系
- PURE(2020):先抽实体再配对,但联合训练
8.4.2 联合模型的训练与优化
损失函数:多任务加权损失
L = λ 1 L N E R + λ 2 L R E \mathcal{L} = \lambda_1 \mathcal{L}{NER} + \lambda_2 \mathcal{L}{RE} L=λ1LNER+λ2LRE
训练技巧:
- 课程学习:先训 NER,再联合微调
- 对抗训练:提升鲁棒性(如 FGM、PGD)
- 解码约束:确保关系两端是有效实体
8.5 实战案例:金融领域"公司-产品-合作"关系抽取
任务目标
从新闻/公告中抽取三元组:
(公司A, 合作, 公司B) 或 (公司, 发布, 产品)
🌰 示例:
"腾讯 与华为 宣布合作开发鸿蒙版微信 。"
→ 三元组1:
(腾讯, 合作, 华为)→ 三元组2:
(腾讯, 发布, 鸿蒙版微信)→ 三元组3:
(华为, 发布, 鸿蒙版微信)
数据准备
使用公开金融关系数据集 FinRE(或自行标注)。
BERT 微调
python
# Step 1: 定义关系类型
RELATIONS = ["合作", "投资", "控股", "发布", "供应", "竞争", "无关系"]
rel2id = {r: i for i, r in enumerate(RELATIONS)}
# Step 2: 构造带标记的输入
def mark_entities(text, e1_start, e1_end, e2_start, e2_end, e1_type, e2_type):
# 在实体前后插入特殊标记
chars = list(text)
# 从后往前插入,避免索引偏移
chars.insert(e2_end, f"[/E2:{e2_type}]")
chars.insert(e2_start, f"[E2:{e2_type}]")
chars.insert(e1_end, f"[/E1:{e1_type}]")
chars.insert(e1_start, f"[E1:{e1_type}]")
return "".join(chars)
# 示例
text = "腾讯与华为合作开发鸿蒙版微信"
marked = mark_entities(text, 0, 2, 3, 5, "ORG", "ORG")
# 输出: "[E1:ORG]腾讯[/E1:ORG]与[E2:ORG]华为[/E2:ORG]合作开发鸿蒙版微信"
# Step 3: Tokenize & 训练
from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer
tokenizer = AutoTokenizer.from_pretrained("hfl/chinese-roberta-wwm-ext")
model = AutoModelForSequenceClassification.from_pretrained(
"hfl/chinese-roberta-wwm-ext",
num_labels=len(RELATIONS)
)
def tokenize_function(examples):
return tokenizer(
examples["marked_text"],
truncation=True,
padding=True,
max_length=128
)
# 假设 dataset 包含 "marked_text" 和 "label"(关系ID)
tokenized_datasets = dataset.map(tokenize_function, batched=True)
training_args = TrainingArguments(
output_dir="./fin-re-model",
evaluation_strategy="epoch",
learning_rate=2e-5,
per_device_train_batch_size=16,
num_train_epochs=5,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_datasets["train"],
eval_dataset=tokenized_datasets["test"],
)
trainer.train()
# Step 4: 预测新句子
def predict_relation(text, e1, e2, e1_type, e2_type):
marked = mark_entities(text, e1[0], e1[1], e2[0], e2[1], e1_type, e2_type)
inputs = tokenizer(marked, return_tensors="pt", padding=True, truncation=True, max_length=128)
with torch.no_grad():
logits = model(**inputs).logits
pred_id = logits.argmax().item()
prob = torch.softmax(logits, dim=1)[0][pred_id].item()
return RELATIONS[pred_id], prob
# 示例调用
relation, confidence = predict_relation(
"腾讯与华为合作开发鸿蒙版微信",
(0, 2), (3, 5), "ORG", "ORG"
)
print(f"关系: {relation}, 置信度: {confidence:.3f}")
# 输出: 关系: 合作, 置信度: 0.982
系统集成建议
- 前置 NER:用医疗/金融领域 NER 模型识别实体
- 实体配对:对同一句中所有实体对进行关系分类
- 后处理:过滤低置信度结果,合并重叠三元组
关系抽取挑战与前沿
| 挑战 | 解决方案 |
|---|---|
| 重叠关系(一个实体参与多个关系) | TPLinker、CasRel 等联合模型 |
| 少样本关系 | Prompt-tuning、原型网络 |
| 文档级关系(跨句) | 图神经网络(GNN)+ 文档编码 |
| 开放关系抽取 | 无预定义关系类型,聚类或生成式方法 |
小结
关系抽取从早期的特征工程发展到今天的预训练语言模型,已成为构建结构化知识的核心技术。BERT 微调 是当前工业界主流方案,而联合抽取模型 能有效缓解流水线错误传播问题。在金融、医疗、法律等专业领域,结合领域知识 和远程监督 是突破数据瓶颈的关键。未来,关系抽取将与大语言模型 、知识图谱补全 、多模态理解深度融合,迈向更精准、更开放的信息抽取。
资料关注
咚咚王
《Python 编程:从入门到实践》
《利用 Python 进行数据分析》
《算法导论中文第三版》
《概率论与数理统计(第四版) (盛骤) 》
《程序员的数学》
《线性代数应该这样学第 3 版》
《微积分和数学分析引论》
《(西瓜书)周志华-机器学习》
《TensorFlow 机器学习实战指南》
《Sklearn 与 TensorFlow 机器学习实用指南》
《模式识别(第四版)》
《深度学习 deep learning》伊恩·古德费洛著 花书
《Python 深度学习第二版(中文版)【纯文本】 (登封大数据 (Francois Choliet)) (Z-Library)》
《深入浅出神经网络与深度学习 +(迈克尔·尼尔森(Michael+Nielsen)》
《自然语言处理综论 第 2 版》
《Natural-Language-Processing-with-PyTorch》
《计算机视觉-算法与应用(中文版)》
《Learning OpenCV 4》
《AIGC:智能创作时代》杜雨 +&+ 张孜铭
《AIGC 原理与实践:零基础学大语言模型、扩散模型和多模态模型》
《从零构建大语言模型(中文版)》
《实战 AI 大模型》
《AI 3.0》