Word2Vec是一組用來(lái)產(chǎn)生詞嵌入的模型,包括兩種主要的模型:skip-gram和CBOW登疗。
Skip-gram vs CBOW
算法層面上, 兩種模型很相似,CBOW模型是從兩邊預(yù)測(cè)中心詞辫红,skip-gram模型是中心詞預(yù)測(cè)兩邊。比如祝辣,對(duì)于“The quick brown fox jumps”,CBOW模型從上下文"the, "quick", "fox", 和"jumps"預(yù)測(cè)中心詞“brown”贴妻,skip-gram模型從“brown”預(yù)測(cè)上下文"the, "quick", "fox", 和"jumps"。
統(tǒng)計(jì)層面上蝙斜,CBOW模型通過將上下文看做一個(gè)樣本組成名惩,將分布信息做了平滑處理。大多數(shù)情況下孕荠,cbow模型適用于小型數(shù)據(jù)集娩鹉;skip-gram模型將每個(gè)上下文-中心詞對(duì)看做一個(gè)樣本,用在大型數(shù)據(jù)集上表現(xiàn)更好稚伍。
在本文中弯予,我們使用skip-gram模型來(lái)構(gòu)建word2vec。為了得到詞嵌入向量个曙,我們需要構(gòu)建一個(gè)單隱藏層的神經(jīng)網(wǎng)絡(luò)锈嫩,然后用來(lái)執(zhí)行特定任務(wù)來(lái)完成訓(xùn)練;但是訓(xùn)練得到的模型并不是我們需要的。我們只關(guān)注隱藏層的權(quán)重呼寸,這些權(quán)重就是詞嵌入向量艳汽。
上面的特定任務(wù)是指給定中心詞預(yù)測(cè)上下文。對(duì)于句子中的某個(gè)詞等舔,在詞的上下文中隨機(jī)選擇一個(gè)詞骚灸;網(wǎng)絡(luò)模型可以輸出整個(gè)詞典中每個(gè)詞是中心詞上下文的概率。
Softmax慌植、Negative Sampling & Noise Contrastive Estimation(NCE)
為了得到某個(gè)詞的所有可能上下文詞的概率分布甚牲,我們使用softmax來(lái)實(shí)現(xiàn)。softmax函數(shù)根據(jù)輸入輸出一個(gè)概率值蝶柿。在這里表示中心詞的一個(gè)可能的上下文:
但是丈钙,softmax用于歸一化的分母的計(jì)算需要遍歷整個(gè)詞典,通常情況下詞典長(zhǎng)度在百萬(wàn)級(jí)別交汤,而且指數(shù)的計(jì)算也比較耗時(shí)雏赦,這就導(dǎo)致了softmax的計(jì)算量進(jìn)一步加大。
為了規(guī)避這個(gè)計(jì)算瓶頸芙扎,我們可以使用分層softmax(hierarchical softmax)和基于采樣的softmax星岗。論文Distributed Representations of Words and Phrases and their Compositionality 指出訓(xùn)練skip-gram模型,和分層softmax方法相比戒洼,使用negative sampling的方法訓(xùn)練速度更快俏橘,得到的詞向量更好。
Negative Sampling(負(fù)采樣)是基于采樣方法的一種圈浇×绕基于采樣的方法也包括重要性采樣(importance sampling)和目標(biāo)采樣(target sampling)。負(fù)采樣方法是NCE的簡(jiǎn)化版:負(fù)采樣對(duì)噪聲樣本(負(fù)樣本)的采樣數(shù)量k以及噪聲數(shù)據(jù)服從的分布Q做了假定磷蜀,kQ(w)=1
召耘。
負(fù)采樣方法用于學(xué)習(xí)詞嵌入表示,并不能保證其梯度值和softmax函數(shù)梯度值相近褐隆;而NCE方法隨著負(fù)樣本采樣數(shù)的增加其提取值也愈來(lái)愈逼近于softmax的梯度值污它。Mnih and Teh(2012)表明使用25個(gè)噪聲樣本的計(jì)算結(jié)果與softmax的計(jì)算值差距不大,而且運(yùn)算速度能加快45倍妓灌。因此轨蛤,我們使用NCE來(lái)實(shí)現(xiàn)word2vec。
基于采樣的方法虫埂,無(wú)論是負(fù)采樣還是NCE方法祥山,只適用于訓(xùn)練階段;在應(yīng)用階段還需要執(zhí)行softmax來(lái)得到正則化的概率結(jié)果掉伏。
數(shù)據(jù)介紹
2006年3月3日的維基百科文本的100MB數(shù)據(jù)text8缝呕。
100MB數(shù)據(jù)訓(xùn)練得到的詞嵌入雖然表現(xiàn)不太好澳窑,但是從中也能看到一些有趣的現(xiàn)象。使用空格切分?jǐn)?shù)據(jù)后供常,文本包括17005207個(gè)詞摊聋。為了得到更好的詞嵌入,需要使用更大的數(shù)據(jù)集栈暇。
Overview
使用TensorFlow實(shí)現(xiàn)模型麻裁,需要景觀兩個(gè)階段:定義計(jì)算圖以及圖的運(yùn)行。
階段一:圖定義
- 導(dǎo)入數(shù)據(jù)(tf.data 源祈、placeholders)
- 定義權(quán)重
- 定義模型
- 定義損失函數(shù)loss
- 定義優(yōu)化器
階段二:執(zhí)行運(yùn)算圖
- 變量初始化
- 初始化迭代器/向模型傳送數(shù)據(jù)
- 執(zhí)行前向計(jì)算
- 計(jì)算cost
- 梯度計(jì)算來(lái)調(diào)整模型參數(shù)
階段一:圖定義
1. 創(chuàng)建dataset煎源,生成樣本
skip-gram模型的輸入為(中心詞,上下文詞)pair對(duì)香缺。數(shù)據(jù)傳送到模型之前手销,需要將字符串類型轉(zhuǎn)換成indices表示,如果“computer”是詞典中第100個(gè)單詞图张,那么對(duì)象下標(biāo)為99锋拖。
每一個(gè)樣本數(shù)據(jù)是一個(gè)標(biāo)量,BATCH_SIZE個(gè)輸入樣本的構(gòu)成tensor的shape 為[BATCH_SIZE]
祸轮,輸出樣本的shape為[BATCH_sIZE, 1]
.
2.定義權(quán)重
在embedding矩陣中每一行表示一個(gè)詞的向量表示兽埃。如果詞向量長(zhǎng)度為EMBED_SIZE,embedding矩陣的shape為[VOCAB_SIZE, EMBED_SIZE]
。
3. Inference
為了從embed_matrix
中得到對(duì)應(yīng)輸入的詞向量表示适袜,我們可以使用tf.nn.embedding_lookup
來(lái)實(shí)現(xiàn):
這個(gè)函數(shù)相當(dāng)于一個(gè)查表操作讲仰,根據(jù)輸入ids在params找到對(duì)應(yīng)的向量。
如果輸入是one_hot表示痪蝇,向量乘以矩陣可以很快地找到one_hot非零值對(duì)應(yīng)的向量(one_hot中非零值為第4個(gè),相乘后結(jié)果就是矩陣的第4行)冕房;使用相乘方法躏啰,由于one_hot表示有很多0值進(jìn)而會(huì)產(chǎn)生許多不必要的計(jì)算;使用tf.nn.lookup
就可以節(jié)省這些不必要的計(jì)算耙册。
為了得到中心詞的embedding表示给僵,
embed = tf.nn.embedding_lookup(embed_matrix, center_words, name='embed')
4. 定義損失函數(shù)
? TensorFlow已經(jīng)為我們實(shí)現(xiàn)了NCE損失函數(shù):
tf.nn.nce_loss(
weights,
biases,
labels,
inputs,
num_sampled,
num_classes,
num_true=1,
sampled_values=None,
remove_accidental_hits=False,
partition_strategy='mod',
name='nce_loss'
)
為了計(jì)算NCE loss,需要定義計(jì)算loss的隱藏層權(quán)重weights和偏置biases详拙。在訓(xùn)練過程中這些參數(shù)會(huì)自動(dòng)更新帝际、優(yōu)化。在采樣之后饶辙,最終結(jié)果的計(jì)算過程如下:
tf.matmul(embed, tf.transpose(nce_weight)) + nce_bias
這項(xiàng)計(jì)算包含在tf.nn_nce_loss
的計(jì)算過程中蹲诀。
nce_weight = tf.get_variable('nce_weight', shape=[VOCAB_SIZE, EMBED_SIZE], initializer=tf.truncated_normal_initializer(stddev=1.0 / (EMBED_SIZE ** 0.5)))
nce_bias = tf.get_variable('nce_bias', initializer=tf.zeros([VOCAB_SIZE]))
損失函數(shù)定義如下:
loss = tf.reduce_mean(tf.nn.nce_loss(weights=nce_weight,
biases=nce_bias,
labels=target_words,
inputs=embed,
num_sampled=NUM_SAMPLED,
num_classes=VOCAB_SIZE))
5. 定義優(yōu)化器
optimizer = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(loss)
階段二:圖的執(zhí)行
創(chuàng)建一個(gè)會(huì)話來(lái)執(zhí)行優(yōu)化op。
with tf.Session() as sess:
# 迭代器初始化
sess.run(iterator.initializer)
# 變量初始化
sess.run(tf.global_variables_initializer())
writer = tf.summary.FileWriter('graphs/word2vec_simple', sess.graph)
for index in range(NUM_TRAIN_STEPS):
try:
# 執(zhí)行優(yōu)化弃揽,計(jì)算loss
loss_batch, _ = sess.run([loss, optimizer])
except tf.errors.OutOfRangeError:
sess.run(iterator.initializer)
writer.close()
完整代碼地址:ClickMe