1. 程式人生 > 其它 >glove中文詞向量_NLP.TM | GloVe模型的原理和實現

glove中文詞向量_NLP.TM | GloVe模型的原理和實現

技術標籤:glove中文詞向量

在進行自然語言處理中,需要對文章的中的語義進行分析,於是迫切需要一些模型去描述詞彙的含義,很多人可能都知道word2vector演算法,誠然,word2vector是一個非常優秀的演算法,並且被廣泛運用,為人們熟知,然而,從結果的優劣性來看,其實word2vector並非唯一的優秀方案,斯坦福大學提出的GloVe就是其中之一。今天我來為大家介紹一下GloVe模型,但是重點,還是放在實現上。

原論文: http://www. eecs.wsu.edu/~sji/class es/DL16/CNN-text/glove.pdf

簡單地說一下原理

這裡的原理我主要參考了兩篇部落格,感謝兩位優秀的博主。

理解GloVe模型(+總結): https:// blog.csdn.net/u01466501 3/article/details/79642083
GloVe模型: https://www. cnblogs.com/Weirping/p/ 7999979.html

前者會比較通俗,後者則比較深刻。

共現關係

和word2vector不同,GloVe更傾向於進行分析前後語境之間的共現關係,通過共現關係抽象出詞向量。

所謂的共現,共同出現,其實就是看一個詞有沒有在另一個詞的附近出現,所謂的附近,其實就是一個移動視窗的概念,定義視窗的半徑(從中心詞到邊緣的距離)後,看看方圓多少範圍內出現詞的個數,就是共現,現在看看例子。

假設語料庫就只有下面一行:

i love you but you love him i am sad

設半徑為2,於是移動視窗的滑動就有下面的形式:

以視窗5為例,此處就可以認為,love分別和but, you, him, i共同出現了一次,通過這種方式去計數,就能知道任意兩個詞之間的共現關係(一般是可逆的),構成共現矩陣X,一般地,X是一個對稱矩陣。

詞向量的產生

首先,模型的損失函式長這樣的:

5855dc92e399a1c089e682643a961c57.png

vi和vj是詞彙i和j的詞向量,bi和bj是常數項,f是特定的權重函式,N是詞彙表大小。

這個損失函式怎麼來的,我覺得上面的第一個連結講的非常清楚,看的時候注意一個核心,就是考慮兩個詞彙的共現關係與詞向量之間的關係(對映)儘可能接近,於是就構造了上面的損失函式。

GloVe的Python實現

在pypi裡面看到了很多GloVe的包,但是很多都有坑,我直接說一個我自己已經走通的包mittens。

下載方式還是比較簡單的, pip install mittens基本沒什麼問題,想要去看看原始碼的話,在這裡:

https:// github.com/roamanalytic s/mittens

一般而言GloVe按照計算共現矩陣和GloVe訓練兩大模組,而mittens裡面其實只提供了後者,前者還是需要自己寫,這是我寫的部分內容,給大家詳細講講(複雜度啥的基本沒做什麼優化,歡迎提出一些意見)。

共現矩陣的計算

將之前事先說明一下,現在讀進來的資料,即程式碼中的“data”變數,每行不是對應的單詞或者短語,而是已經對應在詞典中的該短語的index(自己構建詞典,一般設定為0-(N-1),N為詞典中詞語的個數),尤其在後面的cooccurrence的統計,即如果句子陣列中的第i個詞語是詞典中的第j個詞,則句子向量中第i個位置就是數字j,這種方式對cooccurrence的統計非常方便。

# 構建空的詞表
coWindow = 3 # 共現視窗大小(半徑)
tableSize = 1000 # 共現矩陣維度
cooccurrence = np.zeros((tableSize, tableSize), "int64" )

首先是資料初始化,這裡不詳細說資料載入了,但是共現矩陣當然是需要初始化的(np是numpy別忘了)。

# 開始統計
flag = 0
for item in data:
   itemInt = [int(x) for x in item]
   for core in range(1, len(item)):
       if core <= coWindow + 1:
           # 左視窗不足
           window = itemInt[1:core + coWindow + 1]
           coreIndex = core - 1
           cooccurrence = countCOOC(cooccurrence, window, coreIndex)
       elif core >= len(item) - 1 - coWindow:
           # 右視窗不足
           window = itemInt[core - coWindow:(len(item))]
           coreIndex = coWindow
           cooccurrence = countCOOC(cooccurrence, window, coreIndex)
       else:
           # 左右均沒有問題
           window = itemInt[core - coWindow:core + coWindow + 1]
           coreIndex = coWindow
           cooccurrence = countCOOC(cooccurrence, window, coreIndex)
   flag = flag + 1
   if flag % 1000 == 0:
       endTime = datetime.datetime.now()
       print("已經計算了%s條資料,用時%s" % (flag, endTime - startTime))

這一塊裡面主要是為了設定移動視窗來進行挪動識別,具體統計移動視窗內部的共現,是在countCOOC函式裡面做的。

def countCOOC(cooccurrence, window, coreIndex):
   # cooccurrence:當前共現矩陣
   # window:當前移動視窗陣列
   # coreIndex:當前移動視窗陣列中的視窗中心位置
   for index in range(len(window)):
       if index == coreIndex:
           continue
       else:
           cooccurrence[window[coreIndex]][window[index]] = cooccurrence[window[coreIndex]][window[index]] + 1
   return cooccurrence

countCOOC用來當前移動視窗的共現,一個一個計數即可。

GloVe的訓練

# 包的引入
from mittens import GloVe
# 初始化模型
vecLength=100           # 矩陣長度
max_iter=100000         # 最大迭代次數
display_progress=1000   # 每次展示
glove_model = GloVe(n=vecLength, max_iter=max_iter, display_progress=display_progress)
# 模型訓練與結果輸出
embeddings = glove_model.fit(coocMatric)

引入包之後,配置相應的引數,然後可以開始訓練,訓練完的返回值embeddings就是得到的詞向量詞典,通過詞向量詞典,就能夠將每篇文字的每一個單詞轉化為詞向量,從而進行進一步分析。

小結

GloVe終於寫完了,不知道大家覺得怎麼樣,關於原理寫的人相對比較多,也理解的比我好我就不再解釋了,而程式碼這塊,網上寫的不多,所以我寫得詳細一些,這也是我把結果寫出來的核心程式碼,有什麼問題我來回答,歡迎通過下面的聯絡方式聯絡我。