NLP深度学习:基于TensorFlow实现Skip-Gram模型
作者丨天雨粟
知乎專欄丨機器不學習
地址丨https://zhuanlan.zhihu.com/p/27296712
前言
本篇文章將利用TensorFlow來完成Skip-Gram模型。還不是很了解Skip-Gram思想的小伙伴可以先看一下上一篇的專欄內容。
本篇實戰代碼的目的主要是加深對Skip-Gram模型中一些思想和trick的理解。由于受限于語料規模、語料質量、算法細節以及訓練成本的原因,訓練出的結果顯然是無法跟gensim封裝的Word2Vec相比的,本代碼適合新手去理解與練習Skip-Gram模型的思想。
工具介紹
語言:Python 3
包:TensorFlow(1.0版本)及其它數據處理包(見代碼中)
編輯器:jupyter notebook
線上GPU:floyd
數據集:經過預處理后的維基百科文章(英文)
正文部分
文章主要包括以下四個部分進行代碼構造:
- 數據預處理
- 訓練樣本構建
- 模型構建
- 模型驗證
1 數據預處理
關于導入包和加載數據在這里就不寫了,比較簡單,請參考git上的代碼。
數據預處理部分主要包括:
替換文本中特殊符號并去除低頻詞
對文本分詞
構建語料
單詞映射表
首先我們定義一個函數來完成前兩步,即對文本的清洗和分詞操作。
上面的函數實現了替換標點及刪除低頻詞操作,返回分詞后的文本。
下面讓我們來看看經過清洗后的數據:
有了分詞后的文本,就可以構建我們的映射表,代碼就不再贅述,大家應該都比較熟悉。
我們還可以看一下文本和詞典的規模大小:
整個文本中單詞大約為1660萬的規模,詞典大小為6萬左右,這個規模對于訓練好的詞向量其實是不夠的,但可以訓練出一個稍微還可以的模型。
2 訓練樣本構建
我們知道skip-gram中,訓練樣本的形式是(input word, output word),其中output word是input word的上下文。為了減少模型噪音并加速訓練速度,我們在構造batch之前要對樣本進行采樣,剔除停用詞等噪音因素。
采樣
在建模過程中,訓練文本中會出現很多“the”、“a”之類的常用詞(也叫停用詞),這些詞對于我們的訓練會帶來很多噪音。在上一篇Word2Vec中提過對樣本進行抽樣,剔除高頻的停用詞來減少模型的噪音,并加速訓練。
我們采用以下公式來計算每個單詞被刪除的概率大小:
其中代表單詞的出現頻次。為一個閾值,一般介于1e-3到1e-5之間。
上面的代碼計算了樣本中每個單詞被刪除的概率,并基于概率進行了采樣,現在我們手里就拿到了采樣過的單詞列表。
構造batch
我們先來分析一下skip-gram的樣本格式。skip-gram不同于CBOW,CBOW是基于上下文預測當前input word。而skip-gram則是基于一個input word來預測上下文,因此一個input word會對應多個上下文。我們來舉個栗子“The quick brown fox jumps over lazy dog”,如果我們固定skip_window=2的話,那么fox的上下文就是[quick, brown, jumps, over],如果我們的batch_size=1的話,那么實際上一個batch中有四個訓練樣本。
上面的分析轉換為代碼就是兩個步驟,第一個是找到每個input word的上下文,第二個就是基于上下文構建batch。
首先是找到input word的上下文單詞列表:
我們定義了一個get_targets函數,接收一個單詞索引號,基于這個索引號去查找單詞表中對應的上下文(默認window_size=5)。請注意這里有一個小trick,我在實際選擇input word上下文時,使用的窗口大小是一個介于[1, window_size]區間的隨機數。這里的目的是讓模型更多地去關注離input word更近詞。
我們有了上面的函數后,就能夠輕松地通過input word找到它的上下文單詞。有了這些單詞我們就可以構建我們的batch來進行訓練:
注意上面的代碼對batch的處理。我們知道對于每個input word來說,有多個output word(上下文)。例如我們的輸入是“fox”,上下文是[quick, brown, jumps, over],那么fox這一個batch中就有四個訓練樣本[fox, quick], [fox, brown], [fox, jumps], [fox, over]。
3 模型構建
數據預處理結束后,就需要來構建我們的模型。在模型中為了加速訓練并提高詞向量的質量,我們采用負采樣方式進行權重更新。
輸入層到嵌入層
輸入層到隱層的權重矩陣作為嵌入層要給定其維度,一般embeding_size設置為50-300之間。
嵌入層的lookup通過TensorFlow中的embedding_lookup實現。
嵌入層到輸出層
在skip-gram中,每個input word的多個上下文單詞實際上是共享一個權重矩陣,我們將每個(input word, output word)訓練樣本來作為我們的輸入。為了加速訓練并且提高詞向量的質量,我們采用negative sampling的方法來進行權重更新。
TensorFlow中的sampled_softmax_loss,由于進行了negative sampling,所以實際上我們會低估模型的訓練loss。
請注意代碼中的softmax_w的維度是vocab_size x embedding_size,這是因為TensorFlow中的sampled_softmax_loss中參數weights的size是[num_classes, dim]。4 模型驗證
在上面的步驟中,我們已經將模型的框架搭建出來,下面就讓我們來訓練訓練一下模型。為了能夠更加直觀地觀察訓練每個階段的情況。我們來挑選幾個詞,看看在訓練過程中它們的相似詞是怎么變化的。
訓練模型:
在這里注意一下,盡量不要經常去讓代碼打印驗證集相似的詞,因為這里會多了一步計算步驟,就是計算相似度,會非常消耗計算資源,計算過程也很慢。所以代碼中我設置1000輪打印一次結果。
從最后的訓練結果來看,模型還是學到了一些常見詞的語義,比如one等計數詞以及gold之類的金屬詞,animals中的相似詞也相對準確。
為了能夠更全面地觀察我們訓練結果,我們采用sklearn中的TSNE來對高維詞向量進行可視化。(具體代碼見git)
上面的圖中通過TSNE將高維的詞向量按照距離遠近顯示在二維坐標系中,該圖已經在git庫中,想看原圖的小伙伴去git看~
我們來看一下細節:
上面是顯示了整張大圖的局部區域,可以看到效果還不錯。
關于提升效果的技巧:
增大訓練樣本,語料庫越大,模型學習的可學習的信息會越多。
增加window size,可以獲得更多的上下文信息。
增加embedding size可以減少信息的維度損失,但也不宜過大,我一般常用的規模為50-300。
附錄:
git代碼中還提供了中文的詞向量計算代碼。同時提供了中文的一個訓練語料,語料是我從某招聘網站上爬取的招聘數據,做了分詞和去除停用詞的操作(可從git獲取),但語料規模太小,訓練效果并不好。
上面是我用模型訓練的中文數據,可以看到有一部分語義被挖掘出來,比如word和excel、office很接近,ppt和project、文字處理等,以及邏輯思維與語言表達等,但整體上效果還是很差。一方面是由于語料的規模太小(只有70兆的語料),另一方面是模型也沒有去調參。如果有興趣的同學可以自己試下會不會有更好的效果。
備注:公眾號菜單包含了整理了一本AI小抄,非常適合在通勤路上用學習。
往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習在線手冊深度學習在線手冊AI基礎下載(pdf更新到25集)備注:加入本站微信群或者qq群,請回復“加群”獲取一折本站知識星球優惠券,請回復“知識星球”喜歡文章,點個在看
總結
以上是生活随笔為你收集整理的NLP深度学习:基于TensorFlow实现Skip-Gram模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 科普漫画:什么是区块链?
- 下一篇: NLP深度学习:PyTorch文本分类