自然语言处理实战第二版(MEAP)(六)(2)https://developer.aliyun.com/article/1519690
11.5 指代消解
想象一下,你正在对一段文本进行 NER,然后你获得了模型识别出的实体列表。仔细检查后,你意识到超过一半的实体是重复的,因为它们指代了相同的术语!这就是指代消解派上用场的地方,因为它识别了句子中名词的所有提及。这将在你的知识图中合并相同事物的提及,而不是创建冗余的节点和边缘,并可能创建错误的关系。
在这篇关于那篇论文和她的老板的句子中,你能看到对"Timnit Gebru"的指代吗:
>>> i0 = text.index('In a six') >>> text_gebru = text[i0:i0+308] >>> text_gebru "In a six-page mail sent to an internal collaboration list, Gebru \ describes how she was summoned to a meeting at short notice where \ she was asked to withdraw the paper and she requested to know the \ names and reasons of everyone who made that decision, along with \ advice for how to revise it to Google's liking."
作为人类,你可以理解"Gebru","she"和"her"之间的关系。但对于机器来说,识别这一点就更加困难,特别是如果"she"在"Gebru"之前提及(这种现象称为前行指代)。
这还是一个相对简单的情况!考虑这个句子:“市议员拒绝了示威者的许可证,因为他们担心暴力”。在这句话中,“they"指的是谁?我们的常识告诉我们,它指的是"市议员”,对我们来说答案似乎很容易,但对于深度学习模型来说,使用常识识别提及是非常困难的。这个任务被称为温诺格拉德模式挑战,或者称为"常识推理"或"常识推断"问题。
让我们看看 NLP 如何处理这个困难的 NLP 任务。深刻的问题需要深度学习!
11.5.1 使用 spaCy 进行指代消解
截至撰写本文时,NeuralCoref 4.0 是开源社区中最快、最准确的实体解析器。正如其名称所示,NeuralCoref 使用深度学习神经网络(变压器)来解析指称实体的指代关系。SpaCy 将变压器和 NeuralCoref 整合到其"Universe"管道和模型集合中。NeuralCoref 使用原始的 SpaCy 管道进行POS
标记、命名实体识别,并提取文本中的指代(实体的次要提及)。然后,它将每个实体提及周围的单词输入到前馈神经网络或变压器中,计算一个估计值,判断每对提及是否指向同一个对象(实体)。通过比较这些得分,网络可以确定每个提及指向的内容。
spacy-experimental
包包括CoreferenceResolver
类内的指代消解算法,但要直接使用 NeuralCoref,您需要安装并导入coreferee
包。原始的 NeuralCoref 已不再积极维护,但 spaCy 已将算法移植到coreferee
包中,该包作为 spaCy 内的自定义管道运行。您还需要下载基于 transformer 的 spaCy 语言模型来使用coreferee
管道。
像其他 spacy 语言模型一样,您必须先下载"en_core_web_trf"才能load
并运行它。trf
后缀表示这个语言模型是 spaCy 工具箱的最新添加,它将一个transformer神经网络整合到管道中。这是一个非常庞大的语言模型,因此您可能不想运行cli.download()
函数的次数超过必要的次数。
>>> !python -m spacy.cli download 'en_core_web_trf' # #1 >>> import spacy, coreferee # #2 >>> nlptrf = spacy.load('en_core_web_trf') >>> nlptrf.add_pipe('coreferee') <coreferee.manager.CorefereeBroker at 0x...> >>> doc_gebru = nlptrf(text_gebru) >>> doc_gebru._.coref_chains [0: [13], [16], [26], [34], 1: [51], [56]] >>> doc_gebru._.coref_chains.print() 0: Gebru(13), she(16), she(26), she(34) # #3 1: advice(51), it(56)
因此,该管道能够找到 2 个指代链,将实体的提及链接在一起。这两个链表示两个不同的现实世界对象,“Gebru"和"advice”。位置 13 的"Gebru"标记与位置 16、26 和 34 的三个"she"代词相连。"advice"标记与位置 56 的单词"it"相连。
现在您已经将维基百科中对 Gebru 的所有提及汇总到了这一句中,您可以利用这些指代消解来提取有关她的重要关系和事实。
11.5.2 实体名称规范化
与指代消解密切相关的是实体的规范化问题。实体的规范化表示通常是一个字符串,即使是数字信息如日期也是如此。例如,Timnit Gebru 的出生日期的规范化 ISO 格式将是"1983-05-13"。对实体进行规范化表示使您的知识库能够将世界上在同一日期发生的所有不同事件连接到图中的同一节点(实体)。
您对其他命名实体也会执行相同的操作。您会更正单词的拼写,并尝试解决对象、动物、人物、地点等名称的歧义。例如,旧金山可能在不同的地方被称为"San Fran"、“SF”、“'Frisco"或"Fog City”。命名实体的规范化确保拼写和命名变体不会使您的实体名称词汇受到混淆、冗余名称的污染。
知识图应以相同方式规范化每种类型的实体,以防止同一类型的多个不同实体共享相同的"名称"。您不希望数据库中有多个人名条目指向同一物理人。更重要的是,规范化应该一致应用——无论是在向知识库写入新事实时还是在读取或查询知识库时。
如果你决定在数据库填充后更改归一化方法,则应“迁移”或修改知识库中现有实体的数据以符合新的归一化方案。无模式数据库(键值存储)例如用于存储知识图或知识库的数据库也不免于关系型数据库的迁移责任。毕竟,无模式数据库是关系型数据库的接口包装器。
11.6 依存句法分析
在上一节中,你学会了如何识别和标记文本中的命名实体。现在你将学习如何找到这些实体之间的关系。一个典型的句子可能包含多个不同类型的命名实体,如地理实体、组织机构、人物、政治实体、时间(包括日期)、物件、事件和自然现象。同时句子中可能也包含多个关系,这些关系是在句中命名实体之间关系的事实。
NLP 研究人员确定了可以用于识别句子中单词如何共同创造含义的两个单独的问题或模型:依存句法分析和成分句法分析。依存句法分析将为你的 NLP 流水线提供像你在语法学校(小学)学习的语句图表一样的图表,这些树形数据结构为你的模型提供了一个句子的逻辑和语法的表示。这将帮助你的应用程序和机器人变得更加聪明,以更好解释句子并对其进行操作。
成分句法分析是另一种技术,它专注于识别句子中的成分子短语。虽然依存句法分析涉及单词之间的关系,但成分句法分析的目标是将句子解析为一系列子短语。这些子短语可以是名词短语(“我的新电脑”)或动词短语(“有内存问题”)等。成分句法分析的方法更为自上而下,尝试将成分迭代地分解为更小的单元和它们之间的关系。虽然成分句法分析可以捕捉更多关于句子的句法信息,但其结果的计算速度更慢,更难解释。因此我们现在将专注于依存句法分析。
但等等,你可能会想知道为什么理解实体之间的关系和句子图表如此重要。毕竟,你可能已经忘记了如何创建这些图表,并且可能从未在现实生活中使用过它们。但这只是因为你已经内化了这个世界的模型。我们需要在机器人中创建这种理解,以便它们可以像你一样无意识地完成同样的任务,从简单的语法检查到复杂的虚拟助手。
基本上,依存句法分析将为第一章中提到的所有应用提供帮助。你是否注意到像 GPT-3 这样的聊天机器人在理解简单句子或进行实质性对话时常常失败?一旦你开始询问它们所“说”单词的逻辑或推理,它们就会失误。聊天机器人开发人员和对话设计师通过使用基于规则的聊天机器人来解决这个限制,用于进行治疗和教学等实质性对话。只有当用户试图谈论尚未编程到其中的内容时,才会使用开放式神经网络模型,如 PalM 和 GPT-3。而语言模型的训练目标是将对话引导回机器人知道和有规则的东西。
依存句法分析(Dependency parsing)正如其名称所示,依赖于句子中单词之间的“依存关系”以提取信息。两个单词之间的“依存关系”可以是它们的语法、短语或任何自定义的关系。但在依存句法树的上下文中,我们指的是句子中一对单词之间的语法关系,其中一个充当“头”(head),另一个充当“从属”(dependent)。在句法树中,有一个词在结构树中不依赖于任何其他单词,这个词被称为“根”(root)。根是依存树的起点,就像森林中一棵树的主根一样,它开始生长树干和树枝(关系)。一个词可以有 37 种依存关系,这些关系来自于通用斯坦福依存关系系统。
spaCy 软件包知道如何识别单词和短语之间的这些关系,并为您绘制依存图。让我们尝试对一个句子进行依存句法分析:
>>> text = "Gebru was unethically fired from her Ethical AI team." >>> doc = nlp(text) >>> doc2df(doc) TOK POS TAG ENT_TYPE DEP 0 Gebru PROPN NNP PERSON nsubjpass 1 was AUX VBD auxpass 2 unethically ADV RB advmod 3 fired VERB VBN ROOT 4 from ADP IN prep 5 her PRON PRP$ poss 6 Ethical PROPN NNP ORG compound 7 AI PROPN NNP ORG compound 8 team NOUN NN pobj 9 . PUNCT . punct
你可以看到,这个句子的根是动词"fired"。这是因为在我们的句子中,单词"fired"恰好是主谓宾结构中的主动动词。而单词"Gebru"扮演的依存角色是“被动名词主语”(nsubjpass
)。你能否找到它们之间的依存关系,以创建一个关系或知识图中的事实呢?children
属性给出了一个列表,其中包含所有依赖于特定标记的词。这些依存关系是连接标记、构建事实的关键。
所以,如果你想要展示句子中每个标记的子标记,你需要在 token_dict
函数中包含 children
属性。
>>> def token_dict2(token): ... d = token_dict(token) ... d['children'] = list(token.children) # #1 ... return d >>> token_dict2(doc[0]) OrderedDict([('TOK', 'Gebru'), ('POS', 'PROPN'), ('TAG', 'NNP'), ('ENT_TYPE', 'PERSON'), ('DEP', 'nsubjpass'), ('children', [])])
你可能觉得奇怪的是,在这个句子中,“Gebru”这个标记没有任何子节点(依赖项)。毕竟,它是句子的主语。自然语言语法规则的子父关系一开始可能会有点混乱,但是你可以使用displacy
和你的doc2df
函数来帮助你建立单词相互依赖的心理模型。
重新定义 doc2df 函数以将children
属性作为列添加,这样你就可以看到这个句子中是否有其他单词有依赖项(子节点)。
>>> def doc2df(doc): ... df = pd.DataFrame([token_dict2(t) for t in doc]) ... return df.set_index('TOK') >>> doc2df(doc) POS TAG ENT_TYPE DEP children TOK Gebru PROPN NNP PERSON nsubjpass [] was AUX VBD auxpass [] unethically ADV RB advmod [] fired VERB VBN ROOT [Gebru, was, une... from ADP IN prep [team] her PRON PRP$ poss [] Ethical PROPN NNP ORG compound [] AI PROPN NNP ORG compound [Ethical] team NOUN NN pobj [her, AI] . PUNCT . punct []
看起来句子的根节点(标记为ROOT
)有最多的子节点。"Fired"是句子中最重要的词,所有其他词都依赖于它。依赖树中的每个词都与句子中其他地方的另一个词相连接。要看到这一点,你需要检查句子根节点“fired”中那长长的子节点列表。
>>> doc2df(doc)['children']['fired'] [Gebru, was, unethically, from, .]
句子根节点延伸到“Gebru”一词,以及包括“from”在内的几个其他单词。而“from”一词导向“team”,然后是“her”和“AI”。而“AI”导向“Ethical”。你可以看到子节点修改其父节点。
依赖树的ROOT
是句子的主要动词。这通常是您会找到最多子节点的标记位置。动词在知识图谱中变成关系,子节点成为关系三元组的对象。标记“Gebru”是被动动词"fired"的子节点,所以你知道她是被解雇的人,但是这个句子没有说是谁负责解雇她。由于你不知道动词“fired”的主语,你无法确定谁应该得到描述他们行为的“不道德”副词。
是时候让依赖图发光了!我们将使用 spaCy 的一个子库称为displacy
。它可以生成可缩放矢量图形SVG 字符串(或完整的 HTML 页面),可以在浏览器中作为图像查看。这种可视化可以帮助你找到使用树来创建关系抽取标签模式的方法。
列表 11.2 可视化一个依赖树
>>> from spacy.displacy import render >>> sentence = "In 1541 Desoto wrote in his journal about the Pascagoula." >>> parsed_sent = nlp(sentence) >>> with open('pascagoula.html', 'w') as f: ... f.write(render(docs=parsed_sent, page=True, options=dict(compact=True)))
当你打开文件时,你应该看到类似于图 11.3 的东西。
图 11.3 句子的依赖图
在我们解释依赖解析与关系抽取之间的连接之前,让我们简要介绍一下我们可以使用的另一个工具 - 组成解析。
11.6.1 使用 benepar 进行组成解析
伯克利神经解析器和 Stanza 一直是文本中提取组成关系的首选选项。让我们探索其中一个,伯克利神经解析器。
这个解析器不能单独使用,需要 spaCy 或 NLTK 之一来加载它以及它们现有的模型。你想要使用 spaCy 作为你的分词器和依赖树解析器,因为它不断在改进。
列表 11.3 下载必要的包
>>> import benepar >>> benepar.download('benepar_en3')
下载包后,我们可以先将benepar
添加到 spaCy 的流水线中,然后用一个示例句子测试它。
>>> import spacy >>> nlp = spacy.load("en_core_web_md") >>> if spacy.__version__.startswith('2'): ... nlp.add_pipe(benepar.BeneparComponent("benepar_en3")) ... else: ... nlp.add_pipe("benepar", config={"model": "benepar_en3"}) >>> doc = nlp("She and five others coauthored a research paper,'On the Dangers of Stochastic Parrots: Can Language Models Be Too Big?'") >>> sent = list(doc.sents)[0] >>> print(sent._.parse_string) (S (NP (NP (PRP She)) (CC and) (NP (CD five) (NNS others))) (VP (VBD coauthored) (NP (NP (DT a) (NN research) (NN paper)) (, ,) (`` ') (PP (IN On) (NP (NP (DT the) (NNS Dangers)) (PP (IN of) (NP (NNP Stochastic) (NNPS Parrots))))) (: :) (MD Can) (NP (NN Language) (NNS Models)) (VP (VB Be) (ADJP (RB Too) (JJ Big))))) (. ?) ('' '))
看起来相当神秘,对吗?在上面的示例中,我们为测试句子生成了一个解析字符串。解析字符串包括句子中各种短语和标记的词性标记。你可能会在我们的解析字符串中注意到一些常见的标记,如 NP(“名词短语”)、VP(“动词短语”)、S(“句子”)和 PP(“介词短语”)。现在你可以看出,从成分解析器的输出中提取信息有点难。然而,它可以用来识别句子中的所有短语,并在句子简化和/或摘要中使用它们。
现在你知道如何提取句子的句法结构。这将如何帮助你追求一个智能聊天机器人?
11.7 从依存解析到关系提取
我们已经到了帮助我们的机器人从所阅读的内容中学习的关键阶段。从维基百科上拿这样一句话:
1983 年,苏联防空军的一名中校斯坦尼斯拉夫·彼得罗夫拯救了世界免受核战争的威胁。
如果你在阅读或听到类似的历史课内容后做笔记,你可能会改述这些内容并在大脑中建立概念或词汇之间的联系。你可能将其简化为一个知识点,那就是你从中“得到的东西”。你希望你的机器人也能做同样的事情。你希望它能“记录”它所学到的任何东西,比如斯坦尼斯拉夫·彼得罗夫是一名中校这样的事实或知识。这可以存储在类似以下的数据结构中:
('Stanislav Petrov', 'is-a', 'lieutenant colonel')
这是知识图谱或知识库中两个命名实体节点(‘Stanislav Petrov’ 和 ‘lieutenant colonel’)以及它们之间的关系或连接(‘is a’)的示例。当像这样的关系以符合知识图谱的 RDF 标准(资源描述格式)的形式存储时,它被称为 RDF 三元组。历史上这些 RDF 三元组被存储在 XML 文件中,但它们可以存储在任何能够以(subject, relation, object)
形式持有三元组图的文件格式或数据库中。这些三元组的集合将是你的知识图谱!
让我们继续使用我们所知道的两种方法——模式和机器学习——为你的知识图谱创建一些素材。
自然语言处理实战第二版(MEAP)(六)(4)https://developer.aliyun.com/article/1519696