用深度學習來獲取文本語義: 詞向量應用於自然語言處理
◆ ◆ ◆
序
詞向量是一種把詞處理成向量的技術,並且保證向量間的相對相似度和語義相似度是相關的。這個技術是在無監督學習方麵最成功的應用之一。傳統上,自然語言處理(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)的方法,在保存列之間相似性的同時降低矩陣的行數。不過這些模型的主要問題是:在數據量非常大的時候,計算量也非常得大。
為了避免計算和存儲大量的數據,我們試圖創造一個神經網絡模型來計算詞間的關係,並提高效率。
◆ ◆ ◆
Word2Vec
目前最流行的詞向量模型是由Mikolov等人在2013年提出的word2vec。這個模型的效果很好,且計算效率有了很大的提升。Mikolov等提出的負采樣方法是一個更有效的產生詞向量的方法。更多的信息可以在這裏找到。
這一模型可以使用下述兩種架構的任一種來生成詞的分布:連續詞袋(CBOW)和連續跳躍元語法(skip-gram)。
下麵讓我們分別來看看這兩種架構。
CBOW模型
在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
language_code = “he”
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分鍾。
◆ ◆ ◆
fastText庫
臉書的人工智能研究(FAIR)實驗室最近發布了fastText庫。它是基於Bojanowski等的論文《Enriching Word Vectors with Subword Information》所開發的模型。與word2vec不同,fastText把詞表示成一個n元的字母袋。每個向量代表字符袋裏的一個n元字母,而一個詞則是這些向量的和。
使用臉書的新庫很簡單。安裝命令:
pip install fasttext
訓練模型的命令:
start = time.time()
language_code = “he”
inp = “wiki.{}.text”.format(language_code)
output = “wiki.{}.fasttext.model”.format(language_code)
model = fasttext.cbow(inp,output)
print(time.time()-start)
整個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
[‘woman’]
結果顯示fastText和gensim的word2vec都能正確預測。
W(“woman”) ≃ W(“man”)+ W(“queen”)− W(“king”)
可見,詞向量確實能找到詞匯之間的語義關係。
我們這裏所介紹的模型的基本思路可以被運用到很多的應用場景。如預測商業機構需要的下一個應用、做情感分析、替換生物序列、做語義圖片搜索等。
原文發布時間為:2016-12-12
本文來自雲棲社區合作夥伴“大數據文摘”,了解相關信息可以關注“BigDataDigest”微信公眾號
最後更新:2017-05-27 10:33:28