[NLP] 秒懂詞向量Word2vec的本質

轉自我的公眾號: 『數據挖掘機養成記』

1. 引子

大家好

我叫數據挖掘機

皇家布魯斯特大學肄業

我喝最烈的果粒橙,鑽最深的牛角尖

——執著如我

今天我要揭開Word2vec的神秘面紗

直窺其本質

相信我,這絕對是你看到的

最淺白易懂的 Word2vec 中文總結

(蛤?你問我為啥有這個底氣?

且看下面,我的踩坑血淚史。。。)

2. Word2vec參考資料總結

(以下都是我踩過的坑,建議先跳過本節,閱讀正文部分,讀完全文回頭再來看)

先大概說下我深挖 word2vec 的過程:先是按照慣例,看了 Mikolov 關於 Word2vec 的兩篇原始論文,然而發現看完依然是一頭霧水,似懂非懂,主要原因是這兩篇文章省略了太多理論背景和推導細節;然後翻出 Bengio 03年那篇JMLR和 Ronan 11年那篇JMLR,看完對語言模型、用CNN處理NLP任務有所了解,但依然無法完全吃透 word2vec;這時候我開始大量閱讀中英文博客,其中 北漂浪子 的一篇閱讀量很多的博客吸引了我的注意,裡面非常系統地講解了 Word2vec 的前因後果,最難得的是深入剖析了代碼的實現細節,看完之後細節方面了解了很多,不過還是覺得有些迷霧;終於,我在 quora 上看到有人推薦 Xin Rong 的那篇英文paper,看完之後只覺醍醐灌頂,酣暢淋漓,相見恨晚,成為我首推的 Word2vec 參考資料。下面我將詳細列出我閱讀過的所有 Word2vec 相關的參考資料,並給出評價

  1. Mikolov 兩篇原論文:
    1. 『Distributed Representations of Sentences and Documents』
  • 在前人基礎上提出更精簡的語言模型(language model)框架並用於生成詞向量,這個框架就是 Word2vec
    1. 『Efficient estimation of word representations in vector space』
  • 專門講訓練 Word2vec 中的兩個trick:hierarchical softmax 和 negative sampling
    1. 優點:Word2vec 開山之作,兩篇論文均值得一讀
    2. 缺點:只見樹木,不見森林和樹葉,讀完不得要義。這裡『森林』指 word2vec 模型的理論基礎——即 以神經網路形式表示的語言模型,『樹葉』指具體的神經網路形式、理論推導、hierarchical softmax 的實現細節等等
  1. 北漂浪子的博客:『深度學習word2vec 筆記之基礎篇』
  • 優點:非常系統,結合源碼剖析,語言平實易懂
  • 缺點:太啰嗦,有點抓不住精髓
  1. Yoav Goldberg 的論文:『word2vec Explained- Deriving Mikolov et al.』s Negative-Sampling Word-Embedding Method』
  • 優點:對 negative-sampling 的公式推導非常完備
  • 缺點:不夠全面,而且都是公式,沒有圖示,略顯乾枯
  1. Xin Rong 的論文:『word2vec Parameter Learning Explained』:
  • !重點推薦!
  • 理論完備由淺入深非常好懂,且直擊要害,既有 high-level 的 intuition 的解釋,也有細節的推導過程
  • 一定要看這篇paper!一定要看這篇paper!一定要看這篇paper!
  1. 來斯惟的博士論文『基於神經網路的詞和文檔語義向量表示方法研究』以及他的博客(網名:licstar)
  • 可以作為更深入全面的擴展閱讀,這裡不僅僅有 word2vec,而是把詞嵌入的所有主流方法通通梳理了一遍
  1. 幾位大牛在知乎的回答:『word2vec 相比之前的 Word Embedding 方法好在什麼地方?』
  • 劉知遠、邱錫鵬、李韶華等知名學者從不同角度發表對 Word2vec 的看法,非常值得一看
  1. Sebastian 的博客:『On word embeddings - Part 2: Approximating the Softmax』
  • 詳細講解了 softmax 的近似方法,Word2vec 的 hierarchical softmax 只是其中一種

3. 正文

你會在本文看到:

  1. 提綱挈領地講解 word2vec 的理論精髓
  2. 學會用gensim訓練詞向量,並尋找相似詞

你不會在本文看到

  1. 神經網路訓練過程的推導
  2. hierarchical softmax/negative sampling 等 trick 的理論和實現細節

3.1. 什麼是 Word2vec?

在聊 Word2vec 之前,先聊聊 NLP (自然語言處理)。NLP 裡面,最細粒度的是 詞語,詞語組成句子,句子再組成段落、篇章、文檔。所以處理 NLP 的問題,首先就要拿詞語開刀。

舉個簡單例子,判斷一個詞的詞性,是動詞還是名詞。用機器學習的思路,我們有一系列樣本(x,y),這裡 x 是詞語,y 是它們的詞性,我們要構建 f(x)->y 的映射,但這裡的數學模型 f(比如神經網路、SVM)只接受數值型輸入,而 NLP 里的詞語,是人類的抽象總結,是符號形式的(比如中文、英文、拉丁文等等),所以需要把他們轉換成數值形式,或者說——嵌入到一個數學空間里,這種嵌入方式,就叫詞嵌入(word embedding),而 Word2vec,就是詞嵌入( word embedding) 的一種

我在前作『都是套路: 從上帝視角看透時間序列和數據挖掘』提到,大部分的有監督機器學習模型,都可以歸結為:

f(x)->y

在 NLP 中,把 x 看做一個句子里的一個詞語,y 是這個詞語的上下文詞語,那麼這裡的 f,便是 NLP 中經常出現的『語言模型』(language model),這個模型的目的,就是判斷 (x,y) 這個樣本,是否符合自然語言的法則,更通俗點說就是:詞語x和詞語y放在一起,是不是人話。

Word2vec 正是來源於這個思想,但它的最終目的,不是要把 f 訓練得多麼完美,而是只關心模型訓練完後的副產物——模型參數(這裡特指神經網路的權重),並將這些參數,作為輸入 x 的某種向量化的表示,這個向量便叫做——詞向量(這裡看不懂沒關係,下一節我們詳細剖析)。

我們來看個例子,如何用 Word2vec 尋找相似詞:

  • 對於一句話:『她們 誇 吳彥祖 帥 到 沒朋友』,如果輸入 x 是『吳彥祖』,那麼 y 可以是『她們』、『誇』、『帥』、『沒朋友』這些詞
  • 現有另一句話:『她們 誇 我 帥 到 沒朋友』,如果輸入 x 是『我』,那麼不難發現,這裡的上下文 y 跟上面一句話一樣
  • 從而 f(吳彥祖) = f(我) = y,所以大數據告訴我們:我 = 吳彥祖(完美的結論)

3.2. Skip-gram 和 CBOW 模型

上面我們提到了語言模型

  • 如果是用一個詞語作為輸入,來預測它周圍的上下文,那這個模型叫做『Skip-gram 模型』
  • 而如果是拿一個詞語的上下文作為輸入,來預測這個詞語本身,則是 『CBOW 模型』

3.2.1 Skip-gram 和 CBOW 的簡單情形

我們先來看個最簡單的例子。上面說到, y 是 x 的上下文,所以 y 只取上下文里一個詞語的時候,語言模型就變成:

用當前詞 x 預測它的下一個詞 y

但如上面所說,一般的數學模型只接受數值型輸入,這裡的 x 該怎麼表示呢? 顯然不能用 Word2vec,因為這是我們訓練完模型的產物,現在我們想要的是 x 的一個原始輸入形式。

答案是:one-hot encoder

所謂 one-hot encoder,其思想跟特徵工程里處理類別變數的 one-hot 一樣(參考我的前作『數據挖掘比賽通用框架』、『深挖One-hot和Dummy背後的玄機』)。本質上是用一個只含一個 1、其他都是 0 的向量來唯一表示詞語。

我舉個例子,假設全世界所有的詞語總共有 V 個,這 V 個詞語有自己的先後順序,假設『吳彥祖』這個詞是第1個詞,『我』這個單詞是第2個詞,那麼『吳彥祖』就可以表示為一個 V 維全零向量、把第1個位置的0變成1,而『我』同樣表示為 V 維全零向量、把第2個位置的0變成1。這樣,每個詞語都可以找到屬於自己的唯一表示。

OK,那我們接下來就可以看看 Skip-gram 的網路結構了,x 就是上面提到的 one-hot encoder 形式的輸入,y 是在這 V 個詞上輸出的概率,我們希望跟真實的 y 的 one-hot encoder 一樣。

首先說明一點:隱層的激活函數其實是線性的,相當於沒做任何處理(這也是 Word2vec 簡化之前語言模型的獨到之處),我們要訓練這個神經網路,用反向傳播演算法,本質上是鏈式求導,在此不展開說明了,

當模型訓練完後,最後得到的其實是神經網路的權重,比如現在輸入一個 x 的 one-hot encoder: [1,0,0,…,0],對應剛說的那個詞語『吳彥祖』,則在輸入層到隱含層的權重里,只有對應 1 這個位置的權重被激活,這些權重的個數,跟隱含層節點數是一致的,從而這些權重組成一個向量 vx 來表示x,而因為每個詞語的 one-hot encoder 裡面 1 的位置是不同的,所以,這個向量 vx 就可以用來唯一表示 x。

注意:上面這段話說的就是 Word2vec 的精髓!!

此外,我們剛說了,輸出 y 也是用 V 個節點表示的,對應V個詞語,所以其實,我們把輸出節點置成 [1,0,0,…,0],它也能表示『吳彥祖』這個單詞,但是激活的是隱含層到輸出層的權重,這些權重的個數,跟隱含層一樣,也可以組成一個向量 vy,跟上面提到的 vx 維度一樣,並且可以看做是詞語『吳彥祖』的另一種詞向量。而這兩種詞向量 vx 和 vy,正是 Mikolov 在論文里所提到的,『輸入向量』和『輸出向量』,一般我們用『輸入向量』。

需要提到一點的是,這個詞向量的維度(與隱含層節點數一致)一般情況下要遠遠小於詞語總數 V 的大小,所以 Word2vec 本質上是一種降維操作——把詞語從 one-hot encoder 形式的表示降維到 Word2vec 形式的表示。

3.2.2. Skip-gram 更一般的情形

上面討論的是最簡單情形,即 y 只有一個詞,當 y 有多個詞時,網路結構如下:

可以看成是 單個x->單個y 模型的並聯,cost function 是單個 cost function 的累加(取log之後)

如果你想深入探究這些模型是如何並聯、 cost function 的形式怎樣,不妨仔細閱讀參考資料4. 在此我們不展開。

3.2.3 CBOW 更一般的情形

跟 Skip-gram 相似,只不過:

Skip-gram 是預測一個詞的上下文,而 CBOW 是用上下文預測這個詞

網路結構如下

更 Skip-gram 的模型並聯不同,這裡是輸入變成了多個單詞,所以要對輸入處理下(一般是求和然後平均),輸出的 cost function 不變,在此依然不展開,建議你閱讀參考資料4.

3.3. Word2vec 的訓練trick

相信很多初次踩坑的同學,會跟我一樣陷入 Mikolov 那篇論文(參考資料1.)里提到的 hierarchical softmax 和 negative sampling 里不能自拔,但其實,它們並不是 Word2vec 的精髓,只是它的訓練技巧,但也不是它獨有的訓練技巧。 Hierarchical softmax 只是 softmax 的一種近似形式(詳見參考資料7.),而 negative sampling 也是從其他方法借鑒而來。

為什麼要用訓練技巧呢? 如我們剛提到的,Word2vec 本質上是一個語言模型,它的輸出節點數是 V 個,對應了 V 個詞語,本質上是一個多分類問題,但實際當中,詞語的個數非常非常多,會給計算造成很大困難,所以需要用技巧來加速訓練。

這裡我總結了一下這兩個 trick 的本質,有助於大家更好地理解,在此也不做過多展開,有興趣的同學可以深入閱讀參考資料1.~7.

  • hierarchical softmax
    • 本質是把 N 分類問題變成 log(N)次二分類
  • negative sampling
    • 本質是預測總體類別的一個子集

3.4. 擴展

很多時候,當我們面對林林總總的模型、方法時,我們總希望總結出一些本質的、共性的東西,以構建我們的知識體系,比如我在前作『分類和回歸的本質』里,原創性地梳理了分類模型和回歸模型的本質聯繫,比如在詞嵌入領域,除了 Word2vec之外,還有基於共現矩陣分解的 GloVe 等等詞嵌入方法。

深入進去我們會發現,神經網路形式表示的模型(如 Word2vec),跟共現矩陣分解模型(如 GloVe),有理論上的相通性,這裡我推薦大家閱讀參考資料5. ——來斯惟博士在它的博士論文附錄部分,證明了 Skip-gram 模型和 GloVe 的 cost fucntion 本質上是一樣的。是不是一個很有意思的結論? 所以在實際應用當中,這兩者的差別並不算很大,尤其在很多 high-level 的 NLP 任務(如句子表示、命名體識別、文檔表示)當中,經常把詞向量作為原始輸入,而到了 high-level 層面,差別就更小了。

鑒於詞語是 NLP 里最細粒度的表達,所以詞向量的應用很廣泛,既可以執行詞語層面的任務,也可以作為很多模型的輸入,執行 high-level 如句子、文檔層面的任務,包括但不限於:

  • 計算相似度
    • 尋找相似詞
    • 信息檢索
  • 作為 SVM/LSTM 等模型的輸入
    • 中文分詞
    • 命名體識別
  • 句子表示
    • 情感分析
  • 文檔表示
    • 文檔主題判別

4. 實戰

上面講了這麼多理論細節,其實在真正應用的時候,只需要調用 Gensim (一個 Python 第三方庫)的介面就可以。但對理論的探究仍然有必要,你能更好地知道參數的意義、模型結果受哪些因素影響,以及舉一反三地應用到其他問題當中,甚至更改源碼以實現自己定製化的需求。

這裡我們將使用 Gensim 和 NLTK 這兩個庫,來完成對生物領域的相似詞挖掘,將涉及:

  • 解讀 Gensim 里 Word2vec 模型的參數含義
  • 基於相應語料訓練 Word2vec 模型,並評估結果
  • 對模型結果調優

語料我已經放出來了,可以關注我的公眾號『數據挖掘機養成記』,並回復 Sherlocked 獲取語料,包含5000行生物醫學領域相關文獻的摘要(英文)

我將在下一篇文章里詳細講解實戰步驟,敬請關注本人公眾號。友情建議:請先自行安裝 Gensim 和 NLTK 兩個庫,並建議使用 jupyter notebook 作為代碼運行環境

歡迎各路大神猛烈拍磚,共同交流

====評論區答疑節選====

Q1. gensim 和 google的 word2vec 裡面並沒有用到onehot encoder,而是初始化的時候直接為每個詞隨機生成一個N維的向量,並且把這個N維向量作為模型參數學習;所以word2vec結構中不存在文章圖中顯示的將V維映射到N維的隱藏層。

A1. 其實,本質是一樣的,加上 one-hot encoder 層,是為了方便理解,因為這裡的 N 維隨機向量,就可以理解為是 V 維 one-hot encoder 輸入層到 N 維隱層的權重,或者說隱層的輸出(因為隱層是線性的)。每個 one-hot encoder 里值是 1 的那個位置,對應的 V 個權重被激活,其實就是『從一個V*N的隨機詞向量矩陣里,抽取某一行』。學習 N 維向量的過程,也就是優化 one-hot encoder 層到隱含層權重的過程

Q2. hierarchical softmax 獲取詞向量的方式和原先的其實基本完全不一樣,我初始化輸入的也不是一個onehot,同時我是直接通過優化輸入向量的形式來獲取詞向量?如果用了hierarchical 結構我應該就沒有輸出向量了吧?

A2. 初始化輸入依然可以理解為是 one-hot,同上面的回答;確實是只能優化輸入向量,沒有輸出向量了。具體原因,我們可以梳理一下不用 hierarchical (即原始的 softmax) 的情形:

隱含層輸出一個 N 維向量 x, 每個x 被一個 N 維權重 w 連接到輸出節點上,有 V 個這樣的輸出節點,就有 V 個權重 w,再套用 softmax 的公式,變成 V 分類問題。這裡的類別就是詞表裡的 V 個詞,所以一個詞就對應了一個權重 w,從而可以用 w 作為該詞的詞向量,即文中的輸出詞向量。

PS. 這裡的 softmax 其實多了一個『自由度』,因為 V 分類只需要 V-1 個權重即可

我們再看看 hierarchical softmax 的情形:

隱含層輸出一個 N 維向量 x, 但這裡要預測的目標輸出詞,不再是用 one-hot 形式表示,而是用 huffman tree 的編碼,所以跟上面 V 個權重同時存在的原始 softmax 不一樣, 這裡 x 可以理解為先接一個輸出節點,即只有一個權重 w1 ,輸出節點輸出 1/1+exp(-w*x),變成一個二分類的 LR,輸出一個概率值 P1,然後根據目標詞的 huffman tree 編碼,將 x 再輸出到下一個 LR,對應權重 w2,輸出 P2,總共遇到的 LR 個數(或者說權重個數)跟 huffman tree 編碼長度一致,大概有 log(V) 個,最後將這 log(V) 個 P 相乘,得到屬於目標詞的概率。但注意因為只有 log(V) 個權重 w 了,所以跟 V 個詞並不是一一對應關係,就不能用 w 表徵某個詞,從而失去了詞向量的意義

PS. 但我個人理解,這 log(V) 個權重的組合,可以表示某一個詞。因為 huffman tree 尋找葉子節點的時候,可以理解成是一個不斷『二分』的過程,不斷二分到只剩一個詞為止。而每一次二分,都有一個 LR 權重,這個權重可以表徵該類詞,所以這些權重拼接在一起,就表示了『二分』這個過程,以及最後分到的這個詞的『輸出詞向量』。

我舉個例子:

假設現在總共有 (A,B,C)三個詞,huffman tree 這麼構建:

第一次二分: (A,B), (C)

假如我們用的 LR 是二分類 softmax 的情形(比常見 LR 多了一個自由度),這樣 LR 就有倆權重,權重 w1_1 是屬於 (A,B) 這一類的,w1_2 是屬於 (C) 的, 而 C 已經到最後一個了,所以 C 可以表示為 w1_2

第二次二分: (A), (B)

假設權重分別對應 w2_1 和 w2_2,那麼 A 就可以表示為 [w1_1, w2_1], B 可以表示為 [w1_1, w2_2]

這樣, A,B,C 每個詞都有了一個唯一表示的詞向量(此時他們長度不一樣,不過可以用 padding 的思路,即在最後補0)

當然了,一般沒人這麼干。。。開個腦洞而已

Q3. 是否一定要用Huffman tree?

A3. 未必,比如用完全二叉樹也能達到O(log(N))複雜度。但 Huffman tree 被證明是更高效、更節省內存的編碼形式,所以相應的權重更新尋優也更快。 舉個簡單例子,高頻詞在Huffman tree中的節點深度比完全二叉樹更淺,比如在Huffman tree中深度為3,完全二叉樹中深度為5,則更新權重時,Huffmantree只需更新3個w,而完全二叉樹要更新5個,當高頻詞頻率很高時,演算法效率高下立判

推薦閱讀:

recsys(acm recommender sysytems) 2016 有哪些值得關注的論文?
【專知薈萃23】深度強化學習RL知識資料全集(入門/進階/論文/綜述/代碼/專家,附查看)
深度學習——分類之Densenet
地平線重磅發布 AI 視覺晶元「征程」與「旭日」,落地三大場景打造智能方案
?谷歌最新機器人,Handle將是邁向商業化的第一步?

TAG:自然语言处理 | 机器学习 | 人工智能 |