小白看Word2Vec的正确打开姿势|全部理解和应用
有個用心的讀者最近做了一篇論文,想知道Word2Vec的相關理論和應用方法,作為一個有強迫癥的我,去翻查了大量的文獻資料,決定從Word2Vec的上下文來溫習一下這個NLP的基礎以及做相關的知識體系的基本構建,為做Word2Vec的朋友提供一個參考。
內容目錄:
一、 Word2Vec的用途調查
對接觸到一個新的領域,個人的學習方法是自上往下去逐步深挖,畢竟每個人的時間都比較有限,從應用層,一直挖到算法層,可能已經能讓我們很好的去復現一篇論文,那么從算法層挖到優化層,就可以很好的去發表一篇論文。由于篇幅限制,這里我們只從應用層挖到算法層,對于想繼續深入研究的大牛可以繼續往下研究。廢話不多說:我們先看看這個東西可以做什么用。作為平常喜歡檢索的我,看看一些標題黨就明白了:
使用Word2vec進行音樂推薦?towardsdatascience.com
?
文本數據深度學習方法的動手直觀方法-Word2Vec,GloVe和FastText?towardsdatascience.com
?
使用Word2Vec和Xgboost查找類似的Quora問題?towardsdatascience.com
?
使用Word2Vec更好地嵌入分類功能?towardsdatascience.com
?
使用word2vec分析新聞頭條并預測文章成功?towardsdatascience.com
?
使用Python進行的另一種Twitter情緒分析-第11部分(CNN + Word2Vec)?towardsdatascience.com
?
使用Word2vec構建推薦系統?medium.com
?
以上這些都是medium中的數據科學軟文,寫的都很好,這里只是看看大家都在用Word2Vec研究啥。大概可以看到大部分也都是做推薦和分類的系統的模型。Word2Vec只不過是我們深度學習中做推薦系統的一種。將詞向量用于
- 語言建模
- 聊天機器人
- 機器翻譯
- 問題回答
- … 還有很多
再細分來說他是針對NLP的一個范疇。接下來我們就對Word2Vec做一個定義:
2. Word2Vec是什么?為什么需要他?
NLP前沿實際上都嚴重依賴于單詞向量。現在讓我們討論單詞向量必須具有什么樣的含義才能使模型更好。使用單詞向量時,語義上接近的單詞在模型中似乎是相似的計算。
單詞嵌入是文檔詞匯表最流行的表示形式之一。它能夠捕獲文檔中單詞的上下文,語義和句法相似性,與其他單詞的關系等。
詞嵌入到底是什么?廣義的說,它們是特定單詞的向量表示。話雖如此,接下來是如何生成它們?更重要的是,它們如何捕獲上下文?
單詞向量是單詞的數字表示形式,保留了單詞之間的語義關系。例如,貓一詞的向量與狗一詞的向量非常類似。但是,鉛筆的向量將與cat的詞向量大不相同。這種相似性是由在相同上下文中使用所討論的兩個單詞(即[cat,dog]或[cat,pencil])的頻率定義的。例如,考慮以下句子,
我認為我不需要在上述句子中拼寫出奇數,而顯然需要用鉛筆來拼寫為遺漏詞。你為什么覺得這是一個奇怪的句子?拼寫很好,語法正確,那為什么呢?這是因為上下文,使用的鉛筆一詞不正確。這應該使您相信單詞上下文對單詞本身的影響。詞向量算法使用詞的上下文來學習詞的數字表示,以便在相同上下文中使用的詞具有相似的詞向量。
Word2Vec是使用淺層神經網絡學習單詞嵌入的最流行技術之一。它是由Tomas Mikolov于2013年在Google上開發的。
考慮以下類似的句子:Have a good day?和?Have a great day。它們幾乎沒有不同的含義。如果我們構建一個詳盡的詞匯表(我們稱其為V),則其V = {Have, a, good, great, day}。
現在,讓我們為V中的每個單詞創建一個單編碼的矢量。我們的單編碼的矢量的長度等于V的大小(= 5)。除了索引中代表詞匯表中相應單詞的元素之外,我們將有一個零向量。該特定元素將是一個。下面的編碼可以更好地說明這一點。
Have= [1,0,0,0,0]`; a = [0,1,0,0,0]`; good = [0,0,1,0,0]`; great = [0,0,0,1,0]`; day = [0,0,0,0,1]`(`代表轉置)如果我們嘗試可視化這些編碼,我們可以想到一個5維空間,其中每個單詞占據一個維,而與其余單詞無關(沿著其他維沒有投影)。這意味著‘good’ and ‘great’ 和 ‘day’ and ‘have’不一樣,這是不正確的。
它將「字詞」轉換成「向量」形式,可以把對文本內容的處理簡化為向量空間中的向量運算,計算出向量空間上的相似度,來表示文本語義上的相似度。
- word2vec計算的是余弦值?(cosine),距離范圍為0–1之間,值越大代表兩個詞關聯度越高。
- 詞向量:用Distributed Representation表示詞,通常也被稱為「Word Representation」或「Word Embedding」。
我們的目標是使上下文相似的單詞占據緊密的空間位置。在數學上,此類向量之間的角度的余弦值應接近1,即角度接近0。如下圖所示:
google image : 語義相近的放在同一個空間
這就是生成分布式表示的想法。直觀地,我們引入了一個單詞對其他單詞的某種依賴性。在該詞的上下文中的詞將在這種依賴性中獲得更大的比重。在one hot encoding representations中,所有的單詞是獨立彼此的,如前面提到的。
3. Word2Vec如何工作?
Word2Vec是一種構造此類嵌入的方法。可以使用兩種方法(都涉及神經網絡)來獲得它:
- Skip Gram
- Common Bag Of Words (CBOW)
CBOW模型:此方法將每個單詞的上下文作為輸入,并嘗試預測與上下文相對應的單詞。考慮我們的例子:Have a great day.
讓輸入到神經網絡這個詞為great。注意,這里我們試圖使用單個上下文輸入單詞great預測目標單詞(d?ay?)。更具體地說,我們使用輸入字的一種熱編碼,并與目標字的一種熱編碼(d?ay)相比,測量輸出誤差。 在預測目標詞的過程中,我們學習目標詞的向量表示。
讓我們更深入地研究實際架構。
CBOW模型
看不懂沒關系,后面詳細敘述:
Skip-Gram model:
Skip-Gram model試圖預測給定單詞的直接鄰居。它看起來前面一個單詞,后面一個單詞,或者兩個前面,或者其他一些變化。我們將要建模的單詞用作輸入X,并將周圍的單詞用作目標輸出Y。
一旦我們可以相當準確地預測周圍的單詞,就刪除輸出層,并使用隱藏層獲取我們的單詞向量。這是一個很酷的黑客工具,可以產生非常有趣的結果。
Skip-Gram model
這看起來像多上下文CBOW模型剛剛被翻轉。在某種程度上是對的。
我們將目標詞輸入網絡。該模型輸出C個概率分布。這是什么意思?
對于每個上下文位置,我們獲得V個概率的C個概率分布,每個單詞一個。
在這兩種情況下,網絡都使用反向傳播進行學習。詳細的數學可以在這里找到,接下來到了正式的東西了!
4. Word2Vec的知識大綱
Word2Vec的知識大綱,清晰的大圖在文末獲取
4.1 One-Hot編碼
什么是One-Hot 編碼,這個簡單的編碼方法處理可枚舉的特征時還是很有用的。
One-Hot 編碼,又稱一位有效編碼,其方法是使用N位狀態寄存器來對N個狀態進行編碼,每個狀態都有它獨立的寄存器位,并且在任意時候,其中只有一位有效。舉個例子,假設我們有四個樣本(行),每個樣本有三個特征(列),如圖:
我們的feature_1有兩種可能的取值,比如是男/女,這里男用1表示,女用2表示。feature_2 和feature_3各有4種取值(狀態)。
one-hot編碼就是保證每個樣本中的單個特征只有1位處于狀態1,其他的都是0。上述狀態用one-hot編碼如下圖所示:
說白了就是,一個特征有多少種可能的取值,那么就用多少位二進制表示,所以可以看到,這種編碼方法只適用于可枚舉完的特征,對于連續特征沒法完全枚舉的,這個時候需要靈活處理下,比如對某個范圍內的數當成一個值。
再考慮幾個例子,比如有三個特征:
["male", "female"] ["from Europe", "from US", "from Asia"] ["uses Firefox", "uses Chrome", "uses Safari", "uses Internet Explorer"]將它換成獨熱編碼后,應該是:
feature1=[01,10] feature2=[001,010,100] feature3=[0001,0010,0100,1000]優缺點分析
- 優點:一是解決了分類器不好處理離散數據的問題,二是在一定程度上也起到了擴充特征的作用。
- 缺點:在文本特征表示上有些缺點就非常突出了。首先,它是一個詞袋模型,不考慮詞與詞之間的順序(文本中詞的順序信息也是很重要的);其次,它假設詞與詞相互獨立(在大多數情況下,詞與詞是相互影響的);最后,它得到的特征是離散稀疏的。
為什么得到的特征是離散稀疏的?
上面舉例比較簡單,但現實情況可能不太一樣。比如如果將世界所有城市名稱作為語料庫的話,那這個向量會過于稀疏,并且會造成維度災難。
- 杭州 [0,0,0,0,0,0,0,1,0,……,0,0,0,0,0,0,0]
- 上海 [0,0,0,0,1,0,0,0,0,……,0,0,0,0,0,0,0]
- 寧波 [0,0,0,1,0,0,0,0,0,……,0,0,0,0,0,0,0]
- 北京 [0,0,0,0,0,0,0,0,0,……,1,0,0,0,0,0,0]
在語料庫中,杭州、上海、寧波、北京各對應一個向量,向量中只有一個值為1,其余都為0。
可以看到,當城市數比較大的時候,每一個城市表示的向量是非常長的,這就導致了很大的浪費,因為里面一大堆0幾乎是沒有用的。
一個最簡單粗暴的方法就是降維了,比如PCA操作,降維后的特征肯定就不是0-1的特征了,而是小數表示的特征,這樣才能用很低的維度覆蓋大的特征區間。
當然降維的方法不止PCA,還有很多,我們要說的word2vec就是一種。word2vec
說起word2vec,首先需要簡單理解下基于神經網絡的自編碼模型,自編碼,其實就是一種降維方法。基礎自編碼的網絡結構如下:
網絡的輸入就是一組特征,對應到本文就是一組0-1串的特征,輸出維度和輸入維度一樣,中間有一層隱含層映射,我們的目的就是訓練網絡使得輸出X 盡可能等于輸入X。訓練好以后,任意一個x進入模型都可以得到中間層的輸出結果,此時中間層的輸出結果就可以認為是降維后的結果。像本圖,就是一個4維降二維
因為word2vec是NLP里面應用的,是對詞的一個編碼,NLP里面一個很大的特點是什么呢?就是一段話中,一個詞的表示是和上下文相關的。也就是說這是一個帶有時間先后與相對順序的表示。那么既要實現上面的降維,又要兼顧詞的先后順序關系,word2vec就是要解決這樣的問題。
怎么解決的?首先還是有一個基礎的神經網絡自編碼模型:
那么怎么考慮上下文的信息呢?很簡單,輸入的時候不光是一個詞,而是上下文多個詞一起當成輸入:
5. CBOW模型
這是一種多對一的模型(CBOW),還有一種一對多(Skip-Gram)模型,我們先說這種多對一模型。CBOW的訓練模型如圖所示:
這個網絡結構就是最開始的自編碼網絡,只不過它的輸入不是一次性輸入的,而是好幾批輸入的,而隱含層的結果是好幾批輸入的加權平均值。
詳細的過程為:
1 輸入層:上下文單詞的onehot.
2 這些單詞的onehot分別乘以共享的輸入權重矩陣W.
3 所得的向量相加求平均作為隱層向量.
4 乘以輸出權重矩陣W {NV}
5 得到輸出向量。
6 輸出向量與真實單詞的onehot做比較,誤差越小越好。
這樣就可以訓練網絡了。訓練完畢后,輸入層的每個單詞與矩陣W相乘得到的向量的就是我們想要的詞向量(word embedding),這個矩陣(所有單詞的word embedding)也叫做look up table(其實這個look up table就是矩陣W自身),也就是說,任何一個單詞的onehot乘以這個矩陣都將得到自己的詞向量。有了look up table就可以免去訓練過程直接查表得到單詞的詞向量了。
相比于原始的自編碼,word2vec最大的不同點在于輸入上,要考慮先后關系的自編碼,這一點值得好好理解下。
這是多對一的方式,還有一種一對多的方式:同理,目的為了保證上下文的順序關系的同時實現降維。
word2vec訓練最終我們需要的是訓練出來的權重矩陣,有了此權重矩陣就能實現輸入單詞的onehot降維,同時這個降維還包含了上下文的先后循序關系。這就是word2vec。
考慮由[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q, r,s,t,u,v,w,x,y,z],進一步令整數0至25代表各自的字母。實施CBOW時,將窗口大小保持為2,我們可以看到“ a”與“ b”和“ c”有關,“ b”與“ a”,“ c”和“ d”有關,依此類推。因此,代表輸入詞的一個熱向量將具有尺寸[26,1]。借助該模型,我們將找到大小為[10,1]的密集和分布向量。嵌入向量的大小是任意選擇的。
下圖說明了上下文和目標詞。
CBOW和Skip-gram模型的排列。字符和相應的整數分為輸入和目標列表。對于每一列,第一列代表輸入字符,每個子列表中的其余項目都是輸入的目標。
在窗口大小為2的情況下,黑色區域表示沒有共現,而白色區域表示字符一起出現。#還要注意對角線對稱性-意味著從a到b的共現意味著從b到a的共現,但是描述了這些關系不同的軸。
Word2Vec是一個概率模型。該模型的關鍵組成部分是2個權重矩陣。第一矩陣(w1)的行和第二矩陣(w2)的列分別嵌入輸入詞和目標詞。給定選定的輸入單詞,然后將這兩個單詞向量的乘積用于獲得成為目標單詞的概率。在訓練之后,使用梯度下降來優化這些嵌入矢量,從而使針對真實目標的概率最大化。顯然,矩陣w1和w2是分解概率矩陣,該概率矩陣與共現矩陣非常相似。
下圖說明并說明了模型。
Word2Vec模型的示意圖。輸入和輸出向量的大小為V,而隱藏向量(嵌入)的大小為N
在此插圖中,模型正在學習將6個字符(“ a”至“ f”)嵌入3維嵌入向量中。A.窗口大小為2的這些字符的同時出現矩陣,同時出現表示為存在或不存在。(大小6、6)B.權重矩陣w1-換位。矩陣w1的每一行都嵌入一個單詞的向量,因為一個熱向量唯一選擇w1的對應行(或W1轉置的col)C。一個熱向量的矩陣,每一列代表一個詞/項D。w1和輸入矩陣的乘積得到矩陣h(隱藏層)。在這里,整個輸入矩陣都是一個單位矩陣,只是將權重矩陣w1作為隱藏矩陣h傳遞。然而,不必是一個單位矩陣,輸入矩陣的順序和大小(以及隱藏層)可以是不同的E。權重矩陣w2-已轉置(大小6,3)。矩陣w2的每一列都緊密代表目標詞F。隱藏層-h,與之前G中描述的w1相同。w2的每一行-轉置了帶有隱藏列(嵌入輸入詞)的乘積,輸出的分數為vocabH的大小。如所提到的與隱藏1列w2_transposed相互作用的所有行-在記分矩陣,總產物中的一列的結果w2_transposed和h是矩陣S(尺寸6,δ)I.使用SoftMax被施加到記分矩陣。列中的每個條目都轉換為概率J。概率矩陣-該矩陣的列中的每個項目表示在輸入單詞L的情況下成為目標單詞的概率。錯誤-真實索引位置的概率應最大化,錯誤比較分配給與真實目標M對應的索引的概率來計算。反向支撐—開始時,權重是隨機初始化的,因此所有目標的概率都很低且相似。經過訓練,梯度的反向傳播和權重的優化,目標周圍的概率很密集,其他地方的概率接近于0。6. Implemetation in Pytorch
https://towardsdatascience.com/word2vec-made-easy-139a31a4b8ae?towardsdatascience.com
?
7. 從原始文本到詞向量:高級方法
現在,憑著扎實的直覺,我們將首先討論Word2vec算法的高級機制。我們將在后面的部分中完善細節,直到可以確定我們知道如何實現Word2vec算法為止。為了以無監督的方式學習單詞向量(即沒有人工標記數據),我們必須定義并完成某些任務。這是這些任務的高級列表。
這個看似簡單的過程將導致學習非常強大的單詞向量。讓我們進入上述管道的每個步驟的精妙之處。
1. 從原始文本創建結構化數據
這不是一個非常困難的任務。這是對原始文本的簡單操作,以將其放入特定的結構。想想下面的句子。
The cat pushed the glass off the table
從這句話創建的數據如下所示。句子后的每一行代表一個數據點。藍色框代表one-hot input word(中間單詞,稱為目標單詞),紅色框代表the one-hot output word(上下文窗口中除中間單詞之外的任何單詞,稱為上下文單詞)。從單個上下文窗口創建兩個數據點(正負1的滑窗)。上下文窗口的大小由用戶定義。上下文窗口大小越大,模型的性能越好。但是,當上下文窗口大小較大時,隨著數據量的增加,您將付出計算時間。不要將目標詞與神經網絡的目標(正確的輸出)混淆,這是兩件事。
為Word2Vec滑窗結構化數據的方法
2. 定義嵌入層和神經網絡
神經網絡用于從上面定義的結構化數據中學習。但是,它帶有一個轉折!為了清楚起見,您具有以下組件。
- 一批輸入表示為one-hot vectors
- 一批輸出表示為one-hot vectors(僅在訓練階段)
- 嵌入層
- 神經網絡
如果您不了解最后兩個組件的性能以及工作方式,則不必害怕。我們將探究這些組件中的每一個,以了解它們的作用。
3. Embedding layer: stores all the word vectors
在我們的議程中,首先是嵌入層。嵌入層存儲在詞匯表中找到的所有單詞的單詞向量。如您所見,這是一個巨大的矩陣(of size[vocabulary size x embedding size])。嵌入大小是用戶可調的參數。數值越高,模型的性能越好。但是,超過某個點(例如,嵌入大小為500),您將不會獲得令人瞠目結舌的性能/大小增益。這個巨大的矩陣是隨機初始化的(就像一個神經網絡一樣),并在優化過程中一點一點地進行調整,以揭示強大的單詞向量。這就是它的樣子。
What the embedding layer looks like
4. Neural network: maps word vectors to outputs
接下來的是我們模型的最后一個樂高積木;神經網絡。在訓練過程中,神經網絡將輸入一個單詞并嘗試預測輸出單詞。然后,使用損失函數,我們對模型的錯誤分類進行懲罰,并對模型的正確分類進行獎勵。我們將要求限制為一次處理單個輸入和單個輸出。但是實際上,您要分批處理數據(例如64個數據點)。讓我們描述一下訓練過程中使用的確切過程:
要注意的一件事是,在計算預測時,我們使用softmax激活將預測歸一化為有效概率分布。
5. Fitting all together: inputs to model to outputs
了解了Word2vec算法的所有基本要素后,我們可以將所有部分放在一起。這樣,一旦訓練好該模型,我們要做的就是將嵌入層保存到磁盤上。然后,我們可以在一天中的任何時候享受語義保留的單詞向量。在下面,我們看到了整個圖片。
模型如何看待其最終形式
數據的這種局部排列和模型布局被稱為skip-gram algorithm;Word2vec算法。這就是我們要重點關注的。另一種算法稱為連續詞袋(CBOW)模型。
6. Defining a loss function: to optimize the model
到目前為止,我們尚未討論的關鍵信息之一就是損失函數。通常,標準softmax交叉熵損失是分類任務的良好損失函數。對于Word2vec模型,使用這種損失不是很實際,對于諸如情感分析(您有2種可能的輸出:肯定或否定的結果)這樣的簡單任務而言,這不是很實用。在這里事情會變得時髦。在消耗數十億個單詞的真實單詞任務中,詞匯量可以輕松增長到100,000甚至更多。這使得softmax歸一化的計算繁重。這是因為softmax的完整計算需要針對所有輸出節點計算交叉熵損失。
因此,我們正在尋找一種更智能的替代方法,稱為“?采樣softmax損失”(sampled softmax loss)。在采樣的softmax損失中,執行以下操作。請注意,與標準softmax交叉熵損失相比,有很多變化。首先,計算給定目標單詞的真實上下文單詞ID和對應于真實上下文單詞ID的預測值之間的交叉熵損失。然后,我們加上K根據一些噪聲分布采樣的負樣本的交叉熵損失。概括地說,我們將損失定義如下:
這SigmoidCrossEntropy是我們可以在單個輸出節點上定義的損耗,而與其余節點無關。由于我們的詞匯量可能會很大,因此非常適合我們的問題。我不會詳細介紹這種損失的細節。您無需了解如何實現此功能,因為這些功能可以作為TensorFlow中的內置功能使用。但是了解損耗所涉及的參數(例如K)很重要。采樣的softmax損失通過考慮兩種類型的實體來計算損失:
- 預測向量中真實上下文單詞ID給出的索引(上下文窗口中的單詞)
- K?指示單詞ID并被視為噪音的索引(上下文窗口之外的單詞)
通過舉例說明,我將其進一步可視化。
獲取采樣的softmax層的正樣本和負樣本
?
8. Gensim Python: Skip-gram algorithm
Gensim是用于自然語言處理的開源python庫,首先,我們需要安裝genism軟件包。Gensim可在Linux,Windows和Mac OS X上運行,并且應在支持Python 2.7+和NumPy的任何其他平臺上運行。Gensim取決于以下軟件:
- Python?> = 2.7(經過2.7、3.5和3.6版測試)
- NumPy?> = 1.11.3
- SciPy?> = 0.18.1
- six?> = 1.5.0
- smart_open?> = 1.2.1
有兩種安裝方式。我們可以在終端中運行以下代碼來安裝genism軟件包。
pip install --upgrade gensim或者,對于Conda環境:
conda install -c conda-forge gensimWord2vec不是深度神經網絡,它將文本轉換為數字形式,深度神經網絡可以將其處理為輸入。
如何訓練word2vec模型
- 在帶有滑動窗口的訓練語料庫中移動:每個單詞都是一個預測問題。
- 目的是使用相鄰單詞來預測當前單詞(反之亦然)。
- 預測結果決定我們是否調整當前單詞向量。向量逐漸收斂到(希望)最優值。
數學
以下是word2vec嵌入背后的數學運算。輸入層是一鍵編碼的矢量,因此它在該單詞索引中得到“ 1”,在其他任何地方都得到“ 0”。當我們將此輸入向量乘以權重矩陣時,實際上是在抽出與該單詞索引對應的一行。此處的目的是取出重要的行,然后將其余的行扔掉。
這是word2vec工作原理的主要機制。
當我們使用Tensorflow / Keras或Pytorch進行此操作時,它們在此過程中有一個特殊的層稱為“嵌入層”。因此,我們不會自己做數學運算,只需要傳遞一鍵編碼的矢量,“嵌入層”就可以完成所有臟活。
預處理文本
現在,我們將為BBC新聞數據集實現word2vec嵌入。
- 我們使用Gensim訓練word2vec嵌入。
- 我們使用NLTK和spaCy預處理文本。
- 我們使用t-SNE可視化高維數據。
- We use spaCy for lemmatization.
- Disabling Named Entity Recognition for speed.
- Remove pronouns.
現在,我們可以看看前10個最常用的單詞。
sentences = [row.split() for row in df_clean['text_lemmatize_clean']] word_freq = defaultdict(int) for sent in sentences:for i in sent:word_freq[i] += 1sorted(word_freq, key=word_freq.get, reverse=True)[:10]在Gensim中實現Word2vec嵌入
- min_count:模型中要包含的單詞在語料庫中出現的最小次數。數字越大,語料庫中的單詞越少。
- window:句子中當前詞和預測詞之間的最大距離。
- size:特征向量的維數。
- workers:我知道我的系統有4個核心。
- model.build_vocab:準備模型詞匯。
- model.train:訓練單詞向量。
- model.init_sims():當我們不打算進一步訓練模型時,我們將使用以下代碼行使模型更具存儲效率。
探索模型
- 查找與“經濟”最相似的詞
?
- 這兩個詞彼此有多相似?
w2v_model.wv.similarity('company','business')
代碼地址:
https://github.com/zjgulai/PyCon-Canada-2019-NLP-Tutorial?github.com
?
9. TensorFlow implementation: Skip-gram algorithm
在這里,我們將重新討論剛剛討論的實現。在本節中,我們將實現以下內容。
- 數據生成器
- Skip-gram algorithm模型(使用TensorFlow)
- 運行skip-gram算法
1. 數據產生器
首先讓我們了解如何生成數據。因為我們已經討論了數據生成的內部機制,所以我們將不討論該代碼的細節。這只是將邏輯轉換為實現。
def generate_batch(batch_size, window_size):global data_index # two numpy arras to hold target words (batch)# and context words (labels)batch = np.ndarray(shape=(batch_size), dtype=np.int32)labels = np.ndarray(shape=(batch_size, 1), dtype=np.int32)# span defines the total window sizespan = 2 * window_size + 1 # The buffer holds the data contained within the spanqueue = collections.deque(maxlen=span)# Fill the buffer and update the data_indexfor _ in range(span):queue.append(data[data_index])data_index = (data_index + 1) % len(data)for i in range(batch_size // (2*window_size)):k=0 # Avoid the target word itself as a prediction for j in list(range(window_size))+list(range(window_size+1,2*window_size+1)):batch[i * (2*window_size) + k] = queue[window_size]labels[i * (2*window_size) + k, 0] = queue[j]k += 1 # Everytime we read num_samples data points, update the queuequeue.append(data[data_index])# If end is reached, circle back to the beginningdata_index = (data_index + np.random.randint(window_size)) % len(data)return batch, labels2. Defining the skip-gram model
batch_size = 128 embedding_size = 64 window_size = 4 num_sampled = 32 # Number of negative examples to sample.將batch_size在我們在給定的時間過程定義的數據點的數量。然后,embedding_size是單詞向量的大小。下一個超參數window_size定義了我們上面可視化的上下文窗口的大小。最后,num_sampled定義損失函數(K)中的負樣本數。然后,我們為輸入和輸出定義TensorFlow占位符。
tf.reset_default_graph() #訓練輸入數據(目標單詞ID)。 train_dataset = tf.placeholder(tf.int32,shape = [batch_size])#訓練輸入標簽數據(上下文單詞ID) train_labels = tf.placeholder(tf.int32,shape = [batch_size,1])在這里,train_dataset獲取batch_size代表所選目標單詞集合的單詞ID列表。最后,train_labels代表batch_size所選目標詞的對應上下文詞的列表。接下來,我們定義定義模型所需的模型參數:嵌入層以及神經網絡的權重和偏差。
############################################# model變量 ############################################### #嵌入層embeddings = tf.Variable(tf.random_uniform([vocabulary_size,embedding_size],-1.0,1.0)) #神經網絡權重和偏差softmax_weights = tf.Variable(tf.truncated_normal([vocabulary_size,embedding_size],stddev / math.sqrt(embedding_size)) ) softmax_biases = tf.Variable(tf.random_uniform([vocabulary_size],-0.01,0.01))我們將嵌入層定義為TensorFlow變量:embeddings。然后定義神經網絡的權重(softmax_weights)和偏差(softmax_biases)。此后,我們定義了將嵌入層連接到神經網絡以共同優化嵌入層和神經網絡所需的關鍵操作。
# Look up embeddings for a batch of inputs. embed = tf.nn.embedding_lookup(embeddings, train_dataset)該tf.nn.embedding_lookup函數以我們的嵌入層作為輸入和一組單詞ID(train_dataset),并將相應的單詞向量輸出到變量embed。定義了嵌入查找函數后,我們可以定義上面討論的采樣softmax損失函數。
################################################ # Computes loss # ################################################ loss = tf.reduce_mean(tf.nn.sampled_softmax_loss( weights=softmax_weights, biases=softmax_biases, inputs=embed, labels=train_labels, num_sampled=num_sampled, num_classes=vocabulary_size) )在這里,該tf.nn.sampled_softmax_loss函數采用一組權(softmax_weights),偏差(softmax_biases),與在中找到的單詞ID相對應的一組單詞向量train_dataset,正確的上下文單詞的ID(train_labels),噪聲樣本的數量(num_sampled)和詞匯量(vocabulary_size)。通過輸出計算操作和定義的損失,我們可以定義優化器,以針對嵌入層和神經網絡的參數優化損失。
################################################ # Optimization # ################################################ optimizer = tf.train.AdamOptimizer(0.001).minimize(loss)Then we get the normalized embedding layer by making the vector magnitude equal to 1.
################################################ # For evaluation # ################################################ norm = tf.sqrt(tf.reduce_sum(tf.square(embeddings), 1, keepdims=True)) normalized_embeddings = embeddings / norm3. 運行代碼
在這里,我們將討論有關如何運行先前定義的TensorFlow模型的詳細信息。首先,我們定義a?session,然后隨機初始化所有TensorFlow變量。
num_steps = 250001 session = tf.InteractiveSession() # Initialize the variables in the graph tf.global_variables_initializer().run() print('Initialized') average_loss = 0現在,對于預定義的步驟數,我們生成了一批數據:目標詞(batch_data)和上下文詞(batch_labels)。
for step in range(num_steps): # Generate a single batch of databatch_data, batch_labels = generate_batch( batch_size, window_size)然后,對于每個生成的批次,我們通過運行優化嵌入層和神經網絡session.run([optimize, loss],...)。我們還得出了損失,以確保其隨著時間的推移而減少。
# Optimize the embedding layer and neural network # compute lossfeed_dict = {train_dataset : batch_data, train_labels : batch_labels}_, l = session.run([optimizer, loss], feed_dict=feed_dict)在這里,每隔5000步,我們將平均損失打印出來,作為視覺輔助。
if (step+1) % 5000 == 0:if step > 0:average_loss = average_loss / 5000print('Average loss at step %d: %f' % (step+1, average_loss))average_loss = 0最后,我們得到了最終的嵌入,隨后將其用于某些單詞的可視化。
sg_embeddings = normalized_embeddings.eval() session.close()最后,如果使用諸如t-SNE的流形學習算法可視化嵌入,您將獲得以下內容。
如您所見,與貓有關的單詞是在特定方向上找到的,而與狗有關的單詞是在不同方向上找到的。介于兩者之間的單詞(例如動物或寵物)介于這兩個方向之間,這幾乎是我們所需要的。
代碼地址:
https://github.com/zjgulai/exercises_thushv_dot_com?github.com
?
10.結論
這使我們結束了對話。單詞向量是單詞的非常強大的表示形式,可幫助機器學習模型更好地執行。我們經歷了數據生成過程以及Word2vec模型中發現的不同組件。然后,我們討論了Word2vec算法的一種特定變體;a skip-gram model。我們在TensorFlow中完成了算法的實現。最后,我們對嵌入進行了可視化,發現學習到的嵌入實際上描述了一些有用的語義。您可以在下方找到代碼執行文件。
針對word2vec的主要訓練算法有兩種,一種是連續詞袋(CBOW),另一種稱為跳躍語法。這兩種方法之間的主要區別是CBOW使用上下文預測目標詞,而skip-gram使用單詞預測目標詞。通常,與CBOW方法相比,skip-gram方法具有更好的性能,因為它可以捕獲單個單詞的兩種語義。例如,它將具有兩種用于Apple的矢量表示,一種用于公司,另一種用于水果。
總結
以上是生活随笔為你收集整理的小白看Word2Vec的正确打开姿势|全部理解和应用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: word2vec如何得到词向量
- 下一篇: 产品包装