NSS的這篇文章實在是寫得很經(jīng)典,簡要翻譯學習一下。
原文鏈接:https://www.analyticsvidhya.com/blog/2017/06/word-embeddings-count-word2veec/
目錄
0 介紹
1 什么是詞嵌入?
2 不同種類的詞嵌入
2.1 詞頻嵌入
2.1.1 計數(shù)向量
2.1.2 TF-IDF
2.1.3 共現(xiàn)矩陣
2.2 預測嵌入
2.2.1 CBOW
2.2.2 Skip-gram
3 詞嵌入的應用案例
4 使用預訓練的詞向量
5 訓練屬于自己的詞向量
6 結(jié)語

0 介紹
開始之前先看幾個例子:
- 在谷歌搜索框中輸入一個新聞標題,能返回幾百篇相關(guān)的結(jié)果;
- Nate Silver通過分析幾百萬推文預測2008年美國大選,正確率達到了49/50;
- 在谷歌翻譯中輸入一句英語,得到它的中文翻譯。

這些例子有什么相同點?
答案是——“文本處理”。上面三個場景通過處理海量文本,完成了三個不同的任務(wù):聚類、分類和機器翻譯。
人類處理文本任務(wù)既不可擴展,也十分低效。

讓機器代替人力,關(guān)鍵是創(chuàng)建詞的表征,該表征可以獲取詞義、語義關(guān)系和不同的上下文種類。
表征可以通過詞嵌入和數(shù)值表征來完成。
下面就來看看什么是詞嵌入,和詞嵌入的不同類型,以及如何使用詞嵌入完成返回搜索結(jié)果的任務(wù)。
1 什么是詞嵌入?
簡單來說,詞嵌入就是將文本轉(zhuǎn)換成數(shù)字,方法不同,數(shù)值表征也不同。在深入之前,先來討論下為什么需要詞嵌入?
人們經(jīng)過實踐得出結(jié)論,多數(shù)機器學習算法和幾乎所有的深度學習框架都不能處理原始個格式的字符串和文本。機器需要數(shù)字作為輸入,才能執(zhí)行分類回歸這樣的任務(wù)。文本中蘊含著海量的數(shù)據(jù),有必要從中提取出有用的東西,并創(chuàng)建應用,比如亞馬遜商品評論、文檔或新聞的情感分析、谷歌搜索的分類和聚類。
正式給詞嵌入下個定義:詞嵌入是使用詞典,將單詞映射到矢量上。把這句話分解,逐一分析。
看這個例子:
# 將sentence作為一個變量
sentence = "Word Embeddings are Word converted into numbers"
所謂的字典,是sentence中不同單詞組成的列表,也就是:
[‘Word’,’Embeddings’,’are’,’Converted’,’into’,’numbers’]
可以用獨熱編碼來生成矢量,在獨熱編碼中,1表示單詞在該位置存在,0表示不存在。根據(jù)上面的字典,單詞numbers的獨熱編碼是[0,0,0,0,0,1],converted的編碼是[0,0,0,1,0,0]。
這只是用矢量表征單詞的一個非常簡單的方法。接下來看看不同的詞嵌入或詞向量的方法,以及各自的優(yōu)缺點。
2 不同類型的詞嵌入
可以將詞嵌入大致分成兩類:
- 基于頻率嵌入
- 基于預測嵌入
2.1 基于頻率嵌入
基于頻率,有三種向量表示法:
- 計數(shù)向量
- TF-IDF向量
- 共現(xiàn)向量
2.1.1 計數(shù)向量
一個包含D篇文檔{D1,D2…..DD}的語料庫C,包含有N個不同的單詞。這N個單詞就組成了詞典。計數(shù)向量矩陣M的形狀是D x N。矩陣M的每一行,是單詞出現(xiàn)在D(i)中的頻率。
這么說很難懂,舉個栗子??:
D1: He is a lazy boy. She is also lazy.
D2: Neeraj is a lazy person.
D1和D2兩個文檔的詞典是不同單詞組成的列表,也就是
corpus =[‘He’,’She’,’lazy’,’boy’,’Neeraj’,’person’]
有文檔共有兩篇、詞典中有六個單詞,所以D=2, N=6。
根據(jù)計數(shù)矩陣的定義,就該表示成一個2 x 6的矩陣:

其中,每一列就是單詞的詞向量,例如,lazy的詞向量就是[2,1]。
計數(shù)向量矩陣有幾種變體,區(qū)別在于:
構(gòu)成詞典的方式不同 —— 因為在真實世界的案例中,語料庫可能會包含數(shù)百萬篇文檔。從如此多的文檔中,可以提取出數(shù)百萬不同的單詞。所以用上面方法來生成矩陣,矩陣會特別稀疏(矩陣中的0特別多),會導致計算效率低下。所以只采用總詞典中,頻率最高的10000個詞,作為真正使用的詞典。
每個單詞的計數(shù)方法不同 —— 我們可以使用頻率(某個單詞在文檔中出現(xiàn)的次數(shù))或是否出現(xiàn)(出現(xiàn)就是1,否則是0)作為矩陣中的值。一般來說,詞頻方法用的更多。
下面是一個矩陣的表征圖(注:和剛才的例子相比,文檔和詞的位置發(fā)生了轉(zhuǎn)置):

2.1.2 TF-IDF矢量化
TF-IDF也是一種基于詞頻的方法,跟計數(shù)向量不同的地方是,他不僅考慮了某個詞在一篇文檔中的出現(xiàn)次數(shù),也考慮了單詞在整個預料庫中的出現(xiàn)情況。
像is、the、a這樣的常見詞,總是在文章有更多的出現(xiàn)機會。我們要做的就是降低這些常見詞的權(quán)重。
TF-IDF是這么做的,考慮下面的兩個文檔:

先來解釋下TF和IDF分別是什么?
TF是詞頻兩個單詞term frequency的縮寫:
TF = (某個詞在文檔中出現(xiàn)的次數(shù)) / (文檔中所有詞的總頻次數(shù))
所以,This的TF值應該如下:
TF(This, Document1) = 1/8
TF(This, Document2) = 1/5
TF可以表示某個單詞對文檔的貢獻,也就是說,和文檔相關(guān)性強的詞應該出現(xiàn)的多,例如,一篇關(guān)于梅西的文章,應該會多次出現(xiàn)梅西的名字“Messi”。
IDF是逆文檔頻率inverse document frequency的縮寫:
IDF = log(N/n)
# N是總文檔數(shù),n是文檔出現(xiàn)過某個單詞的文檔數(shù)
因此,This和Messi的IDF值是:
IDF(This) = log(2/2) = 0
IDF(Messi) = log(2/1) = 0.301
IDF的意義是,如果一個單詞在所有文檔中都出現(xiàn)過,那么這個單詞相對于任何一篇文檔都不重要。如果一個單詞只在某些文檔中出現(xiàn)過,說明該單詞和這些文檔有相關(guān)性。
將TF和IDF結(jié)合起來,再比較This和Messi兩個詞的值:
TF-IDF(This,Document1) = (1/8) * (0) = 0
TF-IDF(This, Document2) = (1/5) * (0) = 0
TF-IDF(Messi, Document1) = (4/8)*0.301 = 0.15
對于Document1來說,This的分值低于Messi的分值,說明Messi對于Document1更重要。
2.1.3 共現(xiàn)矩陣(固定內(nèi)容窗口)
根據(jù)常識,相似的詞通常會出現(xiàn)在相似的上下文,比如這兩句話:
Apple is a fruit.
Mango is a fruit.
Apple和Mango有相似的上下文,也就是fruit。
先解釋下什么是共現(xiàn)矩陣和內(nèi)容窗口:
- 共現(xiàn)矩陣:對于給定的預料,兩個詞w1和w2的共現(xiàn)次數(shù)是它們出現(xiàn)在內(nèi)容窗口中的次數(shù);
- 內(nèi)容窗口:某個單詞的一定的前后范圍稱為內(nèi)容窗口。

看一個具體的例子,語料如下:
Corpus = He is not lazy. He is intelligent. He is smart.

紅格子 —— 窗口大小為2時,He和is共現(xiàn)了4次;
藍格子 —— lazy從來沒有和intelligent出現(xiàn)在窗口中;

共現(xiàn)矩陣的變化
假設(shè)語料中有V個不同的詞。共現(xiàn)矩陣可以有兩種變體:
- 共現(xiàn)矩陣的大小是
V x V。這樣的矩陣,對于任何語料V,都會特別大且難于處理,所以很少用; - 共現(xiàn)矩陣的大小是
V x N,N是V(例如去除了停用詞the、a這樣的詞)的子集,矩陣仍然很大,計算還是困難。
其實,共現(xiàn)矩陣并不是通常使用的詞向量,而是經(jīng)過PCA(主成分分析)、SVD(奇異值分解)之后,才構(gòu)成詞向量。
假如對上面大小是V x V的矩陣做了主成分分析,可以獲得V個主成分,從其中挑出k個,就可以構(gòu)成一個大小是V x k的矩陣。
對于某一個單詞,就算經(jīng)過了降維,語義也不會下降很多。k的大小通常是數(shù)百。
其實PCA的作用,是將貢獻矩陣分解成三個三個矩陣U、S和V,U和V都是正交矩陣。重點在于,U和S的點積是詞向量表征,V是詞的上下文表征。
共現(xiàn)矩陣的優(yōu)點:
- 保留了詞之間的語義關(guān)系,比如:“男人”和“女人”通常比“男人”和“蘋果”離得更近;
- 使用主成分分析或奇異值分解,可以獲得更準確的詞向量;
- 一經(jīng)算好一個共現(xiàn)矩陣,可以多次使用。
共現(xiàn)矩陣的缺點
- 存儲矩陣要耗費大量內(nèi)存(但是可以通過分解,將矩陣縮小,將縮小后的矩陣存儲在集群中)
2.2 基于預測的矢量
Mitolov推出的word2vec是一種基于預測的方法,性能比前面的方法好的多。
word2vec是兩種技術(shù)的集合 —— CBOW(連續(xù)詞袋)和Skip-gram模型。這兩種方法都是淺層神經(jīng)網(wǎng)絡(luò)。
2.2.1 CBOW
CBOW的原理是通過給定的上下文,預測詞的概率。上下文可以是一個詞,也可以是一組詞。簡單起見,我舉的例子是用一個詞來預測另一個詞。
假設(shè)語料如下:
C = “Hey, this is sample corpus using only one context word.”
內(nèi)容窗口的大小是1。這個語料可以轉(zhuǎn)化為如下的CBOW模型的訓練集。下圖的左邊是輸入和輸出,右邊是獨熱編碼矩陣,一共包含17個數(shù)據(jù)點。

將這個矩陣輸入給一個只有3層的神經(jīng)網(wǎng)絡(luò):一個輸入層、一個隱藏層、一個輸出層。輸出層是softmax層,確保輸出層的概率之和是1。下面就來看看前向傳播是如何計算隱藏層的。
先來看一個圖像化的CBOW:

一個數(shù)據(jù)點的向量表征如下所示:

過程如下:
- 輸入層和目標值,都是大小為
1 x V的獨熱編碼,在這個例子中V=10; - 有兩組權(quán)重值,一組在輸入層和隱藏層之間,另一組在隱藏層和輸出層之間;
- 層和層之間沒有激活函數(shù);
- 輸入值先乘以輸入-隱藏權(quán)重矩陣,得到隱藏激活矢量;
- 隱藏輸入層乘以隱藏-輸出矩陣,得到輸出值;
- 計算輸出和目標值之間的誤差,使用誤差調(diào)整權(quán)重;
- 將隱藏層和輸出層之間的矩陣,作為詞向量。
這是只有一個上下文詞的情況。假如有多個上下文詞,就要像下圖來進行計算:

下圖是矩陣表征:

在這張圖中,使用3個上下文詞來預測目標值。輸入層有3個1 x V的矢量,輸出層是1個1 x V矢量。不同的地方是隱藏激活矢量需要做一次取平均值。
在上下文詞是1和3的兩種情況下,畫的圖都是只到隱藏激活矢量而已,因為這部分是CBOW區(qū)別于多層感知機網(wǎng)絡(luò)MLP的地方。
MLP和CBOW的區(qū)別在于:
- MLP的目標函數(shù)是平均方根MSE,CBOW的目標函數(shù)是給定上下文時,求某個詞的負對數(shù)概率,即
-log(p(wo/wi)),p(wo/wi)如下:

wo : 輸出詞, wi : 上下文詞
- 對于隱藏-輸出權(quán)重矩陣和輸入-隱藏權(quán)重矩陣的誤差梯度不同,這是因為MLP使用的是sigmoid激活函數(shù),CBOW是線性激活函數(shù)。但是,計算梯度的方法是一樣的。
CBOW的優(yōu)勢:
- 基于概率的方法,擁有更好的性能;
- 因為不用存儲共現(xiàn)矩陣,CBOW消耗內(nèi)存低。
CBOW的劣勢:
- CBOW計算得到的是某個詞的上下文平均值。Apple可以表示水果也可以表示公司,但CBOW得到的是二者的平均值;
- 如果沒有優(yōu)化,訓練CBOW會耗時很久。
2.2.2 Skip-gram模型
Skip-gram的底層原理和CBOW差不多,就是把CBOW正好給反了過來。Skip-gram的目標是根據(jù)單詞預測上下文。還是使用前面的語料,構(gòu)建訓練數(shù)據(jù):
C=”Hey, this is sample corpus using only one context word.”

skip-gram的輸入矢量跟上下文是1時的CBOW模型很像。另外,輸入層到隱藏層的計算也一模一樣。不同的地方在于目標值。因為定義的內(nèi)容窗口大小是1,所以有兩個獨熱編碼目標值,兩個對應的輸出(下圖中的藍色部分)。
分別根據(jù)兩個目標值得到兩個獨立的誤差矢量,兩個誤差矢量合并成一個誤差矢量,再反向傳播更新權(quán)重。
訓練完成后,輸入層和隱藏層之間的權(quán)重矩陣作為詞向量。
skip-gram的架構(gòu)如下所示:

矩陣計算示意圖如下:

在這張圖中,輸入層的大小是1 x V,輸入-隱藏層權(quán)重矩陣的大小是V x N,隱藏層的神經(jīng)元數(shù)量是N,隱藏-輸出權(quán)重矩陣大小是N x V,輸出層的大小是C個1 x V。
在這個例子中,窗口大小C=2, V=10,N=4:
- 紅色部分是隱層激活層,大小和輸入-隱藏矩陣一樣;
- 黃色部分是隱藏-輸出權(quán)重矩陣;
- 藍色部分是隱藏激活層乘以隱藏輸出矩陣的結(jié)果。對于兩個上下文目標詞,得到的結(jié)果會有兩行;
- 藍色部分的每一行都分別經(jīng)過softmax,得到綠色部分;
- 灰色部分是目標值的獨熱編碼矢量;
- 淺綠色部分是誤差,是綠色減灰色得到的;
- 誤差相加之后,再反向傳播進行計算權(quán)重。
skip-gram模型的優(yōu)勢:
- skip-gram模型可以對一個詞獲取兩種語義,即它可以有Apple一詞的兩種表征;
- skip-gram經(jīng)過降采樣之后,比其它方法表現(xiàn)都好。
3 詞嵌入的應用案例
因為詞嵌入是詞的上下文相似性的表示,可以用來做以下任務(wù):
- 計算詞的相似度
model.similarity('woman','man')
0.73723527
- 過濾異常值輸出
model.doesnt_match('breakfast cereal dinner lunch';.split())
'cereal'
- 進行這樣的計算
woman + king - man = queen
model.most_similar(positive=['woman','king'],negative=['man'],topn=1)
queen: 0.508
- 文本在模型中的概率
model.score(['The fox jumped over the lazy dog'.split()])
0.21
一張word2vec的可視化圖:

詞向量在二維的t-SNE表示,可以看到Apple的兩種上下文都獲取到了。
- 做機器翻譯

這張圖表示了中文和英文的雙語詞嵌入,可以看到語義相似的詞,位置也靠近,因此可以用來做翻譯。
4 使用預訓練的詞向量
使用谷歌的預訓練模型。詞典大小是300萬,用大小是1000億詞的谷歌新聞數(shù)據(jù)集訓練而成,大小是1.5GB,下載地址。
from gensim.models import Word2Vec
# 加載模型
model = Word2Vec.load_word2vec_format('GoogleNews-vectors-negative300.bin', binary=True, norm_only=True)
# 加載模型之后,就可以完成上面的任務(wù)了。
# 獲得某個詞的詞向量
dog = model['dog']
# 做king queen的詞語字符串計算
print(model.most_similar(positive=['woman', 'king'], negative=['man']))
# 找出奇異值
print(model.doesnt_match("breakfast cereal dinner lunch".split()))
# 打印相似指數(shù)
print(model.similarity('woman', 'man'))
5 訓練屬于自己的詞向量
使用gensim和自己的語料來訓練word2vec。
訓練數(shù)據(jù)的格式如下:
sentence=[[‘Neeraj’,’Boy’],[‘Sarwan’,’is’],[‘good’,’boy’]]
用這3句話來訓練
model = gensim.models.Word2Vec(sentence, min_count=1,size=300,workers=4)
參數(shù)的含義如下:
sentence —— 包含列表的列表語料;
min_count=1 —— 詞的閾值,只有高于閾值才會計算;
size=300 —— 詞的表征維度,即詞向量的大小
workers=4 —— 并行的worker數(shù)量
6 結(jié)語
詞嵌入一直就是一個活躍的研究領(lǐng)域,但是近年的研究不僅越來越臃腫,還越來越復雜。這篇文章的目的,是用淺顯易懂的語言加少量的數(shù)學,回顧詞嵌入的發(fā)展。