📑 查看全课大纲(第 9 / 26 节)
- 1.知识图谱和语音技术概述
- 2.典型知识库项目简介
- 3.知识图谱技术概览
- 4.典型应用案例
- 5.早期知识表示简介
- 6.基于语义网的知识表示框架
- 7.典型知识库项目的知识表示
- 8.基于本体工具的知识建模实践
- 9.面向非结构化数据的知识抽取
- 10.面向结构化数据的知识抽取
- 11.面向半结构化数据的知识抽取
- 12.实践:基于百科数据的知识抽取
- 13.面向文本的知识抽取
- 14.知识挖掘
- 15.从一个例子开始
- 16.图数据库介绍
- 17.什么是知识融合
- 18.知识融合的基本技术流程
- 19.典型知识融合工具简介
- 20.典型案例简介
- 21.LIMES实战演练
- 22.知识推理
- 23.语义搜索
- 24.知识问答
- 25.IBM watson Lite
- 26.行业知识图谱应用
面向非结构化数据的知识抽取
约 99 分钟
面向非结构化数据的知识抽取:实体、关系与事件的信息抽取流水线
小象实战讲义 · 知识图谱
知识图谱里的知识不会凭空出现。网页、新闻、公告、研报绝大多数是自由文本——人能读懂,机器却无法直接推理。知识抽取(Knowledge Extraction)就是把非结构化文本里的实体、实体间关系、发生的事件,变成结构化三元组与事件记录灌进知识图谱。本节是第 3 章第一节,聚焦最难也最常见的来源:纯文本,沿”实体抽取 → 实体链接 → 关系抽取 → 事件抽取”这条信息抽取(Information Extraction,IE)主线,讲透每一步的任务定义与代表模型,并给出 4 个可运行的 Python 最小实现。
💡 核心导读
- 知识抽取按数据源分四路(结构化、链接数据、半结构化、非结构化),本节专攻非结构化文本抽取,核心难点是准确率与覆盖率。
- 信息抽取可拆成命名实体识别、术语抽取、关系抽取、事件抽取、共指消解等子任务;这门学科由 MUC、ACE、KBP、SemEval 系列评测推着向前走,读懂评测任务就读懂了任务边界。
- 实体抽取的本质是序列标注:IOB/IO 标签体系把”找边界 + 判类型”统一成逐字打标签,HMM、CRF、BiLSTM-CRF 是三代代表性模型。
- 实体识别不等于实体链接:同一个”海阔天空""万达集团”可能指向知识库中不同节点,需要借助别名词典、局部上下文、全局主题消歧。
- 关系抽取有模板、监督学习、弱监督(远程监督与 Bootstrapping)三大流派;事件抽取是多元关系抽取,工程上经历了从多阶段 pipeline 到联合建模、再到端到端神经网络的演进。
1. 知识抽取的任务地图:多源数据与信息抽取子任务
1.1 四类数据源,四条技术路线
知识图谱所需数据按来源形态分四类,各对应一条抽取路线:
数据源 抽取技术 产物
──────────────────────────────────────────────────────────
结构化数据(关系数据库) Direct Mapping / R2RML 标准(D2R 等工具) RDF 三元组
链接数据(已有 RDF/知识库) 图映射(数据对齐) RDF 三元组
半结构化数据(网页/表格/Infobox) 包装器(Wrapper) RDF 三元组
非结构化数据(纯文本) 信息抽取(IE) 实体/关系/事件 → 三元组
──────────────────────────────────────────────────────────
↓ 知识图谱(知识库)结构化数据库走 Direct Mapping / R2RML 标准(D2R Server 等工具),难点在复杂表处理;链接数据走图映射,难点在数据对齐;半结构化网站走包装器,难点在自动生成与维护;纯文本走信息抽取,难点在准确率与覆盖率。结构化、链接数据与半结构化三类来源由后续各节展开,本节只盯纯文本。文本抽取天然不确定,同一事实有无数种说法,所以 IE 始终围绕准确率、召回率、F1 值评价。
1.2 什么是信息抽取
信息抽取 20 世纪 70 年代后期出现于 NLP 领域,目标是自动从文本发现和抽取相关信息、从多个文本碎片合并信息,把非结构化文本转化为模式(Schemas)、关系(Relations)、知识库或 RDF 三元组等结构化产物。IE 通常面向特定领域,只抽预定义信息,而非试图”理解”全文。
信息抽取 IE
├── 命名实体识别 NER:检测实体边界 + 分类实体类型
│ “库克非常兴奋。” → [库克] 是实体,类型为 人物
├── 术语抽取:发现多个词组成的相关术语
├── 关系抽取:两个或多个实体间的语义关系
│ “王健林的独子王思聪” → 父子(王健林, 王思聪)
├── 事件抽取:多元关系,含触发词与一组角色要素
│ “苹果公司举行新品发布会” → 产品发布会(公司, 时间, 地点, 产品)
└── 共指消解:把指向同一对象的不同 mention 合并
“特朗普否决了收购案,他做出决定” → 他 = 特朗普以苹果发布会新闻为例:“苹果公司将于西部时间 9 月 12 日上午 10 点举行新品发布会,地点是乔布斯剧院,将发布 iPhone 8、Apple Watch 3 与 Apple TV。“人一眼能列出事件类型、公司、时间、地点、产品,IE 就是让机器自动产出同样的结构化表。
1.3 评测驱动的学科:MUC、ACE、KBP、SemEval
IE 的任务定义是在国际评测中逐步融合细化出来的。这些会议同时定义了任务、标注规范和标准数据集,论文结果几乎都在这些数据集上比较。
MUC(Message Understanding Conference,消息理解会议):由美国 DARPA 资助,1987 年起共办七届(MUC-1 至 MUC-7),奠定命名实体识别与共指消解两大任务。标注规范沿用至今,如时间用 <TIMEX TYPE="DATE">、人名用 <ENAMEX TYPE="PERSON">、共指链用 <COREF ID="101" TYPE="IDENT" REF="100"> 表示”宁”与编号 100 的”南京市”同指。
ACE(Automatic Content Extraction,自动内容抽取):对 MUC 任务融合、分类、细化,覆盖英语、阿拉伯语、汉语,分五大任务:EDR(实体检测识别,类型扩展到 persons、organizations、locations、facilities(设施)、weapons、vehicles、geo-political entities(缩写 GPE));VAL(数值检测识别,百分比、金额、邮箱、时间区间);TERN(时间表达检测识别);RDR(关系检测识别,含 role、part、located、near、social 等,如 位于(张三, 上海));VDR(事件检测识别,含 interaction、movement、transfer、creation、destruction,如”乘客离开北京前往上海会谈”同时含移动事件与会议事件)。
TAC KBP(Knowledge Base Population,知识库填充):由 NIST 的 TAC 会议主办,对 ACE 修订以贴合”建知识库”需求,含四个独立任务和一个整合任务:EDL(实体发现与链接,识别 PER/ORG/GPE/LOC/FAC 并链接 KB 节点);SF(槽填充,为给定实体补属性,如为”姚明”补出生日期、出生地、祖籍,本质就是补主谓宾三元组);Event(事件,含 Event Nugget 触发词检测 EN 与 Event Argument 要素抽取 EAL);BeSt(信念与情感,检测实体对另一实体、关系或事件的态度立场,区分态度的发起方与承受方);以及端到端冷启动知识构建(给定 schema 与文本从零建 KB)。
SemEval(Semantic Evaluation,语义评测):由 ACL 的 SIGLEX 组织,前身 Senseval,最早以词义消歧(WSD)为核心,后扩展到时间表达、情感分析、框架抽取、共指、语义关系、语义角色标注(SRL)、文本蕴含、生物医学文本等;关系抽取常用的 SemEval-2010 Task 8 就出自该系列。
这些评测的典型领域涵盖安全事件、企业经营、事故调查、公共卫生、会议公告、生物医药,共同点是领域明确、schema 预定义、有金标准。
2. 实体抽取(上):命名实体识别作为序列标注
2.1 任务定义:检测与分类两步
实体抽取(Entity Extraction)抽取文本中的原子信息元素:人名、组织/机构名、地理位置、时间/日期、字符值、金额值。它分两个动作:检测(Detection)解决”边界在哪”,分类(Classification)解决”是什么类型”。例如”启明中学接待了朝阳小学的访问团”中”启明中学""朝阳小学”是机构(学校),“李四和韩梅在杭州大婚”中”李四""韩梅”是人物、“杭州”是地点。命名实体识别(Named Entity Recognition,NER)是实体抽取出最核心、最成熟的部分。
2.2 序列标注与 IOB 标签体系
NER 被统一成序列标注(Sequence Labeling)问题:输入观测序列(一串字或词),输出等长标签序列。中文分词、词性标注、NER 都套这个框架。最常用的 IOB(BIO)标签体系为:O(Other)不属于任何实体;B(Begin)实体首字;I(Inside)实体内部;部分变体加 S(Single)表示单字成实体。去掉 B 只用 I/O 的叫 IO 体系,边界更粗。以”由启明中学的王老师走访朝阳小学的赵校长”为例:
字: 由 启 明 中 学 的 王 老 师 走 访 朝 阳 小 学 的 赵 校 长
IOB: O B-ORG I-ORG I-ORG I-ORG O B-PER I-PER I-PER O O B-ORG I-ORG I-ORG I-ORG O B-PER I-PER I-PER“启明中学”首字打 B-ORG,其余打 I-ORG。标签序列一定,实体边界与类型同时确定——检测与分类一次解码完成。
2.3 三代方法:特征工程、HMM/CRF、BiLSTM-CRF
深度学习普及前,NER 靠特征工程,人工特征分三类:字本身特征(是否数字、字符,利于识别日期金额百分比);前后缀特征(姓氏、地名后缀”省/市”、机构后缀”公司/大学/医院”);词特征(边界词概率、词性 POS、依存关系)。
统计模型有两个经典代表,恰是生成式与判别式对照。HMM(隐马尔可夫模型)是有向图、生成式模型,对联合概率 建模,参数分初始分布、标签转移概率与标签到字的发射概率三块,解码用 Viterbi 求最优路径:
HMM 的代价是观测独立强假设(给定状态,观测只依赖当前状态),与语言事实不符、限制精度。CRF(条件随机场)是无向图、判别式模型,直接对条件概率 建模:
CRF 不做特征独立假设,可任意叠加字、词、前后缀、词性等特征,且在整个标签序列上归一化得全局最优,可通过转移特征与约束解码有效抑制”B-PER 后接 I-ORG”这类非法 IOB 转移;标注少时也能拟合,是深度学习前最好用的 NER 方法。
神经网络时代的主流结构是 BiLSTM-CRF:字/词映射为向量(word/subword embedding),双向 LSTM 捕捉前后文,末尾 CRF 层约束标签转移合法性;判别式、端到端,特征自动提取,配合 Dropout 正则训练。代表工作为 Huang 等 2015 年的 Bidirectional LSTM-CRF Models for Sequence Tagging 与 Lample 等 2016 年 NAACL 的 Neural Architectures for Named Entity Recognition,此后又出现注意力增强变种;公开数据集上 F1 值沿”特征工程 → HMM → CRF → BiLSTM-CRF → 注意力模型”逐级抬升。
下面用最小可运行例子还原 HMM 做 NER 的全过程:内联 IOB 语料统计初始、转移、发射概率(拉普拉斯平滑处理未登录字),Viterbi 解码新句,再把 IOB 还原成实体片段。
# -*- coding: utf-8 -*-
"""代码块1:把 NER 当作序列标注——最小 HMM(转移概率+发射概率,Viterbi 解码)+ IOB 解码
仅用 Python 标准库;训练语料以内联实体片段给出,自动展开为 IOB 标签。"""
from collections import defaultdict
# 内联训练语料:(句子, [(实体文本, 类型), ...]),实体在句中须唯一可定位
TRAIN_SPANS = [
("张三是张小明的父亲", [("张三", "PER"), ("张小明", "PER")]),
("张小明是启明科技董事长张三的独子", [("张小明", "PER"), ("启明科技", "ORG"), ("张三", "PER")]),
("启明中学的王老师走访朝阳小学的赵校长",
[("启明中学", "ORG"), ("王老师", "PER"), ("朝阳小学", "ORG"), ("赵校长", "PER")]),
("李记者在杭州采访了华夏商会的赵磊",
[("李记者", "PER"), ("杭州", "LOC"), ("华夏商会", "ORG"), ("赵磊", "PER")]),
("二零一七年十月三十一日李四和韩梅大婚",
[("二零一七年十月三十一日", "DATE"), ("李四", "PER"), ("韩梅", "PER")]),
("启明科技后来居上在市场上超过了宏远公司", [("启明科技", "ORG"), ("宏远公司", "ORG")]),
("张三从上海回到北京", [("张三", "PER"), ("上海", "LOC"), ("北京", "LOC")]),
("赵磊离开上海前往深圳", [("赵磊", "PER"), ("上海", "LOC"), ("深圳", "LOC")]),
("王老师在杭州接待了赵校长", [("王老师", "PER"), ("杭州", "LOC"), ("赵校长", "PER")]),
("赵校长在北京访问了宏远公司", [("赵校长", "PER"), ("北京", "LOC"), ("宏远公司", "ORG")]),
("启明科技从深圳迁到杭州", [("启明科技", "ORG"), ("深圳", "LOC"), ("杭州", "LOC")]),
]
def spans_to_iob(sentence, spans):
"""把实体片段展开成逐字 IOB 标签序列(O / B-类型 / I-类型)。"""
tags = ["O"] * len(sentence)
for text, etype in spans:
start = sentence.index(text)
tags[start] = "B-" + etype
for i in range(start + 1, start + len(text)):
tags[i] = "I-" + etype
return tags
TRAIN = [(s, spans_to_iob(s, sp)) for s, sp in TRAIN_SPANS]
# ---------- 1. 统计 HMM 参数:初始概率 pi、转移概率 A、发射概率 B(拉普拉斯平滑) ----------
START, END, LAMBDA = "<s>", "</s>", 1.0
init_cnt = defaultdict(float)
trans_cnt = defaultdict(lambda: defaultdict(float))
emit_cnt = defaultdict(lambda: defaultdict(float))
tag_vocab, char_vocab = set(), set()
for chars, tags in TRAIN:
init_cnt[tags[0]] += 1
for i, (ch, tag) in enumerate(zip(chars, tags)):
tag_vocab.add(tag)
char_vocab.add(ch)
emit_cnt[tag][ch] += 1
trans_cnt[tags[i - 1] if i > 0 else START][tag] += 1
trans_cnt[tags[-1]][END] += 1
V = len(char_vocab)
tags_list = sorted(tag_vocab)
def trans_prob(prev, tag):
total = sum(trans_cnt[prev].values())
return (trans_cnt[prev][tag] + LAMBDA) / (total + LAMBDA * (len(tag_vocab) + 1))
def emit_prob(tag, ch):
total = sum(emit_cnt[tag].values())
return (emit_cnt[tag][ch] + LAMBDA) / (total + LAMBDA * (V + 1))
# ---------- 2. Viterbi 解码:求使 P(字序列, 标签序列) 最大的标签路径 ----------
def viterbi(sentence):
n = len(sentence)
bp = [dict() for _ in range(n)] # 每步保存 {标签: (累计概率, 前驱标签)}
for t in tags_list:
bp[0][t] = (init_cnt[t] / len(TRAIN) * emit_prob(t, sentence[0]), None)
for i in range(1, n):
for t in tags_list:
best_p, best_prev = -1.0, None
for pt in tags_list:
p = bp[i - 1][pt][0] * trans_prob(pt, t)
if p > best_p:
best_p, best_prev = p, pt
bp[i][t] = (best_p * emit_prob(t, sentence[i]), best_prev)
best_p, best_t = -1.0, None
for t in tags_list: # 句末转移
p = bp[-1][t][0] * trans_prob(t, END)
if p > best_p:
best_p, best_t = p, t
path = [best_t]
for i in range(n - 1, 0, -1):
best_t = bp[i][best_t][1]
path.append(best_t)
return list(reversed(path))
# ---------- 3. IOB 序列 -> 实体片段(边界检测 + 类型分类的结果) ----------
def iob_to_spans(chars, tags):
spans, cur = [], None
for ch, tag in zip(chars, tags):
if tag.startswith("B-"):
if cur:
spans.append(cur)
cur = {"type": tag[2:], "chars": [ch]}
elif tag.startswith("I-") and cur and cur["type"] == tag[2:]:
cur["chars"].append(ch)
else:
if cur:
spans.append(cur)
cur = None
if cur:
spans.append(cur)
return [("".join(s["chars"]), s["type"]) for s in spans]
# ---------- 4. 对新句子做实体抽取 ----------
for sent in ["韩梅在杭州会见了张三", "张三从上海前往深圳"]:
pred = viterbi(sent)
print(sent)
print(" 逐字标签:", " ".join(pred))
print(" 识别实体:", iob_to_spans(sent, pred))韩梅在杭州会见了张三
逐字标签: B-PER I-PER O B-LOC I-LOC O O O B-PER I-PER
识别实体: [('韩梅', 'PER'), ('杭州', 'LOC'), ('张三', 'PER')]
张三从上海前往深圳
逐字标签: B-PER I-PER O B-LOC I-LOC O O B-LOC I-LOC
识别实体: [('张三', 'PER'), ('上海', 'LOC'), ('深圳', 'LOC')]这个玩具系统只有 11 句语料,却完整展示序列标注三件事:标签体系如何合并检测与分类、生成式模型如何用转移加发射两组概率刻画序列、Viterbi 如何在标签图上找全局最优。工业系统替换语料规模、特征与模型骨架,解码思想不变。
3. 实体抽取(下):细粒度类型、实体链接与消歧
3.1 识别之后为什么还要链接
NER 给出的只是文本中的字符串 mention(名字指称),图谱需要的是确定的知识库节点,这一步叫实体链接(Entity Linking,又称实体消歧)。两个现实问题逼着我们做它。
一是大规模细粒度实体类型。粗粒度人名地名机构名只有十几类,但 schema.org 这类通用本体有六七百个类,音乐领域里”海阔天空”应标为 MusicWork 而非普通字符串;类型越细,每类标注样本越稀疏、类别越不平衡。二是新兴实体与新说法:网络新词、新机构、新产品名不断出现,模型对它们一无所知,同一实体还有简称、别称、旧称、错别字等表面形式。
最典型的歧义是同名。用户说”我想听一首海阔天空”,KB 中至少有两首:Beyond 1993 年的粤语摇滚、信乐团 2004 年的国语作品;NER 只知道”海阔天空”是歌名 mention,链接须结合上下文(“最喜欢 Beyond 的粤语老歌”)决定挂哪个节点,最终生成形如 ex:海阔天空_Beyond rdf:type ex:MusicWork 的三元组。企业领域同理,“万达集团”可能指做商业地产院线的大连万达,也可能指山东东营做橡胶轮胎的中国万达,不消歧会把两家公司的供应商、客户、诉讼混在一张图上。
3.2 实体链接四步流程
自由文本
│ ① mention 识别(NER + 别名词典/anchor 词典)
▼
名字指称 mention(“海阔天空”“万达集团”)
│ ② 候选实体生成(别名词典、同义词表,召回所有可能节点)
▼
候选实体集合 {KB 节点 1, 节点 2, ...}
│ ③ 候选消歧(上下文相似度 / 机器学习排序,输出 top-N 与置信度)
▼
目标知识库节点(生成指向 KB 的 URI;低于阈值标 NIL 走新实体发现)第①②步靠词典匹配:维基类知识库天然提供 anchor 词典——MediaWiki 双方括号超链接 [[目标词条|锚文本]] 中,锚文本(anchor text)就是 mention,目标词条就是标准名(standard name)。锚文本与标准名是多对多关系:一词多义(“海阔天空”指向两首歌)与多词一义(“nonprofit""non-profit organization”指向同一概念)并存。第③步消歧可建模成分类(是不是该节点)或排序(候选打分)问题,输出带置信度的 top-N 候选。
3.3 消歧信号与三个代表系统
消歧信息分两类。不依赖上下文的只看 mention 与候选本身:同义词/简称/别称词典、abstract 摘要、已有属性三元组;做法包括直接词汇匹配(lexical matching)和基于特征的分类器(锚文本与标题一致性、编辑距离、实体流行度等)。依赖上下文的看语境:局部上下文(local context)取 mention 前后窗口的词,用词袋向量+余弦相似度与候选 abstract 比对;全局上下文(global context)用主题模型、社会化标签刻画整篇文档主题(同文实体话题一致);还可用 PageRank 等图方法在”mention-候选”二部图上协同传播,让互相支持的候选集体胜出。
三个代表性系统:Wikipedia Miner(怀卡托大学开发,开源、提供公共 Web 服务,Java 实现、Hadoop 离线预处理,词汇匹配加机器学习 learning to link,目标库为维基百科,支持多语言);DBpedia Spotlight(开源、公共 Web 服务,目标库 DBpedia,在局部上下文用词袋向量空间模型加余弦消歧,工程基于 Lucene,返回 top-N 候选,DBpedia URI 由”域名 + resource + 词条本地名”规整构成);OpenCalais(Reuters 于 2008 年推出,不开源但功能强,目标库为内部 Calais;只处理公开内容、不留内容副本、只留抽取元数据,每天免费 5 万篇,早期用户含 CBS/CNET、Huffington Post 等媒体)。此外还有 TagMe、Junto、Wikify、雅虎 FEL、YAGO 团队的 AIDA、AGDISTIS、PBOH 等开源系统。
下面代码还原实体链接最小闭环:别名词典做 mention 检测与候选生成,局部上下文词袋与实体描述词袋的余弦相似度消歧,输出 top-N 候选与得分。
# -*- coding: utf-8 -*-
"""代码块2:实体链接最小实现——mention 检测、候选实体生成、基于局部上下文的词袋余弦消歧
对应 DBpedia Spotlight 的核心思想:向量空间模型 + 余弦相似度,输出 top-N 候选及置信度。
仅用标准库;为便于演示,中文直接以词为单位给出。"""
import math
from collections import Counter
# ---------- 1. 目标知识库:每个实体带标准名、别名集合、描述文本(模拟 abstract) ----------
KB = {
"dbp:海阔天空_Beyond": {
"aliases": ["海阔天空"],
"abstract": ["粤语", "摇滚", "Beyond", "1993", "专辑", "乐与怒", "黄家驹", "经典", "老歌"],
},
"dbp:海阔天空_信乐团": {
"aliases": ["海阔天空"],
"abstract": ["国语", "流行", "信乐团", "2004", "专辑", "阿信", "翻唱", "高音"],
},
"dbp:大连万达集团": {
"aliases": ["万达", "万达集团", "大连万达"],
"abstract": ["大连", "商业地产", "文化产业", "院线", "传奇影业", "收购", "王健林", "购物中心"],
},
"dbp:中国万达集团": {
"aliases": ["万达", "万达集团", "中国万达"],
"abstract": ["山东", "东营", "橡胶", "轮胎", "制造", "化工", "实体企业", "工业园"],
},
}
# ---------- 2. mention 检测 + 候选生成:用别名词典做 lexical matching ----------
def detect_mentions(tokens):
"""返回 [(起始, 结束, mention 文本, [候选实体 id])];按 token 跨度由长到短匹配。"""
mentions = []
for length in (3, 2, 1): # 由长到短,避免“万达集团”被“万达”截断
for i in range(0, len(tokens) - length + 1):
surface = "".join(tokens[i:i + length])
cands = [eid for eid, v in KB.items() if surface in v["aliases"]]
if cands and not any(i >= s and i + length <= e for s, e, _, _ in mentions):
mentions.append((i, i + length, surface, cands))
return sorted(mentions)
# ---------- 3. 局部上下文消歧:上下文词袋与实体描述词袋的余弦相似度 ----------
def cosine(ctx_bow, doc_bow):
common = set(ctx_bow) & set(doc_bow)
dot = sum(ctx_bow[w] * doc_bow[w] for w in common)
n1 = math.sqrt(sum(x * x for x in ctx_bow.values()))
n2 = math.sqrt(sum(x * x for x in doc_bow.values()))
return dot / (n1 * n2) if n1 and n2 else 0.0
def link(tokens, mention, window=4, top_n=2):
s, e, surface, cands = mention
# local context:mention 两侧窗口内的词(不含 mention 本身)
ctx = tokens[max(0, s - window):s] + tokens[e:e + window]
ctx_bow = Counter(ctx)
scored = []
for eid in cands:
doc_bow = Counter(KB[eid]["abstract"])
score = cosine(ctx_bow, doc_bow)
scored.append((eid, round(score, 3)))
scored.sort(key=lambda x: x[1], reverse=True)
return surface, scored[:top_n]
# ---------- 4. 两个歧义场景:同名歌曲、同名企业 ----------
sentences = [
["我", "想", "听", "一首", "海阔天空", "最", "喜欢", "Beyond", "的", "粤语", "老歌"],
["万达集团", "收购", "传奇影业", "之后", "大举", "布局", "文化产业", "与", "院线"],
]
for toks in sentences:
print("句子:", "".join(toks))
for m in detect_mentions(toks):
surface, ranked = link(toks, m)
print(f" mention={surface} -> top候选: {ranked}")句子: 我想听一首海阔天空最喜欢Beyond的粤语老歌
mention=海阔天空 -> top候选: [('dbp:海阔天空_Beyond', 0.118), ('dbp:海阔天空_信乐团', 0.0)]
句子: 万达集团收购传奇影业之后大举布局文化产业与院线
mention=万达集团 -> top候选: [('dbp:大连万达集团', 0.354), ('dbp:中国万达集团', 0.0)]余弦相似度为 , 是候选描述词频向量、 是上下文词频向量。真实系统会把词袋换成词向量或预训练语言模型、单点打分换成文档级联合排序,但”候选生成 + 上下文打分”的骨架不变。
4. 关系抽取:模板、监督学习与弱监督
4.1 任务定义与图谱中的关系事实
关系抽取(Relation Extraction)抽取两个或多个实体间的语义关系,最常见的是二元关系,产物是三元组(头实体,关系,尾实体),如”王健林谈儿子王思聪”→ 父子(王健林, 王思聪)。它在企业知识图谱中价值直接:刻画公司间子公司、供应商、客户、竞争对手、合作伙伴关系,支撑竞争分析、客户管理、收购兼并分析(如中兴被制裁后沿关系网定位波及公司)。两点工程意识:关系事实往往是时序的(temporal fact),三元组应带时间戳;还要记录来源(provenance,公告/新闻及日期)。因此文本抽出的三元组(textual extraction)先作为带注释的候选事实,经清洗、融合、人工审核才进入高质量图谱。
关系抽取方法
├── 基于模板(规则):基于触发词的 Pattern / 基于依存句法分析的 Pattern
├── 监督学习:传统机器学习(特征工程 + SVM/NN/朴素贝叶斯)/ 深度学习(Pipeline / Joint)
└── 弱监督学习:远程监督(Distant Supervision)/ Bootstrapping(种子自举)4.2 基于模板的方法
基于触发词的 Pattern 最直观:NER 先识别人名等实体,再用含关系触发词的模板匹配,如”姚明老婆叶莉""黄晓明妻子杨颖""刘德华配偶朱丽倩”都命中”X 老婆/妻子/配偶 Y”,归一化为 夫妻(X, Y);触发词可以是名词、动词或介词。
基于依存句法分析的 Pattern 更泛化。依存分析输出句法结构:词间是带标签的有向弧(主谓 sbj、动宾 obj),核心词一般是谓语动词(依存头标 root/-1),常见结构有形容词加名词、介宾短语、动宾短语。依存规则以动词为起点,限定节点词性与边上依存关系,本质是更泛化的正则。以”董卿现身国家博物馆看展”为例,“董卿”是”现身”的主语、“国家博物馆”是宾语,命中得(董卿, 现身, 国家博物馆),再映射为 位于(董卿, 国家博物馆);依存分析可借助哈工大 LTP、Stanford Parser 等工具。
工程流程为:准备模板库 → 分词、词性标注、NER、依存分析 → 依存树匹配规则,每命中一条生成一个三元组 → 扩展归一化 → 评价分类并设置信度阈值 → 迭代到抽不出新三元组。打分既可对每个三元组独立分类,也可对整句三元组集合联合打分(如整数线性规划 ILP 加全局约束)。模板法优点是小规模数据上易实现、构建简单、准确率高;缺点是特定领域模板需专家编写、难维护、可移植差,规则集小时召回率很低。
4.3 监督学习方法
监督学习设定:实体对已确定,依据句子上下文(实体左部、中间、右部)预测关系类别。五步:预定义关系类别、人工标注、设计特征、选分类器(SVM、神经网络、朴素贝叶斯)、评估。特征按投入分三档:轻量级(实体前后词、实体类型、实体间距离);中量级(Chunk 序列,即 NP/VP/PP 浅层句法);重量级(实体间依存路径、依存树距离、特定结构,引入 FrameNet、PropBank、上下位、n-gram)。深度学习把特征也交给网络:输入侧用位置向量(Position Embeddings,刻画词相对实体位置)、词向量、知识向量。
模型分两条路线。Pipeline 路线中实体识别与关系分类完全分离、关系识别依赖实体识别结果,代表有 CR-CNN(Santos 等 2015,仅用词向量与位置向量,卷积窗口相当于 n-gram 局部上下文,最大池化得句子向量后与关系向量做相似度排序,F1 84.1,超过当时最好的非深度方法)、Att-CNN(Liu 等 ACL 2016,输入层与池化层引入注意力,F1 88.0,为当时最好)、Att-BLSTM(Zhou 等 ACL 2016,Embedding → BiLSTM → 注意力 → softmax,成为关系分类标准骨架)。Joint 联合路线让实体识别与关系分类共同优化,代表是 Miwa 等 ACL 2016 的 End-to-End Relation Extraction using LSTMs on Sequences and Tree Structures(序列上用 BiLSTM、依存树上用 Tree-LSTM,双向依存边处理 nsubjpass 被动主谓)。需客观看待:SemEval-2010 Task 8 上联合模型相比 pipeline 提升有限,pipeline 短板也可靠 WordNet 等外部知识弥补,是否上联合模型需权衡工程收益。监督学习整体准确率高、标注越多越准,但标注成本高、且只能在预定义类别中分类,不能扩展新关系。
4.4 弱监督之一:远程监督
远程监督(Distant Supervision)用知识库与文本对齐自动构造训练数据,减少人工标注、增强跨领域能力。它基于强假设:两实体若在 KB 中存在某关系,则包含它们的所有句子都表达该关系。例如 KB 已有 创始人(乔布斯, 苹果公司),则”乔布斯是苹果公司的联合创始人和 CEO”被自动构造成正例。步骤:先从 KB 抽取有关系的实体对,再从文本检索含该实体对的句子作训练样例。
假设过于肯定会引入大量噪声:含”乔布斯""苹果”的句子可能是”乔布斯被赶出苹果”(不表达创立);“乔布斯”与”美国”共现可能表达出身、居住、工作等不同关系。错误正例让模型学偏,产生语义漂移。关系抽取的句子编码器代表是分段卷积神经网络(PCNN,Piecewise CNN,Zeng 等 EMNLP 2015):传统 CNN 对整句一次最大池化会丢失两实体左右上下文差异;PCNN 按两实体位置把句子切左、中、右三段分别池化,一句得三段特征;远程监督的噪声则靠多实例学习与句子级注意力抑制——Ji(纪国梁)、刘康等(2017,课件中的 PCNNs 模型)在 PCNN 上再加入句子级注意力(给噪声句低权重),并配合多实例学习(同一实体对的多句打成一个 bag,bag 中一句符合即认为 bag 符合)缓解噪声。远程监督优点是利用 KB 大幅减少人工标注;缺点是强假设带来噪声与语义漂移,且关系全来自 KB、难发现新关系。
4.5 弱监督之二:Bootstrapping
Bootstrapping(自举)从少量种子出发在语料中滚雪球。以夫妻关系为例,给定种子对(姚明, 叶莉):① 抽出含种子的新闻”姚明老婆叶莉简历身高曝光""姚明与妻子叶莉外出赴约""姚明携爱妻叶莉亮相活动”;② 实体替换为占位符归纳出 Pattern”X 老婆 Y …""X 与妻子 Y …""X 携爱妻 Y …”,统计频次(频次越高越可信,置信度来自语料冗余性),相近 Pattern 聚类抽象;③ 用 Pattern 回配,如”小猪与妻子伊万外出赴约”命中”X 与妻子 Y”,抽出新对(小猪, 伊万);④ 新对回灌种子库迭代,直到不再发现新三元组。优点是构建成本低、适合大规模、能发现隐含关系与新表述;缺点是对初始种子敏感、存在语义漂移(“苹果”既是公司又是水果时会跑偏)、准确率低于专家手写模板(但覆盖率更高)、早期方法缺单结果置信度计算。关系抽取比实体抽取难,因为关系表述极丰富、触发词可隐式不出现,无法靠词典匹配解决。 下面代码完整还原 Bootstrapping 迭代:语料预先分词并给出 NER 人名位置,种子对归纳抽象模板,模板回配发现新对,新对回灌直到收敛。
# -*- coding: utf-8 -*-
"""代码块3:Bootstrapping(种子驱动)关系抽取最小实现
前置:句子已完成分词与 NER(人名位置已知)。流程:
种子实体对 -> 归纳抽象模板(X-触发词-Y 的 token 片段)-> 模板回配发现新实体对
-> 新实体对回灌 -> 迭代到收敛。仅用标准库。"""
from collections import Counter
# 内联语料:(token 序列, 人名所在 token 下标集合),下标集合模拟 NER 的输出
CORPUS = [
(["姚明", "老婆", "叶莉", "简历", "身高", "曝光"], {0, 2}),
(["姚明", "与", "妻子", "叶莉", "外出", "赴约"], {0, 3}),
(["姚明", "携", "爱妻", "叶莉", "亮相", "活动"], {0, 3}),
(["小猪", "与", "妻子", "伊万", "外出", "赴约"], {0, 3}),
(["邓超", "携", "爱妻", "孙俪", "出席", "颁奖", "典礼"], {0, 3}),
(["刘德华", "老婆", "朱丽倩", "现身", "机场"], {0, 2}),
(["黄晓明", "与", "妻子", "杨颖", "参加", "综艺", "录制"], {0, 3}),
(["徐峥", "与", "妻子", "陶虹", "合作", "新", "电影"], {0, 3}),
]
def to_pattern(tokens, head, tail):
"""抽取从 head 到 tail 的 token 片段,实体替换为占位符 X/Y,得到抽象模板。"""
i, j = tokens.index(head), tokens.index(tail)
lo, hi = sorted([i, j])
return tuple("X" if t == head else ("Y" if t == tail else t)
for t in tokens[lo:hi + 1])
def learn_patterns(corpus, seeds):
patterns = Counter()
for tokens, persons in corpus:
names = {tokens[i] for i in persons}
for head, tail in seeds:
if head in names and tail in names:
patterns[to_pattern(tokens, head, tail)] += 1
return patterns
def match_new_pairs(corpus, patterns, known):
"""模板在 token 序列上对齐:普通 token 须全等,X/Y 槽位须落在 NER 标出的人名上。"""
found = set()
for tokens, persons in corpus:
names = [tokens[i] for i in sorted(persons)]
for pat in patterns:
n = len(pat)
for s in range(0, len(tokens) - n + 1):
window = tokens[s:s + n]
x_slot = y_slot = None
ok = True
for k, p in enumerate(pat):
if p == "X":
x_slot = window[k]
elif p == "Y":
y_slot = window[k]
elif p != window[k]:
ok = False
break
if ok and x_slot in names and y_slot in names:
pair = (x_slot, y_slot)
if pair not in known:
found.add(pair)
return found
# ---------- 迭代 Bootstrapping ----------
seeds = {("姚明", "叶莉")}
known_pairs = set(seeds)
for rnd in range(1, 5):
patterns = learn_patterns(CORPUS, known_pairs)
new_pairs = match_new_pairs(CORPUS, patterns, known_pairs)
print(f"第{rnd}轮 模板数={len(patterns)} 新发现实体对={sorted(new_pairs)}")
if not new_pairs:
print("已收敛:不再发现新实体对,停止迭代。")
break
known_pairs |= new_pairs
print("\n最终模板库(频次可近似看作模板置信度,语料中越重复越可信):")
for pat, cnt in learn_patterns(CORPUS, known_pairs).most_common():
print(f" [{cnt}] {''.join(pat)}")
print("\n最终抽得的夫妻关系实体对:")
for h, t in sorted(known_pairs):
print(f" 夫妻({h}, {t})")第1轮 模板数=3 新发现实体对=[('刘德华', '朱丽倩'), ('小猪', '伊万'), ('徐峥', '陶虹'), ('邓超', '孙俪'), ('黄晓明', '杨颖')]
第2轮 模板数=3 新发现实体对=[]
已收敛:不再发现新实体对,停止迭代。
最终模板库(频次可近似看作模板置信度,语料中越重复越可信):
[4] X与妻子Y
[2] X老婆Y
[2] X携爱妻Y
最终抽得的夫妻关系实体对:
夫妻(刘德华, 朱丽倩)
夫妻(姚明, 叶莉)
夫妻(小猪, 伊万)
夫妻(徐峥, 陶虹)
夫妻(邓超, 孙俪)
夫妻(黄晓明, 杨颖)一个种子对在第 1 轮就借三条模板扩展出五个新对、第 2 轮收敛,体现自举”低成本、高覆盖”的威力;若语料混入含歧义触发词的句子,错误对同样会被滚雪球放大,这正是语义漂移必须靠置信度与人工审核兜底的原因。
5. 事件抽取:多元关系的结构预测
5.1 事件定义与四个术语
事件(Event)是发生的事情,通常具有时间、地点、参与者等属性,源于动作产生或状态改变,如”产品发布会""股票上涨""细胞病变”。事件抽取(Event Extraction)从自然语言中抽出事件并结构化呈现。先固定四个术语:事件描述(Event Mention,描述事件的词组或句子);事件触发词(Event Trigger,表明事件出现的主要词汇,多为动词或名词化动词);事件元素(Event Argument,事件的重要信息,实体/时间/数值);元素角色(Argument Role,元素在事件中的语义角色)。
苹果发布会例中,触发词”发布会”决定事件类型为产品发布会,元素苹果公司、9 月 12 日上午 10 点、乔布斯剧院、iPhone 8 等分别承担公司、时间、地点、产品角色;元素由 NER 与数值识别给出,把元素关联到角色叫事件元素角色标注(Argument Role Labeling)。再如”斯瓦拉吉与王毅会谈”是会谈事件,“中印双方周五撤军”是撤军事件,“印军建起工事""毁坏工事”分别是建造与破坏事件。
5.2 多元事件如何落进三元组图谱
关系抽取处理二元关系,事件是多元关系:一个发布会同时连着公司、时间、地点、产品多个槽,而一条三元组只能连两个节点。落地办法是把事件实例化为一个资源节点(n-元关系模式,区别于 RDF 用 rdf:Statement 描述三元组的 reification),让它充当一组二元关系的主语:
四元关系:发布会(公司=苹果公司, 时间=9月12日10点, 地点=乔布斯剧院, 产品=iPhone8/...)
│ 事件实例化(n-元关系模式):为事件建实例节点
▼
ex:Event_1 rdf:type ex:ProductLaunch .
ex:Event_1 ex:company ex:E_AppleInc . # 公司
ex:Event_1 ex:time "西部时间9月12日上午10点" . # 时间
ex:Event_1 ex:place ex:E_SteveJobsTheater . # 地点
ex:Event_1 ex:product "iPhone 8" ; ex:product "Apple Watch 3" ; ... # 产品(多值)一个四元事件由此展开成若干条三元组,每个角色一条(多值角色如产品多条)。注意与 KBP 槽填充(SF)区分:SF 为实体补属性,事件任务的标准步骤是事件元素角色标注——为每个元素判定角色。
5.3 事件嵌套、事件检测跟踪与事理图谱
真实新闻里事件常嵌套:中印边界对峙是冲突类父事件,下含起因、结果、活动、发展——印军建起工事(建造)、毁坏工事(破坏)、双方撤军(撤军)、斯瓦拉吉与王毅会谈(会谈),子事件间有时态先后与因果依赖。把相关事件组织成事件集合即事件检测与跟踪(EDT);事件节点带上时序与因果关系,就构成”事理图谱”(哈工大刘挺团队倡导),刻画事件演化规律而非实体静态关系。事件抽取最基础的三件事:识别触发词及类型、抽取元素并判角色、抽出描述事件的词组句子;此外还有事件属性标注(时态、极性)与事件共指消解(合并多篇报道中同一事件的 mention)。
5.4 Pipeline 方法与误差传播
有监督事件抽取的标准流程是 pipeline,把任务转成多阶段分类,每阶段一个分类器(MaxEnt、SVM):①触发词分类器(Trigger Classifier,判词是否触发词及事件类别);②元素分类器(Argument Classifier,判词组是否事件元素);③元素角色分类器(Role Classifier,K 分类加 others 的多分类);④属性分类器(Attribute Classifier,时态极性);⑤可报告性分类器(Reportable-Event Classifier,判是否存在值得报告的事件实例)。
典型特征围绕触发词与候选元素设计。触发词侧:Trigger 及上下文 token 与 POS、触发词列表与同义词字典、Trigger 在句法树中的深度与到根路径、父节点词组结构与类型、最近实体类型。元素侧:事件类型与触发词(token、类型子类型)、候选实体类型子类型与 head word、上下文词、触发词父节点词组、实体相对触发词位置、到触发词最短依存路径与长度。
pipeline 的根本问题是误差逐级传播:如课件第 79 页的示意,沿实体识别、共指消解、关系抽取、事件抽取、跨文档链接、槽填充各环节,累计性能可能从 100% 逐步衰减到 90%、70%、60%、50%、40%(各环节准确率不同,并非等比连乘;该图为抽象示意而非具体系统实测);各环节独立预测、无法利用全局依赖。
5.5 联合抽取与深度学习方法
解决误差传播有两条思路。联合推理(Joint Inference):子任务仍各自训练,解码阶段把多模型目标函数相加联合求解,手段含约束条件模型、ILP 重排序、对偶分解(Dual Decomposition),概率图路线为马尔可夫逻辑网络。联合建模(Joint Modeling):一个模型同时抽出所有信息,本质是多任务学习(底层词、embedding、句法特征共享),把问题建模成结构预测(Structured Prediction)——输出不是单个类标而是标签序列或依存树等结构,用搜索求解(Li 等 ACL 2013、Li 与 Ji ACL 2014);它避免误差传播,且全局特征能从整体结构学习、反哺局部预测。实验中联合方法优于 pipeline,跨实体(cross-entity,同事件多实体协同消歧)特征增益尤其明显。
传统方法有两个共同缺陷:依赖分词、词性、句法等外部 NLP 工具,误差累积传播,有些语言/领域还缺工具;且需人工设计特征。深度学习正对应解决:端到端减少工具依赖、词向量蕴含语言特征、网络自动提特征。代表模型 DMCNN(动态多池化卷积神经网络,陈钰波等 ACL 2015)分四部分:词向量学习、词汇级特征、句子级特征、分类输出。关键在动态多池化层:单一最大池化把整句压成一个值,无法刻画不同上下文对候选要素的贡献,且一句可能含多事件;DMCNN 按候选触发词/要素位置把句子动态分段、分别池化,保留分段上下文。实验在 ACE2005 英文集(529 篇训练、30 篇开发、其余测试)上显著优于传统方法与普通 CNN。
事件抽取长期受困于语料稀缺,扩充路线有两条:FrameNet 扩充(刘树林等 ACL 2016,语言学家按框架语义学标注、层级组织的语义框架资源,含 1000 多框架、10000 多词法单元、15 万多例句,框架标注可迁移为事件语料);结构化知识库自动生成语料(陈钰波等 2017,综合世界知识与语言知识大规模生成)。另有跨文档信息融合路线:从网络获取同一事件的多篇报道(Narasimhan 等 EMNLP 2016,单篇往往只抽出一两个槽位,用强化学习策略网络决策采信哪篇报道、哪个抽取器的结果)。
下面代码实现最小事件抽取 pipeline:触发词词典做事件分类,机构/地点词典与时间、产品正则做元素抽取和角色归类,最后用 rdflib 把多元事件实例化为 RDF 三元组并序列化为 Turtle。
# -*- coding: utf-8 -*-
"""代码块4:事件抽取最小 pipeline,并把多元事件实例化为 RDF 三元组
步骤:触发词分类(事件类型) -> 元素抽取(机构/地点/时间/产品) -> 元素角色标注
-> 事件实例作为主语展开为多条三元组。依赖 rdflib(pip install rdflib)。"""
import re
from rdflib import Graph, Namespace, Literal
from rdflib.namespace import RDF, RDFS, XSD
EX = Namespace("http://example.org/kg/")
g = Graph()
g.bind("ex", EX)
# ---------- 1. 触发词分类器(Trigger Classifier):词典匹配,判定事件类型 ----------
TRIGGERS = {"发布会": ("产品发布会", "ProductLaunch"),
"爆炸": ("恐怖袭击", "TerroristAttack")}
# ---------- 2. 元素抽取:机构/地点词典(带 IRI 片段)+ 时间、产品正则 ----------
ORGS = [("苹果公司", "AppleInc")]
LOCS = [("史蒂夫乔布斯剧院", "SteveJobsTheater"),
("Parsons Green地铁站", "ParsonsGreenStation"),
("伦敦", "London")]
TIME_PAT = re.compile(r"[西北东京部]*时间?\d{1,2}月\d{1,2}日(上午|下午|凌晨|晚上)?\d{1,2}点|\d{1,2}月\d{1,2}日早\d{1,2}时\d{1,2}分")
PRODUCT_PAT = re.compile(r"iPhone\s?\d+[A-Za-z]*(?:\s?Plus)?|Apple\s?Watch\s?\d?|Apple\s?TV")
def extract_arguments(text):
"""模拟 Argument Classifier + Role Classifier:抽出元素并归入角色槽。"""
args = {"公司": [], "地点": [], "时间": [], "产品": []}
for name, slug in ORGS:
if name in text:
args["公司"].append((name, slug))
for name, slug in LOCS:
if name.replace(" ", "") in text.replace(" ", ""):
args["地点"].append((name, slug))
args["时间"] = [(m.group(0), None) for m in TIME_PAT.finditer(text)]
args["产品"] = [(p.strip(), None) for p in PRODUCT_PAT.findall(text)]
return args
def add_event(event_id, etype_cn, etype_en, args):
"""多元事件实例化:事件实例为主语,rdf:type 给事件类型,每个角色展开成一条三元组。"""
ev = EX[f"Event_{event_id}"]
g.add((ev, RDF.type, EX[etype_en]))
g.add((ev, RDFS.label, Literal(etype_cn, lang="zh")))
role_pred = {"公司": EX.company, "地点": EX.place, "时间": EX.time, "产品": EX.product}
for role, values in args.items():
for name, slug in values:
if role in ("公司", "地点"): # 实体 -> IRI 对象
obj = EX[f"E_{slug}"]
g.add((obj, RDFS.label, Literal(name, lang="zh")))
else: # 时间/产品 -> 字面量
obj = Literal(name, datatype=XSD.string)
g.add((ev, role_pred[role], obj))
# ---------- 3. 对两段新闻文本跑事件抽取 pipeline ----------
texts = [
"苹果公司将于西部时间9月12日上午10点举行新品发布会,"
"发布会地点是全新建造的史蒂夫乔布斯剧院,会上将发布iPhone 8、iPhone 7s Plus、Apple Watch 3与Apple TV。",
"英国当地时间9月15日早8时15分,位于伦敦西南的Parsons Green地铁站发生爆炸,多人受伤。",
]
for idx, text in enumerate(texts, start=1):
trigger = next((w for w in TRIGGERS if w in text), None)
etype_cn, etype_en = TRIGGERS.get(trigger, ("未知事件", "UnknownEvent"))
args = extract_arguments(text)
print(f"文本{idx} 触发词={trigger} 事件类型={etype_cn}")
for role, values in args.items():
if values:
print(f" {role}: {[v[0] for v in values]}")
add_event(idx, etype_cn, etype_en, args)
# ---------- 4. 输出事件知识图谱(Turtle) ----------
print("\n事件实例展开的 RDF 三元组:")
print(g.serialize(format="turtle"))文本1 触发词=发布会 事件类型=产品发布会
公司: ['苹果公司']
地点: ['史蒂夫乔布斯剧院']
时间: ['西部时间9月12日上午10点']
产品: ['iPhone 8', 'iPhone 7s Plus', 'Apple Watch 3', 'Apple TV']
文本2 触发词=爆炸 事件类型=恐怖袭击
地点: ['Parsons Green地铁站', '伦敦']
时间: ['9月15日早8时15分']
事件实例展开的 RDF 三元组(rdflib 实际序列化输出,对象列表用英文逗号分隔):
@prefix ex: <http://example.org/kg/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
ex:Event_1 a ex:ProductLaunch ;
rdfs:label "产品发布会"@zh ;
ex:company ex:E_AppleInc ;
ex:place ex:E_SteveJobsTheater ;
ex:product "Apple TV"^^xsd:string,
"Apple Watch 3"^^xsd:string,
"iPhone 7s Plus"^^xsd:string,
"iPhone 8"^^xsd:string ;
ex:time "西部时间9月12日上午10点"^^xsd:string .
ex:Event_2 a ex:TerroristAttack ;
rdfs:label "恐怖袭击"@zh ;
ex:place ex:E_London,
ex:E_ParsonsGreenStation ;
ex:time "9月15日早8时15分"^^xsd:string .
ex:E_AppleInc rdfs:label "苹果公司"@zh .
ex:E_London rdfs:label "伦敦"@zh .
ex:E_ParsonsGreenStation rdfs:label "Parsons Green地铁站"@zh .
ex:E_SteveJobsTheater rdfs:label "史蒂夫乔布斯剧院"@zh .至此非结构化文本的抽取链条闭合:NER 找到实体 mention,实体链接把 mention 挂到知识库节点,关系抽取补上实体间二元边,事件抽取把多元事件实例化成一组三元组,共指消解保证同一对象不重复建节点。
📝 动手练一练
练习 1(IOB 标注与解码):请用 IOB 体系(O / B-类型 / I-类型,类型限定 PER、ORG、LOC、DATE)给句子”二零一七年十月三十一日,宋仲基和宋慧乔在首尔大婚”逐字打标签,并说明 B 标签在边界检测中的作用;若改用 IO 体系(去掉 B),哪些相邻同类实体会被错误合并?
参考答案
日期”二零一七年十月三十一日”整体标 B-DATE 后接 I-DATE;“宋仲基""宋慧乔”分别为 B-PER + I-PER + I-PER;“首尔”为 B-LOC + I-LOC;其余字与标点(含”和""在""大婚”)标 O。B 标记实体首字,是左边界信号,解码时遇到 B 即开启新片段。改用 IO 后,像”宋仲基和宋慧乔”这种中间隔着 O(“和”标 O)的情况,O 本身就能断开片段、仍可区分;真正会出错的是两个同类实体紧邻、中间没有 O 或标点分隔(如”宋仲基宋慧乔”连写),此时只剩连续 I 段、无法判断边界,会被拼成一个实体。IO 更省标签但边界更粗,IOB 更常用。
练习 2(远程监督的噪声判断):KB 中存在 创始人(乔布斯, 苹果公司)。判断下列句子被远程监督自动标为”创始人”正例时哪些是错误正例(噪声),并解释语义漂移如何产生:①”乔布斯是苹果公司的联合创始人和 CEO”;②”1985 年乔布斯被苹果公司解除了管理职务”;③”乔布斯回到苹果公司后推出了 iMac”。
参考答案
①是真正例;②是错误正例,表达”被解职”;③对”创始人”关系是错误正例,表达”回归后推出产品”。根源是远程监督的强假设——两实体共现即表达 KB 中关系,但同一对实体可在不同句中表达多种关系;错误正例进入训练集会让模型把”解除职务""回到”等上下文学成创始人模式,预测时把无关句判为创始人,即语义漂移。PCNN 提供分段池化编码器,多实例学习与句子级注意力则为这类噪声降噪。
练习 3(事件要素与角色标注):对句子”英国当地时间 9 月 15 日早 8 时 15 分,位于伦敦西南的 Parsons Green 地铁站发生爆炸,目前已确定有多人受伤、具体伤亡人数尚不明确,英国警方已将此次爆炸与起火定性为恐怖袭击”,指出触发词、事件类型及其判定依据、事件元素及角色,并说明如何实例化成三元组。
参考答案
触发词为”发生爆炸”(核心触发词”爆炸”);事件类型为恐怖袭击,判定依据不是爆炸本身,而是后句”英国警方已将此次爆炸与起火定性为恐怖袭击”——触发词分类器同时判定触发词与事件类别:本例”爆炸”提示攻击类事件,“恐怖袭击”这一具体类型需结合后句定性。元素与角色:时间 = 当地时间 9 月 15 日早 8 时 15 分,地点 = Parsons Green 地铁站(伦敦西南为方位修饰);攻击者与伤亡人数均为空槽(课件口径标”-“,因”具体伤亡人数尚不明确”;“多人受伤”只是非数值线索,不填入该槽)。实例化时先建事件实例节点 ex:Event_x,rdf:type 指向恐怖袭击类型,再逐条添加 ex:time、ex:place 三元组;缺失角色不产生三元组,留待跨文档报道补全,这正是事件共指与跨文档元素角色补全的任务。
本章小结
- 知识抽取按数据源分四路:结构化(Direct Mapping/R2RML)、链接数据(图映射)、半结构化(包装器)、非结构化(信息抽取);本节只走通第四路,主线是”实体 → 链接 → 关系 → 事件”,核心矛盾是准确率与覆盖率,前三路仅作定位、留待后续各节展开。
- 任务边界由四系评测定义:MUC 奠定 NER 与共指,ACE 细化出实体/数值/时间/关系/事件五大任务,KBP 面向知识库填充(EDL、槽填充、事件、信念情感、冷启动),SemEval 提供关系分类等标准数据集。
- NER 本质是序列标注,IOB 把检测与分类合并为逐字打标签;HMM 是生成式有向图(转移加发射、独立假设),CRF 是判别式无向图(全局归一化、不做特征独立假设),BiLSTM-CRF 端到端自动提特征成为标配骨架。
- 实体识别后必须实体链接,经 mention 识别、候选生成、上下文消歧挂到知识库节点;消歧信号分不依赖上下文(词典、abstract、属性、词汇匹配)与依赖上下文(局部窗口词袋、全局主题、图协同)两类,代表系统为 Wikipedia Miner、DBpedia Spotlight、OpenCalais。
- 关系抽取三流派:模板(准确率高召回低、可移植差)、监督学习(特征三档、CR-CNN/Att-CNN/Att-BLSTM 与 Miwa 联合模型,准但贵且不能扩展新关系)、弱监督(远程监督靠 KB 对齐造语料但有强假设噪声,Bootstrapping 靠种子自举低成本高覆盖但有语义漂移)。
- 事件抽取是多元关系抽取:四术语为事件描述、触发词、事件元素、元素角色;pipeline 五分类器的误差级联衰减,联合推理与联合建模(结构预测)用全局约束和多任务共享缓解误差,DMCNN 用动态多池化适配一句多事件;语料扩充靠 FrameNet 迁移与知识库自动生成,跨文档融合靠网络多报道证据加强化学习决策;多元事件最终实例化为以事件实例为主语的一组三元组。
📋 行动清单
- 用代码块 1 的 IOB 编解码函数,给本领域 20 个句子手工标注实体片段并自动展开标签,体会 B/I 边界作用。
- 选一段新闻,分别用触发词模板和依存句法模板各写 3 条关系规则,记录命中与漏抽句子,量化准确率与召回率差异。
- 跑通代码块 2 的余弦消歧,把 abstract 换成本领域实体的真实描述,观察上下文窗口大小对消歧的影响。
- 针对一个熟悉的关系准备 3 个种子对,按代码块 3 的 Bootstrapping 在 50 条语料上迭代,记录每轮新增对并人工标记语义漂移样本。
- 找一篇含两个以上事件的新闻,按触发词、元素、角色三栏人工标注,并改写成代码块 4 风格的 Turtle 三元组。
- 画出自己业务的信息抽取流水线图(按 NER、共指、关系、事件、跨文档链接的先后依赖),在每个误差传播节点标注缓解手段(联合建模、注意力、人工审核)。
- 各读一遍 ACE 2005、TAC KBP、SemEval-2010 Task 8 的任务定义与评测指标,对照本节术语整理一张任务对照表。
—— 小象教研组
领取《小象 11GB VIP 课件资料包与大厂真题手册》
包含全套实战 Jupyter 源码、清洗后数据集、大厂高频面试真题与专属学员答疑交流群。
- ✔完整 Python / 数据分析 Jupyter 实战源码
- ✔大厂真实业务数据集与练习题
- ✔微信扫码添加顾问免费领取;想学什么,直接告诉顾问
微信扫码添加顾问