word2vec 是google 推出的做詞嵌入(word embedding)的開源工具。 簡單的說,它在給定的語料庫上訓練一個模型,然后會輸出所有出現在語料庫上的單詞的向量表示,這個向量稱為"word embedding"。基於這個向量表示,可以計算詞與詞之間的關系,例如相似性(同義詞等),語義關聯性(中國 - 北京 = 英國 - 倫敦)等。NLP中傳統的詞表示方法是 one-hot representation, 即把每個單詞表示成dim維的稀疏向量,dim等於詞匯量的大小。這個稀疏向量只有一個維度(該單詞的index)上是1,其余全是0。這個表示方法使得單詞之間是孤立的。 word embedding則是把單詞的表示降維到n維的稠密向量,n<<dim。
作為非NLP專業的人,我不在此講述word embedding的算法原理,本文是對word2vec工具使用過程的整理與總結,方便大家盡快上手。本文以中文處理為例,Word2vec對語言並沒有限制。
安裝 word2vec
從它的項目主頁上下載源碼(或者從我的github上下載 https://github.com/Leavingseason/word2vec 內容是一樣的)。源碼是linux下的c語言寫的,如果要在windows下編譯,需要用到Cygwin。Cygwin就是在windows平台上運行類Unix的模擬環境。安裝需要幾個小時,之后在Cygwin里面編譯Word2vec,不需要改任何代碼。
如果不想裝Cygwin,也可以用Java版本的Word2vec。 我fork了一個java版本的實現:https://github.com/Leavingseason/Word2VEC_java 其中MyWord2VEC_java_eclipse.zip是我自己稍微整理的直接在eclipse上可以用的源碼。經測試java版的也很好用。
准備語料庫
要針對自己的情景,訓練適合自己的詞嵌入,所以要自己准備一個語料庫。我用的是商品點評的語料。如果大家想做實驗試試,可以用wiki的中文語料庫,參考 http://www.52nlp.cn/%E4%B8%AD%E8%8B%B1%E6%96%87%E7%BB%B4%E5%9F%BA%E7%99%BE%E7%A7%91%E8%AF%AD%E6%96%99%E4%B8%8A%E7%9A%84word2vec%E5%AE%9E%E9%AA%8C/comment-page-1 我自己處理了一份中文wiki語料庫,已經完成格式化、繁體轉簡體和分詞的過程,下載頁面: http://pan.baidu.com/s/1jHZCvvo 格式如下圖所示:
對於中文語料,第一步需要分詞。現成的工具很多,我喜歡用SnowNLP https://github.com/isnowfy/snownlp , 除了分詞,它還提供情感分析,繁體轉簡體,漢字to拼音等功能。 當然現有的其他NLP工具很多,像結巴分詞等等。我試用了SnowNLP,感覺效果還挺不錯的。
分完詞后,把語料庫整理成Word2vec的輸入格式。這個格式很簡單,單詞之間用空格隔開就行了。 word2vec 把一個單詞的前面和后面的k個單詞作為context訓練, 其中會自動把換行符替換成 </s> ,也就是句子分隔符。
訓練word2vec模型
其實在源碼目錄有一些類似“demo-train-big-model-v1.sh”的腳本,它們就是運行Word2vec工具的示例。它會自動下載一個語料庫然后執行。如果我們已經有了語料庫,就不用下載了,腳本可以簡化很多(Cygwin中運行):
time ./word2vec -train "data/review.txt" -output "data/review.model" -cbow 1 -size 100 -window 8 -negative 25 -hs 0 -sample 1e-4 -threads 20 -binary 1 -iter 15
-train "data/review.txt" 表示在指定的語料庫上訓練模型
-cbow 1 表示用cbow模型,設成0表示用skip-gram模型
-size 100 詞向量的維度為100
-window 8 訓練窗口的大小為8 即考慮一個單詞的前八個和后八個單詞
-negative 25 -hs 0 是使用negative sample還是HS算法
-sample 1e-4 采用閾值
-threads 20 線程數
-binary 1 輸出model保存成2進制
-iter 15 迭代次數
訓練還是很快的,在我的1G語料庫上訓練2小時左右。
使用結果
得到模型后,可以用命令 ./distance data/review.model 測試單詞的最近鄰。 這個要求剛才生成的模型是保存成二進制的。
除了計算距離,還有一些有意思的例子,例如http://www.tuicool.com/articles/RB7fqaB 所寫。
如果把模型保存成普通文本型,那么可以得到每個單詞的向量表示,使用就靈活了,可以在自己的程序里讀取這個model, 然后和自由計算各種值。
如果想偷懶的話,就用上述提到的java版程序加載model,然后可以做一系列方法調用。