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