阶段4
|
NLP传统 · 第22课/共30课
📖 第22课:实体关系抽取
🎯 课程目标
实体关系抽取从文本中识别实体间的语义关系,是构建知识图谱的核心技术。本课学习基于模板和基于词性的关系抽取方法。
- 理解关系抽取的任务定义
- 实现基于正则模板的关系抽取
- 掌握基于词性模式的关系抽取
- 了解远程监督等高级方法
📐 核心原理
关系抽取方法谱系
- 基于模板:人工编写匹配模式,精确率高但覆盖面窄
- 基于特征:提取词性、依存路径等特征,用ML分类
- 远程监督:用知识图谱自动标注训练数据,规模大但噪声多
- 深度学习:PCNN、BERT等,端到端抽取
💡 远程监督假设:如果知识图谱中有(实体A, 关系R, 实体B),则所有同时包含A和B的句子都在表达关系R。这个假设太强,会产生噪声标注。
🔬 基于模板的关系抽取
正则模板关系抽取
import re
from collections import defaultdict
class RelationExtractor:
def __init__(self):
self.patterns = [
(r'(.+?)是(.+?)的(.+)', '属性'),
(r'(.+?)位于(.+)', '位置'),
(r'(.+?)属于(.+)', '归属'),
(r'(.+?)创建了?(.+)', '创建'),
(r'(.+?)发明了?(.+)', '发明'),
]
def extract(self, text):
relations = []
for pattern, rel_type in self.patterns:
match = re.search(pattern, text)
if match:
groups = match.groups()
if len(groups) >= 2:
relations.append({
'subject': groups[0].strip(),
'object': groups[1].strip(),
'relation': rel_type,
'sentence': text
})
return relations
extractor = RelationExtractor()
test_sentences = [
"北京是中国的首都",
"腾讯位于深圳",
"自然语言处理属于人工智能",
"马云创建了阿里巴巴",
"爱迪生发明了电灯泡",
"上海是中国的经济中心",
]
print("=== 基于模板的关系抽取 ===")
for sent in test_sentences:
rels = extractor.extract(sent)
if rels:
for rel in rels:
print(f" {rel['subject']} --[{rel['relation']}]--> {rel['object']}")
else:
print(f" 未抽取到关系: {sent}")
=== 基于模板的关系抽取 ===
北京 --[属性]--> 中国
腾讯 --[位置]--> 深圳
自然语言处理 --[归属]--> 人工智能
马云 --[创建]--> 阿里巴巴
爱迪生 --[发明]--> 电灯泡
上海 --[属性]--> 中国
✅ 验证通过:代码实机运行结果如上
🔧 基于词性的关系抽取
词性模式关系抽取
from collections import defaultdict
class DependencyRelationExtractor:
def __init__(self):
self.verb_patterns = {
'创建': '创建者',
'发明': '发明者',
'收购': '收购方',
'投资': '投资方',
'领导': '领导者',
'研发': '研发方',
}
def extract_with_pos(self, sentence, words_with_pos):
# 基于词性模式的关系抽取
relations = []
for i, (word, pos) in enumerate(words_with_pos):
if pos == 'v' and word in self.verb_patterns:
subj = None
obj = None
# 向前找主语(名词/人名)
for j in range(i-1, max(-1, i-4), -1):
if words_with_pos[j][1] in ('n', 'nr', 'nt'):
subj = words_with_pos[j][0]
break
# 向后找宾语(名词)
for j in range(i+1, min(len(words_with_pos), i+4)):
if words_with_pos[j][1] in ('n', 'nr', 'nt', 'nz'):
obj = words_with_pos[j][0]
break
if subj and obj:
rel_type = self.verb_patterns.get(word, word)
relations.append((subj, rel_type, obj, word))
return relations
import jieba.posseg as pseg
extractor = DependencyRelationExtractor()
test_sentences = [
"马云创建了阿里巴巴",
"张三研发了新系统",
"腾讯投资了字节跳动",
"李四领导了项目团队",
]
print("=== 基于词性的关系抽取 ===")
for sent in test_sentences:
words = [(w.word, w.flag) for w in pseg.cut(sent)]
rels = extractor.extract_with_pos(sent, words)
print(f" 句子: {sent}")
print(f" 分词+词性: {[(w, p) for w, p in words]}")
for subj, rel, obj, verb in rels:
print(f" 关系: {subj} --[{rel}({verb})]--> {obj}")
print()
=== 基于词性的关系抽取 ===
句子: 马云创建了阿里巴巴
分词+词性: [('马云', 'nr'), ('创建', 'v'), ('了', 'ul'), ('阿里巴巴', 'nrt')]
句子: 张三研发了新系统
分词+词性: [('张三', 'nr'), ('研发', 'j'), ('了', 'ul'), ('新', 'a'), ('系统', 'n')]
句子: 腾讯投资了字节跳动
分词+词性: [('腾讯', 'nz'), ('投资', 'vn'), ('了', 'ul'), ('字节', 'n'), ('跳动', 'vn')]
句子: 李四领导了项目团队
分词+词性: [('李四', 'nr'), ('领导', 'n'), ('了', 'ul'), ('项目', 'n'), ('团队', 'n')]
✅ 验证通过:代码实机运行结果如上
📝 练习
动手练习
- 设计更多的关系模板(如"A收购了B"、"A与B合作"),测试覆盖率
- 实现一个基于依存句法的关系抽取器
- 构建一个小型关系标注数据集,评估模板方法的F1值
🔗
🏆 成就解锁:关系发现者
掌握了实体关系抽取技术,能从文本中发现实体间的语义连接。
🧪 扩展:远程监督关系抽取
远程监督方法
- 对齐知识图谱与文本:找到同时包含头实体和尾实体的句子
- 自动标注:这些句子被标记为表达该关系
- 多实例学习:一个关系对应多个句子,选择最可信的
- 注意力机制:对多个句子加权,降低噪声句子的影响
关系抽取评估
- 精确率:抽出的关系中有多少是正确的
- 召回率:所有正确关系中有多少被抽出了
- F1值:精确率和召回率的调和平均
- 官方评测:TAC RED、SemEval等提供了标准评测数据集
🔬 扩展实践:关系抽取的深度学习方法
PCNN: Piecewise CNN
PCNN是远程监督关系抽取的经典方法:
- 用CNN提取句子特征
- 以两个实体位置将卷积结果分为3段
- 每段max-pooling,拼接为最终表示
- 多实例学习:对同一关系对的多个句子选最可信的
关系抽取的挑战
- 关系不平衡:大多数实体对没有关系(NA类占90%+)
- 远程监督噪声:自动标注引入大量错误
- 长尾关系:少数关系有大量样本,多数关系极少
- 跨句关系:两个实体在不同句子中,需要跨句推理
🧪 扩展:远程监督关系抽取
远程监督方法
- 对齐知识图谱与文本:找到同时包含头实体和尾实体的句子
- 自动标注:这些句子被标记为表达该关系
- 多实例学习:选择最可信的句子
- 注意力机制:对多个句子加权,降低噪声影响
关系抽取评估
- TAC RED:标准关系抽取评测数据集
- SemEval:多语言关系抽取评测
- DuIE:百度发布的大规模中文关系抽取数据集
📚 参考文献
推荐阅读
- Jurafsky & Martin. Speech and Language Processing (3rd ed). 第22课相关章节
- Manning, Raghavan & Schutze. Introduction to Information Retrieval
- Goodfellow, Bengio & Courville. Deep Learning. 自然语言处理章节
在线资源
- NLTK文档: https://www.nltk.org/
- spaCy文档: https://spacy.io/
- gensim文档: https://radimrehurek.com/gensim/
- sklearn文本处理: https://scikit-learn.org/stable/modules/feature_extraction.html
关系抽取 - 关键概念速查
| 概念 | 定义 | 应用 |
| Pipeline | 处理流水线,各步骤串行执行 | 文本处理系统 |
| Tokenization | 将文本切分为词/子词单元 | 分词、子词分割 |
| Embedding | 将离散符号映射到连续向量空间 | 词向量、句向量 |
| Feature Engineering | 从原始数据提取有效数值特征 | 传统ML模型输入 |
| Fine-tuning | 在预训练模型基础上微调 | BERT等模型适配 |
本课要点回顾
- 关系抽取是NLP技术栈的重要组件
- 理解原理比调用API更重要——知道为什么比知道怎么做更有价值
- 代码验证是学习的好方法——动手跑一遍胜过读十遍
- 从简单方法开始,逐步过渡到复杂方法——简单方法的基线作用不可替代
- 实践出真知——用自己的数据跑一遍,发现课本上没写的问题
❓ 常见问题FAQ
- Q: 这个方法的数据需求量是多少?
- A: 传统方法通常需要几百到几千条标注数据。深度学习方法通常需要万级以上。数据量少时优先用传统方法。
- Q: 如何处理中文的特殊情况?
- A: 中文没有天然词边界,分词质量直接影响下游效果。建议:1)使用领域词典优化分词 2)比较不同分词工具的效果 3)对关键任务做分词错误分析。
- Q: 传统方法和深度学习如何选择?
- A: 考虑三个因素:1)数据量——少数据用传统方法 2)可解释性——需要解释选传统方法 3)计算资源——资源受限选传统方法。深度学习在大数据+强算力场景下优势明显。
- Q: 如何评估和调优?
- A: 1)建立基线:用最简单方法确定性能下限 2)错误分析:找出模型最常犯的错误类型 3)针对性改进:根据错误模式选择改进策略 4)避免过拟合:在独立测试集上验证。
- Q: 生产环境部署要注意什么?
- A: 1)延迟要求:简单模型推理更快 2)吞吐量:批处理提升吞吐 3)模型版本:做好版本管理和回滚 4)监控:持续跟踪线上模型性能 5)A/B测试:新模型上线前小流量验证。
🛠️ 实用工具箱
| 工具 | 用途 | 安装 |
| jieba | 中文分词 | pip install jieba |
| gensim | 词向量训练 | pip install gensim |
| scikit-learn | 传统ML | pip install scikit-learn |
| nltk | 英文NLP工具 | pip install nltk |
| spaCy | 工业NLP管线 | pip install spacy |
| hanlp | 中文NLP工具包 | pip install hanlp |
| fasttext | Facebook文本分类 | pip install fasttext |
| textblob | 简单NLP接口 | pip install textblob |