天天看點

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

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

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

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

1. 将常見的單詞組合(word pairs)或者詞組作為單個“words”來處理。 2. 對高頻次單詞進行抽樣來減少訓練樣本的個數。 3. 對優化目标采用“negative sampling”方法,這樣每個訓練樣本的訓練隻會更新一小部分的模型權重,進而降低計算負擔。

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

論文的作者指出,一些單詞組合(或者詞組)的含義和拆開以後具有完全不同的意義。比如“boston globe”是一種報刊的名字,而單獨的“boston”和“globe”這樣單個的單詞卻表達不出這樣的含義。是以,在文章中隻要出現“boston globe”,我們就應該把它作為一個單獨的詞來生成其詞向量,而不是将其拆開。同樣的例子還有“new york”,“united stated”等。

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

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

<a href="http://t.cn/rovde3h" target="_blank">http://t.cn/rovde3h</a>

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

<a href="http://t.cn/rovdszr" target="_blank">http://t.cn/rovdszr</a>

如果想了解這個模型如何進行文檔中的詞組抽取,可以看論文中“learning phrases”這一章,對應的代碼在 word2phrase.c ,相關連結如下。

論文連結: <a href="http://t.cn/rmct1c7" target="_blank">http://t.cn/rmct1c7</a>
代碼連結: <a href="http://t.cn/rmct1c7" target="_blank">http://t.cn/r5auflz</a>

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

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

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

當我們得到成對的單詞訓練樣本時,("fox", "the") 這樣的訓練樣本并不會給我們提供關于“fox”更多的語義資訊,因為“the”在每個單詞的上下文中幾乎都會出現。 由于在文本中“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語言代碼實作了一個計算在詞彙表中保留某個詞機率的公式。

ωi 是一個單詞,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) &lt;= 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語言代碼的公式實作是更權威的一個版本。

訓練一個神經網絡意味着要輸入訓練樣本并且不斷調整神經元的權重,進而不斷提高對目标的準确預測。每當神經網絡經過一個訓練樣本的訓練,它的權重就會進行一次調整。

正如我們上面所讨論的,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%的權重,這樣計算效率就大幅度提高。

我們使用“一進制模型分布(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模型就講完了,對于裡面具體的數學公式推導細節這裡并沒有深入。這篇文章隻是對于實作細節上的一些思想進行了闡述。

如果想了解更多的實作細節,可以去檢視c語言的實作源碼: <a href="http://t.cn/r6w6vi7" target="_blank">http://t.cn/r6w6vi7</a>
其他word2vec教程請參考: <a href="http://t.cn/r6w6viz" target="_blank">http://t.cn/r6w6viz</a>

下一部分将會介紹如何用 tensorflow 實作一個 word2vec 中的 skip-gram 模型。

====================================分割線================================

本文作者:ai研習社

繼續閱讀