用中文資料測試 word2vec

By Shaform, Tue 04 November 2014, in category Notes

Chinese, jieba, python, word2vec

最近因為一些學習上的需要接觸了 word2vec,覺得好像是有點神秘的東西。一般初學自然語言處理的時候,處理文字最簡單的模型就是把每個詞當作一個單位,比如說用個 id 來表示他。然後再去算詞與詞之間的統計關係。或者是利用句子的文法結構來進行其他處理。如果把每個詞出現的次數當作一個維度的話,也可以把句子或文件用一個向量來表示。

不過 word2vec 是把每個詞本身用一個多維向量來表示,把詞投影到一個向量空間裡。而且不知道為什麼投影出來的空間有些特殊的性質,比如說相同屬性的詞可能會靠得很近,甚至部份的向量有邏輯上的線性關係等等:

vector('King') - vector('Man') + vector('Woman') ~= vector('Queen')

這份筆記紀錄了使用 word2vec 處理中文資料的小小實驗。

語料

不太確定有什麼開放的中文語料可供使用,於是決定先用萌典來做實驗,可按照教學,下載萌典資料:

git clone --depth 1 https://github.com/g0v/moedict-data.git
git clone --depth 1 https://github.com/g0v/moedict-epub.git
cp -v moedict-data/dict-revised.json moedict-epub/
cd moedict-epub
perl json2unicode.pl > dict-revised.unicode.json

緊接著我自己寫了一個 extract_json.py 把當中可供訓練的句子抽出來:

python3 extract_json.py < dict-revised.unicode.json > sentences.txt

斷詞

因為 word2vec 的輸入必須是以空白隔開的詞,這樣得出來的句子還不能直接使用。於是我用了結巴斷詞,寫了一個 cut.py 來處理這些句子。

python cut.py < sentences.txt > sentences.segged.txt

斷出來的結果大約像是:

紅樓夢 . 第十七回 : 「 一 槅 一 槅 , 或 有 貯書處 , 或 有 設鼎處 , 或 安置 筆硯 處 , 或供 設瓶花 、 或 安放 盆景 處 。 」

感覺雖不是很理想,但尚可接受。

使用 word2vec 訓練詞向量

接著我就用工作站把詞全部丟給 word2vec 訓練:

./word2vec -train sentences.segged.txt -output vectors.bin -cbow 0 -size 200 -window 10 -negative 5 -hs 0 -sample 1e-4 -threads 24 -binary 1 -iter 20 -min-count 1

因為萌典抽出來的資料不算多,所以訓練起來滿快的,只是當然效果就不太好了:

word2vec running...

測試

首先測試距離相近的字:

./distance vectors.bin

雖然效果差強人意,不過還是可以看到相同屬性的字確實有些群聚效應:

Enter word or sentence (EXIT to break): 法國

Word: 法國  Position in vocabulary: 992

                                            Word         Cosine distance
------------------------------------------------------------------------
                                            英國         0.763948
                                            德國         0.727664
                                          義大利         0.724732
                                            瑞士         0.724247
                                          西班牙         0.715528
                                          奧地利         0.696855
                                          蘇格蘭         0.689557

接著測試線性關係,A 比 B 就好像 C 比什麼?:

./word-analogy vectors.bin

對於國家與都市的推理,也稍有效果:

Enter three words (EXIT to break): 法國 巴黎 英國

Word: 法國  Position in vocabulary: 992

Word: 巴黎  Position in vocabulary: 6379

Word: 英國  Position in vocabulary: 822

                                            Word         Distance
------------------------------------------------------------------------
                                            倫敦         0.583572
                                          七二年         0.576999
                                          莫斯科         0.566673
                                          四四年         0.566332
                                      一九四一年         0.562817
                                          芝加哥         0.559529
                                      一九六二年         0.556010
                                          羅浮宮         0.555593
                                          油畫院         0.554334

訓練出來的詞向量或許可以供進一步利用,只是在實際使用之前無法確定是否適用於特定的應用。

程式碼

我把相關的程式碼放在 GitHub 上面供參考:https://github.com/shaform/experiments/tree/master/word2vec_tw

參考資料

  1. word2vec
  2. 利用中文数据跑Google开源项目word2vec
  3. 如何使用 JIEBA 結巴中文分詞程式