3
本文作者: AI研習(xí)社 | 2017-06-24 10:15 |
雷鋒網(wǎng)按:這是一個(gè)關(guān)于 Skip-Gram 模型的系列教程,共分為結(jié)構(gòu)、訓(xùn)練和實(shí)現(xiàn)三個(gè)部分,本文為最后一部分:實(shí)現(xiàn)篇。原文作者天雨粟,原載于作者知乎專欄,雷鋒網(wǎng)已獲授權(quán)。
上一篇的專欄介紹了Word2Vec中的Skip-Gram模型的結(jié)構(gòu)和訓(xùn)練,如果看過的小伙伴可以直接開始動手用TensorFlow實(shí)現(xiàn)自己的Word2Vec模型,本篇文章將利用TensorFlow來完成Skip-Gram模型。還不是很了解Skip-Gram思想的小伙伴可以先看一下上一篇的專欄內(nèi)容。
本篇實(shí)戰(zhàn)代碼的目的主要是加深對Skip-Gram模型中一些思想和trick的理解。由于受限于語料規(guī)模、語料質(zhì)量、算法細(xì)節(jié)以及訓(xùn)練成本的原因,訓(xùn)練出的結(jié)果顯然是無法跟gensim封裝的Word2Vec相比的,本代碼適合新手去理解與練習(xí)Skip-Gram模型的思想。
● 語言:Python 3
● 包:TensorFlow(1.0版本)及其它數(shù)據(jù)處理包(見代碼中)
● 編輯器:jupyter notebook
● 線上GPU:floyd (https://www.floydhub.com/)
● 數(shù)據(jù)集:經(jīng)過預(yù)處理后的維基百科文章(英文)
文章主要包括以下四個(gè)部分進(jìn)行代碼構(gòu)造:
- 數(shù)據(jù)預(yù)處理
- 訓(xùn)練樣本構(gòu)建
- 模型構(gòu)建
- 模型驗(yàn)證
關(guān)于導(dǎo)入包和加載數(shù)據(jù)在這里就不寫了,比較簡單,請參考git上的代碼。
數(shù)據(jù)預(yù)處理部分主要包括:
替換文本中特殊符號并去除低頻詞
對文本分詞
構(gòu)建語料
單詞映射表
首先我們定義一個(gè)函數(shù)來完成前兩步,即對文本的清洗和分詞操作。
上面的函數(shù)實(shí)現(xiàn)了替換標(biāo)點(diǎn)及刪除低頻詞操作,返回分詞后的文本。
下面讓我們來看看經(jīng)過清洗后的數(shù)據(jù):
有了分詞后的文本,就可以構(gòu)建我們的映射表,代碼就不再贅述,大家應(yīng)該都比較熟悉。
我們還可以看一下文本和詞典的規(guī)模大小:
整個(gè)文本中單詞大約為1660萬的規(guī)模,詞典大小為6萬左右,這個(gè)規(guī)模對于訓(xùn)練好的詞向量其實(shí)是不夠的,但可以訓(xùn)練出一個(gè)稍微還可以的模型。
我們知道skip-gram中,訓(xùn)練樣本的形式是(input word, output word),其中output word是input word的上下文。為了減少模型噪音并加速訓(xùn)練速度,我們在構(gòu)造batch之前要對樣本進(jìn)行采樣,剔除停用詞等噪音因素。
采樣
在建模過程中,訓(xùn)練文本中會出現(xiàn)很多“the”、“a”之類的常用詞(也叫停用詞),這些詞對于我們的訓(xùn)練會帶來很多噪音。在上一篇Word2Vec中提過對樣本進(jìn)行抽樣,剔除高頻的停用詞來減少模型的噪音,并加速訓(xùn)練。
我們采用以下公式來計(jì)算每個(gè)單詞被刪除的概率大?。?/p>
其中 f(wi) 代表單詞 wi 的出現(xiàn)頻次。t為一個(gè)閾值,一般介于1e-3到1e-5之間。
上面的代碼計(jì)算了樣本中每個(gè)單詞被刪除的概率,并基于概率進(jìn)行了采樣,現(xiàn)在我們手里就拿到了采樣過的單詞列表。
構(gòu)造batch
我們先來分析一下skip-gram的樣本格式。skip-gram不同于CBOW,CBOW是基于上下文預(yù)測當(dāng)前input word。而skip-gram則是基于一個(gè)input word來預(yù)測上下文,因此一個(gè)input word會對應(yīng)多個(gè)上下文。我們來舉個(gè)栗子“The quick brown fox jumps over lazy dog”,如果我們固定skip_window=2的話,那么fox的上下文就是[quick, brown, jumps, over],如果我們的batch_size=1的話,那么實(shí)際上一個(gè)batch中有四個(gè)訓(xùn)練樣本。
上面的分析轉(zhuǎn)換為代碼就是兩個(gè)步驟,第一個(gè)是找到每個(gè)input word的上下文,第二個(gè)就是基于上下文構(gòu)建batch。
首先是找到input word的上下文單詞列表:
我們定義了一個(gè)get_targets函數(shù),接收一個(gè)單詞索引號,基于這個(gè)索引號去查找單詞表中對應(yīng)的上下文(默認(rèn)window_size=5)。請注意這里有一個(gè)小trick,我在實(shí)際選擇input word上下文時(shí),使用的窗口大小是一個(gè)介于[1, window_size]區(qū)間的隨機(jī)數(shù)。這里的目的是讓模型更多地去關(guān)注離input word更近詞。
我們有了上面的函數(shù)后,就能夠輕松地通過input word找到它的上下文單詞。有了這些單詞我們就可以構(gòu)建我們的batch來進(jìn)行訓(xùn)練:
注意上面的代碼對batch的處理。我們知道對于每個(gè)input word來說,有多個(gè)output word(上下文)。例如我們的輸入是“fox”,上下文是[quick, brown, jumps, over],那么fox這一個(gè)batch中就有四個(gè)訓(xùn)練樣本[fox, quick], [fox, brown], [fox, jumps], [fox, over]。
數(shù)據(jù)預(yù)處理結(jié)束后,就需要來構(gòu)建我們的模型。在模型中為了加速訓(xùn)練并提高詞向量的質(zhì)量,我們采用負(fù)采樣方式進(jìn)行權(quán)重更新。
輸入層到嵌入層
輸入層到隱層的權(quán)重矩陣作為嵌入層要給定其維度,一般embeding_size設(shè)置為50-300之間。
嵌入層的 lookup 通過 TensorFlow 中的 embedding_lookup 實(shí)現(xiàn),詳見:
嵌入層到輸出層
在skip-gram中,每個(gè)input word的多個(gè)上下文單詞實(shí)際上是共享一個(gè)權(quán)重矩陣,我們將每個(gè)(input word, output word)訓(xùn)練樣本來作為我們的輸入。為了加速訓(xùn)練并且提高詞向量的質(zhì)量,我們采用negative sampling的方法來進(jìn)行權(quán)重更新。
TensorFlow中的sampled_softmax_loss,由于進(jìn)行了negative sampling,所以實(shí)際上我們會低估模型的訓(xùn)練loss。詳見:http://t.cn/RofvS4t
請注意代碼中的softmax_w的維度是vocab_size x embedding_size,這是因?yàn)門ensorFlow中的sampled_softmax_loss中參數(shù)weights的size是[num_classes, dim]。
在上面的步驟中,我們已經(jīng)將模型的框架搭建出來,下面就讓我們來訓(xùn)練訓(xùn)練一下模型。為了能夠更加直觀地觀察訓(xùn)練每個(gè)階段的情況。我們來挑選幾個(gè)詞,看看在訓(xùn)練過程中它們的相似詞是怎么變化的。
訓(xùn)練模型:
在這里注意一下,盡量不要經(jīng)常去讓代碼打印驗(yàn)證集相似的詞,因?yàn)檫@里會多了一步計(jì)算步驟,就是計(jì)算相似度,會非常消耗計(jì)算資源,計(jì)算過程也很慢。所以代碼中我設(shè)置1000輪打印一次結(jié)果。
從最后的訓(xùn)練結(jié)果來看,模型還是學(xué)到了一些常見詞的語義,比如one等計(jì)數(shù)詞以及gold之類的金屬詞,animals中的相似詞也相對準(zhǔn)確。
為了能夠更全面地觀察我們訓(xùn)練結(jié)果,我們采用sklearn中的TSNE來對高維詞向量進(jìn)行可視化。詳見:http://t.cn/Rofvr7D
上面的圖中通過TSNE將高維的詞向量按照距離遠(yuǎn)近顯示在二維坐標(biāo)系中,該圖已經(jīng)在git庫中,想看原圖的小伙伴去git看~
我們來看一下細(xì)節(jié):
上面是顯示了整張大圖的局部區(qū)域,可以看到效果還不錯(cuò)。
關(guān)于提升效果的技巧:
增大訓(xùn)練樣本,語料庫越大,模型學(xué)習(xí)的可學(xué)習(xí)的信息會越多。
增加window size,可以獲得更多的上下文信息。
增加embedding size可以減少信息的維度損失,但也不宜過大,我一般常用的規(guī)模為50-300。
git代碼中還提供了中文的詞向量計(jì)算代碼。同時(shí)提供了中文的一個(gè)訓(xùn)練語料,語料是我從某招聘網(wǎng)站上爬取的招聘數(shù)據(jù),做了分詞和去除停用詞的操作(可從git獲取),但語料規(guī)模太小,訓(xùn)練效果并不好。
上面是我用模型訓(xùn)練的中文數(shù)據(jù),可以看到有一部分語義被挖掘出來,比如word和excel、office很接近,ppt和project、文字處理等,以及邏輯思維與語言表達(dá)等,但整體上效果還是很差。一方面是由于語料的規(guī)模太?。ㄖ挥?0兆的語料),另一方面是模型也沒有去調(diào)參。如果有興趣的同學(xué)可以自己試下會不會有更好的效果。
完整代碼請見:
雷鋒網(wǎng)相關(guān)閱讀:
一文詳解 Word2vec 之 Skip-Gram 模型(結(jié)構(gòu)篇)
一文詳解 Word2vec 之 Skip-Gram 模型(訓(xùn)練篇)
25 行 Python 代碼實(shí)現(xiàn)人臉檢測——OpenCV 技術(shù)教程
雷峰網(wǎng)版權(quán)文章,未經(jīng)授權(quán)禁止轉(zhuǎn)載。詳情見轉(zhuǎn)載須知。