一、理論概述 (主要來源於http://licstar.net/archives/328這篇部落格) 1.詞向量是什麼 自然語言理解的問題要轉化為機器學習的問題,第一步肯定是要找一種方法把這些符號數學化。 NLP 中最直觀,也是到目前為止最常用的詞表示方法是 One-hot Representation,這種方法把每個詞表示為一個很長的向量。這個向量的維度是詞表大小,其中絕大多數元素為 0,只有一個維度的值為 1,這個維度就代表了當前的詞。 舉個栗子, “話筒”表示為 [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ...] “麥克”表示為 [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...] 每個詞都是茫茫 0 海中的一個 1。 這種 One-hot Representation 如果採用稀疏方式儲存,會是非常的簡潔:也就是給每個詞分配一個數字 ID。比如剛才的例子中,話筒記為 3,麥克記為 8(假設從 0 開始記)。如果要程式設計實現的話,用 Hash 表給每個詞分配一個編號就可以了。這麼簡潔的表示方法配合上最大熵、SVM、CRF 等等演算法已經很好地完成了 NLP 領域的各種主流任務。 當然這種表示方法也存在一個重要的問題就是“詞彙鴻溝”現象:任意兩個詞之間都是孤立的。光從這兩個向量中看不出兩個詞是否有關係,哪怕是話筒和麥克這樣的同義詞也不能倖免於難。 Deep Learning 中一般用到的詞向量並不是剛才提到的用 One-hot Representation 表示的那種很長很長的詞向量,而是用 Distributed Representation(不知道這個應該怎麼翻譯,因為還存在一種叫“Distributional Representation”(類似,LDA中用topic表示詞語的詞向量的表示方法)表示的一種低維實數向量。這種向量一般是這個樣子:[0.792, −0.177, −0.107, 0.109, −0.542, ...]。維度以 50 維和 100 維比較常見。 2.詞向量的來歷 Distributed representation 最早是 Hinton 在 1986 年的論文《Learning distributed representations of concepts》中提出的。雖然這篇文章沒有說要將詞做 Distributed representation但至少這種先進的思想在那個時候就在人們的心中埋下了火種,到 2000 年之後開始逐漸被人重視。 3. 詞向量的訓練 要介紹詞向量是怎麼訓練得到的,就不得不提到語言模型。到目前為止我瞭解到的所有訓練方法都是在訓練語言模型的同時,順便得到詞向量的。 這也比較容易理解,要從一段無標註的自然文字中學習出一些東西,無非就是統計出詞頻、詞的共現、詞的搭配之類的資訊。而要從自然文字中統計並建立一個語言模型,無疑是要求最為精確的一個任務(也不排除以後有人創造出更好更有用的方法)。既然構建語言模型這一任務要求這麼高,其中必然也需要對語言進行更精細的統計和分析,同時也會需要更好的模型,更大的資料來支撐。目前最好的詞向量都來自於此,也就不難理解了。 詞向量的訓練最經典的有 3 個工作,C&W 2008、M&H 2008、Mikolov 2010。當然在說這些工作之前,不得不介紹一下這一系列中 Bengio 的經典之作 4. 詞向量的評價 詞向量的評價大體上可以分成兩種方式,第一種是把詞向量融入現有系統中,看對系統性能的提升;第二種是直接從語言學的角度對詞向量進行分析,如相似度、語義偏移等。 4.1 提升現有系統 詞向量的用法最常見的有兩種: 1. 直接用於神經網路模型的輸入層。如 C&W 的 SENNA 系統中,將訓練好的詞向量作為輸入,用前饋網路和卷積網路完成了詞性標註、語義角色標註等一系列任務。再如 Socher 將詞向量作為輸入,用遞迴神經網路完成了句法分析、情感分析等多項任務。 2. 作為輔助特徵擴充現有模型。如 Turian 將詞向量作為額外的特徵加入到接近 state of the art 的方法中,進一步提高了命名實體識別和短語識別的效果。 4.2 語言學評價 還有一個有意思的分析是 Mikolov 在 2013 年剛剛發表的一項發現。他發現兩個詞向量之間的關係,可以直接從這兩個向量的差裡體現出來。向量的差就是數學上的定義,直接逐位相減。比如 C(king)−C(queen)≈C(man)−C(woman)。更強大的是,與 C(king)−C(man)+C(woman) 最接近的向量就是 C(queen)。 為了分析詞向量的這個特點, Mikolov 使用類比(analogy)的方式來評測。如已知 a 之於 b 猶如 c 之於 d。現在給出 a、b、c,看 C(a)−C(b)+C(c) 最接近的詞是否是 d。 在文章 Mikolov 對比了詞法關係(名詞單複數 good-better:rough-rougher、動詞第三人稱單數、形容詞比較級最高階等)和語義關係(clothing-shirt:dish-bowl) 這些實驗結果中最容易理解的是:語料越大,詞向量就越好。其它的實驗由於缺乏嚴格控制條件進行對比,談不上哪個更好哪個更差。不過這裡的兩個語言學分析都非常有意思,尤其是向量之間存在這種線性平移的關係,可能會是詞向量發展的一個突破口。 關於Deep Lerning In Nlp的一些相關論文,《Deep Learning in NLP (一)詞向量和語言模型》(http://licstar.net/archives/328)這篇部落格總結的非常的好。以上內容大多數都是擷取原部落格內容。 二、實際操作 這篇文章是最近幾天看word2vec原始碼以及相關神經網路訓練詞向量論文之後的個人小小的總結,主要是針對word2vec的使用,做一下介紹。望大家使用的過程中,少走彎路。 word2vec工具中包含了對兩種模型的訓練,如下圖。在訓練每種模型的時候又分HS和NEG兩種方法。(看圖就可以發現,其實word2vec並不deep……) 除了google自己的word2vec工具,各位對詞向量感興趣的牛人們也相繼編寫了各自不同的版本。其中比較好用的是Python Gensim主題模型包中的word2vec,但透過閱讀其原始碼python版本只實現了skip-gram模型,並且只實現了透過分層softmax方法對其訓練,並沒有使用negative sampling。下面列舉一下目前出現的版本以及相對應的地址,供大家選擇。如下表: 版本 地址 CBOW Skip-Gram C http://word2vec.googlecode.com/svn/trunk/ HS NEG HS NEG python http://radimrehurek.com/gensim/ HS Java https://github.com/ansjsun/Word2VEC_java HS HS C++ https://github.com/jdeng/word2vec 未知 未知 未知 未知 以上程式碼,C++版本的我沒有看過。最權威的當然是C語言版本,但是閱讀起來比較困難一點。Python版本有最佳化處理,所以速度相對來說也不慢,但只是實現了分層softmax方法對skip-gram模型進行訓練。Java版本分別實現了分層softmax方法對CBOW模型和skip-gram模型進行訓練。C++版本的沒有閱讀其程式碼,所以未知…… 使用之前,先貼一些論文中對兩個模型和不同方法的評價圖片,方便大家根據不同任務進行不同訓練。 下面以c語言正式版本為例,來介紹word2vec的使用。 首先我們將google word2vec專案原始碼checkout 到本機,具體地址是http://word2vec.googlecode.com/svn/trunk/ 使用ssh登入實驗室Linux伺服器,地址192.168.1.143。將剛才checkout的檔案,上傳到伺服器中。 進入目錄,命令列輸入make指令,進行編譯。 這樣我們就可以開始使用,word2vec工具了。 1.將文字語料進行分詞,以空格,tab隔開都可以,中文分詞工具可以使用張華平博士的NLPIR2013 http://ictclas.nlpir.org/ 喜歡用Python 的童鞋也可以使用結巴分詞https://github.com/fxsjy/jieba。 2.將分好詞的訓練語料進行訓練,假定我語料名稱為test.txt且在word2vec目錄中。輸入命令: ./word2vec -train test.txt -output vectors.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1 以上命令表示的是輸入檔案是test.txt,輸出檔案是vectors.bin,不使用cbow模型,預設為Skip-Gram模型。 每個單詞的向量維度是200,訓練的視窗大小為5就是考慮一個詞前五個和後五個詞語(實際程式碼中還有一個隨機選視窗的過程,視窗大小<=5)。不使用NEG方法,使用HS方法。-sampe指的是取樣的閾值,如果一個詞語在訓練樣本中出現的頻率越大,那麼就越會被取樣。-binary為1指的是結果二進位制儲存,為0是普通儲存(普通儲存的時候是可以開啟看到詞語和對應的向量的)除了以上命令中的引數,word2vec還有幾個引數對我們比較有用比如-alpha設定學習速率,預設的為0.025.–min-count設定最低頻率,預設是5,如果一個詞語在文件中出現的次數小於5,那麼就會丟棄。-classes設定聚類個數,看了一下原始碼用的是k-means聚類的方法。 · 架構:skip-gram(慢、對罕見字有利)vs CBOW(快) · 訓練演算法:分層softmax(對罕見字有利)vs 負取樣(對常見詞和低緯向量有利) · 欠取樣頻繁詞:可以提高結果的準確性和速度(適用範圍1e-3到1e-5) · 文字(window)大小:skip-gram通常在10附近,CBOW通常在5附近 3.訓練好模型之後,得到vectors.bin這個模型檔案。vectors.bin這個檔案就是文件中詞語和其對應的向量,這個向量的維度是你訓練時設定的引數大小。下面我們可以利用這個model做很多自然語言處理的任務了。Google程式碼裡面提供了distance的一個應用,說白了就是讀取模型檔案中每一個詞和其對應的向量,計算所輸入query的詞,與其他所有詞語的cosine相似度,排序,返回結果。同理訓練命令中的-classes引數,也是獲取每個詞對應的向量之後,對詞語進行k-means聚類。對於訓練出來的模型進行操作,我推薦大家使用http://blog.csdn.net/zhaoxinfan/article/details/11640573這個java版本的模型讀取類,比較方便,讀取模型之後大家就可以來實現各種各樣有趣的東西了。下面舉幾個例子: a.計算兩個詞語相似度,如圖1計算asp與net的相似度為0.6215127 圖1 b.列出所有相似詞語列表,如圖2為“php”的結果。 圖二 c.尋找對應關係:如圖3: 男人-男孩 女人-? 如圖4:內蒙-呼和浩特 河北-? 圖3 圖4 d.刪選不合群的詞語,可以用來做特徵選擇:如圖5所示:
一、理論概述 (主要來源於http://licstar.net/archives/328這篇部落格) 1.詞向量是什麼 自然語言理解的問題要轉化為機器學習的問題,第一步肯定是要找一種方法把這些符號數學化。 NLP 中最直觀,也是到目前為止最常用的詞表示方法是 One-hot Representation,這種方法把每個詞表示為一個很長的向量。這個向量的維度是詞表大小,其中絕大多數元素為 0,只有一個維度的值為 1,這個維度就代表了當前的詞。 舉個栗子, “話筒”表示為 [0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 ...] “麥克”表示為 [0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 ...] 每個詞都是茫茫 0 海中的一個 1。 這種 One-hot Representation 如果採用稀疏方式儲存,會是非常的簡潔:也就是給每個詞分配一個數字 ID。比如剛才的例子中,話筒記為 3,麥克記為 8(假設從 0 開始記)。如果要程式設計實現的話,用 Hash 表給每個詞分配一個編號就可以了。這麼簡潔的表示方法配合上最大熵、SVM、CRF 等等演算法已經很好地完成了 NLP 領域的各種主流任務。 當然這種表示方法也存在一個重要的問題就是“詞彙鴻溝”現象:任意兩個詞之間都是孤立的。光從這兩個向量中看不出兩個詞是否有關係,哪怕是話筒和麥克這樣的同義詞也不能倖免於難。 Deep Learning 中一般用到的詞向量並不是剛才提到的用 One-hot Representation 表示的那種很長很長的詞向量,而是用 Distributed Representation(不知道這個應該怎麼翻譯,因為還存在一種叫“Distributional Representation”(類似,LDA中用topic表示詞語的詞向量的表示方法)表示的一種低維實數向量。這種向量一般是這個樣子:[0.792, −0.177, −0.107, 0.109, −0.542, ...]。維度以 50 維和 100 維比較常見。 2.詞向量的來歷 Distributed representation 最早是 Hinton 在 1986 年的論文《Learning distributed representations of concepts》中提出的。雖然這篇文章沒有說要將詞做 Distributed representation但至少這種先進的思想在那個時候就在人們的心中埋下了火種,到 2000 年之後開始逐漸被人重視。 3. 詞向量的訓練 要介紹詞向量是怎麼訓練得到的,就不得不提到語言模型。到目前為止我瞭解到的所有訓練方法都是在訓練語言模型的同時,順便得到詞向量的。 這也比較容易理解,要從一段無標註的自然文字中學習出一些東西,無非就是統計出詞頻、詞的共現、詞的搭配之類的資訊。而要從自然文字中統計並建立一個語言模型,無疑是要求最為精確的一個任務(也不排除以後有人創造出更好更有用的方法)。既然構建語言模型這一任務要求這麼高,其中必然也需要對語言進行更精細的統計和分析,同時也會需要更好的模型,更大的資料來支撐。目前最好的詞向量都來自於此,也就不難理解了。 詞向量的訓練最經典的有 3 個工作,C&W 2008、M&H 2008、Mikolov 2010。當然在說這些工作之前,不得不介紹一下這一系列中 Bengio 的經典之作 4. 詞向量的評價 詞向量的評價大體上可以分成兩種方式,第一種是把詞向量融入現有系統中,看對系統性能的提升;第二種是直接從語言學的角度對詞向量進行分析,如相似度、語義偏移等。 4.1 提升現有系統 詞向量的用法最常見的有兩種: 1. 直接用於神經網路模型的輸入層。如 C&W 的 SENNA 系統中,將訓練好的詞向量作為輸入,用前饋網路和卷積網路完成了詞性標註、語義角色標註等一系列任務。再如 Socher 將詞向量作為輸入,用遞迴神經網路完成了句法分析、情感分析等多項任務。 2. 作為輔助特徵擴充現有模型。如 Turian 將詞向量作為額外的特徵加入到接近 state of the art 的方法中,進一步提高了命名實體識別和短語識別的效果。 4.2 語言學評價 還有一個有意思的分析是 Mikolov 在 2013 年剛剛發表的一項發現。他發現兩個詞向量之間的關係,可以直接從這兩個向量的差裡體現出來。向量的差就是數學上的定義,直接逐位相減。比如 C(king)−C(queen)≈C(man)−C(woman)。更強大的是,與 C(king)−C(man)+C(woman) 最接近的向量就是 C(queen)。 為了分析詞向量的這個特點, Mikolov 使用類比(analogy)的方式來評測。如已知 a 之於 b 猶如 c 之於 d。現在給出 a、b、c,看 C(a)−C(b)+C(c) 最接近的詞是否是 d。 在文章 Mikolov 對比了詞法關係(名詞單複數 good-better:rough-rougher、動詞第三人稱單數、形容詞比較級最高階等)和語義關係(clothing-shirt:dish-bowl) 這些實驗結果中最容易理解的是:語料越大,詞向量就越好。其它的實驗由於缺乏嚴格控制條件進行對比,談不上哪個更好哪個更差。不過這裡的兩個語言學分析都非常有意思,尤其是向量之間存在這種線性平移的關係,可能會是詞向量發展的一個突破口。 關於Deep Lerning In Nlp的一些相關論文,《Deep Learning in NLP (一)詞向量和語言模型》(http://licstar.net/archives/328)這篇部落格總結的非常的好。以上內容大多數都是擷取原部落格內容。 二、實際操作 這篇文章是最近幾天看word2vec原始碼以及相關神經網路訓練詞向量論文之後的個人小小的總結,主要是針對word2vec的使用,做一下介紹。望大家使用的過程中,少走彎路。 word2vec工具中包含了對兩種模型的訓練,如下圖。在訓練每種模型的時候又分HS和NEG兩種方法。(看圖就可以發現,其實word2vec並不deep……) 除了google自己的word2vec工具,各位對詞向量感興趣的牛人們也相繼編寫了各自不同的版本。其中比較好用的是Python Gensim主題模型包中的word2vec,但透過閱讀其原始碼python版本只實現了skip-gram模型,並且只實現了透過分層softmax方法對其訓練,並沒有使用negative sampling。下面列舉一下目前出現的版本以及相對應的地址,供大家選擇。如下表: 版本 地址 CBOW Skip-Gram C http://word2vec.googlecode.com/svn/trunk/ HS NEG HS NEG python http://radimrehurek.com/gensim/ HS Java https://github.com/ansjsun/Word2VEC_java HS HS C++ https://github.com/jdeng/word2vec 未知 未知 未知 未知 以上程式碼,C++版本的我沒有看過。最權威的當然是C語言版本,但是閱讀起來比較困難一點。Python版本有最佳化處理,所以速度相對來說也不慢,但只是實現了分層softmax方法對skip-gram模型進行訓練。Java版本分別實現了分層softmax方法對CBOW模型和skip-gram模型進行訓練。C++版本的沒有閱讀其程式碼,所以未知…… 使用之前,先貼一些論文中對兩個模型和不同方法的評價圖片,方便大家根據不同任務進行不同訓練。 下面以c語言正式版本為例,來介紹word2vec的使用。 首先我們將google word2vec專案原始碼checkout 到本機,具體地址是http://word2vec.googlecode.com/svn/trunk/ 使用ssh登入實驗室Linux伺服器,地址192.168.1.143。將剛才checkout的檔案,上傳到伺服器中。 進入目錄,命令列輸入make指令,進行編譯。 這樣我們就可以開始使用,word2vec工具了。 1.將文字語料進行分詞,以空格,tab隔開都可以,中文分詞工具可以使用張華平博士的NLPIR2013 http://ictclas.nlpir.org/ 喜歡用Python 的童鞋也可以使用結巴分詞https://github.com/fxsjy/jieba。 2.將分好詞的訓練語料進行訓練,假定我語料名稱為test.txt且在word2vec目錄中。輸入命令: ./word2vec -train test.txt -output vectors.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1 以上命令表示的是輸入檔案是test.txt,輸出檔案是vectors.bin,不使用cbow模型,預設為Skip-Gram模型。 每個單詞的向量維度是200,訓練的視窗大小為5就是考慮一個詞前五個和後五個詞語(實際程式碼中還有一個隨機選視窗的過程,視窗大小<=5)。不使用NEG方法,使用HS方法。-sampe指的是取樣的閾值,如果一個詞語在訓練樣本中出現的頻率越大,那麼就越會被取樣。-binary為1指的是結果二進位制儲存,為0是普通儲存(普通儲存的時候是可以開啟看到詞語和對應的向量的)除了以上命令中的引數,word2vec還有幾個引數對我們比較有用比如-alpha設定學習速率,預設的為0.025.–min-count設定最低頻率,預設是5,如果一個詞語在文件中出現的次數小於5,那麼就會丟棄。-classes設定聚類個數,看了一下原始碼用的是k-means聚類的方法。 · 架構:skip-gram(慢、對罕見字有利)vs CBOW(快) · 訓練演算法:分層softmax(對罕見字有利)vs 負取樣(對常見詞和低緯向量有利) · 欠取樣頻繁詞:可以提高結果的準確性和速度(適用範圍1e-3到1e-5) · 文字(window)大小:skip-gram通常在10附近,CBOW通常在5附近 3.訓練好模型之後,得到vectors.bin這個模型檔案。vectors.bin這個檔案就是文件中詞語和其對應的向量,這個向量的維度是你訓練時設定的引數大小。下面我們可以利用這個model做很多自然語言處理的任務了。Google程式碼裡面提供了distance的一個應用,說白了就是讀取模型檔案中每一個詞和其對應的向量,計算所輸入query的詞,與其他所有詞語的cosine相似度,排序,返回結果。同理訓練命令中的-classes引數,也是獲取每個詞對應的向量之後,對詞語進行k-means聚類。對於訓練出來的模型進行操作,我推薦大家使用http://blog.csdn.net/zhaoxinfan/article/details/11640573這個java版本的模型讀取類,比較方便,讀取模型之後大家就可以來實現各種各樣有趣的東西了。下面舉幾個例子: a.計算兩個詞語相似度,如圖1計算asp與net的相似度為0.6215127 圖1 b.列出所有相似詞語列表,如圖2為“php”的結果。 圖二 c.尋找對應關係:如圖3: 男人-男孩 女人-? 如圖4:內蒙-呼和浩特 河北-? 圖3 圖4 d.刪選不合群的詞語,可以用來做特徵選擇:如圖5所示: