赞
踩
上次我们介绍过了指代消歧,现在我们介绍句法分析。
句法分析(syntactic parsing)分为两大类:依存句法分析(Dependency Parsing)和成分句法分析(Constituency Parsing)。
本文我们主要介绍成分句法分析。
成分句法分析假设在一个句子里面,某些span组成Constituency(成分),可以把成分想成一个单位。
比如“learing is very”就不是一个单位,但是“deep learning”就是一个单位,“very powerful”看起来也是一个单位,就是看起来放在一起比较通顺,不别扭。
那成分句法分析要做的是把句子里面,所有能组成成分的字符串找出来。
最简单是每个单词就是一个成分。
每个成分都有一个标签(label,或者是POS tag)。
比如“deep learning”的标签是名词短语;而“very powerful”的标签是形容词短语。
那有哪些标签呢
那怎么做呢
首先输入一个句子,这个句子中每个词汇都是一个成分,每个成分都有一个标签;
接下来相邻的成分可能可以组合起来变成一个更大的单位,比如“deep”和“learning”可以组合起来;“very”和“powerful”可以组合起来等等
所有成分组合起来,变成一个句子(S)。
把所有组合起来的成分放在一起,就形成了一个树状的结构。
我们假设这个树是一个二叉树,叶子就是词汇。那如何解决成分句法分析的问题呢,有两大解法。
第一个叫Chart-based方法。
那要怎么做呢,我们要训练一个分类器,给它一个span,它判断这个span是否为一个成分(二分类器)。
除了判断一个span是否为成分之外,我们还要判断这个成分的标签(多分类器)。
举例来说,把“deep learning”丢进去,它输出是成分,并且输出它所属的标签。
对于不是成分的东西,比如“deep learning is”丢进去,它判断不是成分,此时标签的输出就不重要了。
那这个分类器长什么样子呢?
我们输入一串文字,然后把这串文字丢到BERT里面,得到每个token的嵌入向量。然后把你在意的span,用span feature extraction抽出一个代表的向量,然后把这个向量,比如丢到一个多层的全连接网络中,输出就是YES/NO;
然后把这个向量丢到另外的多层全连接网络,输出这个成分所属的标签。
接下来就端到端的学习,就结束了。
所以感觉整个过程还是挺简单的。
假设你有 N N N个token,只要跑 N ( N − 1 ) / 2 N(N-1)/2 N(N−1)/2次,就能知道所有的span是不是一个成分。
实际上这个问题没有这么简单,这里有一个严重的问题。
因为你的分类器并不是完美的,可能你跑完分类器后,你会发现输出了一些矛盾的结果。
可能把“deep learning is”丢到分类器中,它输出是YES。
然后把“is very powerful”丢进去,它也输出是YES。
这时候就矛盾了,因为如果这两者都是成分的话,就没有办法把它们两拼成一个树了。因为它们有重叠的部分。
那如何避免这种矛盾的情况发生呢。
其实实际上你训练好分类器后,你是这样使用的。
给一个句子,你会先穷举处所有可能的树状结构。
可能把“I am”拼成一个成分,然后把“I am good”拼成一个更大的成分。
也可能把“am good”拼成一个成分,把“I am good”拼成一个更大的成分。
下面就用刚才训练出来的分类器,去看哪一个树状结构得到的分数更高,也就是说,你先找出合法的树状结构,再用分类器去判断哪个树状结构是最好的。避免单纯判断成分产生矛盾的情况。
如果你的句子很长,那么穷举所有的树状结构就需要CKY算法。
另外的方法叫作Transition-based方法,是怎么做的呢,我们来看一个例子。
首先要有一个Stack,它初始为空的。然后有一个Buffer,里面放的即使要来做分析的句子。
接着有三个可以采取的动作。
第一个是创建一个成分;第二个是从buffer里面移动一个token到stack;第三个是生成一个完整的成分。
然后我们看具体是如何做的。
因为开始stack都是空的,所以第一个要采取的动作就是创建,首先是创建一个句子。
然后把创建句子这个动作(S
放到Buffer里面,
接下来要创造一个名词短语。
然后我们决定要采取SHIFT这个动作,它要做的事情就是把Buffer里面的东西,移到Stack里面去。
现在Stack里面有两个没有产生完毕的成分,因此需要继续执行SHIFT,把learning拿进去。
接下来根据Stack和Buffer要采取Reduce这个动作。
执行为Reduce后,我们就产生了一个成分,它是名词短语(NP)。接下来再决定下一个动作是什么。
假设现在根据Stack和Buffer里面的值决定要创造一个动词短语,然后需要执行SHIFT把Buffer里面的token放到Stack里面去。
假设接下来决定要创建一个形容词短语(ADJP,视频里面有误)
并且下一步执行SHIFT把very放到stack里面去。然后再次执行SHIFT把buffer最后的token移到stack里面去。
此时BUFFER里面已经空了,由于形容词短语还没有结束,所以就现关闭形容词短语,执行REDUCE动作。
此时又看到动词短语没有结束,再次执行REDUCE。
最后再执行一次REDUCE,结束掉整个句子的成分。
就得到了最后的句法分析结果。
上面我们有一个重要步骤没有细讲,就是如何决定什么时候要采取什么动作。这里可以用深度学习模型来做这件事。但是在之前,有人尝试了用RNN来做。
主要思想是根据stack里面和buffer里面的东西,来决定要采取什么动作。
所以可以拿两个RNN,分别读入stack和buffer里面的序列。也许之前已经采取过的动作,也读入另一个RNN。
然后每个RNN都把最后的输出拿出来,丢给某个网络,由它来决定要采取哪个动作。
其实这就是一个分类问题,你可以知道上面的情况,应该要采取REDUCE。然后希望经过RNN后,最终的网络输出REDUCE。
还有另一种方法,采取基于序列的方法,直接用一个seq2seq模型来做这件事情。
我们今天要做的事情是,让机器看这段文字,然后产生一个树状结构。我们其实可以把这个树状结构表示成一个序列。比如采用由上而下,由做而右遍历的放。首先看到了根节点,然后输出“(S”。
然后进入左节点,也是先看根节点,第一个是NP,然后序列就变成了“(S (NP”。然后又看它的左节点,此时为“deep”,由于它是叶子节点,接着看右边,是“learing”。因此,变成了“(S (NP deep learning”。
接下来由于NP的孩子节点都产生完了,然后需要放要一个符号代表这件事,这里放了一个“)”,整个序列变成了“(S (NP deep learning )”,以此类推,最终产生序列:“(S (NP deep learning ) (VP is (ADJP very powerful ) )”
Seq2Seq的方法其实和RNN Grammar的方法没有太大的区别。比如你要放一个“(S”,就是“CREATE(S)”,你要放一个token进去,就是动作“SHIFT”,等等。
我们主要介绍了监督学习的句法分析,那有没有无监督的方法
其实也是有可能的,具体看上面贴出的地址。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。