天天看點

用深度學習來擷取文本語義: 詞向量應用于自然語言處理

用深度學習來擷取文本語義: 詞向量應用于自然語言處理

◆ ◆ ◆

詞向量是一種把詞處理成向量的技術,并且保證向量間的相對相似度和語義相似度是相關的。這個技術是在無監督學習方面最成功的應用之一。傳統上,自然語言處理(nlp)系統把詞編碼成字元串。這種方式是随意确定的,且對于擷取詞之間可能存在的關系并沒有提供有用的資訊。詞向量是nlp領域的一個替代方案。它把詞或短語映射成實數向量,把特征從詞彙表大小的高次元空間降低到一個相對低的次元空間。

例如,讓我們看看四個詞:“woman”(女人)、“man”(男人)、“queen”(女王)和“king”(國王)。我們把它們都向量化,再使用簡單的代數運算來發現它們之間的語義相似度。計算向量間的相似度可以采用諸如餘弦相似度的方法。當我們把詞“woman”的向量減去詞“man”後,這個內插補點的餘弦相似度應該和詞“queen”的向量減去“king”的向量的內插補點比較接近(參見圖1)。

w(“woman”)−w(“man”) ≃ w(“queen”)−w(“king”)

用深度學習來擷取文本語義: 詞向量應用于自然語言處理

圖1 性别的向量。來源:lior shkiller

有很多不同的模型可以被用來把詞轉換成實數性的向量,包括隐含語義分析(lsa)和隐含狄利克雷分布(lda)。這些模型背後的思路是:相關的詞彙一般都會在相同的文檔裡同時出現。例如,backpack(背包)、school(學校)、notebook(筆記本)和teacher(教師)一般都會一起出現。而school(學校)、tiger(老虎)、apple(蘋果)和basketball(籃球)一般都不會持續同時出現。基于這個相關的詞會在相關的文檔裡出現的基本假設,為了把詞轉化為向量,lsa會建構一個矩陣。矩陣的行是(語料庫或資料裡)所有出現過的詞,而列則是對應于文檔裡的一個段落。lsa使用奇異值分解(svd)的方法,在儲存列之間相似性的同時降低矩陣的行數。不過這些模型的主要問題是:在資料量非常大的時候,計算量也非常得大。

為了避免計算和存儲大量的資料,我們試圖創造一個神經網絡模型來計算詞間的關系,并提高效率。

目前最流行的詞向量模型是由mikolov等人在2013年提出的word2vec。這個模型的效果很好,且計算效率有了很大的提升。mikolov等提出的負采樣方法是一個更有效的産生詞向量的方法。更多的資訊可以在這裡找到。

這一模型可以使用下述兩種架構的任一種來生成詞的分布:連續詞袋(cbow)和連續跳躍元文法(skip-gram)。

下面讓我們分别來看看這兩種架構。

在cbow架構裡,模型根據目标詞的上下文來預測目标詞。是以,mikolov等使用了目标詞w的前n個詞和後n個詞。

一個序列的詞等同于一個物品集。是以,就可以把“詞”了解為“物品”。對于“物品”我們可以使用推薦系統以及協同過濾裡的方法。cbow模型的訓練速度是跳躍元文法模型的七倍,而且預測準确性也稍好(參見圖2)。

用深度學習來擷取文本語義: 詞向量應用于自然語言處理

圖2 基于上下文來預測詞。來源:lior shkiller

與使用目标詞的上下文的方法不同,連續跳躍元文法模型是使用目标詞去預測它的前後詞(參見圖3)。據mikolov等的論文,在訓練資料量比較小的時候,跳躍元文法模型比較好,且對于罕見的詞和短語的處理較好。

用深度學習來擷取文本語義: 詞向量應用于自然語言處理

圖3 用給定的詞來預測上下文。來源:lior shkiller

(你可以在這個github庫裡找到下面例子的代碼)

這個模型(word2vec)的一大好處就是,它可以用于很多種語言。

我們所要做的就是下載下傳一個所要處理的語言的大資料集。

我們可以從維基百科裡面找到很多語言的資料。用下面的步驟就可以獲得一個大資料集。

找到你想處理的語言的iso 639代碼:iso 639代碼的清單

登入https://dumps.wikimedia.org/wiki/latest/ (譯者注:此連結已失效)

下載下傳wiki-latest-pages-articles.xml.bz2

接着,為了讓後續的事情變簡單,我們會安裝gensim。它是一個實作了word2vec的python庫。

pip install –upgrade gensim

我們需要用維基百科的下載下傳檔案來建立語料庫,以用于後續的word2vec模型的訓練。下面這段代碼的輸出就是一個“wiki..text”的檔案。其中包括了維基百科的所有文章的所有詞彙,并按照語言分開。

from gensim.corpora import wikicorpus

language_code = “he”

inp = language_code+”wiki-latest-pages-articles.xml.bz2″

outp = “wiki.{}.text”.format(language_code)

i = 0

print(“starting to create wiki corpus”)

output = open(outp, ‘w’)

space = ” ”

wiki = wikicorpus(inp, lemmatize=false, dictionary={})

for text in wiki.get_texts():

article = space.join([t.decode(“utf-8”) for t in text])

output.write(article + “\n”)

i = i + 1

if (i % 1000 == 0):

print(“saved ” + str(i) + ” articles”)

output.close()

print(“finished – saved ” + str(i) + ” articles”)

參數的說明如下:

size:向量的次元

大的size值會要求更多的訓練資料,但能帶來更準确的模型

window:在一個句子内,目标詞與預測詞之間的最大距離

min_count:忽略所有總詞頻低于這個值的詞。

import multiprocessing

from gensim.models import word2vec

from gensim.models.word2vec import linesentence

inp = “wiki.{}.text”.format(language_code)

out_model = “wiki.{}.word2vec.model”.format(language_code)

size = 100

window = 5

min_count = 5

start = time.time()

model = word2vec(linesentence(inp), sg = 0, # 0=cbow , 1= skipgram

size=size, window=window, min_count=min_count, workers=multiprocessing.cpu_count())

# trim unneeded model memory = use (much) less ram

model.init_sims(replace=true)

print(time.time()-start)

model.save(out_model)

整個word2vec訓練過程用了18分鐘。

臉書的人工智能研究(fair)實驗室最近釋出了fasttext庫。它是基于bojanowski等的論文《enriching word vectors with subword information》所開發的模型。與word2vec不同,fasttext把詞表示成一個n元的字母袋。每個向量代表字元袋裡的一個n元字母,而一個詞則是這些向量的和。

使用臉書的新庫很簡單。安裝指令:

pip install fasttext

訓練模型的指令:

output = “wiki.{}.fasttext.model”.format(language_code)

model = fasttext.cbow(inp,output)

整個fasttext模型訓練用了13分鐘。

下面讓我們用之前的那個例子來評估這兩個模型的準确度。

w(“woman”) ≃ w(“man”)+ w(“queen”)− w(“king”)

下面的代碼首先計算正負詞的權重平均值。

随後,代碼計算了所有的測試詞彙的向量與權重平均的點乘積。

我們的評估例子裡,測試詞彙是整個詞彙表。代碼的最後是列印出和正詞與負詞的權重平均值的餘弦相似度最高的詞。

import numpy as np

from gensim.matutils import unitvec

def test(model,positive,negative,test_words):

mean = []

for pos_word in positive:

mean.append(1.0 * np.array(model[pos_word]))

for neg_word in negative:

mean.append(-1.0 * np.array(model[neg_word]))

# compute the weighted average of all words

mean = unitvec(np.array(mean).mean(axis=0))

scores = {}

for word in test_words:

if word not in positive + negative:

test_word = unitvec(np.array(model[word]))

# cosine similarity

scores[word] = np.dot(test_word, mean)

print(sorted(scores, key=scores.get, reverse=true)[:1])

接着,用我們最初的那個例子來做測試。

用fasttext和gensim的word2vec模型來預測:

positive_words = [“queen”,”man”]

negative_words = [“king”]

# test word2vec

print(“testing word2vec”)

model = word2vec.getmodel()

test(model,positive_words,negative_words,model.vocab)

# test fasttext

print(“testing fasttext”)

model = fasttxt.getmodel()

test(model,positive_words,negative_words,model.words)

testing word2vec

[‘woman’]

testing fasttext

結果顯示fasttext和gensim的word2vec都能正确預測。

可見,詞向量确實能找到詞彙之間的語義關系。

我們這裡所介紹的模型的基本思路可以被運用到很多的應用場景。如預測商業機構需要的下一個應用、做情感分析、替換生物序列、做語義圖檔搜尋等。

原文釋出時間為:2016-12-12

本文來自雲栖社群合作夥伴“大資料文摘”,了解相關資訊可以關注“bigdatadigest”微信公衆号

繼續閱讀