成分句法分析綜述
原文連結:
ofollow,noindex">成分句法分析綜述 - WeiYang Blog一直以來想對保研到現在一年多看過的論文進行一個總結,正好趕上下週二要講組會,所以將自己看過的成分句法分析相關的論文梳理一下,寫一個粗略的綜述。可能有很多細節還不是很懂,理解有誤,還請大家指正。
PPT地址: A Summary of Constituent Parsing
程式碼地址: Constituent Parsing
介紹
成分句法分析(constituent parsing)是自然語言處理中的一個基礎任務,它的任務是給定一個句子,分析出句子的短語結構句法樹。例如給定句子“The little boy likes red tomatoes .”,它的成分句法樹如下圖所示:

成分句法分析可以利用到許多下游任務中去,比如情感分析可以利用句子的成分句法樹來進行遞迴神經網路建模,從而分析出句子的情感。也可以利用在其他基礎任務中去,比如可以將訓練好的成分句法樹直接轉為依存句法樹,從而提升依存句法分析的準確率。
傳統的成分句法分析方法主要是規則(grammar)和統計的,比如結合兩者的概率上下文無關文法(PCFG),在此基礎上產生了應用廣泛的CKY解碼演算法。CKY演算法本質上是一種動態規劃演算法,本文之後要講到的chart-based模型的解碼演算法也是基於動態規劃演算法的,和CKY演算法十分地相似。
Socher在2013年又提出了組合向量文法(CVG),將遞迴神經網路應用到了成分句法分析中,給每個短語結構賦予了向量表示。但是這種方法還是需要用到規則,採用CKY演算法解碼,時間效率比較低。還有一種基於CRF的神經網路句法分析方法,將離散的特徵轉化為了連續的特徵表示。
不過,上面這些方法統統都不在本文的討論範圍之內。本文討論近兩年來研究最熱門的幾種模型,主要包括基於轉移系統(transition-based)的模型、基於動態規劃(chart-based)解碼的模型、基於自頂向下貪心(greedy top-down)解碼的模型和一些將預測樹結構轉化為預測序列(sequence to sequence)的模型。
基於轉移系統的模型
基於轉移系統的模型主要分為三大類。第一種是自底向上(bottom-up)的系統,代表性論文有Transition-based Neural Constituent Parsing等。第二種是自頂向下(top-down)的系統,代表性論文有Recurrent Neural Network Grammars和Span-Based Constituency Parsing with a Structure-Label System and Provably Optimal Dynamic Oracles等。最後一種是2017年提出的基於中序遍歷(in-order)的系統,代表性論文有In-Order Transition-based Constituent Parsing等。
在這三類系統的基礎之上,許多人又做了非常多的改進。例如提出了動態指導(dynamic oracle)技術,來解決序列預測中的exposure bias問題(具體含義之後會講到)。還有使用強化學習中的policy gradient來代替dynamic oracle,解決了針對不同轉移系統需要設計不同的dynamic oracle的問題。
基於轉移的句法分析系統主要包含兩個組成成分,一個是棧(stack),用來存放已分析的句法結構,另一個是快取(buffer),用來存放待分析的句子。而預測句法樹結構就轉化為了預測轉移系統每一個時刻應該採取的動作(action)序列。下面我們分別介紹幾種不同的轉移系統,我們用三元組 來表示轉移系統每一個時刻的狀態,分別代表棧、buffer的第一個單詞下標、句法分析結束標誌。
自底向上的轉移系統
自底向上的轉移系統是根據句法樹的後序遍歷(post-order)順序進行句法分析的,首先將buffer中的單詞移進棧裡,然後將棧頂的若干個單詞歸約為它們的父結點,直至最後buffer為空並且棧裡只有一個根節點。
在句法分析之前,首先要對句法樹進行二叉化,這一點在傳統的CKY演算法中也會用到。例如對於之前的那棵句法樹,二叉化後就變成了下圖所示:

自底向上轉移系統的action形式化定義如下:

其中SHIFT動作就是將buffer裡面的第一個單詞移進棧裡。REDUCE-L/R-X動作就是將棧頂的兩個元素出棧,並且歸約為它們的父結點X,然後再將父結點入棧,而L和R就是用來區分左兒子和右兒子誰是頭結點(head branch)。Unary-X動作就是將棧頂元素出棧,並且歸約為父結點X,這個動作是用來預測一元產生式的。最後FINISH動作用來判斷句法分析是否結束。
注意到這裡有一個問題:為什麼這裡一定要提前對句法樹進行二叉化?主要原因是因為自底向上系統有個弊端,就是在不停地SHIFT之後,你不僅要預測哪一步開始REDUCE,還得預測REDUCE的話要REDUCE棧頂的多少個元素,這樣預測的狀態數就大大增加,導致訓練時間也增加了許多。而二叉化後每次預測就只需要預測哪一步REDUCE就行了,每次REDUCE只REDUCE棧頂的兩個元素。
對於上面的句法樹,用自底向上系統分析的過程如下圖所示:

自底向上轉移系統的優點就是可以充分利用已經生成的子樹資訊,來輔助後面的子樹預測。
但是缺點也很顯然,因為無法知道父結點以及再上層的父結點資訊,所以丟失了許多有用的全域性資訊,這也有點類似於CKY演算法的弊端了,同樣只能根據區域性的子樹資訊預測當前子樹。
另一個缺點就是需要提前進行二叉化,雖然二叉化加入了head結點資訊,事實證明是很有用的,但是head結點的標註需要許多語義學知識,也可以用神經網路來自己學習到head結點,但是二叉化總歸是比較麻煩的。一個較為簡潔的做法就是,用空結點 來作為本不應該歸約的兩個結點的臨時結點,在還原樹結構的時候忽略這種空結點,這樣就可以隱式地進行二叉化操作了。
自頂向下的轉移系統
自頂向下的轉移系統利用的是句法樹的前序遍歷(pre-order)序列,首先將父結點入棧,然後不斷操作直到它的子結點全部入棧,這時將父結點連同所有子結點全部歸約為上一層的父結點。
自頂向下轉移系統的action形式化定義如下:

其中SHIFT動作和之前一樣,都是將buffer的第一個單詞入棧。而NT-X動作就是將父結點X入棧。REDUCE動作就是將棧頂若干個元素直到它們的第一個父結點為止都出棧,然後歸約為一個結點,再次入棧。注意到這裡不同於自底向上系統的地方是沒有FINISH動作,筆者也沒有找到相關解釋,猜測可能是因為自底向上系統存在一元動作Unary-X,所以最後根節點可能會無限歸約下去,需要通過FINISH來提前終止分析。當然其實轉移系統的動作定義並沒有嚴格的要求,不同論文定義的也都不一樣,但是都大同小異,也就是都存在SHIFT-REDUCE動作。
對於上面的句法樹,用自頂向下系統分析的過程如下圖所示:

自頂向下系統的優缺點和自底向上系統恰好互補。優點就是可以充分利用全域性資訊,例如父結點的資訊,並且不需要進行二叉化,因為REDUCE的時候只要往棧裡找到第一個父結點就行了。而缺點就是無法利用區域性資訊,也就是子樹資訊,同樣NT-X動作也可能會出現無限多次執行的情況,所以要加上一些限制條件。
In-order轉移系統
Zhang和Liu兩人在2017年提出了in-order轉移系統,它利用的是句法樹的中序遍歷(in-order)序列,首先將一個子結點SHIFT入棧,然後將父結點入棧,再不斷操作直到該父結點的剩餘子結點全部入棧,然後對它們進行歸約。
自頂向下轉移系統的action形式化定義如下:

其中SHIFT動作和之前一樣,都是將buffer的第一個單詞入棧。PJ-X動作是預測出當前棧頂的元素的父結點X。REDUCE動作就是將棧頂的若干個元素歸約為最裡面倒數第二個元素,也就是它們的父結點。
對於上面的句法樹,用in-order系統分析的過程如下圖所示:

in-order轉移系統提出的動機也很符合人類的直覺,在你讀一個句子的時候,如果你第一個看到的單詞是“The”,那麼你腦海中可能會想到後面緊跟著的可能是個名詞短語NP,然後你繼續往後看,果然驗證了你的猜想,後面的單詞序列是“red tomatoes”。
in-order轉移系統的優點恰好結合了前面兩種轉移系統,既可以考慮到區域性資訊,又可以考慮到全域性資訊。
模型變體: in-order系統就是在自頂向下系統的基礎上,在父結點入棧之前先入棧了1個子結點。那麼如果稍加修改,還可以提前入棧兩個、三個等等。假設在父結點入棧之前先入棧了 個子結點,那麼稱這種轉移系統為k-in-order系統。特別地,如果 ,那麼這就是自頂向下轉移系統;如果
,那麼這就是in-order轉移系統;
,那麼這就是自底向上轉移系統。
模型框架
上面說到的三種基於轉移的句法分析系統,都可以概括為預測每一個時刻的action,那麼每一個時刻的狀態如何表示就是最重要的問題。在每一個時刻,最重要的組成部分有三個,分別是當前棧的狀態、當前buffer的狀態、當前已生成的action序列的狀態。
當前狀態的表示通過下圖所示的三個LSTM得到:

其中棧和buffer的編碼使用的是stack-LSTM,而action的編碼使用的是普通的LSTM。最後將三種LSTM輸出拼接到一起,用softmax預測出正確的action。
另一個問題就是如何編碼棧裡的短語。在以前都是通過遞迴神經網路或者樹狀LSTM來編碼樹狀結構短語的,而在這裡的話直接將父結點和子結點合為一個序列,送入到雙向LSTM中就行了,具體形式如下圖所示:

系統改進
基於span的自底向上的轉移系統 黃亮在2016年論文裡提出了轉移系統的棧裡用span的左右邊界數值來代替分析出來的子樹,並且將REDUCE動作和預測label分開來進行,他們的轉移系統action形式化定義如下:

可以看出,在第偶數個時刻,只預測結構化動作sh和comb(對應於之前轉移系統的SHIFT和REDUCE),sh動作從buffer中移進棧裡一個單詞 ,棧頂的span就變為了
Line"/> 。而comb動作就是將棧頂的兩個span歸約為一個span。在第奇數個時刻,只預測棧頂span的label,如果這個span的確能構成一個短語,那麼就預測它的label,否則的話說明只是個臨時結點,就預測為空結點,這一點在之前就已經提到過了。
論文裡給出了一個具體的例子:


文章開頭提供的程式碼也是基於這個轉移系統的,一個好處是用span來表示的話比較方便,程式碼也好寫。另一個好處就是每一個時刻的狀態可以不再用三個LSTM動態地算出來了,而是可以提前用雙向LSTM對句子進行編碼,然後用兩個單詞輸出的差值作為單詞之間span的表示,最後用它來計算轉移狀態的向量表示。
例如在某個時刻,棧首元素為 ,那麼結構化預測就採用四個span特徵:
,為什麼要用這四個呢?因為comb動作涉及到棧首的兩個span,而之前已經生成的
也可以作為區域性資訊指導預測,buffer中的
也要考慮到,因為可能預測為sh動作,同時也可以作為全域性資訊參考。
而label預測就只要用到三個span特徵: ,因為label動作只需要對棧首的span進行預測,所以三個特徵就足夠了。
生成模型RNNG RNNG是2016年提出的一種文法,全稱叫做“Recurrent Neural Network Grammar”,是一種生成式模型。RNNG本質上就是自頂向下的轉移系統,動作定義和之前介紹的基本一致。只是之前介紹的自頂向下的轉移系統是判別式模型,每次SHIFT的單詞都是buffer中給定的。而RNNG每次SHIFT的單詞需要通過動作GEN(x)預測得出,最終模型對預測出來的句子分析出句法樹。
正式一點就是,對於句子 和對應的句法樹 ,判別式模型是對條件概率 進行建模,而生成式模型是對聯合概率
進行建模。
而RNNG的另一個重要應用是語言模型(language model),也就是建模 。因為
,所以只需要枚舉出所有可能的句法樹 即可,但是這是指數級別的,顯然不現實,這時候就需要用到“重要性取樣(importance sampling)”。
令 為RNNG作為判別式模型的時候產生句子 的條件概率,那麼
可以改寫為
然後就可以採用蒙特卡羅方法進行取樣了,從分佈 中取樣
個樣本:
那麼 就可以近似表示為:
Dynamic Oracle 文章開頭提到了一個轉移系統會遇到的問題:“exposure bias問題”,這個問題意思就是訓練的時候轉移系統的每個時刻都是按照標準的action來進行訓練的,但是如果測試的時候遇到了一個訓練時從來沒有遇見過的狀態,這時候該怎麼預測?如果預測錯了,那麼之後的時刻可能錯的越來越離譜,偏差越來越大。
解決的方法就是採用Dynamic Oracle技術,在預測錯誤的時候,按照標準樹的結構指導轉移系統向著錯誤儘可能小的狀態進行轉移。但是比較麻煩的是,對於每一個轉移系統,可能大家定義的狀態都不盡相同,所以Dynamic Oracle要針對特定的轉移系統單獨設計,一個解決方法就是之後要提到的Policy Gradient方法。
這裡舉一個針對上面的“基於span的自底向上的轉移系統”的Dynamic Oracle例子。
首先是結構化oracle,如果當前的棧首span是 ,那麼就在標準樹中尋找所有包含
並且最小的span,記為
,那麼下一步可以採取的動作定義如下:

也就是說,如果 比
右邊界多出一部分,那麼為了向著標準span靠近,就只能sh單詞入棧;否則如果左邊界多出一部分,那麼就必須先comb之前的兩個span,擴大span左邊的邊界;否則的話左右兩邊都有空出,那就隨機預測一個動作就行了。
然後是label oracle,這個就很簡單了,如果當前的棧首span是 ,只需要在標準樹中尋找是否存在
,如果存在,那麼就給他正常預測label就行了;如果不存在,那麼直接預測為空結點。oracle定義如下:

而關於這個Dynamic Oracle的證明和更加深入的理解,參見我之前寫過的一篇部落格:
深入理解成分句法分析中的Dynamic Oracle但是如果直接按照這個Dynamic Oracle來實現程式碼的話,效果不會有什麼提升,原因就是訓練的時候遇到的錯誤情形還是太少了,不足以應付所有的測試階段遇到的未知情形。所以要在訓練階段加上exploration操作,也就是轉移的每一個時刻,不要總是預測概率最大的action,而是以一定的概率隨機選擇一個action,誘導系統進入一個錯誤的狀態,這樣系統就能學到更多錯誤狀態下的回正技巧了。
Policy Gradient 序列預測存在著兩個問題:一個就是之前提到的exposure bias問題,另一個就是loss mismatch問題,意思就是在每一個狀態的loss累和得到最終整個序列的loss,但是因為是貪心解碼,並沒有考慮到之後的結果,所以某一個狀態的loss其實並不能代表整個序列的loss。
Dynamic Oracle可以解決第一個問題,如果修改一下也可以解決第二個問題,但是Dynamic Oracle需要針對特定的轉移系統單獨設計,不能通用,所以這裡引入了強化學習中的Policy Gradient來解決這個問題。
首先用風險函式(risk objective)代替原來的損失函式:
其中 是訓練集中的標準資料。可以看出,風險函式其實就是所有可能的句法樹和標準樹的差異
的期望,訓練的目的就是最小化所有句法樹和標準樹的差異,這樣就消除了之前提到的兩個問題。
但是可以發現,顯然不可能列舉所有可能的句法樹,這時候想到了之前用到的重要性取樣方法。
但是不能直接對風險函式進行重要性取樣,不然就會發現取樣後的函式 消失了!那就沒辦法求導了。所以先對風險函式求導:
這裡的 是根據分佈 取樣得到的結果。實驗中可以將標準樹也加入到取樣結果中,可以提升準確率。 至於
項是怎麼來的,可以如下推導得來:
編碼解碼模型
上面介紹完了基於轉移的句法分析系統,下面開始介紹編碼解碼(Encoder-Decoder)模型。
模型的大致框架如下圖所示:

首先通過編碼器將句子編碼成向量,然後用解碼器對向量操作,解碼出句法樹。
編碼器(Encoder)
編碼器的主要目的是將每個短語編碼成語義向量,用來給解碼器預測splits和labels。
編碼器主要有兩種,一種是簡單的雙向LSTM編碼,下圖是一個用雙向LSTM對句子進行編碼的示例:

例如要編碼“played soccer in”這個短語,那麼就用“in”處的前向LSTM輸出減去“She”處的前向LSTM輸出,得到了短語的前向LSTM表示。類似的,用“played”處的反向LSTM輸出減去“the”處的反向LSTM輸出,得到了短語的反向LSTM表示。
另一種是multi-headed self-attention編碼。Attention是谷歌在“Attention is all you need”中提出的一種方法,嚴格來說它並不能算作一種模型,只能說是一種機制。具體原理在這裡就不細講了,可以直接去看一下原文。
大體框架就是,每個單詞的詞向量經過三個不同的 矩陣變換之後得到了三個不同的向量表示
,分別拼接起來組成了矩陣
,其中
相乘就得到了任意兩個單詞之間的相似度矩陣,然後對矩陣每一行進行softmax就得到了每一個單詞對於其他所有單詞的權重。再乘上矩陣
就得到了它對其他所有單詞的加權求和,以此來作為它的向量表示。
下圖就是self-attention的框架圖:

形式化定義就是:
其中 ,
是向量
的維度,用它作為分母是為了防止數值太大溢位。最後的矩陣
是為了將輸出對映到與輸入相同的維度。
而multi-headed self-attention就是將剛剛的attention計算8次,並且相加:
注意這8個attention的引數矩陣是不共享的,也可以不相加,改為直接拼接。
最終的編碼器模型如下圖所示:

也就是說,將剛剛的multi-headed self-attention經過一層layernorm之後再經過一層前饋神經網路,最後再經過一層layernorm得到輸出。將上述模型複製8份,首尾拼接,即前面的輸出作為後面的輸入,即可得到編碼器最終的輸出,也就是每個單詞最終的向量表示。
至於每個短語的表示,和雙向LSTM編碼一樣,用短語邊界兩個單詞向量的差值作為短語的表示。只是這裡沒有前向後向的概念,所以要將每個單詞向量一分為二,前一半作為前向向量,後一半作為後向向量。當然在實際實現中,將單數維度提取出來作為前向表示,雙數維度提取出來作為後向表示。
解碼器(Decoder)
得到了每個短語的向量表示之後,就需要對它們進行解碼,得到最終的句法樹,解碼的方法主要有兩種。
基於動態規劃解碼的模型 這種方法在論文中被叫做“chart-based model”,正如其名,就是利用一個數組來進行動態規劃,求出每個span的最優split和最優label。
定義一棵句法樹的分數為所有子結點的label分數之和,即:
其實原本論文中的定義還多了一項span的分數,但是由於具體實現中去掉這一項並沒有什麼影響,所以為了簡便我就只算label分數了。
要使得句法樹分數最大,不可能列舉所有的句法樹,那就只能用動態規劃演算法求解了。對於任意一個 ,我們將它通過編碼器產生的表示
輸入到前饋神經網路中,直接取得分最高的那一維作為最優label,即:
而對於split,遍歷所有的split,取兩個子結點與自己結點得分之和最高的那個split即可:
最後的訓練過程和以往一樣,採用max-margin訓練方法,即使得標準樹的得分比預測樹的得分至少高一個margin,在這裡margin大小定義為兩棵樹不同短語的數量,最終的損失函式定義為:
基於自頂向下貪心解碼的模型 基於動態規劃的解碼演算法時間複雜度為 ,對於長度大一點的句子來說還是有點不可接受的。但是如果採用自頂向下、貪心地去選擇每一個span的最優split和最優label,那麼時間複雜度將降到
。具體操作過程如下,首先從根節點也就是
開始,選擇一個split,使得兩個子結點與自己結點得分之和最高,而label還是向之前那樣直接通過短語的向量計算得出。具體公式為:
而由於貪心解碼和轉移系統action預測一樣,在預測階段可能會遇到訓練階段沒有碰到過的狀態,所以也需要用到Dynamic Oracle。同樣也需要用到exploration,來增加訓練階段遇到的錯誤狀態數。
Sequence to Sequence模型
上面最主流的兩大模型:轉移系統和編碼解碼模型都已經介紹完了,下面介紹幾種比較新穎的方法。
大家都知道句法樹和某些序列存在一一對應關係,句法樹可以唯一轉換成序列,序列也可以唯一轉換成句法樹,所以預測句法樹的問題就轉變為了預測序列問題,下面幾種方法都是將句法樹轉換為了某種序列來進行預測。
樹結構轉化為括號序列
這種方法思路特別簡單,因為訓練集裡原始資料的表示形式就是括號序列嘛,所以就採用語言模型直接預測出括號序列的概率。
但是不可能枚舉出所有的句法樹括號序列,所以最終還是隻對其他句法分析器預測出來的最好的若干棵樹進行預測概率,然後重排序選出概率最高的一棵樹。
句法距離(Syntactic Distance)
這個方法就很新穎了,本質上也是將樹結構轉換成了唯一對應的序列。

首先看上面一張圖,對於長度為 的句子,存在一個長度為 的數字序列,滿足如下條件: 個單詞存在
個兩兩相鄰的單詞對,而兩個相鄰的單詞的最近公共祖先(LCA)在句法樹中有一個高度,所以這
個數的大小關係恰好對應了從左向右任意兩個相鄰單詞對的LCA的高度的大小關係。
拿上面那張圖為例,“She”和“enjoys”的最近公共祖先是“S”,所以高度最高,對應的數字也最大。“enjoys”和“playing”的最近公共祖先是“VP”,高度排第三,所以對應的數字大小也是排第三。依次類推,剩下的數也滿足這個性質。可以證明,這個數字序列和句法樹是一一對應的。更進一步可以發現,這個序列其實就是“中序遍歷的結點的高度”,文中將其稱為句法距離。
預測這個序列也很簡單,通過一個雙向LSTM,然後將每相鄰兩個單詞的輸出做一次卷積操作(因為要預測相鄰兩個單詞的LCA高度嘛),然後再將輸出送到一個雙向LSTM中去,最後通過一個前饋神經網路得到每相鄰兩個單詞的數字。
而從樹到序列和從序列到樹的演算法都很簡單,這裡就不詳述了,可以直接去看論文。
總結
實驗結果
下面列出了成分句法分析領域目前為止最好的一些結果:

最好的是採用self-attention編碼器+外部預訓練詞向量ELMo的模型,第二是模型融合+重排序之後的結果,之後的模型也基本都是本文介紹過的,最厲害的就是最後一個2006年的模型,十幾年了依然如此強悍。
心得體會
雖然看起來貌似已經看了不少的成分句法分析相關的工作了,但是其實還有很多細節性的工作還沒有去了解。前兩年ACL等頂會成分句法分析的論文都很少,但是18年又好像多了起來,但終究還是伯克利Dan Klein、斯坦福Socher、黃亮等一批大佬在做這個,想在巨人的肩膀上面做出點東西還是很有挑戰性的。
目前能想到的工作只有在編碼器上面做文章,學習出語義更加豐富的短語表示。或者可以採用失傳多年的遞迴神經網路,解碼時對句法樹進行建模,但是隨便試了一下,速度很慢而且存在梯度消失的問題,效果也不是很好。轉移系統的話暫時也想不出什麼好的點子,序列預測的話如果能再想出個新穎的一一對應的序列就好了。
前路還很長,說長也不長了,只有三年不到的時間了,做不出東西就要延畢了。但願能在有限的三年時間裡做出點成果,提高自己的程式碼能力,對這個領域也有更加深入的理解!
參考文獻
[ACL15] Transition-based Neural Constituent Parsing
[NAACL16] Recurrent Neural Network Grammars
[EMNLP16] Span-Based Constituency Parsing with a Structure-Label System and Provably Optimal Dynamic Oracles
[TACL17] In-Order Transition-based Constituent Parsing
[EMNLP17] Effective Inference for Generative Neural Parsing
[ACL18] Policy Gradient as a Proxy for Dynamic Oracles in Constituency Parsing [ACL17] A Minimal Span-Based Neural Constituency Parser
[ACL18] Constituency Parsing with a Self-Attentive Encoder
[EMNLP16] Parsing as Language Modeling
[ACL18] Straight to the Tree: Constituency Parsing with Neural Syntactic Distance