TensorFlow教程之完整教程 2.7 字词的向量表示
摘要: 本文檔為TensorFlow參考文檔,本轉(zhuǎn)載已得到TensorFlow中文社區(qū)授權(quán)。 Vector Representations of Words 在本教程我們來看一下Mikolov et al中提到的word2vec模型。
本文檔為TensorFlow參考文檔,本轉(zhuǎn)載已得到TensorFlow中文社區(qū)授權(quán)。
Vector Representations of Words
在本教程我們來看一下Mikolov et al中提到的word2vec模型。該模型是用于學(xué)習(xí)文字的向量表示,稱之為“word embedding”。
亮點
本教程意在展現(xiàn)出在TensorfLow中構(gòu)建word2vec模型有趣、本質(zhì)的部分。
- 我們從我們?yōu)楹涡枰褂孟蛄勘硎疚淖珠_始。
- 我們通過直觀地例子觀察模型背后的本質(zhì),以及它是如何訓(xùn)練的(通過一些數(shù)學(xué)方法評估)。
- 同時我們也展示了TensorFlow對該模型的簡單實現(xiàn)。
- 最后,我們著眼于讓給這個簡單版本的模型表現(xiàn)更好。
但是首先,讓我們來看一下為何需要學(xué)習(xí)word embeddings。如果你對word embeddings相關(guān)內(nèi)容已經(jīng)是個專家了,那么請安心跳過本節(jié)內(nèi)容,直接深入細節(jié)干一些臟活吧。
動機: 為什么需要學(xué)習(xí) Word Embeddings?
通常圖像或音頻系統(tǒng)處理的是由圖片中所有單個原始像素點強度值或者音頻中功率譜密度的強度值,把它們編碼成豐富、高緯度的向量數(shù)據(jù)集。對于物體或語音識別這一類的任務(wù),我們所需的全部信息已經(jīng)都存儲在原始數(shù)據(jù)中(顯然人類本身就是依賴原始數(shù)據(jù)進行日常的物體或語音識別的)。然后,自然語言處理系統(tǒng)通常將詞匯作為離散的單一符號,例如 "cat" 一詞或可表示為?Id537?,而 "dog" 一詞或可表示為?Id143。這些符號編碼毫無規(guī)律,無法提供不同詞匯之間可能存在的關(guān)聯(lián)信息。換句話說,在處理關(guān)于 "dogs" 一詞的信息時,模型將無法利用已知的關(guān)于 "cats" 的信息(例如,它們都是動物,有四條腿,可作為寵物等等)。可見,將詞匯表達為上述的獨立離散符號將進一步導(dǎo)致數(shù)據(jù)稀疏,使我們在訓(xùn)練統(tǒng)計模型時不得不尋求更多的數(shù)據(jù)。而詞匯的向量表示將克服上述的難題。
向量空間模型?(VSMs)將詞匯表達(嵌套)于一個連續(xù)的向量空間中,語義近似的詞匯被映射為相鄰的數(shù)據(jù)點。向量空間模型在自然語言處理領(lǐng)域中有著漫長且豐富的歷史,不過幾乎所有利用這一模型的方法都依賴于?分布式假設(shè),其核心思想為出現(xiàn)于上下文情景中的詞匯都有相類似的語義。采用這一假設(shè)的研究方法大致分為以下兩類:基于技術(shù)的方法?(e.g.?潛在語義分析), 和?預(yù)測方法?(e.g.?神經(jīng)概率化語言模型).
其中它們的區(qū)別在如下論文中又詳細闡述?Baroni et al.,不過簡而言之:基于計數(shù)的方法計算某詞匯與其鄰近詞匯在一個大型語料庫中共同出現(xiàn)的頻率及其他統(tǒng)計量,然后將這些統(tǒng)計量映射到一個小型且稠密的向量中。預(yù)測方法則試圖直接從某詞匯的鄰近詞匯對其進行預(yù)測,在此過程中利用已經(jīng)學(xué)習(xí)到的小型且稠密的嵌套向量。
Word2vec是一種可以進行高效率詞嵌套學(xué)習(xí)的預(yù)測模型。其兩種變體分別為:連續(xù)詞袋模型(CBOW)及Skip-Gram模型。從算法角度看,這兩種方法非常相似,其區(qū)別為CBOW根據(jù)源詞上下文詞匯('the cat sits on the')來預(yù)測目標(biāo)詞匯(例如,‘mat’),而Skip-Gram模型做法相反,它通過目標(biāo)詞匯來預(yù)測源詞匯。Skip-Gram模型采取CBOW的逆過程的動機在于:CBOW算法對于很多分布式信息進行了平滑處理(例如將一整段上下文信息視為一個單一觀察量)。很多情況下,對于小型的數(shù)據(jù)集,這一處理是有幫助的。相形之下,Skip-Gram模型將每個“上下文-目標(biāo)詞匯”的組合視為一個新觀察量,這種做法在大型數(shù)據(jù)集中會更為有效。本教程余下部分將著重講解Skip-Gram模型。
處理噪聲對比訓(xùn)練
神經(jīng)概率化語言模型通常使用極大似然法?(ML) 進行訓(xùn)練,其中通過?softmax?function?來最大化當(dāng)提供前一個單詞?h?(代表 "history"),后一個單詞的概率??(代表 "target"),
當(dāng)?score(w_t,h)?計算了文字?w_t?和 上下文?h?的相容性(通常使用向量積)。我們使用對數(shù)似然函數(shù)來訓(xùn)練訓(xùn)練集的最大值,比如通過:
這里提出了一個解決語言概率模型的合適的通用方法。然而這個方法實際執(zhí)行起來開銷非常大,因為我們需要去計算并正則化當(dāng)前上下文環(huán)境?h?中所有其他?V?單詞?w'?的概率得分,在每一步訓(xùn)練迭代中。
從另一個角度來說,當(dāng)使用word2vec模型時,我們并不需要對概率模型中的所有特征進行學(xué)習(xí)。而CBOW模型和Skip-Gram模型為了避免這種情況發(fā)生,使用一個二分類器(邏輯回歸)在同一個上下文環(huán)境里從?k?虛構(gòu)的 (噪聲) 單詞??區(qū)分出真正的目標(biāo)單詞?。我們下面詳細闡述一下CBOW模型,對于Skip-Gram模型只要簡單地做相反的操作即可。
從數(shù)學(xué)角度來說,我們的目標(biāo)是對每個樣本最大化:
其中??代表的是數(shù)據(jù)集在當(dāng)前上下文?h?,根據(jù)所學(xué)習(xí)的嵌套向量??,目標(biāo)單詞?w?使用二分類邏輯回歸計算得出的概率。在實踐中,我們通過在噪聲分布中繪制比對文字來獲得近似的期望值(通過計算蒙特卡洛平均值)。
當(dāng)真實地目標(biāo)單詞被分配到較高的概率,同時噪聲單詞的概率很低時,目標(biāo)函數(shù)也就達到最大值了。從技術(shù)層面來說,這種方法叫做?負抽樣,而且使用這個損失函數(shù)在數(shù)學(xué)層面上也有很好的解釋:這個更新過程也近似于softmax函數(shù)的更新。這在計算上將會有很大的優(yōu)勢,因為當(dāng)計算這個損失函數(shù)時,只是有我們挑選出來的?k?個?噪聲單詞,而沒有使用整個語料庫?V。這使得訓(xùn)練變得非常快。我們實際上使用了與noise-contrastive estimation (NCE)介紹的非常相似的方法,這在TensorFlow中已經(jīng)封裝了一個很便捷的函數(shù)tf.nn.nce_loss()。
讓我們在實踐中來直觀地體會它是如何運作的!
Skip-gram 模型
下面來看一下這個數(shù)據(jù)集
the quick brown fox jumped over the lazy dog
我們首先對一些單詞以及它們的上下文環(huán)境建立一個數(shù)據(jù)集。我們可以以任何合理的方式定義‘上下文’,而通常上這個方式是根據(jù)文字的句法語境的(使用語法原理的方式處理當(dāng)前目標(biāo)單詞可以看一下這篇文獻?Levy et al.,比如說把目標(biāo)單詞左邊的內(nèi)容當(dāng)做一個‘上下文’,或者以目標(biāo)單詞右邊的內(nèi)容,等等。現(xiàn)在我們把目標(biāo)單詞的左右單詞視作一個上下文, 使用大小為1的窗口,這樣就得到這樣一個由(上下文, 目標(biāo)單詞)?組成的數(shù)據(jù)集:
([the, brown], quick), ([quick, fox], brown), ([brown, jumped], fox), ...
前文提到Skip-Gram模型是把目標(biāo)單詞和上下文顛倒過來,所以在這個問題中,舉個例子,就是用'quick'來預(yù)測 'the' 和 'brown' ,用 'brown' 預(yù)測 'quick' 和 'brown' 。因此這個數(shù)據(jù)集就變成由(輸入, 輸出)組成的:
(quick, the), (quick, brown), (brown, quick), (brown, fox), ...
目標(biāo)函數(shù)通常是對整個數(shù)據(jù)集建立的,但是本問題中要對每一個樣本(或者是一個batch_size?很小的樣本集,通常設(shè)置為16 <= batch_size <= 512)在同一時間執(zhí)行特別的操作,稱之為隨機梯度下降?(SGD)。我們來看一下訓(xùn)練過程中每一步的執(zhí)行。
假設(shè)用?t?表示上面這個例子中quick?來預(yù)測?the?的訓(xùn)練的單個循環(huán)。用?num_noise?定義從噪聲分布中挑選出來的噪聲(相反的)單詞的個數(shù),通常使用一元分布,P(w)。為了簡單起見,我們就定num_noise=1,用?sheep?選作噪聲詞。接下來就可以計算每一對觀察值和噪聲值的損失函數(shù)了,每一個執(zhí)行步驟就可表示為:
整個計算過程的目標(biāo)是通過更新嵌套參數(shù)??來逼近目標(biāo)函數(shù)(這個這個例子中就是使目標(biāo)函數(shù)最大化)。為此我們要計算損失函數(shù)中嵌套參數(shù)??的梯度,比如,??(幸好TensorFlow封裝了工具函數(shù)可以簡單調(diào)用!)。對于整個數(shù)據(jù)集,當(dāng)梯度下降的過程中不斷地更新參數(shù),對應(yīng)產(chǎn)生的效果就是不斷地移動每個單詞的嵌套向量,直到可以把真實單詞和噪聲單詞很好得區(qū)分開。
我們可以把學(xué)習(xí)向量映射到2維中以便我們觀察,其中用到的技術(shù)可以參考?t-SNE 降緯技術(shù)。當(dāng)我們用可視化的方式來觀察這些向量,就可以很明顯的獲取單詞之間語義信息的關(guān)系,這實際上是非常有用的。當(dāng)我們第一次發(fā)現(xiàn)這樣的誘導(dǎo)向量空間中,展示了一些特定的語義關(guān)系,這是非常有趣的,比如文字中?male-female,gender?甚至還有?country-capital?的關(guān)系, 如下方的圖所示 (也可以參考?Mikolov et al., 2013論文中的例子)。
這也解釋了為什么這些向量在傳統(tǒng)的NLP問題中可作為特性使用,比如用在對一個演講章節(jié)打個標(biāo)簽,或者對一個專有名詞的識別 (看看如下這個例子?Collobert et al.或者?Turian et al.)。
不過現(xiàn)在讓我們用它們來畫漂亮的圖表吧!
建立圖形
這里談得都是嵌套,那么先來定義一個嵌套參數(shù)矩陣。我們用唯一的隨機值來初始化這個大矩陣。
embeddings = tf.Variable(tf.random_uniform([vocabulary_size, embedding_size], -1.0, 1.0))對噪聲-比對的損失計算就使用一個邏輯回歸模型。對此,我們需要對語料庫中的每個單詞定義一個權(quán)重值和偏差值。(也可稱之為輸出權(quán)重?與之對應(yīng)的?輸入嵌套值)。定義如下。
nce_weights = tf.Variable(tf.truncated_normal([vocabulary_size, embedding_size],stddev=1.0 / math.sqrt(embedding_size))) nce_biases = tf.Variable(tf.zeros([vocabulary_size]))我們有了這些參數(shù)之后,就可以定義Skip-Gram模型了。簡單起見,假設(shè)我們已經(jīng)把語料庫中的文字整型化了,這樣每個整型代表一個單詞。Skip-Gram模型有兩個輸入。一個是一組用整型表示的上下文單詞,另一個是目標(biāo)單詞。給這些輸入建立占位符節(jié)點,之后就可以填入數(shù)據(jù)了。
# 建立輸入占位符 train_inputs = tf.placeholder(tf.int32, shape=[batch_size]) train_labels = tf.placeholder(tf.int32, shape=[batch_size, 1])然后我們需要對批數(shù)據(jù)中的單詞建立嵌套向量,TensorFlow提供了方便的工具函數(shù)。
embed = tf.nn.embedding_lookup(embeddings, train_inputs)好了,現(xiàn)在我們有了每個單詞的嵌套向量,接下來就是使用噪聲-比對的訓(xùn)練方式來預(yù)測目標(biāo)單詞。
# 計算 NCE 損失函數(shù), 每次使用負標(biāo)簽的樣本. loss = tf.reduce_mean(tf.nn.nce_loss(nce_weights, nce_biases, embed, train_labels,num_sampled, vocabulary_size))我們對損失函數(shù)建立了圖形節(jié)點,然后我們需要計算相應(yīng)梯度和更新參數(shù)的節(jié)點,比如說在這里我們會使用隨機梯度下降法,TensorFlow也已經(jīng)封裝好了該過程。
# 使用 SGD 控制器. optimizer = tf.train.GradientDescentOptimizer(learning_rate=1.0).minimize(loss)訓(xùn)練模型
訓(xùn)練的過程很簡單,只要在循環(huán)中使用feed_dict不斷給占位符填充數(shù)據(jù),同時調(diào)用?session.run即可。
for inputs, labels in generate_batch(...):feed_dict = {training_inputs: inputs, training_labels: labels}_, cur_loss = session.run([optimizer, loss], feed_dict=feed_dict)嵌套學(xué)習(xí)結(jié)果可視化
使用t-SNE來看一下嵌套學(xué)習(xí)完成的結(jié)果。
Et voila! 與預(yù)期的一樣,相似的單詞被聚類在一起。
嵌套學(xué)習(xí)的評估: 類比推理
詞嵌套在NLP的預(yù)測問題中是非常有用且使用廣泛地。如果要檢測一個模型是否是可以成熟地區(qū)分詞性或者區(qū)分專有名詞的模型,最簡單的辦法就是直接檢驗它的預(yù)測詞性、語義關(guān)系的能力,比如讓它解決形如king is to queen as father is to ?這樣的問題。
超參數(shù)的選擇對該問題解決的準確性有巨大的影響。想要模型具有很好的表現(xiàn),需要有一個巨大的訓(xùn)練數(shù)據(jù)集,同時仔細調(diào)整參數(shù)的選擇并且使用例如二次抽樣的一些技巧。不過這些問題已經(jīng)超出了本教程的范圍。
優(yōu)化實現(xiàn)
以上簡單的例子展示了TensorFlow的靈活性。比如說,我們可以很輕松得用現(xiàn)成的tf.nn.sampled_softmax_loss()來代替tf.nn.nce_loss()構(gòu)成目標(biāo)函數(shù)。如果你對損失函數(shù)想做新的嘗試,你可以用TensorFlow手動編寫新的目標(biāo)函數(shù)的表達式,然后用控制器執(zhí)行計算。這種靈活性的價值體現(xiàn)在,當(dāng)我們探索一個機器學(xué)習(xí)模型時,我們可以很快地遍歷這些嘗試,從中選出最優(yōu)。
一旦你有了一個滿意的模型結(jié)構(gòu),或許它就可以使實現(xiàn)運行地更高效(在短時間內(nèi)覆蓋更多的數(shù)據(jù))。比如說,在本教程中使用的簡單代碼,實際運行速度都不錯,因為我們使用Python來讀取和填裝數(shù)據(jù),而這些在TensorFlow后臺只需執(zhí)行非常少的工作。如果你發(fā)現(xiàn)你的模型在輸入數(shù)據(jù)時存在嚴重的瓶頸,你可以根據(jù)自己的實際問題自行實現(xiàn)一個數(shù)據(jù)閱讀器,參考?新的數(shù)據(jù)格式。
如果I/O問題對你的模型已經(jīng)不再是個問題,并且想進一步地優(yōu)化性能,或許你可以自行編寫TensorFlow操作單元,詳見?添加一個新的操作。請自行調(diào)節(jié)以上幾個過程的標(biāo)準,使模型在每個運行階段有更好地性能。
總結(jié)
在本教程中我們介紹了word2vec模型,它在解決詞嵌套問題中具有良好的性能。我們解釋了使用詞嵌套模型的實用性,并且討論了如何使用TensorFlow實現(xiàn)該模型的高效訓(xùn)練。總的來說,我們希望這個例子能夠讓向你展示TensorFlow可以提供實驗初期的靈活性,以及在后期優(yōu)化模型時對模型內(nèi)部的可操控性。
總結(jié)
以上是生活随笔為你收集整理的TensorFlow教程之完整教程 2.7 字词的向量表示的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tensorflow搞一个聊天机器人
- 下一篇: 深度学习利器:TensorFlow与NL