一文弄懂word2vec(從源碼解析)

一、簡介

Word2Vec並非指一個模型,而是2013年Google開源的一個獲取詞向量的工具包,由於簡單高效,大大降低了詞向量在工業界的應用門檻。我們先來看下Word2Vec能夠取得的效果:

相似詞:通過向量間距離的遠近來尋找相似詞,如man的相似詞woman;
詞語線性運算:V(King) - V(man) + V(woman) = V(Queen)

由此可見,Word2Vec可以通過上下文將語義較好的嵌入到向量空間中。由於Word2Vec生成的詞向量將自然語言的特徵較好地融合進了低維度稠密詞向量中,使用詞向量進行後續的各種NLP任務便可以取得較好的結果。

要理解Word2Vec,我們主要需要了解其中的四個概念:

  • CBOW
  • Skip-gram
  • Hierarchical softmax
  • Negative Sampling

其中,前兩個代表Word2Vec中兩種不同的獲取詞向量的策略,或者說模型結構;後兩個則是兩種改進softmax計算複雜度過高問題的方法。

需要提到一點的是,這個詞向量的維度(與隱含層節點數一致)一般情況下要遠遠小於詞語總數 V 的大小,所以 Word2vec 本質上是一種降維操作——把詞語從 one-hot encoder 形式的表示降維到 Word2vec 形式的表示。

作者論文:http://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf
word2vec原理分析:http://www.cnblogs.com/peghoty/p/3857839.html
[NLP] 秒懂詞向量Word2vec的本質:https://mp.weixin.qq.com/s/aeoFx6sIX6WNch51XRF5sg

二、兩種模型

1、CBOW

CBOW(Continuous Bag-of-Words Model)是一種根據上下文的詞語預測當前詞語的出現概率的模型。以當前詞的周圍詞語作爲輸入,當前詞作爲輸出。即上下文預測當前詞。
在這裏插入圖片描述

  • 輸入層: 包含當前詞w(t)中的2c個詞的詞向量w(t-2)、w(t-1)、w(t+1)、w(t+2)。
  • 投影層: 將輸入層的2c個向量做求和累加(實現代碼中往往都是直接使用均值)。
    在這裏插入圖片描述
  • 輸出層: 從投影層到輸出層一般使用softmax求概率,其中每個單詞對應的多個上下文單詞實際上是共享一個權重矩陣 。爲了加速訓練並且提高詞向量的質量,可以採用我們採用Huffman樹或負採樣(negative sampling)的方法來進行權重更新。如下采用負採樣的方式(主要使用tf.nn.nce_loss函數)實現:
    在這裏插入圖片描述

參考:
使用TENSORFLOW實作WORD2VEC CBOW:https://vinachangblog.wordpress.com/2017/08/13/使用tensorflow實作word2vec-cbow
一種源碼實現:https://github.com/edwardbi/DeepLearningModels/blob/master/CBOW/TFCBOW.ipynb

2、Skip-Gram

Skip-gram只是逆轉了CBOW的因果關係而已,以當前詞作爲輸入,當前詞的周圍詞作爲輸出。即當前詞預測上下文。
在這裏插入圖片描述

  • 輸入層: 只含有當前樣本的中心詞w的詞向量
  • 投影層: 這是一個恆等投影,把v(w)投影到v(w),某些博文說詞向量就是隱層權重矩陣就是源於此,因此,這個投影層其實是多餘的,這裏之所以保留投影層主要是方便與CBOW模型的網絡結構做對比。從輸入層到投影層的實現代碼(代碼見下文鏈接):
    在這裏插入圖片描述
    首先,通過tf.random_uniform函數產生字典對應的權重矩陣(其實質就是對應的詞向量),輸入層到投影層是通過tf.nn.embedding_lookup根據輸入數據lookup到對應詞向量。
  • 輸出層: 從投影層到輸出層同CBOW一樣。區別在於直接使用每個(input word, output word)訓練樣本來作爲我們的輸入。如下采用負採樣的方式(主要使用tf.nn.sampled_softmax_loss)實現:
    在這裏插入圖片描述

參考:
理解 Word2Vec 之 Skip-Gram 模型:https://zhuanlan.zhihu.com/p/27234078
基於TensorFlow實現Skip-Gram模型:https://zhuanlan.zhihu.com/p/27296712
一種代碼實現:https://github.com/NELSONZHAO/zhihu/blob/master/skip_gram/Skip-Gram-Chinese-Corpus.ipynb
tensorflow官網examples的實現:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/word2vec/word2vec_basic.py

三、Trick

模型的最後一層softmax層計算非常耗時,爲了加速模型訓練,使模型能夠應用於大規模語料庫。可以採用如下方式優化:

1、hierarchical softmax

本質是把 N 分類問題變成 log(N)次二分類

Hierarchical Softmax是一種對輸出層進行優化的策略,輸出層從原始模型的利用softmax計算概率值改爲了利用Huffman樹計算概率值。一開始我們可以用以詞表中的全部詞作爲葉子節點,詞頻作爲節點的權,構建Huffman樹,作爲輸出。從根節點出發,到達指定葉子節點的路徑是唯一的。Hierarchical Softmax正是利用這條路徑來計算指定詞的概率,而非用softmax來計算。

2、negative sampling

本質是預測總體類別的一個子集

Negative Sampling(簡寫NEG,負採樣),這是Noise-Contrastive Estimation(簡寫NCE,噪聲對比估計)的簡化版本:把語料中的一個詞串的中心詞替換爲別的詞,構造語料 D 中不存在的詞串作爲負樣本。在這種策略下,優化目標變爲了:最大化正樣本的概率,同時最小化負樣本的概率。

參考:
word2vec原理(二) 基於Hierarchical Softmax的模型:https://www.cnblogs.com/pinard/p/7243513.html
word2vec原理(三) 基於Negative Sampling的模型:http://www.cnblogs.com/pinard/p/7249903.html

四、比較

根據Word2Vec作者Mikolov的說法,兩者的比較如下:

  • Skip-gram: works well with small amount of the training data, represents well even rare words or phrases.(在小數據集和低頻詞能取得更好的效果。)
  • CBOW: several times faster to train than the skip-gram, slightly better accuracy for the frequent words.(CBOW訓練速度更快,在高頻詞上效果優於Skip-gram。)

關於訓練集大小:Skip-gram在數據集較小時能取得更好的效果;原因我認爲有兩點:1. 數據集較小時,低頻詞較多,Skip-gram對低頻詞的表示效果較好;2. 同樣的語料庫,Skip-gram能產生更多(子)樣本。
關於訓練速度:CBOW訓練速度更快。這是因爲,一個batch中,CBOW包含batch_size箇中心詞樣本,Skip-gram包含batch_size/num_skips箇中心詞樣本,同樣的batch_size遍歷一次樣本集,CBOW需要更少的step。

參考:
BERT發展史(三)全方位多角度理解Word2Vec:https://www.jianshu.com/p/18a601ec9103
不懂word2vec,還敢說自己是做NLP?https://www.jianshu.com/p/cede3ae146bb

五、最佳實踐

  • 生產環境訓練過程一般直接使用基於Gensim的Word2Vec更好(底層還是google的word2vec)
    參考:基於Gensim的Word2Vec實現:https://zhuanlan.zhihu.com/p/24961011
  • word2vec一旦訓練完,未登錄詞將無法取得向量,因此訓練時候要求詞料庫儘量大而全,這個收集數據難度較高,在滿足業務的前提下,建議直接用一些開源詞向量即可。

開源詞向量集:
騰訊AI Lab開源大規模高質量中文詞向量數據(800萬中文詞): https://ai.tencent.com/ailab/nlp/embedding.html
Chinese Word Vectors中文詞向量:https://github.com/Embedding/Chinese-Word-Vectors

  • 對一些未登錄詞,一般自定義向量,例如:
try:
    embedding = word2vec_dict[word]
except Exception:
    embedding = np.random.uniform(low_bound, high_bound, embed_size)
  • word2vec沒有考慮語序,這裏會有訓練效果損失,在需要考慮一些語序的場景使用需注意。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章