CS224n 2019 Winter 笔记(三):句子依存分析(Dependency Parsing)
一、概述
由于官方note04对句法分析的背景知识描述不详,公开课视频中也说的不是太清楚。在这里引用宗成庆的《统计自然语言处理(第二版)》中的描述:
句法分析(syntactic parsing)是自然语言处理中的关键及时之一,其基本任务是确定句子的句法结构(syntactic structure)或句子中词汇之间的依存关系。一般来说,句法分析不是一个自然语言处理任务的最终目标,但是,它往往是实现最终目标的重要环节,甚至是关键环节。因此,在自然语言处理研究中,句法分析始终是众多专家关注的核心问题之一,围绕这一问题人们不断提出各种新的理论和方法。
句法分析分为句法结构分析(syntactic structure parsing)和依存关系分析(dependency parsing)两种。句法结构分析又可称为成分结构分析(constituent structure parsing)或短语结构分析(phrase structure parsing)。以获取整个句子的句法结构为目的的句法分析称为完全句法分析或者完全短语结构分析,而以获得局部成分(如基本名词短语)为目的的句法分析称为局部分析或浅层分析。
依存关系分析又称为依存句法分析或依存结构分析,简称依存分析。
虽然这本书的一些术语与cs224n的术语略有出入,但是大多数还是一致的。句子句法的分析工作,涉及到一些术语,这里做一统一归纳:
序号 | 名称 | 对应英文 | 缩写 |
---|---|---|---|
1 | 名词 | Nouns | N |
2 | 形容词 | Adjective | Adj |
3 | 动词 | Verb | V |
4 | 冠词 | Determiners / Articles | Det |
5 | 介词 | Preposition | P |
6 | 代词 | Pronoun | Pron |
7 | 谓语 | Predicate | Pre |
序号 | 名称 | 对应英文 | 缩写 |
---|---|---|---|
1 | 助动词 | Auxiliaries | Aux |
2 | 名词短语 | Noun Phrase | NP |
3 | 介词短语 | Prepositional Phrase | PP |
3 | 动词短语 | VerbPhrase | VP |
二、语言结构的两种Views
Parse trees in NLP, analogous to those in compilers, are used to analyze the syntactic structure of sentences.There are two main types of structures used - constituency structures and dependency structures.
译:解析树在NLP中,就像编译器,用于分析句子的句法结构。有两种主要的结构类型(constituency structures),组成性结构和依存关系结构(dependency structures)
根据官方note04,对语言结构(linguistic structure)有两种观点。一是成分结构,一种是依存结构。分别对应着“成分分析(constituent parsing)”和“依存分析(dependency parsing)”。这与《统计自然语言处理(第二版)》描述一致。
两种语法分析能够揭示句子中不同的信息。任务中,需要用到句子中的短语结构就用constituent parsing,而需要用到词与词之间的依赖关系就用dependency parsing。
(一)成分分析(constituent parsing)
在成分结构中,有:
Constituency (成分)
=
phrase structure grammar(短语结构语法)
=
context-free grammars (CFGs,无上下文语法)
\begin{aligned} &\text{Constituency (成分)} \\ &\quad = \text{phrase structure grammar(短语结构语法)}\\ &\quad = \text{context-free grammars (CFGs,无上下文语法)} \end{aligned}
Constituency (成分)=phrase structure grammar(短语结构语法)=context-free grammars (CFGs,无上下文语法)
再引用note04中的原话解释什么是成分结构:
Dependency structure of sentences shows which words depend on (modify or are arguments of) which other words
可以看出,成分结构分析其实就是识别出句子中的短语结构(phrase)以及短语之间的层次句法关系,所以又称为“phrase structure grammar”。也正是因为这个,分析时并不注重单词与单词间的关系(如修饰、定语、状语等),所以又称为“context-free grammars ”。例如给定句子“The old tree swayed in the wind”,它的成分句法树如下图所示:
(二)依存分析(dependency parsing)
成分句法把句子组织成短语的形式,如eating fish就是一个动词短语。而依存句法主要揭示了句子中词的依赖关系,引用note04的一句话:
Dependency structure shows which words depend on (modify or are arguments of) which other words.
与成分分析一样,依存分析也有类似于句法树的表示——依存句法树。它是表示一个句子中词与词之间的依存关系,如下图:
上图涉及到的依存关系简写,请参考 依存关系简写表。
其中两个词之前的弧表示这两个词有依存关系,弧上的标签为二者的关系,弧的始发点为父亲节点,箭头指向为孩子节点。比如“The boy” 是名词短语,“The” 是“boy” 的冠词(Det)。
除了一个词,即根节点(这里为cried)外,其他词都有词作为父亲节点,而该根节点(cried)的父亲节点为root。
但是注意:依存句法树是不允许弧之间回路。且除少数例外(下图),大多数情况下不会有交叉。
依存分析的一些重要概念
- 依存句法认为**“谓语”中的动词是一个句子的中心**,其他成分与动词直接或间接地产生联系。
- 依存句法理论中,“依存”指词与词之间支配与被支配的具有方向的不对等关系。确切的说,处于支配地位的成分称之为支配者(governor,regent,head),而处于被支配地位的成分称之为从属者(modifier,subordinate,dependency)。
- 依存语法存在一个共同的基本假设:句法结构本质上包含词和词之间的依存(修饰)关系。一个依存关系连接两个词,分别是核心词(head)和依存词(dependent)。依存关系可以细分为不同的类型,表示两个词之间的具体句法关系。
- 依存树是满足以下约束的有向图:1)有一个指定的根节点,没有传入它的弧;2)除了根节点外,每个顶点都有一个传入弧,从根节点到每个顶点有一条唯一的路径
- 投射性(projective):如果从头部到句子中的每个单词之间都有一条路径,则从头部到依赖方的弧线被称为有投射性的。如果组成依赖树的所有弧都是投射性的,则称该依赖树具有投射性。如果依赖树可以在没有交叉边的情况下绘制,则依赖树是可投射的。(投射性部分,Manning教授在课上跳过了,这里也不细究)
句法分析可用的特征
- 双词汇亲和(Bilexical affinities),比如discussion与issues
- 词语间距,因为一般相邻的词语才具有依存关系
- 中间词语,如果中间词语是动词或标点,则两边的词语不太可能有依存
- 词语配价,一个词语最多有几个依赖者
依存句法分析的几个约束条件
- ROOT只能被一个词依赖
- 无环
• Only one word is a dependent of ROOT
• Don’t want cycles A → B, B → A
依存句法树的数据表示
通过建立模型,分析句子可以得到句法树。那么,句法树如何用数据来表示呢?
依存句法树的文本表示格式为conll格式,根据表的父亲节点索引和对应的弧上关系就能还原该依存句法树(其中-1表示根节点),如下表:
词 | 词性 | 父节点索引 | 弧上关系 |
---|---|---|---|
The | DT | 2 | Det |
little | JJ | 2 | Amod |
boy | NN | 3 | Nsubj |
cried | VBD | -1 | root |
with | IN | 3 | prep |
grievance | NN | 4 | pobj |
in | IN | 3 | prep |
the | DT | 8 | det |
classroom | NN | 6 | pobj |
这节课以及练习用的都是依存句法树,而不是短语结构树。这并不是随机选择,而是由于前者的优势。90年代的句法分析论文99%都是短语结构树,但后来人们发现依存句法树标注简单,parser准确率高,所以后来(特别是最近十年)基本上就是依存句法树的天下了(至少80%)。
- 不标注依存弧上关系的依存句法树(下图右图)就是短语结构树的一种
- 标注了依存弧上关系的短语结构树,和不标注依存弧上关系的短语结构树,两者就彻底不同了
这里箭头的尾部是head(被修饰的主题),箭头指向的是dependent(修饰语)
依存句法树的用途
通常将依存句法的特征融入到任务模型中,比如机器翻译、意见挖掘、语篇分析等,一般能得到更好的性能。
那怎么得到依存句法特征呢?通常有两种方法:
将依存句法树喂给递归神经网络,得到的隐层表示可以作为该依存句法的特征表示。
将依存句法树交给特征模板,从而得到该依存句法的特征表示。
依存分析器的性能评价
通常使用的指标包括无标记依存正确率(unlabeled attachment score,UAS)、带标记依存正确率(labeled attachment score, LAS)、依存正确率(dependency accuracy,DA)、根正确率(root accuracy,RA)、完全匹配率(complete match,CM)等。这些指标的具体意思如下:
无标记依存正确率(UAS):测试集中找到其正确支配词的词(包括没有标注支配词的根结点)所占总词数的百分比。
带标记依存正确率(LAS):测试集中找到其正确支配词的词,并且依存关系类型也标注正确的词(包括没有标注支配词的根结点)占总词数的百分比。
依存正确率(DA):测试集中找到正确支配词非根结点词占所有非根结点词总数的百分比。
根正确率(RA):有二种定义,一种是测试集中正确根结点的个数与句子个数的百分比。另一种是指测试集中找到正确根结点的句子数所占句子总数的百分比。
完全匹配率(CM):测试集中无标记依存结构完全正确的句子占句子总数的百分比。
三、Transition-based Dependency Parsing(基于转移的依存分析)
状态(configuration)和动作是生成依存树的两个重要概念,状态用来记录不完整的预测结果,动作则用来控制状态之间的转移。
算法从空状态开始,通过动作转移到下一个状态,一步一步生成依存句法树,最后的状态就是一个完整的依存树。依存分析是用来预测词与词之间关系的,在算法中即表现为预测动作序列。
所以,整个训练+预测的过程就是,将标记好的依存树数据集作为训练输入(也可以是句子的别的特征),以UAS/LAS/DA/RA/CM等作为需要优化的目标函数进行训练,目的是预测句子中词与词之间的关系。
对于任意一个句子 S = w 0 w 1 ⋯ w n S = w_0 w_1 \cdots w_n S=w0w1⋯wn,其状态可表示为 c = ( α , β , A ) c = (\boldsymbol{\alpha},\boldsymbol{\beta}, \boldsymbol{A}) c=(α,β,A),其中 α \boldsymbol{\alpha} α 为用于存放 w i w_i wi 的stack(就叫它栈吧), α \boldsymbol{\alpha} α 为用于存放 w i w_i wi 的buffer(叫它缓存吧), A = { ( w i , r 1 , w j ) , ⋯ , ( w p , r k , w q ) } \boldsymbol{A} = \left\{(w_i,r_1,w_j),\cdots,(w_p,r_k,w_q)\right\} A={(wi,r1,wj),⋯,(wp,rk,wq)} 为依存关系的集合, r k r_k rk 是 w i w_i wi 和 w j w_j wj 之间的依存关系。
初始状态 c 0 c_0 c0 表示为 c 0 = ( [ w 0 ] α , [ w 1 , ⋯ , w n ] β , ∅ ) c_0 = ([w_0]_{\alpha},[w_1,\cdots,w_n]_{\beta}, \varnothing) c0=([w0]α,[w1,⋯,wn]β,∅),此时 w 0 w_0 w0 就是ROOT,剩下的所有词都在 β \boldsymbol{\beta} β 中。而终止状态为 ( σ , [ ] β , A ) (\boldsymbol{\sigma},[]_{\boldsymbol{\beta}}, \boldsymbol{A}) (σ,[]β,A) 。
状态间的转移有三种方式:
- SHIFT \text{SHIFT} SHIFT:从buffer中移除第一个词,并将其送入栈的顶部(前提条件:buffer为非空)
- LEFT-ARC r \text{LEFT-ARC}_r LEFT-ARCr:添加 ( w j , r , w i ) (w_j,r,w_i) (wj,r,wi) 到 A \boldsymbol{A} A,其中 w i w_i wi 是栈次顶端的词(第二个词), w j w_j wj 是栈最顶端的词;然后再将 w i w_i wi 从栈中移除。(前提条件:栈至少包含两个词,且 w i w_i wi 不能是ROOT)
- RIGHT-ARC r \text{RIGHT-ARC}_r RIGHT-ARCr:添加 ( w i , r , w j ) (w_i,r,w_j) (wi,r,wj) 到 A \boldsymbol{A} A,其中 w i w_i wi 是栈次顶端的词(第二个词), w j w_j wj 是栈最顶端的词;然后再将 w j w_j wj 从栈中移除。(前提条件:栈至少包含两个词)
用数学方式表示,即为:
SHIFT
σ
,
w
i
∣
β
,
A
→
σ
∣
w
i
,
β
,
A
LEFT-ARC
r
σ
∣
w
i
∣
w
j
,
β
,
A
→
σ
∣
w
j
,
β
,
A
∪
{
r
(
w
j
,
w
i
)
}
RIGHT-ARC
r
σ
∣
w
i
∣
w
j
,
β
,
A
→
σ
∣
w
i
,
β
,
A
∪
{
r
(
w
i
,
w
j
)
}
\begin{aligned} \quad \text{SHIFT} \quad \quad &\boldsymbol{\sigma} ,w_i| \boldsymbol{\beta}, \boldsymbol{A} \quad \rightarrow \quad \boldsymbol{\sigma} | w_i,\boldsymbol{\beta}, \boldsymbol{A}\\ \quad \text{LEFT-ARC}_r \quad \quad &\boldsymbol{\sigma}| w_i | w_j , \boldsymbol{\beta}, \boldsymbol{A} \quad \rightarrow \quad \boldsymbol{\sigma} | w_j,\boldsymbol{\beta}, \boldsymbol{A} \cup \left\{ r(w_j,w_i) \right\}\\ \quad \text{RIGHT-ARC}_r \quad \quad &\boldsymbol{\sigma}| w_i | w_j , \boldsymbol{\beta}, \boldsymbol{A} \quad \rightarrow \quad \boldsymbol{\sigma} | w_i,\boldsymbol{\beta}, \boldsymbol{A} \cup \left\{ r(w_i,w_j) \right\} \end{aligned}
SHIFTLEFT-ARCrRIGHT-ARCrσ,wi∣β,A→σ∣wi,β,Aσ∣wi∣wj,β,A→σ∣wj,β,A∪{r(wj,wi)}σ∣wi∣wj,β,A→σ∣wi,β,A∪{r(wi,wj)}
三种转移方式的区别
这里会有一个问题: SHIFT \text{SHIFT} SHIFT、 LEFT-ARC \text{LEFT-ARC} LEFT-ARC 和 RIGHT-ARC \text{RIGHT-ARC} RIGHT-ARC三者之间到底有什么区别,算法什么时候选择那个转移方式?
- SHIFT \text{SHIFT} SHIFT:把队列中的一个词加入到栈顶。主要用在两种情况下:1)在算法启动阶段栈中无任何元素时;2)栈顶两个元素之间不存在依赖关系时
- LEFT-ARC r \text{LEFT-ARC}_r LEFT-ARCr:栈顶和它下面的词构成依存关系,并且中心词是栈顶元素,把这个依存关系加入到已parse的数据结构里,最后把除中心词之外的词从栈中移除
- RIGHT-ARC r \text{RIGHT-ARC}_r RIGHT-ARCr :栈顶和它下面的词构成依存关系,中心词是下面的元素,把这个依存关系加入到已parse的数据结构里( A \boldsymbol{A} A),最后把除中心词之外的词从栈中移除
举例说明
下面通过一个例子说明算法流程:
句子:
B
o
o
k
m
e
t
h
e
m
o
r
n
i
n
g
f
l
i
g
h
t
Book\quad me \quad the \quad morning \quad flight
Bookmethemorningflight
步骤 | 栈 | 缓存 | 下步转移 | 新关系 |
---|---|---|---|---|
1 | [Root] | [book, me, the, morning, flight] | SHIFT | |
2 | [Root, book] | [me, the, morning, flight] | SHIFT | |
3 | [Root, book, me] | [the, morning, flight] | RIGHT-ARC | book → \rightarrow → me |
4 | [Root, book] | [the, morning, flight] | SHIFT | |
5 | [Root, book, the] | [morning, flight] | SHIFT | |
6 | [Root, book, the, morning] | [flight] | SHIFT | |
7 | [Root, book, the, morning, flight] | [ ∅ \varnothing ∅] | LEFT-ARC | morning ← \leftarrow ← flight |
8 | [Root, book, the, flight] | [ ∅ \varnothing ∅] | LEFT-ARC | the ← \leftarrow ← flight |
9 | [Root, book, flight] | [ ∅ \varnothing ∅] | RIGHT-ARC | book → \rightarrow → flight |
10 | [Root, book] | [ ∅ \varnothing ∅] | RIGHT-ARC | Root → \rightarrow → book |
11 | [Root,] | [ ∅ \varnothing ∅] | Done |
四、基于神经网络的依存句法分析(Neural Dependency Parsing)
虽然依存分析有许多可用模型,但本节主要关注基于转换的贪婪的神经网络依存句法分析器。与传统的基于特征的区别依赖解析器相比,主要区别是依赖于密集而非稀疏的特征表示,具有相当的性能和显著的效率。
该模型的目的是预测从初始状态 c i n i t c_{init} cinit 到最终状态 c e n d c_{end} cend 的转移动作序列,转移动作集为 { SHIFT , LEFT-ARC r , RIGHT-ARC r } \left\{ \text{SHIFT},\text{LEFT-ARC}_r,\text{RIGHT-ARC}_r \right\} {SHIFT,LEFT-ARCr,RIGHT-ARCr} 。
模型输入的选择
可以根据模型复杂性灵活地选择神经网络的输入,一个给定句子的特征通常包括:
- S w o r d S_{word} Sword:句子中一些词(以及他们之间的依存关系)的向量表示
- S t a g S_{tag} Stag:句子中一些词的词性标注(part-of-speech tags,POS,也称词类)所组成的离散集合: P = { N N , N N P , N N S , D T , J J , ⋯ } \mathcal{P} = \left\{ NN,NNP,NNS,DT,JJ,\cdots \right\} P={NN,NNP,NNS,DT,JJ,⋯}
- S l a b e l S_{label} Slabel:句子中一些词的弧标签所组成的小的离散的集合: L = { a m o d , t m o d , n s u b j , c s u b j , d o b j , ⋯ } \mathcal{L} = \left\{ amod,tmod,nsubj,csubj,dobj,\cdots \right\} L={amod,tmod,nsubj,csubj,dobj,⋯}
对于每一种特征类型,都有一个嵌入矩阵(Embedding Matrix)将词的one-hot向量映射为 d d d 维向量表示。 S w o r d S_{word} Sword对应的完整的嵌入矩阵为 E w ∈ R d × N w E^w \in \mathbb{R}^{d \times N_w} Ew∈Rd×Nw , N w N_w Nw是词汇表大小。相应地, S t a g S_{tag} Stag 和 S l a b e l S_{label} Slabel 对应的完整的嵌入矩阵为 E t ∈ R d × N t E^t \in \mathbb{R}^{d \times N_t} Et∈Rd×Nt 和 E l ∈ R d × N l E^l \in \mathbb{R}^{d \times N_l} El∈Rd×Nl 。
输入举例
上面的描述不是很清楚,我们举一个例子来说明如何选择 S w o r d S_{word} Sword、 S t a g S_{tag} Stag、 S l a b e l S_{label} Slabel。
首先看官方note的原文(其实就是EMNLP2014 - A Fast and Accurate Dependency Parser using Neural Networks原文描述):
- S w o r d S_{word} Sword:在栈和缓存中的前三个词表示为: s 1 , s 2 , s 3 , b 1 , b 2 , b 3 s_1,s_2,s_3,b_1,b_2,b_3 s1,s2,s3,b1,b2,b3。对于栈顶的两个单词,它们左边/右边的子词为: l c 1 ( s i ) , r c 1 ( s i ) , l c 2 ( s i ) , r c 2 ( s i ) lc_1(s_i),rc_1(s_i),lc_2(s_i),rc_2(s_i) lc1(si),rc1(si),lc2(si),rc2(si),其中 i = 1 , 2 i=1,2 i=1,2。栈顶的两个单词,它们左边/右边的子词的左边/右边的子词: l c 1 ( l c 1 ( s i ) ) , r c 1 ( r c 1 ( s i ) ) , l c 2 ( l c 2 ( s i ) ) , r c 2 ( r c 2 ( s i ) ) lc_1(lc_1(s_i)),rc_1(rc_1(s_i)),lc_2(lc_2(s_i)),rc_2(rc_2(s_i)) lc1(lc1(si)),rc1(rc1(si)),lc2(lc2(si)),rc2(rc2(si)),其中 i = 1 , 2 i=1,2 i=1,2,因此 n t a g = 18 n_{tag} = 18 ntag=18。(注意:用NULL来替代不存在的元素)
- S w o r d S_{word} Sword总共有 n w = 18 n_w = 18 nw=18 个词,选择stack和buffer的顶端三个词。用 l c j ( s i ) lc_j(s_i) lcj(si) 表示 s i s_i si 左边第 j j j 个词,用 r c j ( s i ) rc_j(s_i) rcj(si) 表示 s i s_i si 右边第 j j j 个词 ( i , j = 1 , 2 ) (i,j=1,2) (i,j=1,2) 。
- S t a g S_{tag} Stag:总共有 n t = 18 n_t = 18 nt=18 个词性标注
- S l a b e l S_{label} Slabel:总共有 n l = 12 n_l = 12 nl=12 个标签
问题:这个 n t a g = 18 n_{tag} = 18 ntag=18 是怎么算出来的呢?
比如句子:
H
e
h
a
s
g
o
o
d
c
o
n
t
r
o
l
.
He \quad has \quad good \quad control \quad .
Hehasgoodcontrol.
这个 n t a g = 18 n_{tag} = 18 ntag=18分成三部分:
- 栈和缓存中的前三个词: s 1 , s 2 , s 3 , b 1 , b 2 , b 3 s_1,s_2,s_3,b_1,b_2,b_3 s1,s2,s3,b1,b2,b3,共计6个
- 栈和缓存的top 2的词的 “leftmost / rightmost children”,共计8个
这里划重点:所谓的“leftmost / rightmost children”,字面意思就是最左/右侧的子词。对应到上图,“has”的“leftmost children”就是从“has”画起的箭头所指向的所有单词中最靠左的那个——就是“He” - 栈和缓存的top 2的词的 “leftmost / rightmost children”的 “leftmost / rightmost children”,共计4个
神经网络结构
对一个给定句子例子,按照上述方法选择单词、词性标注和依存标签,从嵌入矩阵
E
w
,
E
t
,
E
l
E^w, E^t, E^l
Ew,Et,El中提取它们对应的稠密的特征的表示,然后将这些向量 拼接起来 作为输入
[
x
w
,
x
t
,
x
l
]
[x_w,x_t,x_l]
[xw,xt,xl]。
网络结构由一个输入层、一个隐含层、一个softmax输出层组成,使用交叉熵损失函数。神经元非线性激活函数为 f ( x ) = x 3 f(x) = x^3 f(x)=x3。
Reference
依存句法分析
Constituent Parsing & Dependency Parsing 句法分析简介
详解Transition-based Dependency parser基于转移的依存句法解析器
CS224n笔记6 句法分析
自然语言处理基础技术之依存句法分析
CS224n笔记(三)