斯坦福大学-自然语言处理入门 笔记 第十四课 CGSs和PCFGs

一、概率上下文无关文法((Probabilistic) Context-Free Grammars)

1、上下文无关文法(Context-Free Grammars)

  • 我们也可以称之为词组结构语法(Phrase structure grammars)
  • 由四个成分构成G=(T,N,S,R)
    • T表示最终端(terminal),如下图粉色部分的子节点
    • N表示非最终端(nonpreterminal),如下图粉色部分的中间节点
    • S表示开始(S∈N),如下图粉色部分的根节点
    • R表示一系列的规则,格式为X→γ,其中X∈N,γ∈(N∪T),例子如下图左边的规则

2、NLP的上下文无关文法(Context-Free Grammars)

  • 在NLP的背景下,我们对上下文无关文法的定义进行了一定的修改
  • 由六个成分组成G=(T,C,N,S,L,R)
    • T表示最终端(terminal),如上图粉色部分的子节点,和上面定义一致
    • C表示次终端(preterminal),如上图粉色部分的子节点的父节点
    • N表示非最终端(nonpreterminal),如上图粉色部分的中间节点,和上面定义一致
    • S表示开始(S∈N),如上图粉色部分的根节点,和上面定义一致
    • L表示字典(lexicon),格式为X→x,其中X∈C并且x∈T,如上图中间的规则
    • R表示一系列的语法规则,格式为X→γ,其中X∈N,γ∈(N∪C),如上图左边的规则
  • 按照惯例,S表示开始。但是,在统计自然语言中,我们在最开始还会使用另外一个节点(ROOT,TOP)
  • 对空序列,我们会用e来表示

3、概率上下文无关文法(Probabilistic/stochastic Context-Free Grammars

  • 概率上下文无关文法是上下文无关文法的拓展,在原来的四个元素上增加了一个元素P
  • 由五个成分构成G=(T,N,S,R,P)
    • T表示最终端(terminal),如下图粉色部分的子节点
    • N表示非最终端(nonpreterminal),如下图粉色部分的中间节点
    • S表示开始(S∈N),如下图粉色部分的根节点
    • R表示一系列的规则,格式为X→γ,其中X∈N,γ∈(N∪T),例子如下图左边的规则
    • P表示概率函数,P的范围是[0,1],并且和为1,公式如下:
      在这里插入图片描述
  • 文法规则表示如下(增加了概率):
  • 概率计算
    • 句法结构树的概率P(t)计算:生成它的规则的概率的乘积
    • 字符串的概率P(s)计算: 有这个字符串的句法结构树的和
    • 例子:同一个句子的两个不同的句法结构树
      在这里插入图片描述
      第一颗树是动词附属(verb attach),概率计算是0.0008232,第二颗树是名词附属(noun attach),概率计算是0.00024696。字符串的概率是两者之和0.00107016

二、语法转化

1、Chomsky Normal Form

  • 我们可以把上下文无关文法(Context-Free Grammars)转化为Chomsky Normal Form的形式。这种形式不会改变语言本身,但是呈现出的句法结构树可能会有所不同。可以使得句法分析更加高效。
  • 在这种形式中,所有的规则可以转化为两种形式:X→Y Z或者是X→w,其中X,Y,Z∈N,w∈T
  • 为了实现这种形式,空和一对一的规则(X→Y)会被递归地消除
  • 一对N的规则(N>2)则会被拆解成新的非终端项(nonterminals)

2、一个转化的例子

  • 初始的上下文无关文法(Context-Free Grammars)
    在这里插入图片描述
  • 第一步:消除空(e),由于NP→e,要把这一条删除同时保留下这一条的信息,我们可以把左边规则中箭头右侧出现NP的规则做两种假设,比如S→NP VP可以改进为两条规则:S→NP VP和S→VP
    在这里插入图片描述
  • 第二步:消除一对一的规则(X→Y)。把一对一的规则转化为字典形式放在字典(lexicon)中。具体如VP→V,则和字典(lexicon)中V在左侧的规则一起生成新规则,如VP→people。并进行迭代消除。
    在这里插入图片描述
    在这里插入图片描述
  • 第三步:一对N的规则拆成一对二的规则,比如VP→V NP PP拆成两个规则VP → V @VP_V,@VP_V →NP PP
    在这里插入图片描述
  • 在实践中,完整的Chomsky Normal Form转换是很痛苦的,一对N的规则拆分是很容易的,但是空(e)和一对一规则的消除非常麻烦。对于上下文无关文法(CFG)句法分析而言,一对N的规则拆分可以帮助建立二叉树,可以有效降低复杂度。而其他操作不是必要的,充其量就是会使得算法更干净更快而已。下图右边就是一对N的规则拆分的句法分析树。
    在这里插入图片描述
    下图有颜色的部分表示了同一个短语的不同的四个句法结构树,第一个是初始,第二个是去掉了空,第三个是去掉了一对一保留了最高的父节点,第四个是去掉了一对一保留了最低的父节点(三四比起来我们更倾向于四,因为可以保留完整的字典)
    在这里插入图片描述

三、CKY算法

1、算法介绍

  • 我们采用CKY算法来进行句法分析的时间复杂度是在O(N³)
  • 大致来说,计算方法是一个动态规划的方法。如下图,从最底层开始,最底层的每一格代表对应的一个单词,其中包含若干种可能以及对应的概率。次底层的每一格代表的是次终端(preterminal),包含左下角和右下角两个底层的格子对应的单词构成的成分(constituency)。
    在这里插入图片描述
  • 举例而言:下面的例子中有两个词people fish,根据字典(lexicon),people对应三种成分(NP,V,N),fish对应四种成分(VP,NP,V,N)。接下来,计算的是两个单词组合的成分。根据规则NP→ NP NP,people fish的成分是NP的时候概率是=P(NP→people)*P(NP→fish)*P(NP→ NP NP)=0.350.140.1=0.0049。当有两种组合的结果成分是相同的时候,我们选取最大的概率放入对应的格子中。
    在这里插入图片描述

2、算法拓展

  • 一对一规则:可以整合进算法。虽然可能会使得算法比较混乱,但是不会影响到算法的复杂度
  • 空:可以使用fencepost整合进算法,并且不会影响算法的复杂度。例子如下,假设有n个单词,底层构建的时候选用0-n位置,在每个整数位都可以插入空,在整数之间的位置则是单词。
    在这里插入图片描述
  • 二分化,即去掉一对N规则是很有必要的。这是使得算法复杂度降低从指数级到O(N³)的关键,所以在进行CKY算法之前,一定要进行二分化。

3、代码

function CKY(words, grammar) returns [most_probable_parse,prob]
  score = new double[#(words)+1][#(words)+1][#(nonterms)]  //存储格子中所有可能成分和对应的概率
  back = new Pair[#(words)+1][#(words)+1][#nonterms]] //指针,指出最佳的成分
  
  ****接下来主要处理字典lexicon*****
  for i=0; i<#(words); i++ 对每个单词
    for A in nonterms 对每个非终端
      if A -> words[i] in grammar 如果A指向对应的单词的话,就在score中存储
        score[i][i+1][A] = P(A -> words[i])
    //handle unaries 下面部分处理一对一规则
    boolean added = true
    while added 
      added = false
      for A, B in nonterms
        if score[i][i+1][B] > 0 && A->B in grammar 一对一规则搜寻
          prob = P(A->B)*score[i][i+1][B]
          if prob > score[i][i+1][A] 判断一对一的概率是否会比原来的大,如果是的话就覆盖原来的概率
            score[i][i+1][A] = prob
            back[i][i+1][A] = B
            added = true
            
   ****接下来主要处理语法规则*****
	for span = 2 to #(words)
	  for begin = 0 to #(words)- span
	    end = begin + span
	    for split = begin+1 to end-1 对一串语句而言,选择二分的节点
	      for A,B,C in nonterms
	            prob=score[begin][split][B]*score[split][end][C]*P(A->BC) 计算对应的概率
	        if prob > score[begin][end][A] 如果概率大于原来的概率就覆盖,修改back指针
	          score[begin]end][A] = prob
	          back[begin][end][A] = new Triple(split,B,C)
	    //handle unaries  下面部分处理一对一规则
	    boolean added = true
	    while added
	      added = false
	      for A, B in nonterms
	        prob = P(A->B)*score[begin][end][B];
	        if prob > score[begin][end][A]  判断一对一的概率是否会比原来的大,如果是的话就覆盖原来的概率
	          score[begin][end][A] = prob
	          back[begin][end][A] = B
	          added = true
return buildTree(score, back)

四、例子

  • 没有空(e)的规则
    在这里插入图片描述
  • socre数组,行数和列数都是单词数
  • 第一步:利用lexicon在score中写入规则:以0-1的fish为例,对应的lexicon是N→fish 0.2和V→fish 0.6(下面每一步的结果都在下一步的图中给出)
  • 第二步:处理字典部分的一对一规则。以0-1的fish为例,已有的lexicon是N→fish 0.2和V→fish 0.6。可以找到一对一语法规则VP→V(概率是0.60.1),NP→N(概率是0.70.2),因为原来的概率是0,所以对其直接进行覆盖。对一共四个的语法规则再迭代,可以找到一对一的语法规则S→VP(概率为0.60.10.1)
  • 第三步:处理语法规则。计算次底层的概率,以fish和people为例
    • NP -> NP NP : P(NP->N)*P(NP->N)*P(NP -> NP NP)=0.14*0.35*0.1
    • VP ->V NP: P(V->fish)*P(NP->N)*P(VP ->V NP)=0.6*0.35*0.5
    • S->NP VP: P(NP->N)*P(VP->V)*P(S->NP VP)=0.14*0.01*0.9=0.00126
  • 第四步:处理一对一语法规则。以fish和people为例,S->VP:P(VP ->V NP)*P(S->VP)=0.6*0.35*0.5*0.1=0.0105,比之前算出的概率大,覆盖S的概率
  • 第五步,计算第三层的语法规则。以fish people fish为例,可能存在两种可能:二元分割点在1,二元分割点在2。分别计算可能的概率,并进行一对一规则的处理。
  • 第六步:计算最后一层。
  • 结果

五、成分句法分析评估方法

  • 计算方法:对每一格单词间隔进行索引,将每个嵌套的成分,从上到小从左到右用索引表示出来。比如下面的句法分析,第一层的S是0-11,接下来NP是0-2,VP是2-9。
    在这里插入图片描述
    基于上面的成分索引,计算对应的precision和recall。标注评价是另外给出的一个正确率。
    在这里插入图片描述
  • PCFGs模型的优点

猜你喜欢

转载自blog.csdn.net/kunpen8944/article/details/83280155