【自然語言處理】word2vec/doc2vec基礎學習以及簡單實踐

一、前言

        當我們要說起word2vec,那就不得不再提word2vec之前說一下關於“文本向量化”這個概率啦。既然算法是拿來用的,不言而喻,您肯定會問用在哪裏?這就是我們要提“文本向量化”這個概念的意圖奧。首先:文本向量化的方法有很多,從之前的基於統計的方法,到時下流行的基於神經網絡的方法,而掌握好word2vec詞向量算法和doc2vec文本向量化算法是學習文本向量化的再好不過的方式啦。
       那接下來咋們就從文本向量化的概念說起吧,走你、、、、、、


二、 向量化算法word2vec

2.1 引言

       詞袋(Big of Word)模型是最早的以詞語爲基本處理單位的文本向量化方法。
       詞袋的原理:
       1、兩個簡單的文本

  • John likes to watch movies, Mary likes too.
  • John also likes to watch football games.

       2、基於上述兩個文檔出現的詞語,我們來構建詞典庫:

{“John”:1,“likes”:2,“to”:3,“watch”:4,“movies”:5,“also”:6,“football”:7,“games”:8,“Mary”:9,“too”:10}

       3、構建向量
       此詞典包含10個單詞,每個單詞有唯一的索引,那麼每個文本我們可以使用一個10維的向量來表示。如下所示:

[1,2,1,1,1,0,0,0,1,1]
[1,1,1,1,0,1,1,1,0,0]

       4、向量說明

該向量與原來文本中單詞出現的順序沒有任何關係,,而是詞典中每個單詞在文本中出現的頻率。
那麼關於詞袋的問題就來了:

1:維度過大。很顯然,如果上述例子詞典庫包含10000個單詞,那麼每個文本需要用10000維的向量表示,也就是說除了文本中出現的詞語位置不爲0,其餘9000多的位置均爲0,這麼高維度的向量嚴重影響到計算速度。
2:無法保留詞序信息。
3:存在語義鴻溝的問題(詞序信息發生改變,自然語義也就發生的變化)

所以、根據詞袋的不足之處,就引出了word2vec。那麼接下來我們就開始對word2vec的學習。


2.2 word2vec原理

1、詞向量(word2vec)技術就是爲了利用神經網絡從大量無標註的文本域中提取有用的信息從而產生的
2、 word2vec主要解決的問題是,把詞典中的詞表示成一個詞向量(或詞嵌入,word embedding,把詞嵌入到一個向量空間中),這個向量是低維的、稠密的。通過研究詞向量的性質,可以得到詞之間的各種性質,如距離、相似性等。好吧,以上感覺解釋的太過於精簡了,那我們繼續往下了解。


簡而言之,詞向量就是將詞轉化爲稠密向量,並且對於相似的詞,其對應的詞向量也相近。


根據上述所介紹的“詞袋”,它就是將詞語符號化,所以詞袋模型是不包含任何語義信息的。如何將“詞表示”包含語義信息也就是接下來我們首先要介紹的。

2.3 詞的表示

       在自然語言處理任務中,首先需要考慮詞如何在計算機中表示。通常,有兩種表示方式:one-hot representation和distribution representation。翻譯過來就是:離散表示和分佈式表示
        one-hot represention:也就是向量中每一個元素都關聯着詞庫中的一個單詞,指定詞的向量表示爲:其在向量中對應的元素設置爲1,其他的元素設置爲0(每個詞表示爲一個長向量。這個向量的維度是詞表大小,向量中只有一個維度的值爲1,其餘維度爲0,這個維度就代表了當前的詞) 。採用這種表示無法對詞向量做比較,後來就出現了分佈式表徵。
       distribution representation:word2vec中就是採用分佈式表徵,在向量維數比較大的情況下,每一個詞都可以用元素的分佈式權重來表示,因此,向量的每一維都表示一個特徵向量,作用於所有的單詞,而不是簡單的元素和值之間的一一映射。這種方式抽象的表示了一個詞的“意義”。 向量的長度爲詞典的大小,向量的分量只有一個 1,其他全爲 0, 1 的位置對應該詞在詞典中的位置,例如

“話筒”表示爲 [0 0 0 1 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 0 …]

       也正是這些原因,Hinton在 1986 年提出了Distributional Representation,可以克服 one-hot representation的缺點。解決“詞彙鴻溝”問題,可以通過計算向量之間的距離(歐式距離、餘弦距離等)來體現詞與詞的相似性 。分佈式表示所謂基本想法是直接用一個普通的向量表示一個詞,這種向量一般長成這個樣子:[0.792, −0.177, −0.107, 0.109, −0.542, …],常見維度50或100。

優點:解決“詞彙鴻溝”問題
缺點:訓練有難度。沒有直接的模型可訓練得到。所以採用通過訓練語言模型的同時,得到詞向量 。
       當然一個詞怎麼表示成這麼樣的一個向量是要經過一番訓練的,訓練方法較多,word2vec是其中一種。值得注意的是,每個詞在不同的語料庫和不同的訓練方法下,得到的詞向量可能是不一樣的。


用詞向量表示詞並不是Word2vec的首創,很久之久就出現了。最早的詞向量是很冗長,它使用詞向量維度大小爲整個詞彙表的大小(詞袋的原理),對於每個具體的詞彙表中的詞,將對應的位置置爲1。比如我們有下面的5個詞組成的詞彙表,詞"Queen"的序號爲2, 那麼它的詞向量就是(0,1,0,0,0)。詞"Woman"的詞向量就是(0,0,0,1,0)。這種詞向量的編碼方式我們一般叫做1-of-N representation或者one hot representation.

在這裏插入圖片描述

One hot representation用來表示詞向量非常簡單,但是卻有很多問題。最大的問題是我們的詞彙表一般都非常大,比如達到百萬級別,這樣每個詞都用百萬維的向量來表示簡直是內存的災難。這樣的向量其實除了一個位置是1,其餘的位置全部都是0,表達的效率不高,能不能把詞向量的維度變小呢?

Distributed representation可以解決One hot representation的問題,它的思路是通過訓練,將每個詞都映射到一個較短的詞向量上來。所有的這些詞向量就構成了向量空間,進而可以用普通的統計學的方法來研究詞與詞之間的關係。這個較短的詞向量維度是多大呢?這個一般需要我們在訓練時自己來指定。

比如下圖我們將詞彙表裏的詞用"Royalty",“Masculinity”, "Femininity"和"Age"4個維度來表示,King這個詞對應的詞向量可能是(0.99,0.99,0.05,0.7) 。當然在實際情況中,我們並不能對詞向量的每個維度做一個很好的解釋。

在這裏插入圖片描述
有了用Distributed Representation表示的較短的詞向量,我們就可以較容易的分析詞之間的關係了.


獨白:通過語言模型構建上下文與目標詞之間的關係是一種常見的方法。神經網絡詞向量模型就是根據上下文和目標詞之間的關係進行建模。在初期,詞向量只是訓練神經網絡語言模型過程中產生的副產品,而後神經網絡語言模型對後期詞向量的發展怪好有着決定性的作用。


爲了後面能夠更好的理解Word2vec,我們先來了解一下神經網絡語言模型。

三、神經網絡語言模型

神經網絡語言模型(Neural Network Language Model,NNLM) ,與傳統方法估算P(wiwi(n1),...wi1)P(w_i|w_{i-(n-1)},...w_{i-1})不同,NNLM模型直接通過一個神經網絡結構對n元條件概率進行估計(從概率角度出發)。NNLM的基本結構如下所示:
在這裏插入圖片描述
它包含三層:輸入層,隱藏層,輸出層。大體的操作過程是:

1、從語料庫中搜集一系列長度爲n的文本序列:wi(n1),...wi1,wiw_{i-(n-1)},...w_{i-1},w_i
2、假設這些長度爲n的文本序列組成的集合爲D
3、得到NNLM的目標函數:DP(ωiωi(n1),,ωi1)\sum_{D} P\left(\omega_{i} | \omega_{i-(n-1)}, \cdots, \omega_{i-1}\right)意思是:在輸入詞序列爲wi(n1),...wi1w_{i-(n-1)},...w_{i-1}的情況下,計算目標詞wiw_i的概率。

步驟
1、爲了解決詞袋模型數據稀疏問題,輸入層的輸入爲底維度、緊密的詞向量;輸入層的操作就是將詞序列wi(n1),...wi1w_{i-(n-1)},...w_{i-1}中的每個詞向量按順序拼接:

x=[v(wi(n1));;v(wi2);v(wi1)]x=\left[v\left(w_{i-(n-1)}\right) ; \cdots ; v\left(w_{i-2}\right) ; v\left(w_{i-1}\right)\right]

2、拼接完成之後,得到x,將x輸入到隱藏層得到h(x—>h),再將h接入到輸出層得到最後的輸出變量y,其中隱藏層變量h和輸出層變量y的計算如下所示:

h=tanh(b+Hx)h=\tanh (b+H x)y=b+Uhy=b+U h

說明:1、HH是輸入層到隱藏層的權重矩陣,維度:h×(n1)e|h|×(n-1)|e|;2、UU是隱藏層到輸出層的權重矩陣,維度:V+h|V|+|h|V|V|表示詞表的大小,其他絕對值符號類似;3、bb爲模型中的偏置頂。

3、NNLM模型中計算量最大的操作就是從隱藏層到輸出層的矩陣運算UhUh。輸出變量yy是一個V|V|維的向量,該向量的每個分量依次對應下一個詞爲詞表中某個詞的可能性。y(w)y(w)表示由HHLM模型計算得到的目標詞ww的輸出量,爲保證輸出y(w)y(w)的表示概率值,需要對輸出層進行歸一化操作。通常會在輸出層之後加上一個softmax函數,將yy轉成對應的概率值:

P(ωiωi(n1),,ωi1)=exp(y(ωi))k=1Mexp(y(ωk))P\left(\omega_{i} | \omega_{i-(n-1)}, \cdots, \omega_{i-1}\right)=\frac{\exp \left(y\left(\omega_{i}\right)\right)}{\sum_{k=1}^{M} \exp \left(y\left(\omega_{k}\right)\right)}

其中exp(y)是以e爲底的指數函數奧。

由於NNLM模型使用低維緊湊的詞向量對上文進行表示,這無疑解決了詞袋模型帶來的數據稀疏,語義鴻溝等問題,顯然NNLM模型是一種更好的n元語言模型;另外,在相似的上下文語境中,NNLM模型可以預測處相似的目標詞,而傳統模型無法做到這一點。
例如,在某語料中A=""A="一隻小狗躺在地毯上"出現了2000次,而B=""B="一隻貓躺在地毯上"出現了1次。
根據頻率計算概率,P(A)P(A)自然遠遠大於P(B)P(B),而語料AABB唯一的區別在於貓和狗,這兩個詞無論在語義和語法上都相似,而P(A)P(A)遠大於P(B)P(B)顯然是不合理的。如果採用NNLM模型計算則得到的P(A)P(A)P(B)P(B)是相似的,原因是:NNLM模型採用低維的向量表示詞語,假定相似的詞其詞向量也應該是相似的。

4、如步驟3中所述,輸出的y(wi)y(w_i)代表上文出現詞序列wi(n1),...wi1w_{i-(n-1)},...w_{i-1}的情況下,下一個詞爲wiw_i的概率,因此在語料庫DD中最大化y(wi)y(w_i)便是NNLM模型的目標函數:

wi(n1),iDlogP(ωiωi(n1),,ωi1)\sum_{w_{i-(n-1),i∈D}} \log P\left(\omega_{i} | \omega_{i-(n-1)}, \cdots, \omega_{i-1}\right)

一般使用隨機梯度下降算法對NNLM模型進行訓練。在訓練每個batch時,隨機從語料庫DD中抽取若干樣本進行訓練,梯度迭代公式:θ:θ+αlogP(ωtωt(n1),,ωt1)θ\theta : \theta+\alpha \frac{\partial \log P\left(\omega_{t} | \omega_{t-(n-1)}, \cdots, \omega_{t-1}\right)}{\partial \theta},其中,α\alpha是學習率;θ\theta是模型中設計的所有參數,包括NNLM模型中的權重,偏置以及輸入的詞向量。

關於梯度下降算法的學習,可以參考此篇博文

四、C&W模型

       NNLW模型的目標是構建一個語言概率模型,而C&W 則是以生成詞向量爲目標的模型。
在NNLM模型的求解中,最耗時的部分當屬隱藏層到輸出層的權重計算。由於C&W模型沒有采用語言模型的方式去求解詞語上下文的條件概率,而是直接對n元短語打分,這是一種更爲快速獲取詞向量的方式。
       C&W模型的核心機理是:如果n元短語在語料庫中出現過,那麼模型會給該短語打高分;如果是爲出現在語料庫中的短語則會得到較低的評分。


在這裏插入圖片描述
對於整個語料庫而言,C&W模型需要優化的目標函數:

(ω,c)DωVmax(0,1score(ω,c)+score(ω,c))\sum_{(\omega, c) \in D} \sum_{\omega^{\prime} \in V} \max \left(0,1-\operatorname{score}(\omega, c)+\operatorname{score}\left(\omega^{\prime}, c\right)\right)

說明

1、(w,c)(w,c)爲從語料庫中抽取出來的n元短語,爲了保證上下文詞數的一致性,nn應爲奇數;
2、ww是目標詞
3、c表示目標詞的上下文語境
4、ω\omega^{\prime}是從詞典中隨機抽取的一個詞語
5、C&W模型採用成對的詞語的方式對目標函數進行優化,
6、公式中可以看出,目標函數期望正樣本的得分比負樣本至少高一分,其中(w,c)(w,c)表示正樣本,(ω,c)(\omega^{\prime},c)表示負樣本。正樣本來自語料庫,負樣本是將正樣本序列中的中間詞替換成其他詞得到的。

       一般而言,用一個隨機的詞語替換正確文本序列的中間詞,得到新的文本序列基本上都是不符合語法習慣的錯誤序列,因此這種構造負樣本的方法是合理的。同時由於負樣本僅僅是修改了正樣本一個詞得來的,故其基本的語境沒有改變,因此不會對分類效果造成太大影響。
       與NNLM模型的目標詞在輸出層不同,C&W模型輸入層就包含了目標詞,其輸出層也變爲一個節點,該節點輸出值的大小代表n元短語的打分高低。相應的,C&W模型的最後一層運算次數是h|h| ,遠低於NNLM模型的v+h|v|+|h|次。綜合而言,較NNLM模型而言,C&W模型可大大降低運算量。
       到此,C&W模型的理論就學習到這裏啦,接下來我們繼續學習有關更高效獲取詞向量的CBOW模型。在學習連續詞袋之前,我們不得不先再次複習回顧一下詞向量基礎:


五、CBOW模型

爲了更高效的獲取詞向量:CBOW(Continuous Bag of-Words)模型是結合了NNLM和C&W模型的核心部分發展而來的語言模型。(CBOW:連續詞袋)

5.1 CBOW模型結構圖

在這裏插入圖片描述

1、從圖中不難看出,CBOW模型就只有兩層:輸入層,輸出層。
2、CBOW模型使用一段文本的中間詞作爲目標詞
3、CBOW模型使用上下文各詞的詞向量的平均值替代NNLM模型各個拼接的詞向量。
4、由於CBOW模型去除了隱藏層,所以其輸入層就是語義上下文的表示。
5、CBOW模型對目標詞的條件概率計算:
P(ωc)=exp(e(ω)Tx)oter exp(e(ω)Tx)P(\omega | c)=\frac{\exp \left(e^{\prime}(\omega)^{\mathrm{T}} x\right)}{\sum_{\text {oter }} \exp \left(e^{\prime}\left(\omega^{\prime}\right)^{\mathrm{T}} x\right)}
6、CBOW的目標函數與NNLM模型類似,具體爲最大化式:
(ω,c)DlogP(ω,c)\sum_{(\omega, c) \in D} \log P(\omega, c)

5.2 CBOW的輸入輸出

       CBOW模型的訓練輸入是某一個特徵詞的上下文無關的詞對應的詞向量,而輸出就是這個特定的一個詞的詞向量。
       比如下面這段話,我們的上下文大小取值爲4,特定的這個詞是"Learning",也就是我們需要的輸出詞向量,上下文對應的詞有8個,前後各4個,這8個詞是我們模型的輸入。由於CBOW使用的是詞袋模型,因此這8個詞都是平等的,也就是不考慮他們和我們關注的詞之間的距離大小,只要在我們上下文之內即可。

在這裏插入圖片描述
       這樣我們這個CBOW的例子裏,我們的輸入是8個詞向量,輸出是所有詞的softmax概率(訓練的目標是期望訓練樣本特定詞對應的softmax概率最大),對應的CBOW神經網絡模型輸入層有8個神經元,輸出層有詞彙表大小個神經元。
       隱藏層的神經元個數我們可以自己指定。通過DNN的反向傳播算法,我們可以求出DNN模型的參數,同時得到所有的詞對應的詞向量。這樣當我們有新的需求,要求出某8個詞對應的最可能的輸出中心詞時,我們可以通過一次DNN前向傳播算法並通過softmax激活函數找到概率最大的詞對應的神經元即可

六、Skip-gram模型

在word2vec模型中—skip-gram模型,也是一個比較常用的詞向量模型。

6.1 Skip-gram模型結構圖

在這裏插入圖片描述
       同樣,Skip-gram模型也是沒有隱藏層,但是和連續詞袋模型(CBOW)輸入上下文詞的平均詞向量不同,Skip-gram模型是從目標詞w的上下文中選擇一個詞,將其詞向量組成上下文的表示
       Skip-gram和CBOW實際上是word2vec兩種不同的思想實現:CBOW的目標是根據上下文來預測當前詞語的概率,且上下文所有的詞對當前詞出現概率的影響的權重是一樣的,所以叫做continuous bag-of-words模型。如在袋子中去詞,取出數量足夠的詞就可以了,去除的先後順序則是無關緊要的。Skip-gram剛好相反,其是根據當前詞來預測上下文概率的。

6.2 Skip-gram模型輸入輸出

1、Skip-gram模型和CBOW的思路是反着來的,即輸入是特定一個詞的詞向量,而輸出是特定詞對應的上下文詞向量。還是上面的例子,我們的上下文大小取值爲4, 特定的這個詞"Learning"是我們的輸入,而這8個上下文詞是我們的輸出。
2、這樣我們這個Skip-Gram的例子裏,我們的輸入是特定詞, 輸出是softmax概率排前8的8個詞,對應的Skip-Gram神經網絡模型輸入層有1個神經元,輸出層有詞彙表大小個神經元。隱藏層的神經元個數我們可以自己指定。
3、通過DNN的反向傳播算法,我們可以求出DNN模型的參數,同時得到所有的詞對應的詞向量。這樣當我們有新的需求,要求出某1個詞對應的最可能的8個上下文詞時,我們可以通過一次DNN前向傳播算法得到概率大小排前8的softmax概率對應的神經元所對應的詞即可。
注:既然是反着來的,想着CBOW的輸入輸出是什麼,則skip-gram的輸出輸入也就是什麼啦。

七、向量化算法doc2vec/str2vec

       前面我們介紹了word2vec的原理以及生成詞向量神經網絡模型的常見方法,word2vec基於分佈式假說理論可以很好的提取詞語的詞義信息,因此,利用word2vec技術計算詞語間的相似度有非常好的效果。
       同樣word2vec技術也用於計算句子或者其他長文本間的相似度,其一般做法是對文本分詞後,提取關鍵詞,用詞向量表示這些關鍵詞,接着對關鍵詞向量求平均或者將其拼接,最後利用詞向量計算文本間的相似度。

總結:文本分詞—>提取關鍵詞—>詞向量表示關鍵詞—>對關鍵詞向量求平均或者將其拼接—>計算相似度

       此種方法丟失了文本的語義信息,而恰好文本的語序包含重要信息。例如:“小王送給小紅一個蘋果”和“小紅送給小王一個蘋果”,雖然組成兩個句子的詞語相同,但是表達的信息卻是完全不同。爲了充分利用文本詞序信息,有研究者在word2vec的基礎上有提出了文本向量化(doc2vec),又稱str2vec和para2vec。

7.1 doc2vec模型

       doc2vec技術存在兩種模型——Distributed Memory(DM)和Distributed Bag of Words(DBOW),分別對應word2vec技術裏的CBOW和Skip-gram模型。

1:DM模型和CBOW模型類似,試圖預測給定上下文中某詞出現的概率,只不過DM模型的上下文不僅包括上下文單詞還包括相應的段落。
2:DBOW模型則在僅給定段落向量的情況下預測段落中一組隨機單詞的概率,與Skip-gram模型只給定一個詞語預測目標詞分佈類似。


       爲了更好理解DM模型,咋們先來回顧一下CBOW模型。
在這裏插入圖片描述
如上圖所示的一個利用CBOW模型訓練詞向量的例子。以“the cat sat”這句話爲例,用來構建預測下一個詞的概率分佈。

首先,用固定長度的不同詞向量表示上文的三個詞語。
接着,將這三個詞向量平均起來組成上文的向量化表示。
最後,將這個上文向量化表示輸入CBOW模型預測下一個詞的概率分佈。

與CBOW模型類似,DM模型增加了一個與詞向量長度相等的段向量,也就是說DM模型結合詞向量和段向量預測目標詞的概率分佈。
在這裏插入圖片描述

1、如上圖所示,在訓練的過程中,DM模型增加了一個paragraph ID,和普通的Word2vec一樣,paragraph ID也是先映射成一個向量,即paragraph vector。paragraph vector 與word vector的維度雖然一樣,但是代表着兩個不同的向量空間。

2、在之後的計算裏,paragraph vector和word vector 累加或者連接起來,將其輸入softmax層。在一個句子或者文檔的訓練過程中,paragraph ID保持不變,共享這同一個paragraph vector,相當於每次在預測單詞的概率時候,都利用了整個句子的語義。

3、在預測階段,給待預測的句子新分配一個paragraph ID,詞向量和輸出層softmax的參數保持訓練階段得到的參數不變,重新利用隨機梯度下降算法訓練待預測的句子。待誤差收斂之後,即得到預測句子的paragrap vector。


DM模型通過段落向量和詞向量相結合的方式預測目標詞的概率分佈, 而DBOW模型的輸入只有段向量,如下圖所示.

在這裏插入圖片描述

DBOW模型通過一個段落向量預測段落中某個隨機詞的概率分佈。

總結:以上小部分主要介紹了doc2vec的兩個模型:DM模型和DBOW模型。由於doc2vec全是從word2vec技術擴展過來的,DM模型和CBOW模型相對應,故可根據上下文詞向量和段向量預測目標詞的概率分佈;DBOW模型和skip-gram模型對應,只輸入段向量,預測從段落中隨機抽取的詞組概率分佈。總體來說。doc2vec是word2vec的升級,doc2vec不僅提取了文本的語義信息,而且提取了溫飽而語序信息。在一般的文本處理任務中,會將詞向量和段向量相結合使用以希望獲得更好的效果。

關於第五、六章的理論知識,會繼續填補的,暫且就先學習到這裏吧!!!


接下來,我們來實際看幾個操作案例

八、文本向量化案例

8.1 詞向量的訓練

8.1.1 說明

windows10
conda 4.6.14
Python 3.6.8 |Anaconda, Inc.| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)] on win32
pycharm

8.1.2 準備工作

在正式開始之前,需要一些準備工作,除了上述一些說明之外,還需要安裝gensim庫langconv庫。igho
命令安裝:pip install gensim
在這裏插入圖片描述
本地安裝pip install 本地文件路徑
由於網速的問題,博主就選擇本地安裝吧,具體安裝及結果如下所示:
在這裏插入圖片描述
說明:

1、langconv庫:是繁簡字體轉換的庫,gensim
2、Gensim是一款開源的第三方Python工具包,用於從原始的非結構化的文本中,無監督地學習到文本隱層的主題向量表達。它支持包括TF-IDF,LSA,LDA和word2vec在內的多種主題模型算法,支持流式訓練,並提供了諸如相似度計算,信息檢索等一些常用任務的API接口。
3、繁簡體字使用:將langconv.pyzh_wiki.py放在源碼所在目錄即可使用


關於繁簡體轉換說明:

zh_wiki.py和langconv.py這兩個文件是放在本地,然後直接來用,而在pycharm自然不會識別所以就會有報錯標記,
直接在同目錄下:from langconv import * 或者放在創建好的文件夾util下:from util.langconv import * 即可,
我傻吊的,測試都沒測試,看到報錯就想着如何解決報錯了(因爲自己覺得沒有安裝langconv包,所以都不用運行直接思考如何解決報錯了,而忽略了本地離線放置的zh_wiki.py和langconv.py文件),

測試源碼:

from util.langconv import *

# from  langconv import  *

def cat_to_chs(sentence): #傳入參數爲列表
        """
        將繁體轉換成簡體
        :param line:
        :return:
        """
        sentence =",".join(sentence)
        sentence = Converter('zh-hans').convert(sentence)
        sentence.encode('utf-8')
        return sentence.split(",")
def chs_to_cht(sentence):#傳入參數爲列表
        """
        將簡體轉換成繁體
        :param sentence:
        :return:
        """
        sentence =",".join(sentence)
        sentence = Converter('zh-hant').convert(sentence)
        sentence.encode('utf-8')
        return sentence.split(",")

if __name__ == '__main__':
    li_1 = ['雞', '雞', '虎', '牛', '豬', '虎', '兔']
    li_2 = ['雞', '雞', '虎', '牛', '豬', '虎', '兔']
    rest_fon = chs_to_cht(li_1) #簡體轉換成繁體
    # print("簡體轉換成繁體:{0}".format(rest_fon))
    rest_chinese = cat_to_chs(li_2)
    print("簡體轉換成簡體:{0}".format(rest_chinese))

在這裏插入圖片描述


8.1.3 前言

統計自然語言處理任務多需要語料數據作爲支撐,還不可避免的要對語料進行一定的預處理,因此本小節將對詞向量的訓練分爲兩個部分:

  • 對中文語料進行處理
  • 利用gensim模塊訓練詞向量

8.1.4 中文語料預處理

       中文語料庫我們就採用的是微機百科裏的中文網頁作爲訓練語料庫,獲取地址:下載鏈接
       維基百科提供的語料是xml格式的,因此需要將其轉化爲txt格式。由於維基百科中有很多繁體中文網頁,所以也需要將這些繁體字轉化爲簡體字。另外,再用語料庫訓練詞向量之前需要對中文句子進行分詞,這裏我就循規蹈矩的用很成熟的jieba分詞吧(關於分詞可以瀏覽博主博客:分詞1分詞2
最終處理截圖如下所示:
在這裏插入圖片描述
在這裏插入圖片描述

1、源碼獲取:鏈接下名爲:data_pre_process.py文件
2、轉化好的txt格式語料獲取:
說明:再將xml格式的語料轉化爲txt格式的語料的時候,時間會有點長奧。

8.1.5 向量化訓練

       接下來我們就利用gensim模塊訓練詞向量,word2vec函數中第一個參數是預處理後的訓練語料庫。sg=0表示使用CBOW模型訓練詞向量;sg=1表示利用Skip-gram訓練詞向量。參數size表示詞向量的維度。windows表示當前詞和預測詞可能的最大距離,其中windows越大所需要枚舉的預測此越多,計算時間就越長。min_count表示忽略該詞語。最後一個workers表示訓練詞向量時使用的線程數。
最終訓練的結果如下所示:
在這裏插入圖片描述
在這裏插入圖片描述
源碼獲取:此鏈接下word2vec_training.py文件


8.1.6 測試

接下來我們就測試一波

import gensim
def my_function():

    model = gensim.models.Word2Vec.load('./yuliao/zhiwiki_news.word2vec')# 加載訓練好的模型
    print(model.similarity('西紅柿','番茄'))# 0. 
    print(model.similarity('西紅柿','香蕉'))#  
    #print(model.similarity('人工智能','機器學習'))
    #print(model.similarity('滴滴','共享單車'))

    word = '中國'
    if word in model.wv.index2word:
        print(model.most_similar(word))# 如果word包含在模型中,則輸出最相似的詞

if __name__ == '__main__':
    my_function()# 調用函數

在這裏插入圖片描述
源碼獲取:此鏈接下word2vec_test.py文件

到了這裏關於詞向量的基本語料處理,模型訓練以及測試就結束了,接下來我們再來了解一下段落向量的訓練。


8.2 段落向量的訓練

       上一小節介紹了關於詞向量的訓練方法,接下來將介紹段落向量的訓練方法。與訓練詞向量類似,段落向量的訓練分爲訓練數據預處理和段落向量訓練兩個步驟。
       1、通過定義TaggerdWikiDocument來預處理數據,所不同的是這裏不再是將每個文檔進行分詞,而是直接將轉化後的簡單文本保留。
       2、doc2vec在訓練時候能夠採用tag信息來更好的輔助訓練(表明是同一類doc),因此相對word2vec模型,輸入文檔多了一個tag屬性。

docs:表示用於訓練的語料文章
size:代表段落向量的維度
widow:表示當前詞和預測此可能的最大距離
min_count:表示最小出現的次數
workers:表示訓練詞向量時使用的線程數
dm:表示訓練時使用的模型種類,一般dm=1,這時默認使用DM模型;當dm=其他值時,使用DBOW模型訓練詞向量

說明:爲了以防萬一,博主就使用了學生價位的那種類型的阿里雲Centos7.3系統來跑,具體如圖所示:
在這裏插入圖片描述
在這裏插入圖片描述
到了此處:你就會深切感受到硬件設備的重要性呀。
源碼獲取:此鏈接下的doc2vec_traing_models.py文件
接下來就到了測試的地步了~~~


8.3 word2vec和doc2vec計算網頁相似度

       前面我們已經利用gensim模塊訓練詞向量和段落向量了,接下來將利用訓練好的詞向量和段落向量針對一些文章進行向量化,並計算此文章的相似度。

測試語料:此鏈接下的p1.txt

       word2vec計算網頁相似度的基本方法:抽取測試語料中的關鍵詞,接着將關鍵詞進行向量化,然後將得到的各個詞向量相加,最後得到的一個詞向量總和和代表測試語料的向量化表示,利用這個總的向量計算網頁相似度。具體步驟是:1:提取關鍵詞;2:關鍵詞向量化;3:相似度計算

8.3.1 word2vec計算網頁相似度

8.3.1.1 關鍵詞提取源碼

"""
 author:jjk
 datetime:2019/9/23
 coding:utf-8
 project name:Pycharm_workstation
 Program function: 關鍵字提取
 
"""

import jieba.posseg as pseg
from jieba import analyse

def keyword_extract(data,file_name): # 提取關鍵字
    tfidf = analyse.extract_tags
    keywords = tfidf(data)
    return keywords

def getKeywords(docpath,savepath):
    with open(docpath,'r',encoding='utf-8') as docf, open(savepath,'w',encoding='utf-8') as outf:
        for data in docf:
            data = data[:len(data)-1]
            keywords = keyword_extract(data,savepath)
            for word in keywords:
                outf.write(word+' ') # 寫入
            outf.write('\n') # 換行

if __name__ == '__main__':
    getKeywords('../yuliao/P1.txt','../yuliao/P1_keywords.txt')

在這裏插入圖片描述
源碼獲取:此鏈接下的keyword_extract.py文件


8.3.1.2 關鍵詞向量化和相似度計算

"""
 author:jjk
 datetime:2019/9/25
 coding:utf-8
 project name:Pycharm_workstation
 Program function: 利用詞向量word2vec計算文本相似度
 
"""
# -*- coding: utf-8 -*-
import codecs
import numpy
import gensim
import numpy as np
# from keyword_extract import *

wordvec_size = 192


def get_char_pos(string, char):
    chPos = []
    try:
        chPos = list(((pos) for pos, val in enumerate(string) if (val == char)))
    except:
        pass
    return chPos


def word2vec(file_name, model):
    #with codecs.open(file_name, 'r') as f:
    with open(file_name,'rb',encoding='utf-8') as f:
        word_vec_all = numpy.zeros(wordvec_size)
        for data in f:
            space_pos = get_char_pos(data, ' ')
            first_word = data[0:space_pos[0]]
            if model.__contains__(first_word):
                word_vec_all = word_vec_all + model[first_word]

            for i in range(len(space_pos) - 1):
                word = data[space_pos[i]:space_pos[i + 1]]
                if model.__contains__(word):
                    word_vec_all = word_vec_all + model[word]
        return word_vec_all


def simlarityCalu(vector1, vector2): # 使用餘弦函數計算兩個向量的相似度
    vector1Mod = np.sqrt(vector1.dot(vector1))
    vector2Mod = np.sqrt(vector2.dot(vector2))
    if vector2Mod != 0 and vector1Mod != 0:
        simlarity = (vector1.dot(vector2)) / (vector1Mod * vector2Mod)
    else:
        simlarity = 0
    return simlarity


if __name__ == '__main__':
    model = gensim.models.Word2Vec.load('zhiwiki_news.word2vec') # 此處就用使用提前訓練好的語料啦
    #p1 = './data/P1.txt'
    #p2 = './data/P2.txt'
    p1_keywords = 'P1_keywords.txt'
    p2_keywords = 'P2_keywords.txt'
    #getKeywords(p1, p1_keywords)
    #getKeywords(p2, p2_keywords)

    p1_vec = word2vec(p1_keywords, model)
    p2_vec = word2vec(p2_keywords, model)

    print(simlarityCalu(p1_vec, p2_vec))

說明:此處就要用計算網頁相似度訓練好的語料了,由於博主硬件設備資源簡陋,還沒訓練出來,再次就不給出結果信息了。
源碼獲取:此鏈接下doc2vec_traing_model.py文件

8.3.2 doc2vec計算網頁相似度

使用段向量計算網頁相似度主要包括:1:預處理;2:文檔向量化;3:計算文本相似

"""
 author:jjk
 datetime:2019/9/25
 coding:utf-8
 project name:Pycharm_workstation
 Program function: 使用段向量計算網頁相似度
 
"""

import gensim.models as g
import codecs
import numpy
import numpy as np

model_path = 'zhiwiki_news.doc2vec'
start_alpha = 0.01
infer_epoch = 1000
docvec_size = 192 # 段落向量的維度


def simlarityCalu(vector1, vector2): # 採用餘弦函數計算文本相似度
    vector1Mod = np.sqrt(vector1.dot(vector1))
    vector2Mod = np.sqrt(vector2.dot(vector2))
    if vector2Mod != 0 and vector1Mod != 0:
        simlarity = (vector1.dot(vector2)) / (vector1Mod * vector2Mod)
    else:
        simlarity = 0
    return simlarity


def doc2vec(file_name, model):
    import jieba
    doc = [w for x in codecs.open(file_name, 'r', 'utf-8').readlines() for w in jieba.cut(x.strip())] # 分詞
    doc_vec_all = model.infer_vector(doc, alpha=start_alpha, steps=infer_epoch) # 句子向量化操作
    return doc_vec_all
    
if __name__ == '__main__':
    model = g.Doc2Vec.load(model_path) # 加載模型路徑
    p1 = './data/P1.txt'
    p2 = './data/P2.txt'
    P1_doc2vec = doc2vec(p1, model) # 獲取文本向量化
    P2_doc2vec = doc2vec(p2, model)
    print(simlarityCalu(P1_doc2vec, P2_doc2vec))

源碼獲取:此鏈接下doc2vec_test_sim.py文件


在訓練模式的時候,才深切的感受到硬件設備的重要性,到此,關於word2vec和doc2vec的基本概念和原理以及簡單的實現就算完了,word2vec是word embedding最常用的方法,而doc2vec則是基於word2vec發展而來的。它們經常被用來豐富的各種NLP任務的輸入,例如在文本分類或者機器翻譯中,將輸入的文本進行向量化操作後,一般都能取得更好的效果。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章