OpenUE:一个开源的通用文本信息抽取工具
OpenKG地址:http://openkg.cn/tool/openue
GitHub地址:https://github.com/openkg-org/openue
Gitee地址:https://gitee.com/openkg/openue
OpenUE网站:http://openue.openkg.cn
论文地址:https://aclanthology.org/2020.emnlp-demos.1.pdf
开放许可协议:GPL 3.0
贡献者:浙江大学(张宁豫、谢辛、毕帧、王泽元、陈想、叶宏彬、余海阳、田玺、邓淑敏、郑国轴、陈华钧),阿里巴巴集团(陈漠沙、谭传奇、黄非)
该论文是浙江大学和阿里达摩院合作发表在EMNLP2020
上的Demo论文,本文提出了一个简单的思想,即大多数自然语言处理任务可以用一种通用的抽取范式来表示,进而提出了一个OpenUE开源知识图谱抽取工具。
?
知识图谱构建旨在从海量结构化和非结构化数据中进行实体、关系、属性和事件的信息提取,将知识存储到知识库中,最后进行进一步的知识推理和图谱应用。对于这里如何从海量结构化和非结构化数据中进行实体、关系、属性和事件的信息提取,主要可以分为两类任务,第一类是词级别分类,比如,命名实体识别、槽填充和参数角色分类等等;第二类是句子级别的理解(例如,关系分类、意图检测和事件分类等)。以前的大部分工作通常使用专门设计的神经网络架构来完成这些任务。但是这些任务中的大多数都共享类似的编码器和解码器模块,同时由于知识的复杂性和异构性,如果不同的抽取任务需要设计不同的模型,在一定程度上影响了知识抽取的效率。因此,本文提出了一个轻量级的知识图谱抽取工具OpenUE ,以统一的范式实现实体、关系、事件等各种信息抽取任务。OpenUE 底层支持pytorch lightning, 兼容huggingface transformer库。
OpenUE可以干什么,即它的实现的应用场景,首先是
-
三元组抽取
三元组抽取目的是为了从非结构化文本抽取实体以及实体间蕴含的关系。比如对于句子“巴黎被称为法国的浪漫之都”,理想三元组抽取应获得三元组<法国, 首都, 巴黎>,其中首都是巴黎和法国两个实体的关系。本文中提供了一种简单的思路,即首先对与句子的关系进行分类,然后进行序列标记以提取实体,这个会在模块设计中详细介绍。
关系优先方法在真实场景中是很大帮助,因为大多数句子都包含NA关系(也就是没有关系)。因此OpenUE可以预先过滤掉没有关系的文本,提高计算效率。此外OpenUE还提供了从Web提取知识的简单实现,包含了使用爬虫来获取原始网页,并从网页文本中提取事实知识。
-
第二应用为 事件抽取
从自然语言文本中抽取事件非常具有难度的。当给定一个文档时,事件抽取系统需要识别具有特定类型的事件触发词以及包含的元素和角色。在真实场景中,OpenUE先对文档进行基于事件类型分类,进而并基于序列标注进行角色抽取。OpenUE集成了无需触发词检测的事件抽取功能。
例如,左图的第二个框,触发词为married,参与事件的实体为Dr.Germ,参与事件的实体在事件所扮演的地点角色为USA。
argument:参与事件的实体
role:参与事件的实体在事件所扮演的角色
-
第三应用为槽填充和意图检测
自然语言理解(NLU)对于对话系统是至关重要,它通常包括意图检测和槽填充两个任务,为用户话语形成一个语义解析。例如给定用户的话语,槽填充在单词级别上理解该文本,为指示特定单词分配相应的槽位类型。而意图检测在句子级别上进行,为整个句子打上意图标签。槽填充和意图检测依赖于token级别和句子级别的理解, OpenUE也集成了该任务。
例如,左图的第三个框,这句话的意思为让Google Music 播放 某人的一个唱片,槽填充就会显示如下结果,在响应的单词下面标记出来。意图检测就可以检测出来要播放音乐。
第三部分,介绍一下OpenUE的模块设计和代码设计,首先先看模块设计,
-
Tokenization
首先是分词器,分词器将输入文本转化为多个token。OpenUE同时实现了单词级标记和子单词级标记。这两种可以满足大多数Tokenization的需求。
-
Classification
第二个模块是分类器,分类模块是为句子级任务设计的。OpenUE中采用预训练的语言模型作为默认实例编码器,我看着github代码使用的基础模型为
bert
。对于训练集中的每个句子 \(x=\left\{w_{1}, w_{2}, \ldots, w_{n}\right\}\) ,其中 \(w_{i} \in x\) 是句子中的单词标记。首先以以下形式构造输入句子: \(\left\{[C L S], w_{1}, w_{2}, \ldots, w_{n},[S E P]\right\}\) 。然后,我们利用[CLS]表示的输出对整个句子信息进行编码,应用具有交叉熵损失的MLP层来执行句子分类。[CLS]是用于分类输出的特殊符号,[SEP]是用于分隔非连续token序列的特殊符号,即可以简单理解为句子之间的分隔符。
-
Sequence Labeling
第三个模块是序列标签模块,用于token级任务,用与上一节相同的编码器来表示实例。将分类模块的输出与原始句子连接起来作为序列标签的输入。具体以关系三元组提取为例,输入为\(\left\{[C L S]\right.\), relation, \(\left.[S E P], w_{1}, w_{2}, \ldots, w_{n}\right\}\)
-
Extractor
OpenUE实现了一个抽取器模块,用来结合分类和序列标记的输出。对于实体和关系提取,利用贪心的方法来组合最终结果,对于其他任务,例如空位填充和意图检测,将这些输出分组即为最终预测。
这就是OpenUE的具体模块设计,接下来,简单介绍一下OpenUE的代码结构,总体分为三个模块models
,lit_models
,data
。首先是
-
models
模块,它主要负责模型的逻辑,里面有三个子模型第一个模块是
ReModel
,主要功能是识别句子中的关系,本质上是一个分类模型。第二个模块是
SeqMode
,它利用ReModel
识别的这种关系抽取出来对应的头尾实体。组后一个是
InferModel
,主要负责将两个模型整合起来,并且负责总的推理逻辑。其存放了我们主要的三个模型。针对整句的关系识别模型;针对已知句中关系的命名实体识别模型。还有将前两者整合起来的推理验证模型。
-
lit_models
模块
其中的代码主要继承自pytorch_lightning.Trainer
,整体负责模型的训练,日志log以及测试功能,其可以自动构建单卡、多卡、GPU
、TPU
等不同硬件下的模型训练 -
data模块,主要负责数据的逻辑,分为三个子模块
我们常见的
Tokenizer
,它来自于Transformer
库,先使用Tokenizer
把文本转化为id
,然后可以使用DataSet
以及pytorch
的DataLoader
生成这种batch形式的数据,然后喂进去这个模型。data中存放了针对不同数据集进行不同操作的代码。使用了transformers库中的tokenizer先对数据进行分词处理再根据不同需要将数据变成我们需要的features。
第四部分,对openUE进行一个简单的应用,首先先看一下OpenUE输入的数据长什么样子。
这个数据来自于ske,数据集是基于schema的中文信息抽取数据集,其包含超过19万中文句子及50个已定义好的schema。数据集中的句子来自百度百科、百度贴吧和百度信息流文本。数据集划分为17万训练集,1万验证集和1万测试集。
openUE输入数据形式:
在json文件中,text
就是输入的文本,下面的spo_list
是输出的各种三元组,三元组中包含了头实体,尾实体以及他们中间对应的各种关系,比如,这里的predicate
就是代表着关系,object
,subject
对应着头尾实体。
下面,以三元组抽取任务为例子,我们简单,介绍一下OpenUE的主要功能模块以及训练的流程,具体实验环境平台选择Google的colab,首先第一步需要下载好最新版本的OpenUE,可以用git clone ,也可以用使用pip install
然后,第二步,载入好预先设定好的各种超参数。这里超参数存储在run-seq.yaml文件中,
为了保证实验的可复现性,需要统一设定随机种子,像numpy的随机数种子以及一些torch的随机数种子。 并引入我们上文之前提到的三个主要模块 data, model, litmodel 。
这里我们设置训练日志逻辑中的子模块。 early_callback 负责在训练逻辑中early stopping的操作。 像early stopping也是在训练模型中经常使用的一种方式,它可以避免模型中的过拟合。
Model_checkpoint 负责自动保存模型以及设置模型路径。
OpenUE比较轻量级,只需要trainer.fit 和 test 即可实现模型自动训练以及测试。
模型保存,模型自动保存在output文件夹下,但训练的GPU时间很长。