Language Model and Recurrent Neural Networks (一)

本文是我去年十月份在公司的團隊技術分享會里面分享過的內容,分享這個內容的初衷是我發現自己對RNN(本文均指Recurrent Neural Networks而非Recursive Neural Networks)比較陌生,想找個時間攻克一下,以便以後有此類工作需求可以快速上手。另外本文加入了CS224N關於語言模型和RNN的課堂內容。因此本文屬於科普性質的文章,基本上RNN的細節會涉及到,但並非每個細節都會深入去研究。
因爲篇幅較長,所以重新編輯了一下,把標題提到的兩部分分開了,本文是語言模型部分。


語言模型

語言模型的應用很常見,例如輸入法會自動計算你接下來可能要輸入的字或詞,搜索引擎會自動補全你可能要搜索的內容等等。所以一句話描述,語言模型就是一個用來預測接下來的詞的模型,可以描述爲P(x(t)x(t1),x(t2),...,x(0))P(x^{(t)}|x^{(t-1)},x^{(t-2)},...,x^{(0)})。這樣我們就可以根據這個概率來估計或者採樣出下面將要出現的詞。

1.基於統計的語言模型

傳統的語言模型是根據詞頻來預測的,那麼上面那個式可以寫成
P(x(t)x(t1),x(t2),...,x(0))=P(x(t),x(t1),x(t2),...,x(0))P(x(t1),x(t2),...,x(0)) P(x^{(t)}|x^{(t-1)},x^{(t-2)},...,x^{(0)})=\frac{P(x^{(t)},x^{(t-1)},x^{(t-2)},...,x^{(0)})}{P(x^{(t-1)},x^{(t-2)},...,x^{(0)})}

對於給定的一個語料庫,我們只需要統計一下出現次數就行
P(x(t)x(t1),x(t2),...,x(0))=count(x(t),x(t1),x(t2),...,x(0))count(x(t1),x(t2),...,x(0))P(x^{(t)}|x^{(t-1)},x^{(t-2)},...,x^{(0)}) = \frac{count(x^{(t)},x^{(t-1)},x^{(t-2)},...,x^{(0)})}{count(x^{(t-1)},x^{(t-2)},...,x^{(0)})}

但是文本序列越長,需要統計的序列也越長,計算量就越大,這顯然不合理的,於是聰明的人們就想,要不就簡化一下吧,假定後面出現的這個次只跟前面的k=n-1個詞有關就好了,於是乎,n-gram就出現了
P(x(t)x(t1),...,x(tn+1))P(x^{(t)}|x^{(t-1)},...,x^{(t-n+1)})

所以n=1時的語言模型就等於各個詞的出現頻率,n=2時的語言模型就是隻用前一個詞預測後一個詞的條件概率……

基於統計的方式去計算語言模型會有一些問題。假設我要計算的某個詞的概率P(x(t)P(x(t1)))P(x^{(t)}|P(x^{(t-1)})),但尷尬的是我語料庫裏面[x(t1),x(t)][x^{(t-1)},x^{(t)}]這個組合從來沒出現過,那計算這個語言模型的時候概率就爲0咯?

這顯然是不科學的,不能因爲沒見過這個詞組而說它的條件概率就爲0,於是人們想到可以對它進行一些平滑操作。至於詳細的平滑操作到底有哪些,咱就不深入討論了,方法有很多,也各有利弊,可以理解成最簡單的辦法就是把所有出現的可能性都加上一個固定的很小的常數,那麼就可以把未出現過的變成一個小概率。

平滑操作雖然可以避免分子或分母爲0時帶來的問題,但它根本上並沒有辦法解決統計上n-gram的稀疏性問題。即便語料庫再大,也總有不出現的配對,而且n越大就越稀疏,存儲空間的需求也是越大,搜索起來就越慢。

2.基於固定滑動窗口的語言模型

上面我們一直討論的是語言模型是用詞頻來計算的,但如果這個P(y|x)是個神經網絡,那上面提到的困難就迎刃而解了。

與n-gram一樣,我們假設輸入是前面n-1個詞,那麼我們就可以通過一個神經網絡,以這n-1個詞的詞向量作爲輸入,輸出下一個詞的概率,假設這裏我們n=5:

圖一 使用滑動窗口的語言模型

這個過程乍一看跟CBOW算法很像,但CBOW預測的是中間詞,這裏預測的是下一個詞。還有個細節是CBOW的輸入層到隱藏層之間的權值其實是詞向量,這個過程除了詞向量之外是沒有額外權值的,但這裏圖中藍色那層已經是詞嵌入向量e,這裏到隱藏層h之間還有一個權值矩陣W。更多詳細細節就不繼續討論了,關於CBOW的詳細描述請戳這裏

然而,固定滑動窗口這個辦法也有些問題。首先,窗口大小我們不好取,取小了,距離較遠的詞不能加入計算,哪怕它們相互之間是有關係的;取大了,模型參數的shape也會變大,計算量也就越大了。其次,每個詞的處理是與位置有關的,也就是e(1)e^{(1)}~e(4)e^{(4)}它們是各自與一個權重相乘,而非權值共享的。最後,也就是它最天然的問題了,窗口是固定的,窗口以外的詞就沒辦法加入訓練,這個模型是沒有記憶的

CS224n課堂上提出第二點的這個問題,我個人其實認爲並不是很嚴重的問題,不同的詞序確實是會導致產生不同的上下文環境,所以權值共享是不是十分必要,我個人持保留意見,只不過這個順序關係是基於權值來確定那就確實過分生硬了。

3.基於循環神經網絡的語言模型

用RNN來建立語言模型可以比較好的解決上面提到的問題,因爲RNN的循環結構使得語言模型可以以任意的長度作爲輸入而不會引起模型參數的增加,而且RNN在每次計算的時候會使用當期的input以及上期的output統一作爲輸入,這樣可以使得模型具備一定的“記憶”能力。

圖二 使用RNN的語言模型

關於RNN的技術細節,我們接下來將詳細討論。

4.語言模型的採樣過程

在inference過程,我們可能需要使用語言模型生成文本,這就涉及到採樣(sampling)。所謂採樣,就是根據模型輸出的各個詞概率分佈,抽取適當的詞作爲估計值。所謂“適當”,其實是可以根據實際情況選取適合的策略,例如可以採用貪心策略,即每一步都採取最大概率的預測詞作爲結果,又或者更爲靈活一點,按照概率分佈進行加權抽樣。更魯棒一點,可以採用Beam Search採樣出更好的結果。那麼怎麼樣的結果纔算好呢?

5.語言模型的性能評估

我們知道分類模型可以用精準率、召回率或者準確率之類的評估指標來衡量性能,迴歸模型可以則用MAE、MSE、SSE之類的指標。對語言模型而言,它本質上是一個分類模型,並且使用交叉熵作爲損失函數,但用準確率作爲語言模型的評估未免太過苛刻,畢竟自然語言是十分靈活的,同樣的意思可以有多種表述方式。這裏我們介紹使用困惑度(perplexity)作爲評估指標,CS224N課堂說這是語言模型的標準評估指標。
perplexity=t=1T(1PLM(x(t+1)x(t),...,x(1)))1T perplexity = \prod_{t=1}^{T}{(\frac{1}{P_{LM}{(x^{(t+1)}|x^{(t)},...,x^{(1)})}})^{\frac{1}{T}}}

細心的朋友可能會發現,如果我們對困惑度取對數,那麼就等於交叉熵。所以不難反推出,困惑度就是exp(交叉熵)。e爲底的指數函數是單調遞增的,那麼困惑度與交叉熵一樣,都是越數值越小越好。

參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章