基于语义解析的KBQA——代码和论文详细分析

根据论文:Semantic Parsing on Freebase from Question-Answer Pairs,分析其代码和步骤,以加强对这一流程的深入理解,重点关注模型的输入、输出和具体方法。

前言

提供阅读本文的前提知识,引用自Semantic Parsing on Freebase from Question-Answer Pairs这篇论文。

语义解析

知识库由大量的三元组组成,并且这些三元组的实体和实体关系都是形式化的语言。

比如(BarackObama, PlaceOfBirth, Honolulu),给定一个自然语言的问题 “Where was Obama born?”,我们面临的第一个挑战就是,如何建立问题到知识库的映射

语义解析KBQA的思路是通过对自然语言进行语义上的分析,转化成为一种能够让知识库理解的语义表示,进而通过知识库中的知识,进行推理(Inference)和查询(Query),得出最终的答案。

简而言之,语义解析就是将自然语言的问题,转化为一种能够让知识库“看懂”的语义表示,这种语义表示即逻辑形式(Logic Form)

逻辑形式

为了能够对知识库进行查询,我们需要一种能够“访问”知识库的逻辑语言,Lambda-DCS是一种经典的逻辑语言,它用于处理逻辑形式而实际操作中我们经常用SPARQL,它通常可以在Virtuoso engine上对Freebase进行查询。如果把知识库看作是一个数据库,逻辑形式则可以看作是查询语句的表示。

我们用 z 表示一个逻辑形式,用 k 表示知识库,e 表示实体,p 表示实体关系(有的也称谓语或属性)。逻辑形式分为一元形式(unary)和二元形式(binary)。对于一个一元实体 e ,我们可以查询出对应知识库中的实体;给定一个二元实体关系 p ,可以查到它在知识库中所有与该实体关系 p 相关的三元组中的实体对。

并且,我们可以像数据库语言一样,进行连接Join,求交集Intersection和聚合Aggregate(如计数,求最大值等等)操作。具体来说,逻辑形式有以下形式和操作:

有了上面的定义,我们就可以把一个自然语言问题表示为一个可以在知识库中进行查询的逻辑形式

比如对于问句 “Number of dramas starring Tom Cruise?”

它对应的逻辑形式是 count(Genre.Drama \cap Performance.Actor.TomCruise)

当自然语言问题转化为逻辑形式之后,通过相应的逻辑语言(转化为SPARQL query)查询知识库就可以得到答案。

所以接下来就是我们要学习和研究的重点:语义解析如何把自然语言问题正确地转化为相应的逻辑形式

1. 概要

该论文该方法来自斯坦福的 Jonathan Berant,发表于2013年的EMNLP会议,是一个经典的语义解析baseline。

论文在Freebase上提出训练一个语义解析器,并基于该语义解析器进行KBQA,不再依赖于代价大的标注逻辑形式,而直接从问题-答案对中学习。给定自然语言问句,KBQA最棘手的问题就是存在相关的大量可能的逻辑谓词,对于怎么从问题句子中降低可能的逻辑谓词(logical predicates),作者提出了两种方法:

(1)短语到谓词的映射(mapping):通过将大型文本语料库与Freebase对齐,构建一个语句到谓词的粗糙映射

(2)桥接操作(bridging operation):基于相邻谓词生成与之兼容的逻辑谓词

2. 模型

该模型为使用本文所将方法而实现的一个小的demo模型,具体流程和框架与原论文基本一致,其中2.1解析器方法会重点介绍论文中使用的Sempre源代码和方法

2.1 模型架构

输入:英语自然语言查询

输出:从Freebase中检索出的自然语言答案

示例: Who did Obama marry? -> (SBARQ (WHNP (WP Who)) (SQ (VBD did) (NP (NNP Obama)) (VP (VB marry))) (. ?))

-> {'subject': 'Obama', 'property': 'marry'}

-> SELECT ?valLabel WHERE { { wd:Q76 p:P26 ?prop . ?prop ps:P26 ?val . } SERVICE wikibase:label { bd:serviceParam wikibase:language "en"} }

-> Michelle Obama

2.2 解析器方法—Sempre 1.0

源代码文件框架

主要源文件:

  • Main.java:Sempre 主类,包含了 Sempre 的入口点。

  • Master.java:Sempre 主控类,负责调度和管理解析任务。

  • Session.java:Sempre 会话类,表示一个解析任务的会话。

  • Builder.java:Sempre 构建器类,用于构建语义解析器的各个组件。

解析器相关:

  • Parsers.java:解析器管理类,用于管理不同类型的解析器。

  • Parser.java:解析器接口,定义了解析器的基本行为。

  • BeamParser.java:Beam 解析器类,实现了基于 Beam Search 的解析算法。

语法和特征提取:

  • Grammar.java:语法类,用于管理语法规则。

  • FeatureExtractor.java:特征提取器类,用于从输入中提取特征。

  • FeatureVector.java:特征向量类,用于表示特征。

执行器相关:

  • Executor.java:执行器接口,定义了执行器的基本行为。

  • SparqlExecutor.java:SPARQL 执行器类,用于执行 SPARQL 查询。 其他支持类:

  • LanguageInfo.java:语言信息类,用于表示语言相关信息。

  • StringCacheServer.java:字符串缓存服务器类,用于管理字符串缓存。

  • FreebaseSearch.java:Freebase 搜索类,用于在 Freebase 中进行实体搜索。

输入:给定 i)一个知识库K ii)问题-答案对训练集\{(x i, y i)\}_{i=1}^{n}

输出:通过潜在逻辑形式z和知识库K将问题x映射到答案y上的语义解析器

整体是一个自底向上构造语法树的过程,树的根节点,就是该自然语言问题最终的逻辑形式表达。可以分为两个步骤:

  1. 1. 词汇映射(Lexicon):即构造底层的语法树节点。将单个自然语言短语或单词映射到知识库实体或知识库实体关系所对应的逻辑形式。作者通过构造一个词汇表(Lexicon)来完成这样的映射。

  2. 2. 构建(Composition):即自底向上对树的节点进行两两合并,最后生成根节点,完成语法树的构建。这一步有很多种方法,诸如构造大量手工规则,组合范畴语法(Combinatory Categorical Grammars,CCG)等等,本方法中作者采用了最暴力的方法:对于任何两个节点都可以执行上面所谈到的连接Join,求交Intersection,聚合Aggregate三种操作。以及使用独创的桥接操作进行结点合并。缺点是这种合并方式复杂度是指数级的,最终会生成很多棵语法树,因此还需要通过对训练数据进行训练,训练一个分类器,对语法树进行筛选

自然语言—>逻辑形式流程如下图所示:

  • 红色部分即逻辑形式
  • 绿色部分where was Obama born 为自然语言问题
  • 蓝色部分为词汇映射(Lexicon)和构建(Composition)的操作
  • 最终形成的语义解析树的根节点为语义解析结果

针对上面的方法,有三个待解决的细节问题:(1)如何训练分类器?(2)如何构建词汇表?(3)什么是桥接操作?

2.2.1 训练分类器

分类器的任务是计算每一种语义解析结果d(Derivation)的概率,对于对每个 d ∈ D(x),使用判别对数线性模型discriminative log-linear model进行建模,使用Softmax进行概率归一化,公式如下:

其中\phi(x,d_{i}) 是b维的参数向量,它是一个从语义解析结果d_{i}和x中提取出来的b维特征向量(该特征向量包含了构造该语法树所有操作的对应特征,每种操作的具体特征之后会提到),

对于训练数据对,训练的目标是最大化Log-likelihood损失函数,通过AdaGrad算法(一种动态调整学习率的随机梯度下降算法)进行参数更新。

2.2.2 构建词汇表

词汇表即自然语言与知识库实体或知识库实体关系的单点映射,这一操作也被称为对齐(Alignment)。

将自然语言实体映射到知识库实体相对比较简单,比如将“Obama was also born in Honolulu.”中的实体Obama映射为知识库中的实体BarackObama,可以使用一些简单的字符串匹配方式进行映射

但是要将自然语言短语如“was also born in”映射到相应的知识库实体关系,如PlaceOfBirth, 则较难通过字符串匹配的方式建立映射。

可以进行统计,如果有较多的实体对(entity1,entity2)作为主语和宾语出现在was also born in的两侧,并且在知识库中,这些实体对也同时出现在包含PlaceOfBirth的三元组中,那么我们可以认为“was also born in”这个短语可以和PlaceOfBirth建立映射。简而言之就是:如果一个句子两端实体和知识库谓词两端实体重复很多,则将这两者对齐。

比如(“Barack Obama”,“Honolulu”),(“MichelleObama”,“Chicago”)等实体对在文档中经常作为“was also born in”这个短语的主语和宾语,并且它们也都和实体关系PlaceOfBirth组成三元组出现在知识库中。

本论文在ClueWeb09上抽取15millions个三元组构成一个数据集,如(“Obama”, “was also born in”, “August 1961”),可以看出三元组的实体和关系都是自然语言的形式,取出其中的一个三元组子集,对里面的每一个三元组的主语实体和宾语实体通过字符匹配的方式替换为知识库的实体,并对数据进行归一化。

如(“Obama”, “was also born in”, “August 1961”) 经过预处理后转化为 (BarackObama, “was also born in”, 1961-08)。

接着对每一个三元组中的自然语言短语r_{1} 两边的实体对(entity1,entity2)进行统计。

注意⚠️ 由于自然语言短语具有多义性,r_{1}和知识库实体关系r_{2}的对应关系是多对多的,比如“was also born in”可能对应PlaceOfBirth或DateOfBrith,我们需要对每一个r_{1}进行区分。可以通过知识库查询到每一个实体的类型(type),比如1961-08的类型是date,而Honolulu的类型是place,我们对r_{1}两边的实体类型进行查询可以得到主语实体的类型t_{1}和宾语实体的类型t_{2},因此r_{1}可以进一步表示为r_{1}[t_{1},t_{2}],我们对其所在三元组两边的实体进行统计,得到实体对集合F(r_{1}[t_{1},t_{2}])。对齐构造主要如下图:

图中绿色字体为r_{1},蓝色字体为r_{2}。作者定义了词汇映射操作的三种特征用于训练分类器:对齐特征(Alignment features),文本相似度特征(Text similarity features),和词汇化特征(Lexicalized features),具体内容如下表所示:

其中文本相似度特征中的s_{2}指r_{2}的freebase name。

在实际使用中,我们可以通过词性标注(POS)和命名实体识别(NER)来确定哪些短语和单词需要被词汇映射(Lexicon),从而忽略对一些skipped words进行词汇映射。并且,作者还建立了18种手工规则,对问题词(question words)进行逻辑形式的直接映射,如“where,how many”映射为Type.Location 和 Count。

构建词汇表/对齐部分的代码位于文件:sempre/src/edu/stanford/nlp/sempre/paraphrase/Aligner.java

其中对齐操作在align()方法中:

public Alignment align(ParaphraseExample example, Params params) {example.ensureAnnotated();Alignment alignment = new Alignment(example);alignment.buildAlignment(example, params);example.setAlignment(alignment);return alignment;
}

构建对齐结果,包括计算同义词替换、删除、添加等操作在Alignment 内部类的buildAlignment()方法中:

public void buildAlignment(ParaphraseExample example, Params params) {computeIdentityAlignments(example);computePhraseTableAlignments(example);computeSubstitutionsAlignment(example);computeDerivationsAlignment(example);//this needs to be done lastmarkDeletions(example);if(opts.useSyntax)computeSyntacticAlignment(example);if(opts.verbose>=1) {printFeaturesAndWeights(params);}score = featureVector.dotProduct(params);}

2.2.3 桥接操作

完成词汇表的构建后,仍然存在一些问题。比如,对于go,have,do这样的轻动词(light verb)难以直接映射到一个知识库实体关系上,其次,有些知识库实体关系极少出现,不容易通过统计的方式找到映射方式,还有一些词比如actress,实际上是两个知识库实体关系进行组合操作后的结果(actor \cap gender.female) 。因此需要找到一个额外的二元关系来将当前的逻辑形式连接起来,这就是桥接。

举个具体的例子,比如 “Which college did Obama go to?

假设“Obama”和“college”可被词汇映射映射为 BarackObamaType.University,这里"go to"却难以找到一个映射,所以这里我们需要去寻找一个中间二元关系b(即Education)使得上面的句子可以被解析为(Type.University \cap Education.BarackObama),如下图所示:

具体来说就是给定两个一元逻辑形式z_{1}, z_{2},它们的类型分别为t_{1}, t_{2},对于每个二元关系b如果它的主语宾语类型和t_{1}, t_{2}相同,则在b对应的实体类型满足(t_{1}, t_{2})的条件下,生成逻辑形式z_{1} \cap b.z_{2}

桥接部分的代码位于:sempre/src/edu/stanford/nlp/sempre/BridgeFn.java,其中

  • bridgeUnary()方法处理一元关系的桥接,它根据候选上下文和问题上下文的类型信息,以及二元关系的信息,将一元关系与二元关系连接起来;

  • bridgeEntity 方法处理实体的桥接操作,它根据问题上下文的类型信息和二元关系的信息,将实体与相应的二元关系连接起来;

  • injectIntoCvt方法处理将实体注入到复合关系中的桥接操作,它找到复合关系中的待填充位置,并将实体与相应的二元关系连接起来。

3. 模型代码

模型主要实现代码位于nlquery代码的nlquery/nlquery/nlquery.py文件,其中:

NLQueryEngine类包含了整个查询流程的实现:

  • __init__方法会创建一个StanfordServerParser对象,用于将自然语言问题解析成树状结构。

  • subject_query方法的作用是将匹配到的上下文转换为查询参数,并执行查询操作。这个方法主要用于处理主语查询,即从自然语言问题中提取出主语、动词动作、属性等信息,然后根据这些信息执行查询操作,最终返回查询结果。

  • find_entity_query 方法的作用是将匹配到的上下文转换为查询参数,并执行查询以找到实体。该方法通常用于解析自然语言查询,提取查询中的实体、属性和限定条件,并将其转换为可以用于查询实体的参数。最终,该方法将返回一个包含查询结果的 Answer 对象。

  • get_property 方法的作用是获取给定主题的属性。该方法通常用于根据给定的主题和属性查询相应的信息,比如查询某个人的年龄、职业等属性。根据查询的结果,该方法会返回一个包含查询结果的 Answer 对象。

  • preprocess 方法的作用是对查询语句进行预处理,主要是添加必要的标点符号,确保查询语句的格式正确。通常情况下,查询语句应以问号结尾,如果查询语句缺少问号,则该方法会自动在末尾添加问号。

4.细节

  • 对于知识库的存储,常见采用的是Virtuoso SPARQL engine,配合lambda-DCS进行查询。

  • 知识库存储也可采用jena+sparql框架实现,环境搭建https://jena.apache.org/download/

3. 参考/代码资料

  • 论文阅读:Semantic Parsing on Freebase from Question-Answer Pairs-CSDN博客

  • 解析器Sempre第一版代码: Sempre 1.0 Webquestions training · Issue #47 · percyliang/sempre · GitHub

  • KBQA_Demo代码:GitHub - ayoungprogrammer/nlquery: Natural Language Engine on WikiData

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/504955.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

技术活也能轻松搞定!Xinstall一键完成Android多渠道打包

随着移动互联网的迅猛发展,Android应用市场呈现出百花齐放的态势。为了满足不同市场的需求,开发者们常常需要为同一个应用打包多个渠道版本。然而,传统的打包方式繁琐且耗时,让渠道运营人员苦不堪言。今天,我们就来聊聊…

【黑马程序员】4、TypeScript高级类型_黑马程序员前端TypeScript教程,TypeScript零基础入门到实战全套教程

课程地址:【黑马程序员前端TypeScript教程,TypeScript零基础入门到实战全套教程】 https://www.bilibili.com/video/BV14Z4y1u7pi/?share_sourcecopy_web&vd_sourceb1cb921b73fe3808550eaf2224d1c155 目录 4、TypeScript高级类型 4.1 class类 4…

什么是片内片间均匀性?

均匀性在芯片制程的每一个工序中都需要考虑到,包括薄膜沉积,刻蚀,光刻,cmp,离子注入等。较高的均匀性才能保证芯片的产品与性能。那么片内和片间非均匀性是什么?如何计算?有什么作用呢&#xff…

查找算法——java

顺序查找(顺序表查找) 顺序查找也称为线形查找,属于无序查找算法。从数据结构线形表的一端开始,顺序扫描,依次将扫描到的结 点关键字与给定值k相比较,若相等则表示查找成功;若扫描结束仍没…

Sublime Text4代码配色自定义方案

文章目录 前言效果图 前言 关于Sublime Text对于我的使用体验,只能说内置的代码主题真的都太low了,一点都不好看。所以接下来我分享一下我自定义代码配色。当然,大家也可以通过我给的中文翻译注释来自定义自己喜欢的颜色。废话不多说&#x…

Unity中URP下实现水体(C#动态生成渐变图)

文章目录 前言一、Shader部分1、申明水渐变图纹理和采样器2、在片元着色器,进行纹理采样,并且输出 二、C#脚本部分1、我们新建一个C#脚本2、我们定义两个变量3、在Start内,new 一个Texture2D(宽,高)4、定义一个Color[宽*高]的颜色…

vue3 vite项目一运行就401(Unauthorized)

问题:项目一执行: pnpm run dev, 启动就出错, Failed to load resource: the server responded with a status of 401 (Unauthorized) 分析: 项目之前是正常运行的,没有问题,回溯刚刚改动,还原…

操作系统原理与实验——实验三优先级进程调度

实验指南 运行环境: Dev c 算法思想: 本实验是模拟进程调度中的优先级算法,在先来先服务算法的基础上,只需对就绪队列到达时间进行一次排序。第一个到达的进程首先进入CPU,将其从就绪队列中出队后。若此后队首的进程的…

Linux:kubernetes(k8s)node节点加入master主节点(3)

Linux:kubernetes(k8s)搭建mater节点(kubeadm,kubectl,kubelet)-CSDN博客https://blog.csdn.net/w14768855/article/details/136415575?spm1001.2014.3001.5502 我在上一章部署好了主节点&…

【JSON2WEB】07 Amis可视化设计器CRUD增删改查

总算到重点中的核心内容,CRUD也就是增删改查,一个设计科学合理的管理信息系统,95%的就是CRUD,达不到这个比例要重新考虑一下你的数据库设计了。 1 新增页面 Step 1 启动amis-editor Setp 2 新增页面 名称和路径随便命名&#xf…

2024最新算法:电鳗觅食优化算法(Electric eel foraging optimization,EEFO)求解23个基准函数(提供MATLAB代码)

一、电鳗觅食优化算法 电鳗觅食优化算法(Electric eel foraging optimization,EEFO)由Weiguo Zhao等人提出的一种元启发算法,EEFO从自然界中电鳗表现出的智能群体觅食行为中汲取灵感。该算法对四种关键的觅食行为进行数学建模:相…

【贪心算法】Leetcode 455.分发饼干 376. 摆动序列 53. 最大子数组和

【贪心算法】Leetcode 455 分发饼干 376. 摆动序列【规律很多】53. 最大子数组和 455 分发饼干局部最优推全局最优:尽量用大饼干去满足大胃口的小朋友 376. 摆动序列【规律很多】思想:注意考虑一个坡度留首尾两个点、平坡、首尾 53. 最大子数组和【好思想…