我以前寫過一篇關(guān)于word2vec的文章,說實話,寫的一坨,我決定以后寫博客認(rèn)認(rèn)真真的去寫。
我的博客來自于網(wǎng)上各位前輩的資料的整理,這位這位和這位翻譯的讓我對word2vec有了深入的理解。word2vec有兩種模型,一個是skip-gram,一個是cbow。這兩個模型應(yīng)該是在一起講的。cbow是輸入詞向量求平均,二skip-gram輸入只有一個,不要求平均。首先說一點,cbow和skip-gram的目標(biāo)函數(shù),下圖是cbow的,skip-gram反過來而已


詞向量基礎(chǔ)
詞向量很早以前就有了。最早的詞向量成為one-hot representation,它使用的詞向量維度大小為整個詞匯表的大小,對于詞匯表中每個具體的詞,對應(yīng)位置置為1,其余位置為0。例如,我們得到一個為2000大小的詞匯表,“dog”的詞序為3,那么它的詞向量表示為(0,0,1,0,...,0)。是不是感覺這樣很蠢,只是將改詞所在的位置表示出來,而其余位置都沒有啥意義,占用存儲空間。如果上千萬大小的詞匯表,一個詞就需要上千萬的位置,將會導(dǎo)致維度災(zāi)難。
于是,人們搞出一個Distributed representation,它的思路是通過訓(xùn)練,將每個詞都映射到一個較短的詞向量上,所有的詞向量就構(gòu)成了向量空間,進(jìn)而可以用統(tǒng)計學(xué)的方法研究詞和詞之間的關(guān)系。比如谷歌用google news訓(xùn)練的詞向量,維度為300,一般維度自己指定。

上圖僅僅展示了一個詞匯表中詞向量的一部分,可以看出“Man”這個詞和“Woman”這個詞在“Gender”所占的比重還是很大的,在其他屬性占的比重小。當(dāng)然實際上,我們并不能對詞向量的每一個維度做很好的解釋。
使用t-SNE算法對詞向量進(jìn)行非線性降維,可得到下面映射結(jié)果:

可以看到同一類的詞,基本上聚集在了一起。例如,給定對應(yīng)關(guān)系“man”對“woman”,要求機(jī)器類比出“King”對應(yīng)的詞匯,可發(fā)現(xiàn)詞向量存在數(shù)學(xué)關(guān)系“Man - Woman = King - Queen”
第一部分
模型
在word2vec模型中,主要有Skip-Gram和CBOW兩種模型。CBOW是給定上下文,來預(yù)測input word,而Skip-Gram是給定input word來預(yù)測上下文。

我暫時文章沒怎么看懂,就看懂了最后一篇翻譯的,所以暫時只寫skip-gram。
Skip-Gram實際上分為了兩個部分,第一部分為建立模型,第二部分為通過模型獲取嵌入詞向量。word2vec的整個建模過程實際上與自編碼器(auto-encoder)相似,即先基于訓(xùn)練數(shù)據(jù)構(gòu)建一個神經(jīng)網(wǎng)絡(luò),當(dāng)這個模型訓(xùn)練號以后,我們并不會用這個訓(xùn)練好的模型處理新的任務(wù),我們需要的是這個模型通過訓(xùn)練所學(xué)到的參數(shù),如隱層的權(quán)值矩陣-----這些權(quán)重在word2vec中實際上就是我們試圖學(xué)習(xí)的“word vectors(詞向量)”?;谟?xùn)練數(shù)據(jù)建模的過程,我們給它取一個名字叫“Fake Task”,意味著建模不是最終目的。
上面提到的這種方法實際上會在無監(jiān)督特征學(xué)習(xí)(unsupervised feature learning)中見到,最常見的是自編碼器(auto-enconder):通過在隱層將輸入進(jìn)行編碼壓縮,繼而在輸出層將數(shù)據(jù)解碼回復(fù)到初始狀態(tài),訓(xùn)練完成后,我們將會去掉輸出層,只保留隱層。(ps:讓我想起了生成對抗網(wǎng)絡(luò))
The Fake Task
“fake task”就是構(gòu)建網(wǎng)絡(luò),但只要訓(xùn)練數(shù)據(jù)得到的隱層。它的完整過程如下:
假如我們有一個句子“The fox jumps over the lazy dog”。
- 首先我們選取句子中的一個詞作為輸入詞(實際訓(xùn)練過程中,是依次將句子中的每個詞作為輸入詞構(gòu)建訓(xùn)練對的),例如選取“fox”作為input word;
- 有了input word后,我們再定義一個叫skip_window的參數(shù),它代表我們從當(dāng)前input word的一側(cè)選取詞的數(shù)量。如果設(shè)置skip_window = 2,那么我們最終獲得窗口中的詞(包括input word在內(nèi))就是['The', 'fox', 'jumps', 'over']。那么整個窗口大小span =
= 4。另外一個參數(shù)叫num_skips,它代表我們選取多少個不同的詞作為我們的output word,當(dāng)skip_window = 2,num_skips = 2時,我們將會得到兩組(input word,output word)形式的訓(xùn)練數(shù)據(jù),即('fox', 'jumps'),('fox', 'the')
- 神經(jīng)網(wǎng)絡(luò)基于這些訓(xùn)練數(shù)據(jù)將會輸出一個概率分布,這個概率代表著我們詞典中的每個詞是output word的可能性。例如,上面我們得到兩組數(shù)據(jù)。我們先用一組數(shù)據(jù)('fox', 'jumps')來訓(xùn)練神經(jīng)網(wǎng)絡(luò),那么模型通過前面學(xué)習(xí)這個訓(xùn)練樣本,會告訴我們詞匯表中其他單詞的概率大小和“jumps”的概率大小。
模型的輸出概率代表著我們的詞典中每個詞有多大可能跟input word同時出現(xiàn)。例如,我們向神經(jīng)網(wǎng)絡(luò)模型中輸入一個單詞“Soviet”,那么最終模型的輸出概率中,像“Union”,“Russia”這些相關(guān)詞的概率遠(yuǎn)遠(yuǎn)高于“dog”,“l(fā)ove”這些非相關(guān)詞的概率。
我們將通過給神經(jīng)網(wǎng)絡(luò)輸入文本中成對的單詞來訓(xùn)練它完成上面所說的概率計算。下面的圖給出了一個完整的例子。我們選定句子“The quick brown fox jumps over lazy dog”,設(shè)定窗口大小為2(skip_window = 2)。下圖中,藍(lán)色代表input_word,方框內(nèi)代表位于窗口內(nèi)的單詞。

模型細(xì)節(jié)
首先,神經(jīng)網(wǎng)絡(luò)只能接受數(shù)值輸入,所以我們必須將單詞進(jìn)行one-hot編碼,上面我們介紹的詞向量發(fā)揮作用了。假設(shè)我們在訓(xùn)練數(shù)據(jù)中只能取出10000個不重復(fù)的單詞作為詞匯表,那么我們對每個單詞編碼都是的向量。在上面的例子中,如果“** The dog barked at the mailman**”,按照簡單的情況,每個單詞在詞匯表的位置為1,2,3,4,5,6,那么這6個單詞將會被編碼成
維度的向量,為了表示方便,我只寫出前2個
模型的輸入是10000為的向量,那么輸出也是10000維(詞匯表的大?。┫蛄?,它包含了10000個概率,每一個概率代表著當(dāng)前詞是輸入樣本中output word的概率大小。如下圖,神經(jīng)網(wǎng)絡(luò)架構(gòu):

隱層不使用任何激活函數(shù),但是輸出層用來softmax
第二部分
上面結(jié)尾我們說輸出層用softmax,但是要知道,如果真的用softmax來算,計算量大的驚人。所以可以用這三個方法來減少計算量:
- 將常見的單詞組合(word pairs)或者詞組作為單個“words”來使用。
- 對高頻詞進(jìn)行抽樣來減少訓(xùn)練樣本的個數(shù)
- 最后最重要的一點,就是“nagative sampling”方法,這樣每個訓(xùn)練樣本只會更新一小部分模型權(quán)重,從而降低計算負(fù)擔(dān)。
其他的我不想講,原作者博客中有,我想講講nagative sampling(負(fù)采樣)。不同于原本每個訓(xùn)練樣本更新所有的權(quán)重,負(fù)采樣每次讓一個訓(xùn)練樣本僅僅更新一部分的權(quán)重,這樣就好降低梯度下降過程中的計算量。
當(dāng)我們用訓(xùn)練樣本(input word:"fox", output word:"quick")來訓(xùn)練我們的神經(jīng)網(wǎng)絡(luò)時,“fox”和“quick”都是經(jīng)過one-hot編碼的。如果我們的vocabulary大小為10000時,在輸出層,我們希望“quick”單詞那個位置輸出1,其余都是0。這些其余我們期望輸出0的位置所對應(yīng)的單詞我們成為“negative” word。
當(dāng)使用負(fù)采樣時,我們將隨機(jī)選擇一小部分的negative words(比如選5個negative words)來更新對應(yīng)的權(quán)重。我們也會對我們的positive word進(jìn)行權(quán)重更新(上面的例子指的是"quick")。
- 在論文中,作者指出指出對于小規(guī)模數(shù)據(jù)集,選擇5-20個negative words會比較好,對于大規(guī)模數(shù)據(jù)集可以僅選擇2-5個negative words。
回憶一下我們的隱層-輸出層擁有300 x 10000的權(quán)重矩陣。如果使用了負(fù)采樣的方法我們僅僅去更新我們的positive word-“quick”的和我們選擇的其他5個negative words的結(jié)點對應(yīng)的權(quán)重,共計6個輸出神經(jīng)元,相當(dāng)于每次只更新300 6 = 1800個權(quán)重。對于3百萬的權(quán)重來說,相當(dāng)于只計算了0.06%的權(quán)重,這樣計算效率就大幅度提高。
寫到這里,其實還有很多東西沒說明白。但這個主題說大了,我暫時先擱置著,等研究透了再來修改增加。