GloVe:另一種Word Embedding方法


若想深層地理解GloVe和本文,最好了解SVD, word2vec(skip-gram為主)的相關知識。
若僅尋求一種新的word embedding方法,可以不必了解以上前置知識。


一言以蔽之,GloVe的思想就是借鑒word2vec的pair-wise的方法以及其他一些trick來進行傳統矩陣分解運算進而得到word vectors。

GloVe(Global Vectors for Word Representation)是斯坦福大學發表的一種word embedding 方法,GloVe: Global Vectors for Word Representation,它看起來很new,其實有着old school的內核。GloVe嘗試借鑒NNLM和word2vec的優勢來彌補舊方法的劣勢,取得了不錯的效果。該文發表於word2vec之后,其方法內核比較朴實和簡單,實現也頗有粗暴之處。官方實驗中,GloVe是略勝w2v一籌的,至於實際應用如何,還是建議再進行試驗,或者作為一種算法補充。

個人實驗中,GloVe是略遜於w2v的,不過一來是肉眼debug,二來場景並不是十分典型的NLP場景,故見仁見智,仍然建議再做實驗再來定奪。

Word Representation 歷史

自然語言處理(Natural Language Processing),曾經也叫做“Computational linguistics”。從名字就能看出,核心就在於讓language變得computational,在可以計算的前提下,一切計算機/數學方法才得以使用。

這就是word representation的出發點,將language/paragraph/sentence/word/character 用數學形式來表示。目前通常采用的representation形式是向量形式。

簡單梳理一下word representation的歷史,了解各方法的背景和之間聯系,有助於對word embedding有更好的理解,以及更好地理解GloVe。

Non-distributed Representation

One-hot Encoding

最簡單的編碼方式當然是one hot 形式,每個詞獨占一個維度,每個詞向量 有一個維度是1,其他為0,詞向量的維度是vocabulary的長度。
如句子'a dog is not a cat'中,按照one hot encoding,有:

vocab = ('a', 'dog', 'is', 'not', 'cat') a = [1, 0, 0, 0, 0] dog = [0, 1, 0, 0, 0] is = [0, 0, 1, 0, 0] not = [0, 0, 0, 1, 0] cat = [0, 0, 0, 0, 1] 

One hot 編碼的特點是假設所有的word互相獨立,這是一個很強的假設,顯然在有些任務中並不合適,如詞語相似度方面,dogcat的相似度應當比dognot高,但是在one hot中,他們都是0。

One-hot的優缺點

One hot encoding的優點:

  • 至少讓word 有了一個向量表示,讓語言可以計算
  • one hot encoding 很稀疏,在一些對稀疏數據友好的問題(如部分分類問題)有比較不錯的效果

One hot encoding的缺點:

  • 假設太強,許多NLP task不適用
  • 對大詞庫的language建模,向量維度太大,難以儲存
  • 無法加入新詞

在One hot encoding的缺點中,無法加入新詞的原因是,一個維度只表達一個word的信息,一個word的信息也只由一個維度表達,滿足這個映射特性的word representation叫做Non-distributed Representation, 也叫做Localist Representation。

Distributed Representation

與Non-distributed Representation相對地,有Distributed Representation的概念。Distributed Representation的意思是,描述language的向量是定長的(fix-length),在定長的向量中,一個語義信息可能由多個維度共同決定,一個維度也可能決定着多方面的語義信息。此時,word vector就比較稠密(dense),不再像one-hot encoding一樣稀疏。

在這種表示方法下,word vector可以大大縮短向量長度,因此,通常得到Distributed Representation的word vectors的方法也叫做word embedding方法(直譯即詞嵌入,將word的語義信息嵌入fix-length的向量中)。

矩陣分解方法

以下內容需要線性代數和矩陣分解的相關知識
對推薦系統的矩陣分解算法有了解會更有利於理解這部分內容

Word都出現在document中,應用bag-of-words[5]或者sliding window,可以得到cooccurence matrix,如:
對於如下的三句話的語料:

  1. I enjoy flying.
  2. I like NLP.
  3. I like deep learning.

有 共現矩陣:

對該共現矩陣進行SVD分解[6][7][8]來降維。
SVD是一個常見的矩陣分解算法,其基本原理如下:

Datamn=UmmSmnRnnDatam∗n=Um∗m∗Sm∗n∗Rn∗n


奇異值類似主成分,在實際應用中,往往取top k個奇異值就能夠表示絕大部分信息量,因此SVD經常拿來做損失較小的有損壓縮:

Datamn=UmkSkkRknDatam∗n=Um∗k∗Sk∗k∗Rk∗n


SVD的幾何意義實際上是通過線性變換來找到最能表達矩陣信息的一組正交基,原1*n維詞向量在取得top k 奇異值后,可以用1*k維向量來表示該word,進而實現word embedding的效果。

 

如果想更深入理解SVD,推薦[6][7][8]三篇文章

用代碼來實際跑一下:

import numpy as np import matplotlib.pyplot as plt la = np.linalg words = ["I","like","enjoy","deep","learning","NLP","flying","."] X=np.array([[0,2,1,0,0,0,0,0], [2,0,0,1,0,1,0,0], [1,0,0,0,0,0,1,0], [0,1,0,0,1,0,0,0], [0,0,0,1,0,0,0,1], [0,1,0,0,0,0,0,1], [0,0,1,0,0,0,0,1], [0,0,0,0,1,1,1,0]]) U,s,Vh=la.svd(X,full_matrices=False) plt.axis([-0.8,0.2,-0.8,0.8]) for i in xrange(len(words)): plt.text(U[i,0],U[i,1],words[i]) plt.show() 

結果如圖下,可以看到,對三個句子的語料,已經有一點點語義距離的關系在里面了,比如enjoy和like在方向上是一致的,兩個動詞距離比較接近等等。

矩陣分解的優缺點

矩陣分解方法的優點是:

  • 訓練速度很快
  • 能夠實現word embedding

其缺點也很明顯:

  • 因為僅關注cooccurence,word vector包含的詞向量語義信息有限,僅僅能進行詞語相似度計算等有限的任務。

NNLM 以及 word2vec

於是發展到了用language model來搞事情的時代。
word vectors是LM的副產品,本來LM是用來做language modeling的。
這個方法出奇的好,因為lm相當於做了sentence粒度的modeling,對詞語在語義空間上的建模更充分。
更多的話題不詳細展開了,也不是本文重點,注意nnlm和word2vec的幾個關鍵:

  • 求解max log likelihood作為object func
  • pair-wise應用SGD的求解過程

他們的好處是:

  • 有了更多語言學層面的支撐,在更多NLP task上表現更好
  • pair-wise的求解對計算資源很友好

但是,也有一些缺點:

  • context 很小,沒有使用全局的cooccur,所以實際上對cooccur的利用很少

GloVe

GloVe發明的初衷,就是想結合兩者的長處,搞出一個充分利用統計量的更好train的適用程度更廣的word embedding方法。

動機

我們注意到,在篇章中,語義距離相近的詞,共現次數多,語義距離遠的詞貢獻次數少。見圖下:

然而可以看到的是,區分度不算高。於是想到,能否用共現之間的比值來增大區分度?
對於wordi,wordj,wordkwordi,wordj,wordk,應當有:

  • 如果ij很相關,ik不相關,那么P(j|i)/P(k|i)P(j|i)/P(k|i)應當很大
  • 如果ij很相關,ik也不相關,那么P(j|i)/P(k|i)P(j|i)/P(k|i)應當趨近於1

對應圖上的數據,可以看到區分度已經好很多。

這就是GloVe的動機,對word-pair cooccur進行建模,擬合不同word-pair的cooccur之間的差異。

模型推導

根據GloVe的思想,我們關注:

F(wi,wj,w~k)=PijPjkF(wi,wj,w~k)=PijPjk

 

其中,取wordiwordi的出現次數為XiXi, 定義Pij=P(j|i)=Xij/XiPij=P(j|i)=Xij/Xi表示在XiXi的context下wordjwordj的出現幾率, F則是某一種能夠實現我們需求的變換。
wi,wjwi,wj是實數空間下的wordi,wordjwordi,wordj的word vector,wk˜wk~也是實數空間下的wordkwordk的context word vector,其作用類似word2vec中的context vector。

在word2vec中,context vector最終被舍棄,但是由於GloVe的context只有一個word,所以這個context word vector也是一個word vector的,更加有趣的是,后面可以看到,在GloVe中,公式是完全對稱的,所以兩個word vector理論上擁有同樣的表示能力,是同一個語義空間下的word representation。

因為一個好的word vector應當是線性可加減的,因此對於word之間的差異,可以用減法來進行衡量,可以拍腦門一個公式,將FF對向量的約束縮小為FF對向量差的約束,這樣易於計算,也比較解釋得通:

F(wiwj,w~k)=PijPjkF(wi−wj,w~k)=PijPjk


現在,參數變少了。又,我們目前關注的是很單純很美的線性關系,而word vector通常都很多維度,每個維度照理來講,是有其語義含義的,像NN那樣上百維的向量進行非線性變換,讓維度和維度之間進行運算,會丟掉這種單純的關系在模型中的作用,因此GloVe 拍腦門一個公式,不妨讓兩個向量點乘一下,在公式中就約束住維度的“純正血統”,避免維度之間不必要的計算:

F((wiwj)Tw~k)=PijPjkF((wi−wj)Tw~k)=PijPjk


這樣就避免了長向量的復雜運算丟掉模型初心的問題。

 

回到問題本身,我們是基於cooccur進行計算,實際上在一次共現中wordi,wordjwordi,wordj是同等地位的,那么對於一個合適的FF,更換word pair單詞的順序理應不影響輸出結果,換言之,FF應當是對稱的,一個合適的FF應當滿足 F(wi,wj)==F(wj,wi)F(wi,wj)==F(wj,wi),當然現在的公式還不滿足這一點,GloVe想了辦法讓公式變得符合預期。

首先,想要公式能夠對稱,先讓其擁有結構不變性,可以給未知的FF一個新的約束,使FF是一個同態變換:

F((wiwj)Tw~k)=F(wTiw~k)F(wTjw~k)F((wi−wj)Tw~k)=F(wiTw~k)F(wjTw~k)

 

選擇除法有幾個原因,一個是這樣的同態變換好找(exp就是這樣一個變換),二是和(5)式在形式和參數上都能完美符合.

(5)式和(6)式相對應的,有:

F(wTiw~k)=Pik=XikXiF(wiTw~k)=Pik=XikXi


對於(6)式,我們很容易想到exp就是這樣一個符合要求的變換:

F=expwTiw~k=log(Pik)=log(Xik)log(Xi)F=expwiTw~k=log(Pik)=log(Xik)−log(Xi)


我們將log(Xi)log(Xi)移到等式左邊,它是wordiwordi的出現次數,是一個常量,和wordkwordk無關,因此可以歸入wiwi的biasbibi中,為了保持公式的對稱性,再加入wkwk的biasbkbk,公式變成:

wTiw~k+bi+b~k=log(Xik)wiTw~k+bi+b~k=log(Xik)


這個公式呢,就是我們從(3)式的初心出發,推導出的一個具有比較漂亮的對稱形式的公式,式左是我們對word vector的運算,式右是一個共現常量。看起來非常棒,其形式跟LSE也有相似之處,不過不展開了。

 

很容易得到Object function,一個典型的square loss:

J=i,j=1V(wTiw~j+bi+b~jlog(Xij))2J=∑i,j=1V(wiTw~j+bi+b~j−log(Xij))2

 

當然此時還有問題,共現矩陣是很稀疏的,大部分共現都是0,需要合理的loss加權,對共現多的詞給予更高關注,GloVe給了一個weighted square loss:

J=i,j=1Vf(Xij)(wTiw~j+bi+b~jlog(Xij))2J=∑i,j=1Vf(Xij)(wiTw~j+bi+b~j−log(Xij))2


加權函數 ff為:

f(x)={(x/xmax)αifx<xmax,1otherwisef(x)={(x/xmax)αifx<xmax,1otherwise


其圖像如圖:

 

意思是,在共現超過閾值后,其loss的權重維持在1.0的不變水平。當然,這也橫生了兩個超參:xmaxxmax 和 αα GloVe給的參考值分別為xmax=100,α=0.75xmax=100,α=0.75。

至此,GloVe推導完畢。過程到處充滿了蠻橫無理,最終形式倒出奇的還蠻好看。

兩個詞向量

上面說到,GloVe每個詞涉及到兩個詞向量,一個詞語本身的向量wiwi,一個詞的context向量w~iw~i。最初這樣設計,將word和context的向量分開,不用一套,是為了在更新參數的時候能夠簡單地套用SGD。
但是呢,我們可以看到,公式本身是對稱的,context和word其實並沒有什么區別。
那么兩個向量應該是一樣語義空間中的差不多的詞向量,context word vector這個副產品自然不能落下,GloVe經過一番試驗,最終發現,兩個向量加起來最后起到的效果最好。

“這樣損失了一些模型的可解釋性,但是模型表現更好了”,助教在該校CS224N 2017 winter課程中如是說。

十分暴力,但無法反駁。

GloVe 和 其他模型的關系

當看到GloVe拍腦門找到loglog函數的時候,就覺得和word2vec中應用language model有幾分類似。
其實確有千絲萬縷的聯系的,推一推,會發現兩者的相似性,不過我寫到這里懶得寫了,更多的細節有興趣可以自己琢磨下。

GloVe 使用

GloVe已經在github開源,源碼以及binary可以在GloVe Github找到。
GloVe的代碼寫的比較糙,每一步是獨立的程序,因此要按照以下步驟進行:

  1. 運行./vocab_count 進行詞頻統計
  2. 運行./cooccur 進行共現統計
  3. 運行./shuffle 進行打散
  4. 運行./glove 進行訓練詞向量

具體參數和word2vec比較類似,具體用法可以見
https://github.com/stanfordnlp/GloVe/blob/master/demo.sh

Reference

[1] (Paper) GloVe: Global Vectors for Word Representation
[2] CS224N Lecture 3 | GloVe: Global Vectors for Word Representation
[3] GloVe Github
[4] word co-occurrence and theory of meaning
[5] Bag-of-words_model
[6] 奇異值分解(SVD)原理詳解及推導
[7] 強大的矩陣奇異值分解(SVD)及其應用
[8] We Recommend a Singular Value Decomposition

費盡心思寫了一個自己不那么喜歡的模型感覺有些奇怪,不過這是一篇很勵志的paper和算法,它告訴我兩個道理:
1. 發吊文章不一定需要特別吊的算法,也可以在老算法上改進一下,沒准就很厲害
2. 斯坦福的厲害人物偶爾也會划划水
當然GloVe本身很厲害,只是寫完了文章,調侃一下。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM