导论

Phoenix parser是为简单健壮的自然语言接口应用程序,特别是口语应用的开发设计的解析器。因为自然语言经常是有语病的并且识别器也会有识别错误,所以parser具有鲁棒性在识别、语法和流畅性中修正错误是很有必要的。这类parser是为了提升解析这些类型的输入语料而设计的。

Parser 将每个输入(input)表达成一个或者几个语义上的frame。开发者需要定义一套frame并且提供将词句列入frame中槽位语法规则。

产品配置(不过多阐述)

  • ParserLib
  • Grammer
  • Scripts
  • Example
  • Server
  • Doc

操作理论

Parser将输入的词句映射到一个语义frame序列。一个frame是一套命名的槽位,这些槽位代表相关的一条条信息,图一展示了一个航班信息query的frame示例。每个槽位有一个相关的无关上下文的语法,这些语法指定词句匹配槽位的pattern,并且编译到递归转移网络(Recursive Transition Networks)中。图2展示了一个解析过的frame。当parser填充的时候,每个槽位包含一个语义解析树用于它所跨越的字串,语义解析树的跟就是槽位的名字。

图3展示了整个解析的流程。在搜索算法中,与声学匹配很相似,生成了一个词图,语法的槽位与字串相匹配并且生成了一个槽位图。这些active frames集合定义了active槽位的集合。每个槽点指向相关递归转移网络的根。这些网络与自上而下递归转移网络图标解析算法的输入词序列相匹配。

解析的过程从输入的每个词开始从左到右尝试去匹配每一个槽位网络,如下:

for (each word of input)for (each active slot)match_net ( slot, word )

match_net函数是一个与指定位置开始的字串匹配RTN的递归函数,这个函数生成所有的从词语位置开始的,或许有一些不同的结束点的网络匹配。这些网络并不是为解析整条语句而设计的,仅仅是解析词条的序列。递归传递网络的槽位在匹配的过程中调用其他的网络。每次网络匹配就是一种尝试(整个网络,不仅仅是槽位)。所有匹配的网络都被添加到网络中,任何时候尝试一次网路匹配,图表是首先被核对来判断匹配是否在之前被尝试过。当一个槽位匹配成功了,就会被添加到槽位图中。每一个在槽位图中的槽位序列就是一条路径,路径的分数是由序列所解释的单词数。当匹配一个槽位时,词语是不会被跳过的,但是在已经匹配过的槽位就可以被跳过。在图的扩展过程中低得分的路径会被去除,就像声学搜索那样。去除的标准是:第一,解释词语的数量,第二,序列碎片化的程度。如果两种路径覆盖了相同的输入部分并且其中一个比另一个解释了更多的词语,那么少的那个就会被移除。如果两条路径解释了相同数量的词语,并且其中一条路径比另外一条用了更少的槽位,那么那个用的更多槽位的那条路径就会被移除。最终结果图代表了所有的序列发现有个分数等于最好的,槽位序列用图表示出来然后整合到frames中,这仅仅是通过将frame标签分配到槽位完成的。然后回到整合中,更少的碎片化解析是更好的,这意味着如果有两个解析各有5个槽位,其中一个用了两个frame,另外一个用了三个frame,那么解析用两个frame的那个会更好。结果是一个槽位图,每个槽位被一个或者多个frame标签所标注,每条路径穿过这个图,所有得分都相等,就是一个解析(parse)。这些机制自然地产生部分或者碎片化的解析。考虑到语法和输入,动态的编程搜索会尽可能地产生最完整碎片化最少的解析。
解析器(parser)不需要语句边界,并且可以处理很长的输入。它按照自然断点给输入语句进行分词并且在缓存里展示一些垃圾的收集。这使得它在必要时允许将整个报告解析为单独的表达,处理的速度和输入的长度是线性相关的。
如何健壮或者约束一个系统是取决于frame和语法是如何构建的。用一个槽位的frame会产生一个标准的CFG解析器,这样做虽然高效,但是对于无法预测输入是没有鲁棒性的。在另一方面,让每个内容词语有相互独立的槽位将会产生一个关键词解析器。介于这两者之间的某个地方,通常会有精确性和鲁棒性最好的结合。

编写语义语法和frame

解析器需要两个输入文件,frame文件和语法文件(.gra)。

frame文件

这个文件指定frame需要被解析器所调用,一个frame就代表程序的一些基本的类型的操作或者对象,frame中的槽位表示与这些操作或者对象的相关信息,每个槽位都有相关的一套语法规则,槽位的名字就是相应语法解析树的根。
frame的句法定义如下:

 #commentFRAME:<frame name>NETS: slot names[<slot name>][<slot name>][<slot name>];举一个酒店frame的例子,如下所示:#预定酒店房间FRAME:酒店NETS:[酒店请求][酒店名][入住时长][酒店地址][房间类型][到达时间][需求];

frame的终结标识是’;’,写在下一行的开始处。
不要忘记以分号结束frame,否则就不会被识别。
不要忘记以分号结束frame,否则就不会被识别。
不要忘记以分号结束frame,否则就不会被识别。(重要事情说三遍)

语法文件(.gra)

语法文件的名字结束的地方是以".gra"扩展名结尾的,这些文件包含了语法规则。语法都是遵循无关上下文规则,它所指定的词语模式对应于标识(网络名称)。
对应标识的语法句法如下:

 #optional comment[标识名称](<模式 a>)(<模式 b>)<宏1>(<复写宏1的规则>)<宏2>(<复写宏2的规则>);

如上所示,标识名称被方括号括起来,在这之后跟着一套复写的规则,每一行写一条,被圆括号括起来并在前面有空格标识。之后再跟着宏的复写,格式和之前的是一样的。
在模式(pattern)中的符号运用规则如下:
*小写的字符串是终端。
*大写的字符串是宏。
*被方括号[]括起来的是非终端(会调用其他的标识规则)。
*被尖括号括<>起来的是宏。
*常规表达
*item 表示0个或者1个item的副本
+表示1个或者多个副本
+*表示0个或者多个副本
#include<文件名> 在那个点读取文件

宏在相同的语法规则之后会复写指定的规则,这些会让复写的文本替代原有的宏,但是不会引起非终端的标识出现在parser中。宏允许一个更加简单的语法表达式,并且排除不想要的标识在parser中。

举一个例子解释标识的语法规则,[酒店需求]和[想要]:
[酒店需求](*[想要]*{一间}<酒店>)
<酒店>(酒店)(房间)(公寓)(宾馆)
;[想要](*[我]<想>)
[我](我)(我们)
<想>(想要)(需要)(想去)(想)
;

同时再举一个英文的例子,[hotel_request]和[want]:

[hotel_request](*[want] *a HOTEL)
HOTEL(hotel)(motel)(room)(accommodations)(place to stay)
;
[want](*I WANT)
I(i)(we)
WANT(want)(need)(would like)
;

按照整个grammar文件来看,I would like a hotel room 就是:
[hotel_request]([want](i would like)a hotel room)

编译语法

语法是调用脚本编译来进行编译的,在轮流调用常规的compile_grammar的语法的字典中,图4展示了一个示例的编译脚本。其中语法文件可以是一份单独的文件,也可以是分布在多个文件中。如果语法是在多个文件中的话,编译脚本会将他们连接到一个单独的文件中,然后再传递到compile_grammar中。接下来是编译语法的脚本的例子,他在本地路径用了两个语法文件,Place.gra和Schedule.gra,并且它从本地库中加载了grammar文件date_time.gra,numbers.gra和next.gra。独立的grammar文件首先连接到EX.gra文件中,然后EX.gra文件会编译到EX.net中。编译的脚本在本地路径创建了一个base.dic文件,这是一个字典文件,一个包含许多被数字标注的词语的文本文件,文件中的每一行都有一个词语并且有数字将其标注。这些词语数字并不是连续的,它们是哈希编码之后得到的结果,这些数字将会在parser中用到。

.net file - 编译后的语法(grammar)文件

 这些是ASCII文件表示的递归转移网络并且有如下的格式:第一行给到了一个已经编译过的网络编号 网络编号 Number of Nets = 378然后就是编译的网络,对每一个网络来说:第一行给到了:网络编号,网络中节点的编号,concept leaf 标志然后节点会排列,然后每一个后面都跟着一个arc。一个节点进入到了文件中就会有如下的格式:节点编号,节点之外的arc编号,结束标志位(final flag):0代表非终端节点 1代表终端节点对于每一个网络,从0开始,节点的编号是连续的。节点的arc遵循节点的条目。Arc条目有如下的格式:word_number net_number to_nodearc 或许是:word arc, 并且word_number和net_number=0null arc,由word_number=0并且net_number=0call arc,由net_number>0(这种情况下忽略word_number)[航空公司] 27 5 00 5 00 0 220294 0 3372 372 4344 344 230 30 21 0 12 1 072 72 13 3 018753 0 118762 0 116707 0 14 3 018753 0 118762 0 116707 0 1

####数据结构
语法结构:

Phoenix parser可以使用多种语法,read_grammar这个方法会从一个.net文件读取一个编译过的语法,并且返回一个指向关联语法结构的指针。

 struct gram *read_grammar(dir, dict_file, grammar_file, frames_file);typedef struct gram{FrameDef    *frame_def;     /* pointers to frame definition structures */char    **frame_name;    /* pointers to frame names */int    num_frames;    /* pointers of frames read in */char   **labels;    /* pointers to name of nets */Gnode    **Nets;    /* pointers to heads of compiled nets */int    num_nets;    /* number of nets read in */char    **words;    /* pointers to strings for words */int    num_words;  /* number of words in lexicon */int    *node_counts;    /* number of nodes in each net */char    *leaf;    /* concept leaf flags */char    *sym_buf;    /* strings for words and names */     } Gram;

根据需要可以尽可能多的读取独立的语法,并且指针指向相应的gram储存结构。当parse的方法被调用,它将字串传到parse和指向gram结构体的指针,来实现parse方法:parse(word_string,gram)。

活跃的槽位组

除了控制语法在语法分析中使用外,当调用每个parse方法的时候,开发者同样有整套槽位的动态的控制。全局变量cur_nets(int *cur_nets)和num_active()是用来实现这个的。cur_nets指向这一套槽位(网络号码)用于解析和num_active指定数组中元素的数量。parser主要的匹配环路如下所示:

for( word_position=1; word_position < script_len; word_position++ ) {for( slot_number= 0; slot_number < num_active; slot_number++ ) {match_net( cur_nets[slot_number], word_position, gram)

如果cur_net是空的,parser就会创建一套语法frame的网络,并相应地指向cur_net和num_active。因此系统会在第一次调用parser()的时候初始化。为了在parser中使用所有槽位的子集,产生一组要用的网络号码,从cur_nets指向数组和数组中的数字元素。为了重置在语法中所有的槽位,只需要将cur_nets或者num_active设置为空。

图表

图表是一种数据结构,用来记录所有它们找到的网络匹配。 这样做是为了如果在语法中其他点调用的话不需要重复操作。在一些情况下,节省了相当大的计算量。这个图表是个三角形矩阵,它由单词的起始词和结束词索引,如图5所示。

由于它是一个稀疏矩阵,所以图表实际上并不是作为一个矩阵来实现的,而是作为一个链表,以开始词作为主键,结尾词为小键。

parser数据结构

当最终parser结构创建后,它们被放入一个由变量解析器指向的缓冲区中。parser是一个SeqNodes序列,这些序列代表含有frame id的边缘。SeqNode结构包含了frame id,并且在图表中指向边缘。含有相同frame id都在同一个frame实体里面。节点按照顺序写进了缓冲区,在前一次解析的最后一个槽后,新解析的第一个插槽被写入。所有的话语都有相同数量的插槽,因为任何更分散的都将被去掉。每个解析器中的插槽数就是一个全局变量n_slots。在num_parses中寸有备用的解析器的数量。

打印parses

方法print_parses()是用来将parses写入文本缓存的。参数如下:

  • parse的数字会被打印出来(从0开始)
  • 指向文本缓存的指针会被写入
  • 提取的标志位(0=解析后的形式,1=提取后的形式)
  • 一个指向语法结构体的指针

提取的形式

解析器提供了一种更加直接的打印输出机制,它会打印token和字符串,这些都会被提取,提取输出的格式如下:

 <frame_name>:<Node_Name>.[<Node_Name>.[<Node_Name>.]][<value>]

举个例子:《猩球崛起3》在哪里上映?将会产生解析和提取的形式:

 电影信息:[电影信息]([电影](《猩球崛起3》)[在](在)[上映电影]([_影院名称](哪里))[上映](上映))------>电影信息:[上映电影].影院名称    电影信息:[电影].《猩球崛起3》

eg. Where is American Beauty playing?

 movie_info:[movie_info] ([Display_Movie]([_theatre_name](where))[is](is)[Movie](AMERICAN BEAUTY)[showing](playing))------>movie_info:[Display_Movie].theatre_name    movie_info:[Movie].AMERICAN BEAUTY

为了运用这种机制,开发者必须按照协定来编写语法。

终端前缀

提取的第二个特征输出就是终端前缀,这些网络名从一个下花心标志符“_”开始。对于这些网络而言,提取的输出是这些网络的名字而不是字符串。在上述的例子中,[_影院名称]或者是[_theatre_name]就是这样的。这是一种很方便的方法将值放置于一种规范的形式。举个例子,有很多种表达yes的方式,但是你需要将实际的yes传到数据库。如果你定义了一个[_yes]的网络,并且写出了所有表达yes的方式,而不是将会出现在提取结果中的原始的字符串,这同样适用于像Philly到Philadelphia的映射。举个例子,就像下面的规则:

 [Answer]([_yes])([_no]);[_yes](yes)(fine)(sure)(that's good)(sounds good *to *me);[_no](no *way)(*i don't think so);

所以sounds good to me 会被解析成:

     [Answer]([_yes](sounds good to me))

并且会被提取:

     [Answer].yes

同理 I don’t think so 会被解析成

     [Answer]([_no](I don't think so))

提取出来:

     [Answer].no。

语义解析Parser用户手册相关推荐

  1. 揭开知识库问答KB-QA的面纱2·语义解析篇

    内容速览 什么是语义解析(Semantic Parsing) 什么是逻辑形式(Logic Form) 语义解析KB-QA的方法框架 实验结果 本期我们从传统方法之一的语义解析(有时也被称为语义分析)开 ...

  2. 超详细解读:神经语义解析的结构化表示学习 | 附代码分析

    在碎片化阅读充斥眼球的时代,越来越少的人会去关注每篇论文背后的探索和思考. 在这个栏目里,你会快速 get 每篇精选论文的亮点和痛点,时刻紧跟 AI 前沿成果. 点击本文底部的「阅读原文」即刻加入社区 ...

  3. 语义解析KB-QA的方法框架

    向AI转型的程序员都关注了这个号???????????? 机器学习AI算法工程   公众号:datayx 什么是语义解析(Semantic Parsing) 什么是逻辑形式(Logic Form) 语 ...

  4. lnk200无法解析的外部符号_语义解析

    一.智能问答系统与推理 任务需求 人机对话的三个层次:闲聊.问答.对话 基于知识图谱的问答系统有两条路: 对用户的问题进行语义理解,一般用Semantic Parsing(语义分析),得到了一个句子的 ...

  5. 知识问答(KBQA)两种主流方法:基于语义解析和基于信息检索的方法介绍

    什么是知识问答 基于知识的问答是以知识库为认知源,在知识库的基础上回答自然语言问题. 知识库(KB)是一个结构化数据库,其中包含形式<主题,关系,对象>的事实集合,每个事实都可以随附所谓的 ...

  6. 知识库问答KB-QA——语义解析

    一.语义解析 二.逻辑形式 三.语义解析KB-QA的方法框架 训练分类器 构建词汇表 桥接操作 实验结果 该方法的缺陷 以一个经典的语义解析baseline方法为例,介绍语义解析如何进行KB-QA.该 ...

  7. 5分钟NLP-知识问答(KBQA)两种主流方法:基于语义解析和基于信息检索的方法介绍...

    来源:DeepHub IMBA 本文约1200字,建议阅读5分钟本文介绍了知识问答的两种主流方法. 什么是知识问答 基于知识的问答是以知识库为认知源,在知识库的基础上回答自然语言问题. 知识库(KB) ...

  8. 我来说话你来查,智能代码新技术!语义解析专场干货

    点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 一直以来是,语义解析(Semantic Parsing) 都是自然语言处理领域一个非常基础且重要的研究问题.通俗来讲,语义解析旨在让计算 ...

  9. 基于Go的语义解析开源库FMR,“屠榜”模型外的NLP利器

    (由AI科技大本营付费下载自视觉中国) 作者 | 刘占亮 一览群智技术副总裁 编辑 | Jane 出品 | AI科技大本营(ID:rgznai100) 如何合理地表示语言的内在意义?这是自然语言处理业 ...

最新文章

  1. React+Redux+中间件
  2. LeetCode实战:除自身以外数组的乘积
  3. 按home退出程序到后台后再打开崩溃的问题
  4. 深入浅出数据库设计三范式
  5. 面试官:GET和POST两种基本请求方法有什么区别
  6. Android中的JSON解析方式:json; Gson ; Fastjson
  7. 背景颜色及背景图片相关的属性
  8. css文字溢出部分在另一个div显示(代码篇)
  9. mysql中gbk编码汉字和英文_MySQL字符集 GBK、GB2312、UTF8区别 解决 MYSQL中文乱码问题...
  10. 推荐一个vs自带工具分析代码的复杂度
  11. 如何找出当前占用磁盘io 最多的进程 - linux,如何找出当前占用磁盘IO最多的进程...
  12. Android 系统源码中添加 androidx 依赖
  13. oracle元转换为万元,Excel表格中快速实现元转换成以万元显示的方法
  14. 如何提高英文的科研写作能力(转自施一公的博客)
  15. 别让just do it 误导了你
  16. ie11启用java时打不开_ie11打不开解决方法
  17. 点云ply格式文件详解
  18. web端自动化测试框架之selenium4从入门到项目实战-3- unittest使用
  19. 猜生日 Java小游戏
  20. 在线视频观看系列二:视频搜索

热门文章

  1. 小猿圈Java讲师分享开发9年Java进阶大全
  2. 插上u盘显示格式化怎么办?
  3. 操作系统实战 45 讲:运行HelloOS界面
  4. 项目管理工具之甘特图
  5. 用了TCP协议,就一定不会丢包嘛?
  6. android mux协议,协议细节 - Mux.Cool - 《Project V(V2RAY)文档手册》 - 书栈网 · BookStack...
  7. JavaScript_第一天
  8. 红楼梦人物分析系统c语言,红楼梦人物分析.doc
  9. CCS如何调整字体大小
  10. 存储基础:DAS/NAS/SAN存储类型及应用