1. 程式人生 > >Word2Vec模型之訓練篇

Word2Vec模型之訓練篇

第一部分我們瞭解skip-gram的輸入層、隱層、輸出層。在第二部分,會繼續深入講如何在skip-gram模型上進行高效的訓練。

在第一部分講解完成後,我們會發現Word2Vec模型是一個超級大的神經網路(權重矩陣規模非常大)。

舉個栗子,我們擁有10000個單詞的詞彙表,我們如果想嵌入300維的詞向量,那麼我們的輸入-隱層權重矩陣隱層-輸出層的權重矩陣都會有 10000 x 300 = 300萬個權重,在如此龐大的神經網路中進行梯度下降是相當慢的。更糟糕的是,你需要大量的訓練資料來調整這些權重並且避免過擬合。百萬數量級的權重矩陣和億萬數量級的訓練樣本意味著訓練這個模型將會是個災難(太凶殘了)。

Word2Vec 的作者在它的第二篇論文中強調了這些問題,下面是作者在第二篇論文中的三個創新:

1. 將常見的單詞組合(word pairs)或者片語作為單個“words”來處理。

2. 對高頻次單詞進行抽樣來減少訓練樣本的個數。

3. 對優化目標採用“negative sampling”方法,這樣每個訓練樣本的訓練只會更新一小部分的模型權重,從而降低計算負擔。

事實證明,對常用詞抽樣並且對優化目標採用“negative sampling”不僅降低了訓練過程中的計算負擔,還提高了訓練的詞向量的質量。

Word pairs and "phases"

論文的作者指出,一些單詞組合(或者片語)的含義和拆開以後具有完全不同的意義。比如“Boston Globe”是一種報刊的名字,而單獨的“Boston”和“Globe”這樣單個的單詞卻表達不出這樣的含義。因此,在文章中只要出現“Boston Globe”,我們就應該把它作為一個單獨的詞來生成其詞向量,而不是將其拆開。同樣的例子還有“New York”,“United Stated”等。

在Google釋出的模型中,它本身的訓練樣本中有來自Google News資料集中的1000億的單詞,但是除了單個單詞以外,單詞組合(或片語)又有3百萬之多。

如果你對模型的詞彙表感興趣,可以點選:

你還可以直接瀏覽這個詞彙表:

如果想了解這個模型如何進行文件中的片語抽取,可以看論文中“Learning Phrases”這一章,對應的程式碼在 word2phrase.c ,相關連結如下。

對高頻詞抽樣

在第一部分的講解中,我們展示了訓練樣本是如何從原始文件中生成出來的,這裡我再重複一次。我們的原始文字為“The quick brown fox jumps over the laze dog”,如果我使用大小為2的視窗,那麼我們可以得到圖中展示的那些訓練樣本。

一文詳解 Word2vec 之 Skip-Gram 模型(訓練篇)

但是對於“the”這種常用高頻單詞,這樣的處理方式會存在下面兩個問題:

  1. 當我們得到成對的單詞訓練樣本時,("fox", "the") 這樣的訓練樣本並不會給我們提供關於“fox”更多的語義資訊,因為“the”在每個單詞的上下文中幾乎都會出現。

  2. 由於在文字中“the”這樣的常用詞出現概率很大,因此我們將會有大量的(”the“,...)這樣的訓練樣本,而這些樣本數量遠遠超過了我們學習“the”這個詞向量所需的訓練樣本數。

Word2Vec通過“抽樣”模式來解決這種高頻詞問題。它的基本思想如下:對於我們在訓練原始文字中遇到的每一個單詞,它們都有一定概率被我們從文字中刪掉,而這個被刪除的概率與單詞的頻率有關。
如果我們設定視窗大小(即),並且從我們的文字中刪除所有的“the”,那麼會有下面的結果:

1. 由於我們刪除了文字中所有的“the”,那麼在我們的訓練樣本中,“the”這個詞永遠也不會出現在我們的上下文視窗中。

2. 當“the”作為input word時,我們的訓練樣本數至少會減少10個。

這句話應該這麼理解,假如我們的文字中僅出現了一個“the”,那麼當這個“the”作為input word時,我們設定span=10,此時會得到10個訓練樣本 ("the", ...) ,如果刪掉這個“the”,我們就會減少10個訓練樣本。實際中我們的文字中不止一個“the”,因此當“the”作為input word的時候,至少會減少10個訓練樣本。

上面提到的這兩個影響結果實際上就幫助我們解決了高頻詞帶來的問題。

抽樣率

word2vec的C語言程式碼實現了一個計算在詞彙表中保留某個詞概率的公式。

ω是一個單詞,Z(ωi) 是 ωi 這個單詞在所有語料中出現的頻次。舉個栗子,如果單詞“peanut”在10億規模大小的語料中出現了1000次,那麼 Z(peanut) = 1000/1000000000 = 1e - 6

在程式碼中還有一個引數叫“sample”,這個引數代表一個閾值,預設值為0.001(在gensim包中的Word2Vec類說明中,這個引數預設為0.001,文件中對這個引數的解釋為“ threshold for configuring which higher-frequency words are randomly downsampled”)。這個值越小意味著這個單詞被保留下來的概率越小(即有越大的概率被我們刪除)。

P(ωi) 代表著保留某個單詞的概率:

一文詳解 Word2vec 之 Skip-Gram 模型(訓練篇)

一文詳解 Word2vec 之 Skip-Gram 模型(訓練篇)

圖中x軸代表著 Z(ωi) ,即單詞 ωi 在語料中出現頻率,y軸代表某個單詞被保留的概率。對於一個龐大的語料來說,單個單詞的出現頻率不會很大,即使是常用詞,也不可能特別大。

從這個圖中,我們可以看到,隨著單詞出現頻率的增高,它被取樣保留的概率越來越小,我們還可以看到一些有趣的結論:

● 當 Z(ωi) <= 0.0026 時,P(ωi) = 1.0 。當單詞在語料中出現的頻率小於 0.0026 時,它是 100% 被保留的,這意味著只有那些在語料中出現頻率超過 0.26% 的單詞才會被取樣。

● 當時 Z(ωi) = 0.00746 時,P(ωi) = 0.5,意味著這一部分的單詞有 50% 的概率被保留。

● 當 Z(ωi) = 1.0 時,P(ωi) = 0.033,意味著這部分單詞以 3.3% 的概率被保留。

如果你去看那篇論文的話,你會發現作者在論文中對函式公式的定義和在C語言程式碼的實現上有一些差別,但我認為C語言程式碼的公式實現是更權威的一個版本。

負取樣(negative sampling)

訓練一個神經網路意味著要輸入訓練樣本並且不斷調整神經元的權重,從而不斷提高對目標的準確預測。每當神經網路經過一個訓練樣本的訓練,它的權重就會進行一次調整。

正如我們上面所討論的,vocabulary的大小決定了我們的Skip-Gram神經網路將會擁有大規模的權重矩陣,所有的這些權重需要通過我們數以億計的訓練樣本來進行調整,這是非常消耗計算資源的,並且實際中訓練起來會非常慢。

負取樣(negative sampling)解決了這個問題,它是用來提高訓練速度並且改善所得到詞向量的質量的一種方法。不同於原本每個訓練樣本更新所有的權重,負取樣每次讓一個訓練樣本僅僅更新一小部分的權重,這樣就會降低梯度下降過程中的計算量。

當我們用訓練樣本 ( input word: "fox",output word: "quick") 來訓練我們的神經網路時,“ fox”和“quick”都是經過one-hot編碼的。如果我們的vocabulary大小為10000時,在輸出層,我們期望對應“quick”單詞的那個神經元結點輸出1,其餘9999個都應該輸出0。在這裡,這9999個我們期望輸出為0的神經元結點所對應的單詞我們稱為“negative” word。

當使用負取樣時,我們將隨機選擇一小部分的negative words(比如選5個negative words)來更新對應的權重。我們也會對我們的“positive” word進行權重更新(在我們上面的例子中,這個單詞指的是”quick“)。

在論文中,作者指出指出對於小規模資料集,選擇5-20個negative words會比較好,對於大規模資料集可以僅選擇2-5個negative words。

回憶一下我們的隱層-輸出層擁有300 x 10000的權重矩陣。如果使用了負取樣的方法我們僅僅去更新我們的positive word-“quick”的和我們選擇的其他5個negative words的結點對應的權重,共計6個輸出神經元,相當於每次只更新 300 x 6 = 1800 個權重。對於3百萬的權重來說,相當於只計算了0.06%的權重,這樣計算效率就大幅度提高。

如何選擇negative words

我們使用“一元模型分佈(unigram distribution)”來選擇“negative words”。

要注意的一點是,一個單詞被選作negative sample的概率跟它出現的頻次有關,出現頻次越高的單詞越容易被選作negative words。

在word2vec的C語言實現中,你可以看到對於這個概率的實現公式。每個單詞被選為“negative words”的概率計算公式與其出現的頻次有關。

程式碼中的公式實現如下:

一文詳解 Word2vec 之 Skip-Gram 模型(訓練篇)

每個單詞被賦予一個權重,即 f(ωi), 它代表著單詞出現的頻次。

公式中開3/4的根號完全是基於經驗的,論文中提到這個公式的效果要比其它公式更加出色。你可以在google的搜尋欄中輸入“plot y = x^(3/4) and y = x”,然後看到這兩幅圖(如下圖),仔細觀察x在[0,1]區間內時y的取值,x^(3/4) 有一小段弧形,取值在 y = x 函式之上。

一文詳解 Word2vec 之 Skip-Gram 模型(訓練篇)

負取樣的C語言實現非常的有趣。unigram table有一個包含了一億個元素的陣列,這個陣列是由詞彙表中每個單詞的索引號填充的,並且這個陣列中有重複,也就是說有些單詞會出現多次。那麼每個單詞的索引在這個陣列中出現的次數該如何決定呢,有公式,也就是說計算出的負取樣概率*1億=單詞在表中出現的次數

有了這張表以後,每次去我們進行負取樣時,只需要在0-1億範圍內生成一個隨機數,然後選擇表中索引號為這個隨機數的那個單詞作為我們的negative word即可。一個單詞的負取樣概率越大,那麼它在這個表中出現的次數就越多,它被選中的概率就越大。

到目前為止,Word2Vec中的Skip-Gram模型就講完了,對於裡面具體的數學公式推導細節這裡並沒有深入。這篇文章只是對於實現細節上的一些思想進行了闡述。

其他資料