準備將NLP知識系統化,所以會寫一個系列文章:NLP綜述。內容會涵蓋NLP的各個部分,各個部分有粗有細。

本文是本系列第一篇,總結靜態詞向量發展的歷史,包括基於SVD的方法,word2vec,Glove以及subword-units對詞向量的補充。

首先為什麼要做詞向量,其實這個問題可以換個問法"為什麼要做embedding"?原因有三:

  • 抽象的事物應該有一個低維的表示。比如我們看到一張含有一張小狗的圖片,它底層的表示就是像素值。同樣的我們看到"dog」這個單詞時,它也應該有更低維的表示。
  • 計算機和神經網路善於處理低緯度信息。
  • 解決one-hot編碼問題。one-hot編碼是一 種特殊的高維到低維的映射,具有稀疏性,且向量長度較長並隨著樣本集變化而變化。one-hot編碼是一種」討巧」的編碼方式,一般無法表示兩個實體之間的相關性,embedding可以一定程度上解決這些問題。

說白了,任何embedding的終極目標都是在尋找一個長度固定的向量,它可以表示一個實體的「本質」。接下來篇幅會根據詞向量發展的歷史寫。

詞向量分為靜態詞向量和動態(上下文)詞向量,靜態詞向量指的是一個單詞不管上下文如何變化只有一個唯一的詞向量表示,所以它最大的缺點是無法表達多意性,動態詞向量指的會根據上下文動態適應性的調整詞向量,可以一定程度上解決單詞多意性。

一般而言,動態詞向量會歸類為預訓練模型,例如elmo,bert模型。但是其實嚴格來說,不管靜態還是動態詞向量本身都是一種預訓練的思想, 即第一階段訓練詞向量,第二階段根據使用預訓練的詞向量並根據需要是否進行fine-tuning。但是為了突出預訓練的重要性,我們這裡也只單獨說靜態詞向量,後面有文章專門說基於預訓練的動態詞向量。這裡說這麼一段廢話是希望讀者能意識到這兩塊內容是有深刻的歷史沿革的。


1. 基於矩陣分解的方法

這種方法的基本思想是通過大量的數據統計到詞的累計共現矩陣X,然後對X進行奇異值分解得到?,U的每一列對應一個詞的向量表示,SVD更多信息參考這裡。

共現矩陣一般分為詞-文檔共現矩陣和詞-詞共現矩陣。

詞-文檔共現矩陣

這種共現矩陣的思想認為相關的詞會出現在同一個文檔中。假設詞表大小為?,文檔數 量為?,那麼詞-文檔共現矩陣規模為?,矩陣元素?表示詞i在文 檔j中的出現次數,只要對所有文檔循環一次就可以統計得到該矩陣

詞-詞共現矩陣

詞-詞共現矩陣的思想是詞i的窗口內出現了j,那麼認為i和j的共現次數加一,?表 示兩個詞的共現次數,X是一個?的方陣。窗口一般是對稱的,長度一般為 5-10。

這種基於共現矩陣進行SVD分解的方法存在問題:

  • 矩陣的維度經常發生變化(新詞和新文檔的加入)
  • 矩陣非常稀疏
  • 矩陣過大
  • SVD分解的計算複雜度大,對於n×m的矩陣進行分解的複雜度為?
  • 需要對X矩陣進行一些修正來修複詞頻分佈不均勻問題
  • 無法適應一詞多義(靜態詞向量的痛點)

對X矩陣的一些修正:

  • 功能詞(the, he, has)過於頻繁,對語法有很大影響,解決辦法是降低使用或完全忽略功能詞
  • 採用帶權重的窗口,距離當前詞距離越近共現權重越大
  • 用皮爾遜相關係數代替計數,並置負數為0

那能否不構造這種共現矩陣,就可以學習詞向量呢?這就是迭代的方法——2013年橫空出世的word2vec。


2.word2vec

如果要評出nlp最重要的里程碑,word2vec絕對是一個candidate。

word2vec來源於2013年的論文《Efficient Estimation of Word Representation in Vector Space》,它的核心思想是通過詞的上下文得到詞的向量化表示,有兩種方法:CBOW(通過附近詞預測中心詞)、Skip-gram(通過中心詞預測附近的詞)。

word2vec部分有太多的資料了,這裡推薦word2vec的數學原理詳解,多看兩遍,否則容易陷入繁亂的數學推導中。

word2vec的優點是克服了基於矩陣分解的部分問題:

  • 語料庫可以動態的變化,可以在線學習
  • 不需要進行矩陣分解這種重量級的運算

缺點:

  • 每次更新只使用少語料上下文信息,缺少全局上下文的大局觀。
  • 無法適應一詞多義(靜態詞向量的痛點)

3. Glove

基於SVD的方法使用的是全局共現信息,能有效地利用統計信息, 但在 word analogy 任務上效果相對較差, 這意味著其向量空間結構並非最優;而word2vec使用的是局部共現信息,在 word analogy 任務上效果好, 但利用語料的統計信息的能力較差, 因為它基於分離的局部上下文進行訓練, 而非全局的 co-occurrence 統計。

而Glove(Global Vectors for Word Representation)融合了兩者的優點,利用詞共現矩陣充分利用了統計信息,高效地對語義進行編碼。先定義符號:

  • X ?:詞共現矩陣
  • ? X_{ij} :在整個語料庫中,單詞i和單詞j共同出現在一個窗口中的次數
  • ? X_i =sum_kX_{ik} :所有單詞在單詞 i的上下文中出現的次數
  • ? P_{ij} = P(j|i) = frac {X_{ij}} {X_i} :單詞 j 在單詞i的上下文中出現的概率。

作者的基本思路是這樣的:比如word i = ice,word j = steam,考慮如下情況:

  • 對於與ice相關而與steam不相關的詞,例如solid,我們期望共現概率比值? P(solid | ice) / P(solid | steam) 較大;
  • 對於與ice不相關而與steam相關的詞,例如gas,我們期望共現概率比值? P(gas| ice) / P(gas | steam) 較小;
  • 對於與ice和steam都相關的詞,例如water,我們期望共現概率比值 P(water| ice) / P(water| steam) ?接近1;
  • 對於與ice和steam都不相關的詞,例如fashion,我們期望共現概率比值 P(fashion| ice) / P(fashion| steam) ?接近1。

下圖是在一個60億單詞語料庫中的統計:

可以看出作者的假設(先驗)還是很正確的。然後我們看下作者的建模過程。

F(v_i, v_j,v_k) =frac {P_{i,k}} {P_{j,k}}

? v_i, v_j.v_k 分別表示i,j,k的詞向量。左側是模型給的值, 右側是經驗值。不妨對右側F進行猜測:

F(v_i, v_j,v_k) = frac {f(v_i, v_k)} {f(v_j, v_k)} = frac {P_{i,k}} {P_{j,k}}

現在可以讓分子分母對應相等即可,即? f(v_i, v_j) = P_{i,j} ,由於? P_{i,j} > 0 恆成立,所以不妨讓? f(v_i, v_j) = exp(v_i^T * v_j)

但是我們注意到,P矩陣不是對稱的,即 P_{i,j} 
e P_{k,j} ?,但是 exp(v_i^T * v_j) = exp(v_j ^T* v_i) ?,所以我們再想想辦法...

由於 P_{i,j} = frac {X_{ij}} {X_i}  = exp(v_i^T*v_j) ?,變換如下:

log(X_{ij}) - log(X_i) = exp(v_i^T*v_j)\

上式變為如下形式

log(X_{ij}) = exp(v_i^T*v_j) + b_i + b_j

其中? b_i = log(X_i) , 為了對稱為其也加入關於word j的偏置。

loss函數就呼之欲出了

J = sum_{i,j}^{N}(v_i^T*v_j + b_i + b_j - log(X_{ij}))^2

然後基於出現頻率越高的詞對兒權重應該越大的原則,在代價函數中添加權重項,於是代價函數進一步完善:

J = sum_{i,j}^{N}f(X_{ij})(v_i^T*v_j + b_i + b_j - log(X_{ij}))^2

具體權重函數應該是怎麼樣的呢? 首先應該是非減的,其次當詞頻過高時,權重不應過分增大,作者通過實驗確定權重函數為:

\f(x) = left{ egin{aligned} & (x / x_{max})^{0.75} , & if space x < x_{max}\  & 1, & if space x ge x_{max} end{aligned} 
ight.

Glove優點是綜合了LSA和word2vec的優點,它的缺點主要是無法解決一詞多義,這個缺點將在動態詞向量中解決,先按下不表。


4.subword-units

上面說的詞向量一般來說都是對於word級別的,但是自然語言是在不斷發展變化的,特別是各種網路詞,那麼以word為原子單位進行embedding勢必會有OOV(out of vocabulary)問題,subword可以在一定程度上緩解該問題。

關於OOV問題,可以參考這篇文章:zhuanlan.zhihu.com/p/22

subwords其實就是一個詞的character-level的n-gram。比如單詞」hello」,長度至少為3的char-level的ngram有」hel」,」ell」,」llo」,」hell」,」ello」以及本身」hello」。每個ngram都可以用一個dense的向量?表示,這樣可以豐富辭彙表,當遇到rare word的時候可以使用subword給出它的詞向量。這其實就是fasttext訓練詞向量的方法,當然fasttext還是一個高效的文本模型,這裡不再做介紹。

還有一種獲得subword-unit的方法——BPE(Byte Pair Encoding)演算法。演算法也很簡單,步驟如下:

  1. 初始化符號詞表。用所有的字元加入到符號詞表中
  2. 迭代對所有符號進行計數,找出次數最多的(A, B),用AB代替。
  3. 上述步驟執行M次。

這種演算法獲得的subword是具有解釋性的,比如#ing可能會作為一個有意義的subword-unit,它表示一種進行時的時態。

但是需要說明的是,這種方法對於英文好用,但是對於中文要謹慎使用。

比方說」english-born」和」china-born」,從單詞層面上看,是兩個不同的單詞,但是如果用char-level的ngram來表示,都有相同的後綴」born」。因此這種表示方法可以學習到當兩個詞有相同的詞綴時,其語義也具有一定的相似性。這種方法對英語等西語來說可能是奏效的,因為英語中很多相同前綴和後綴的單詞,語義上確實有所相近。但對於中文來說,這種方法可能會有些問題。比如說,」原來」和」原則」,雖有相同前綴,但意義相去甚遠。可能對中文來說,按照偏旁部首等字形的方式拆解可能會更有意義一些。


推薦閱讀:
相關文章