天天看點

無監督循環神經網絡文法 (URNNG) | NAACL19

雷鋒網 AI 科技評論按,本文作者[韋陽](https://www.zhihu.com/people/godweiyang/posts "韋陽"),本文首發于知乎專欄[自然語言處理與深度學習](https://zhuanlan.zhihu.com/godweiyang "自然語言處理與深度學習"),雷鋒網 AI 科技評論獲其授權轉載。 **論文位址:**[Unsupervised Recurrent Neural Network Grammars](http://arxiv.org/abs/1904.03746) **代碼位址:**[github](https://github.com/harvardnlp/urnng) # 介紹 --- 這篇是新鮮出爐的 NAACL19 的關于無監督循環神經網絡文法(URNNG)的論文,在語言模型和無監督成分句法分析上都取得了非常不錯的結果,主要采用了變分推理和 RNNG。本文公式量較大,是以我也推了好久,算法也挺多的,首先上一張我推導的公式筆記: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5ccfe8d71f197.jpg) 我這篇部落格就不按照論文的順序來講了,就按照我上面這張筆記講一講我的了解吧,很多細節可能會忽略,請參見原文吧。 首先對于無監督成分句法分析,正常做法就是學習一個生成模型![](https://static.leiphone.com/uploads/new/article/740_740/201905/5ccff4c4e9ea9.png),就比如 RNNG 就是一個生成模型,但是缺少句法樹 z 的監督信号怎麼辦呢?現在給你的輸入隻有句子 x,那麼隻能用語言模型![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0018247697.png)來做監督了。習慣上我們喜歡取對數,也就是: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0019a1a3ae.png) 這裡就存在幾個問題,比如 z 的狀态空間太大了,不可能窮舉所有的,是以接下來按步驟講解如何求解。 # URNNG模型 --- 先上一張模型圖,讓大家對整體模型有個大概的認知: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd001d48aec7.png) 左邊是一個推理網絡(Inference Network),用來根據輸入 x 推理出隐變量也就是句法樹 z 的機率分布![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0022261540.png)。右邊是一個生成模型(Generative Model),用來計算從推理網絡中采樣出來的句法樹 z 的聯合機率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0023ebd1a7.png),最後根據上面語言模型算出句子的機率,最大化這個機率即可。 接下來分别講解這兩個部分和具體的優化方法。 ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd002c44eea8.png) 首先将詞向量![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0031285a42.png)和位置向量![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00322db624.png)拼接,作為推理網絡 LSTM 的輸入: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0034a094fe.png) 然後算出![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0036de95e8.png)的得分,計算方式和以往一樣,用 BiLSTM 前後向輸出做差,然後通過一個前饋神經網絡得到分數: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0056fdb506.png) 接下來就需要計算句法樹的機率分布了,這裡不直接計算句法樹 z,而是計算它的鄰接矩陣 B 的機率分布,這個鄰接矩陣意思就是如果![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0059732fb2.png)存在,那麼![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd005b539800.png),否則的話![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd005ca68054.png)。然後就可以用 CRF 計算出鄰接矩陣 B 對應的機率: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd005f4dd93b.png) 其中![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0060b1878b.png)是配分函數,也就是用來将機率歸約到 0 到 1 之間的: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00620c7d27.png) 注意這裡的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0064462a9e.png)并不是所有的 01 矩陣集合,而是必須滿足能産生合法句法樹的矩陣,情況也很多,不能窮舉求解,在這裡采用經典的 inside 算法來求解這個配分函數: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00669436e2.jpg) 不過我覺得這裡是錯的!就是這裡的兩處![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd006c10dc7e.png)應該改成![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd006d1b4efd.png)。不過具體代碼實作的時候并沒有這麼做,初始值一樣都是![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd006e5cf5f9.png),但是遞推的時候采用了如下式子: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00703cf397.png) 其實就是用![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd007198598f.png)來取代![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00744ca553.png)了,化簡後就是代碼實作這個式子,應該是為了防止數值溢出。 然後就是采樣了,推理網絡的目的就是計算出句法樹的機率分布,然後根據這個分布采樣出若幹個句法樹,那麼現在給定一棵句法樹可以根據上面的算法計算出它的機率了,那怎麼采樣呢?其實還是可以通過剛剛計算得出的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0076183c1a.png)數組來采樣,采樣算法如下: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd008cad79c7.jpg) 其實就是自頂向下的根據機率分布來采樣每個 span 的 split,用一個隊列來儲存所有還沒有采樣出 split 的 span,然後把所有采樣出的 span 在鄰接矩陣中的對應值标為1。 最後推理網絡采樣出了若幹個句法樹 z,然後根據 CRF 計算出每個句法樹的機率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00937a3d16.png),後面的事情就交給生成網絡了。 ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0094a504bb.png) 上面的推理網絡采樣出了若幹個句法樹 z,生成網絡的目的就是計算它的聯合機率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd009d0b7269.png)。這個其實不難,在之前的 RNNG 論文筆記中,我已經大緻講過了,可以去複習一下:[Recurrent Neural Network Grammars](https://godweiyang.com/2018/09/02/RNNG/),這裡稍稍做了一些改進。 首先需要定義一個棧用來存放轉移的曆史狀态,這裡定義棧裡放的元素為二進制組(h, g),一個是 stack-LSTM 編碼的輸出,一個是子樹的結構表示。首先需要預測下一步的 action 是什麼,是以取出棧頂的元素![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00a0993c7a.png),預測 action 的時候隻要用到隐含層輸出: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00a2527fe7.png) 然後根據這個機率預測 action 是 SHIFT 還是 REDUCE,下面分兩種情況讨論。 如果是 SHIFT,那麼因為是生成模型,是以需要預測下一個移進的單詞是什麼: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00a9b68a11.png) 然後将單詞 x 的詞向量輸入到 stack-LSTM 中得到下一個時刻的隐含層輸出: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00acb80148.png) 最後将![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00adcd092c.png)推進棧裡。 如果是 REDUCE,那麼首先需要取出棧頂的兩個元素![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00b3f16ad7.png)和![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00b4d004fb.png),然後用 TreeLSTM 計算出兩個子結點合并後的子樹的表示: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00be43318f.png) 接着還是計算 stack-LSTM 下一個時刻的隐含層輸出: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00bfb2133e.png) 最後将![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00c0f3cf6c.png)推進棧裡。 為了防止數值溢出,正常上我們計算聯合機率的對數: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00c27f19cf.png) 從這個式子可以看出,聯合機率定義為所有給定某段單詞和 action 預測下一個單詞和給定某段單詞和 action 預測下一個 action 的機率之積。 如果是監督任務比如 RNNG,那麼隻需要最大化這個聯合機率就足夠了,但是現在要做無監督,沒有 z,注意别搞混了,推理網絡采樣出的 z 可不能用來監督哦,因為那本來就不是正确的,是以接下來要采用語言模型來作為最終的目标函數。 ## Variational Inference 句子 x 的對數機率定義為: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd00c637b136.png) 其中![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0192ac578b.png)是所有合法句法樹的集合,但是這裡不可能窮舉所有的句法樹,是以就要用到變分推理,具體的理論知識不仔細介紹了,可以去查閱變分推理相關知識,下面直接推導。 ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0194ced2d8.png) 其中最後一行叫做先驗![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd019b000b7e.png)的證據下界(ELBO),要想最大化先驗,可以最大化這個 ELBO,如果我們對這個 ELBO 變化一下形式可以得到: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd019dd14ef4.png) 是以這個 ELBO 和先驗就相差了一個 KL 散度,最大化 ELBO 的話等價于最小化 KL 散度,也就是使推理網絡産生句法樹的機率分布和生成模型盡量接近。 但是這個 ELBO 還是不好算,盡管它把![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a6b14e49.png)移到了求和符号也就是期望裡面,是以轉換一下形式: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a586f2ef.png) 因為模型一共有兩組參數,一個是推理網絡的參數![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a8852ffc.png),一個是生成網絡的參數![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01a96dfd87.png),是以下面分别對兩個參數求導。 首先對![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01aac8c546.png)求偏導,因為隻有第一項有這個參數,是以偏導為: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01abef116c.png) 這個偏導可以按照機率![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01ad0d3953.png)采樣得到: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01afc11128.png) 然後對![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01b1a34d63.png)求偏導,因為有兩項含有這個參數,分别求偏導。第二項是熵,它的值其實可以用之前的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01b2fa2a6b.png)數組算出來,算法如下: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01b4d4da00.jpg) 然後偏導可以交給深度學習庫的自動微分,就不用你自己求啦。 至于第一項的偏導可以用類似于政策梯度的方法解決: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bac0deb4.png) 這裡最後也是轉化為了采樣,和政策梯度做法類似,這裡加入 baseline 來提升性能: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bc65131a.png) 其中![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bd90b591.png)定義為所有其他的對數聯合機率的均值: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01bec80a30.png) 至此所有偏導都已求出來了,兩個通過采樣得到,一個通過 inside 算法結果自動微分得到,是以去掉導數符号并相加就得到了最終的損失函數: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c03b63c7.png) 一定要注意,這裡的![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd0290b4e43e.png)在代碼實作的時候不能傳入梯度,不然的話對![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c2b70fc5.png)的偏導就會多出這一項的偏導了! # 實驗 --- 實驗結果這裡就不多說了,細節具體看論文吧,就貼兩個結果,一個是語言模型: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c41e1884.jpg) 可以看出在标準的 PTB 資料集上,URNNG 效果隻比監督學習的 RNNG 和用 URNNG 損失函數微調後的 RNNG 效果略差一點,但是在大資料集上,URNNG 的優勢就展現出來了。 另一個是無監督成分句法分析,這裡是用的全部長度的測試集: ![](https://static.leiphone.com/uploads/new/article/740_740/201905/5cd01c6670faa.jpg) 這個任務上 URNNG 效果是最好的。 # 結論 --- 和之前兩篇語言模型做無監督成分句法分析類似,這篇論文用推理網絡學習句法樹的機率分布并采樣句法樹,再用生成網絡計算這些句法樹和句子的聯合機率,最後用變分推理最大化句子的機率,也就是學習出一個好的語言模型。 雷鋒網 (公衆号:雷鋒網)

雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。

繼續閱讀