原理
word2vec的大概思想是,認為,距離越近的詞,相關性就越高,越能夠表征這個詞。所以,只需要把所有的條件概率\(P(w_{t+j}|w_t)\)最大化,這樣就能夠得到一個很好的用來表征詞語之間關系的模型了。
最大化的方法就是使用最大似然估計,構建損失函數,然后使用梯度下降進行優化就可以了。
而這里的核心問題就是,如何去用參數表征這個條件概率,也就是說,如何計算p(wt+j | wt ; θ),下面是計算的方式,這里使用了兩個參數 u 和v ,兩個都代表莫一個詞的表征,只不過含義不一樣,u代表這個詞作為context word來計算的時候,使用的表征,v代表這個詞作為中心詞計算的時候,使用的表征。

這里可以用點積來比較相似度,點積越大,越相似,就是讓臨近的單詞相似度變高,然后在進行歸一化操作,因為概率值必須在0-1之間,本質上理解就是,使用點積建模相似度,越相似的詞,點積越大,最終的概率就越大。

Skip-gram & CBOW
首先,這里面的u和v是用Embedding進行編碼的,一般是300維度,然后這300維度的向量在做softmax操作,最后在做優化,而優化的時候有兩種算方法
第一種是skip-gram,這個就是上面提到的,使用中間詞預測周邊詞,計算方法和上面一致
embed_o = self.embedding(index_0)
embed_v = self.embedding(index_v)
第二種是CBOW,這個不同的是,使用兩邊的詞,預測中間的詞,這里計算的時候就會出現差異,這個時候應該如何計算softmax, 首先假設周邊詞為w1 w2 w3 w4
這個時候需要對周邊詞進行平均操作,在求softmax
embed_v_list = self.embedding(w1,w2,w3,w4)
embed_v_mean = mean(embed_v_list)
embed_o = self.embedding(index_o)
負采樣
可以發現,在上面計算softmax的時候,要對所有的詞進行計算,這樣要耗費巨大的算力,而且實際上很多詞根本就不可能一起出現,所以就出現了稱為負采樣的策略。
所以換了一種策略,這里直接使用sigmoid來建模條件概率,首先,讓相關的兩個詞概率變大,然后隨機選取一些詞(K個詞),作者默認這些詞與要計算的詞不相關,這個時候,在點積前加上一個負號,約束讓概率變小。所以最終的損失函數就改造為了:
評估
對詞向量好壞的評價方法,分為內部和外部兩種。
-
內部主要是計算詞相似度,這個通過t-sne降維可視化,就可以直觀的觀察到。
-
外部是指通過一些任務,例如翻譯,命名體識別等各種任務,可以用來評估詞向量的效果。
使用gensim訓練詞向量
可以參考:https://www.kaggle.com/pierremegret/gensim-word2vec-tutorial
首先是對要訓練的文本進行分詞處理,英文可以使用NLTK,中文可以直接使用jieba,分完詞之后,需要將其放入到一個list中,例如
[["蘋果","很","好吃"],["香蕉","也","好吃"]]
之后就可以直接喂入到genism中進行訓練了
from gensim.models import Word2Vec
model = Word2Vec(min_count=20,
sg=1
window=2,
size=300,
sample=6e-5,
alpha=0.03,
min_alpha=0.0007,
negative=20,
workers=cores-1)
t = time()
model.train(sentences, total_examples=model.corpus_count, epochs=30, report_delay=1)
print('Time to train the model: {} mins'.format(round((time() - t) / 60, 2)))
參數:
min_count: 頻率小於min_cout的詞,會被過濾掉,默認為5
window:預測窗口的尺寸
size:詞向量的維度
sample: 閾值,決定多高頻率的詞語會被隨機的下采樣,更高頻率的詞被隨機下采樣到所設置的閾值,默認值為1e-3。
sg: 訓練模式,1: skip-gram; 0: CBOW
alpha: 初始學習率
min_alpha: 最小的學習率
negative:如果>0, 會使用負采樣算法,可以設置有多少詞被負采樣,一般為5-20
worker: 使用多少核心進行計算
使用訓練好的模型:
model.save(fname) # 保存
model = Word2Vec.load(fname) # 加載
model.similarity("蘋果","香蕉") #計算相似度
model.most_similar(positive=['母親','皇帝'],negative=['父親']) #計算相對距離
# '皇后'
#讀取詞向量
model['computer']
