1. 程式人生 > >利用中文數據跑Google開源項目word2vec

利用中文數據跑Google開源項目word2vec

訓練數據 ear most text 處理 spa csdn 增量 archive

word2vec註釋

1、多線程並行處理:

1、分配內存空間,創建多線程,執行多線程。malloc,pthread_create,pthread_join
2、每個多線程處理的訓練文檔根據線程id,分配不同的文檔內容,由fseek定位


2、vocab相關:

1、每個vocab對象都含以下內容:詞(char[]),詞頻(long long),詞在哈夫曼樹中的父節點們(可以理解為編碼的次序)(int*),哈夫曼編碼(char*),哈夫曼碼長度(char)
2、獲取vocab詞典有兩條路徑
1、是從詞典文件直接讀取。這個要求第一行是,也就是句子的分隔符(如果在訓練語料裏沒有這個分隔符,則基本默認1000個詞(最長句子長度)為一句話)
第二,每行應該是一個詞後面接詞頻信息
2、從訓練語料中統計。如果沒指定詞典文件,則在訓練之前,程序會先遍歷一邊文檔,統計出詞典信息。
3、vocab的添加是增量式的

,比如最初是1000的大小,當空間不夠的時候會再添加2000,再不夠,再添加3000,每次添加的數額比上次多1000
4、程序中設定了vocab_hash_size是300W,如果要求裝填因子在0.7左右,則vocab中詞的個數不應該超過210W,所以當個數超過210W的時候就會刪除詞頻比較低的詞
最開始設置的刪除詞頻為1(min_reduce)及以下的詞,再次超過210W的時候,min_reduce會加1,刪除詞頻<=2的詞,一直如此
5、在添加vocab的時候,同時維護了一張vocab_hash的哈希表
1、vocab_hash的key是詞通過hash函數得出的int型值,value是這個詞在vocab中的下標(從0開始),vocab_hash就是一個int型數組
2、獲取word的hash key值得hash函數如下:for (a = 0; a < strlen(word); a++) hash = hash * 257 + word[a];
3、解決沖突的方法就是開放地址法,while (vocab_hash[hash] != -1) hash = (hash + 1) % vocab_hash_size;向下順移
4、vocab_hash的構建是為了方便查找
6、在統計完成之後需要對vocab進行排序,按照詞頻的大小逆序排序,

1、第一個詞,也就是不進行排序
2、排完序之後,需要將詞頻小於min_count的詞去掉(直接free)
2、排完序之後,需要對vocab_hash重新就行計算


3、net initialization相關:

    1、初始化三個矩陣,syn0(vocab_size*layer1_size),syn1(vocab_size*layer1_size),syn1neg(vocab_size*layer1_size)
    2、vocab_size是詞表的大小,layer1_size即詞向量的維數
    3、syn0用一個-0.005~0.005之間的數隨機初始化裏面的元素,syn1,syn1neg直接用0初始化
    4、syn0就是最後得到的詞的詞向量,與vocab相呼應;即vocab[i].word這個詞的詞向量時syn0中的第i行(i從0開始)
    5、syn1是用hierachical softmax算法時候的輔助矩陣,syn1neg是用negative sampling算法時候的輔助矩陣
    6、syn1的每一行可以認為是哈夫曼樹中的一個非葉子節點,這一行應該就代表了以他為祖先的葉子節點(詞)的綜合含義;
            對於一個哈夫曼樹,如果有N個葉子節點,則有N-1個非葉子節點,所以syn1和syn1neg裏面的最後一行應該是無意義的
            行數越大,代表的詞也就越多,如第V-2行(哈夫曼樹的根節點)理論上代表了所有詞的意思
    7、syn1neg的每一行與vocab相呼應,也就是vocab[i].word這個詞在做負樣本時有一個向量的表示,在syn1neg的第i行(從0開始)

4、binary tree create相關:

    1、用詞頻進行編碼,詞頻越大的詞的編碼長度越小
    2、用了三個2*vocab_size的long long 型數組,代碼比較巧妙,可以學學
    3、初始化vocab結構體其他的成員:codelen,code(從上到下),point(從上到下跟該詞相關的節點(不包括根節點)/該詞相應code的編碼時機次序)

5、訓練相關:

1、每訓練10000個詞打印一次progress信息,並更新學習速率alpha(starting_alpha是0.025)
2、同時每次是取出一句話後再進行訓練,處理完一句話後,再讀取下一句,循環叠代

            1、讀取句子時,以</s>分隔符為標識,如果沒有</s>則以上屆1000個詞為一句話。ps:在訓練的時候是將換行符換成了</s>的
            2、如果選擇的了sub_sampling,則在遍歷訓練文檔,構建句子的過程中,會隨機的忽視掉一些頻率比較高的詞,具體方法可以看代碼,不太懂

3、在程序執行過程中,每次的詞窗大小是在隨機變化的,如果設置參數-window 5,則窗口的大小就是3~11之間,也就是前k個詞+後k個詞+中間詞,k在1~5之間

4、有兩個向量值得關註:neu1,neu1e,都是layer1_size的大小,在cbow和skip gram model中具體略有不同

5、cbow模型:

1、cbow模型就是continuous bag of words,根據前k個詞和後k個詞預測中間詞
2、找到前k個詞和後k個詞在vocab中的位置,並從syn0中找出他們的詞向量,各維數相加,得到一個layer1_size的向量,即neu1
3、用hierachical softmax算法時,需要根據該詞的每一位code編碼進行計算,假定第j位code:

                1、先找到該位code在哈夫曼樹中的位置(存儲在vocab[i].point[j]中),然後以此位置在syn1中找到對應的向量
                2、用neu1與syn1中的這行向量相乘,得到f值,這個f就是輸出值,然後對f進行歸一化,映射到0~1之間
                3、這點跟邏輯回歸有點類似。在程序中,把softmax的label設置的是1-code[j],這個label就是logistic regression裏面的真實值,f就是猜測
                4、通過3,和邏輯回歸的理論類推,我們就能得到一個loss function 或者負log 似然函數
                5、loss function關於兩個向量(neu1和syn1中的那行)的梯度共同部分為(1 - vocab[word].code[d] - f),對了,還有一個學習速率
                6、 更新neu1e和syn1[vocab[i].point[j]],比如更新neu1,就用g = (1 - vocab[word].code[d] - f) * alpha;neu1e = g.*syn1[vocab[i].point[j]](標量與向量的乘積)
                            更新syn1[vocab[i].point[j]],syn1[vocab[i].point[j]] = g.*neu1;

4、用negative sampling算法時,並不需要考慮code編碼的問題:

                1、在參數設置的時候,假設我們選定了negative samples 為k個
                2、我們隨機的在詞表當中抽取k個negative samples 詞,當然有可能會抽到與當前這個詞相同(雖然概率很小),我們就pass過去,也就是說真實的negative samples可能沒有k個
                3、假設我們現在考慮的是第j個negative sample,則從syn1neg裏面找到j的向量表示,同neu1(上下文向量表示)相乘,得到輸出值f,同樣歸一化
                4、這裏的g與hs中的g有點不同,這裏g = (label-f)*alpha;如果是負樣本的話label是0,如果是當前詞label是1
                5、更新neu1e和syn1neg[vocab[i].point[j]],同3.6

5、在上述第3或第4步處理完畢後,我們有一個neu1e的向量,我們再用這個neu1e去更新前k個詞和後k個詞的詞向量,就是syn0裏面的2k維向量(直接相加),從而完成了一個窗口的叠代更新
6、skip-gram 模型:

            1、skip-gram model與cbow正好相反,是根據當前詞來預測前k個和後k個詞
            2、假設現在當前詞為cur_word,而我們要推測出窗口中的某個詞last_word,last_word在窗口中,有2*k個這樣的last_word都需要推測
            3、用hierachical softmax算法時,同樣需要對cur_word的每一位code編碼進行計算,假定第j位code:
                1、找到last_word在vocab中的位置,以此位置在syn0中找到對應的向量
                2、先找到該位code在哈夫曼樹中的位置(存儲在vocab[i].point[j]中),然後以此位置在syn1中找到對應的向量
                3、用last_word的向量與syn1中的這行向量相乘,得到f值,這個f就是輸出值,然後對f進行歸一化,映射到0~1之間
                4、同樣計算出梯度,並通過梯度來更新neu1e和syn1,具體的和cbow-hs幾乎一樣
            4、用negative sampling算法時,所有流程基本與cbow的negative sampling一樣,唯一的區別就是不是用neu1向量與syn1neg相乘,而是用last_word的詞向量

6、tips:

    1、程序中在對輸出值f進行0~1之間映射的時候,是提前算好了一個數組expTable,這個數組的值在0.01~1(1/(1+e-6)~1/(1+e6))之間,所以f值小於-6或者大於6就continue了。
    2、在進行negative sampling的時候,隨機選擇的word是和word的概率的power次方成正比的
    3、隨機數的生成:每次乘以一個很大的數,然後加11,然後取模,然後歸一化

word2vec訓練參數說明

訓練命令:

./word2vec -train text8 -output vectors.bin -cbow 1 -size 200 -window 8 -negative 25 -hs 0 -sample 1e-4 -threads 20 -binary 0 -iter 15
./distance vectors.bin

中的text8更改成自己的訓練數據名稱all_words,如果你的數據有後綴,記得帶後綴。
技術分享
參數解釋:
-train 訓練數據
-output 結果輸入文件,即每個詞的向量
-cbow 是否使用cbow模型,0表示使用skip-gram模型,1表示使用cbow模型,默認情況下是skip-gram模型,cbow模型快一些,skip-gram模型效果好一些
-size 表示輸出的詞向量維數
-window 為訓練的窗口大小,8表示每個詞考慮前8個詞與後8個詞(實際代碼中還有一個隨機選窗口的過程,窗口大小<=5)
-negative 表示是否使用NEG方,0表示不使用,其它的值目前還不是很清楚
-hs 是否使用HS方法,0表示不使用,1表示使用
-sample 表示 采樣的閾值,如果一個詞在訓練樣本中出現的頻率越大,那麽就越會被采樣
-binary 表示輸出的結果文件是否采用二進制存儲,0表示不使用(即普通的文本存儲,可以打開查看),1表示使用,即vectors.bin的存儲類型

除了上面所講的參數,還有:
-alpha 表示 學習速率
-min-count 表示設置最低頻率,默認為5,如果一個詞語在文檔中出現的次數小於該閾值,那麽該詞就會被舍棄
-classes 表示詞聚類簇的個數,從相關源碼中可以得出該聚類是采用k-means

===============================================================

一直聽說word2vec在處理詞與詞的相似度的問題上效果十分好,最近自己也上手跑了跑Google開源的代碼(https://code.google.com/p/word2vec/)。

1、語料

首先準備數據:采用網上博客上推薦的全網新聞數據(SogouCA),大小為2.1G。

從ftp上下載數據包SogouCA.tar.gz:
1 wget ftp://ftp.labs.sogou.com/Data/SogouCA/SogouCA.tar.gz [email protected] --ftp-password=4FqLSYdNcrDXvNDi -r

解壓數據包:

1 gzip -d SogouCA.tar.gz
2 tar -xvf SogouCA.tar

再將生成的txt文件歸並到SogouCA.txt中,取出其中包含content的行並轉碼,得到語料corpus.txt,大小為2.7G。

1 cat *.txt > SogouCA.txt
2 cat SogouCA.txt | iconv -f gbk -t utf-8 -c | grep "<content>" > corpus.txt

2、分詞

用ANSJ對corpus.txt進行分詞,得到分詞結果resultbig.txt,大小為3.1G。

分詞工具ANSJ參見 http://blog.csdn.net/zhaoxinfan/article/details/10403917 在分詞工具seg_tool目錄下先編譯再執行得到分詞結果resultbig.txt,內含426221個詞,次數總計572308385個。 分詞結果: 技術分享 3、用word2vec工具訓練詞向量
1 nohup ./word2vec -train resultbig.txt -output vectors.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1 &

vectors.bin是word2vec處理resultbig.txt後生成的詞的向量文件,在實驗室的服務器上訓練了1個半小時。

4、分析 4.1 計算相似的詞:
1 ./distance vectors.bin

./distance可以看成計算詞與詞之間的距離,把詞看成向量空間上的一個點,distance看成向量空間上點與點的距離。

下面是一些例子:

技術分享

技術分享

技術分享

技術分享

技術分享

技術分享

技術分享

技術分享

4.2 潛在的語言學規律

在對demo-analogy.sh修改後得到下面幾個例子: 法國的首都是巴黎,英國的首都是倫敦, vector(“法國”) – vector(“巴黎) + vector(“英國”) –> vector(“倫敦”)”

技術分享

技術分享

技術分享

技術分享

4.3 聚類

將經過分詞後的語料resultbig.txt中的詞聚類並按照類別排序:

1 nohup ./word2vec -train resultbig.txt -output classes.txt -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -classes 500  &
2 sort classes.txt -k 2 -n > classes_sorted_sogouca.txt

例如:

技術分享

技術分享

4.4 短語分析

先利用經過分詞的語料resultbig.txt中得出包含詞和短語的文件sogouca_phrase.txt,再訓練該文件中詞與短語的向量表示。

1 ./word2phrase -train resultbig.txt -output sogouca_phrase.txt -threshold 500 -debug 2
2 ./word2vec -train sogouca_phrase.txt -output vectors_sogouca_phrase.bin -cbow 0 -size 300 -window 10 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1

下面是幾個計算相似度的例子:

技術分享

技術分享

技術分享

5、參考鏈接

1. word2vec:Tool for computing continuous distributed representations of words,https://code.google.com/p/word2vec/

2. 用中文把玩Google開源的Deep-Learning項目word2vec,http://www.cnblogs.com/wowarsenal/p/3293586.html

3. 利用word2vec對關鍵詞進行聚類,http://blog.csdn.net/zhaoxinfan/article/details/11069485

6、後續準備仔細閱讀的文獻:

[1] Tomas Mikolov, Kai Chen, Greg Corrado, and Jeffrey Dean. Efficient Estimation of Word Representations in Vector Space. In Proceedings of Workshop at ICLR, 2013.
[2] Tomas Mikolov, Ilya Sutskever, Kai Chen, Greg Corrado, and Jeffrey Dean. Distributed Representations of Words and Phrases and their Compositionality. In Proceedings of NIPS, 2013.
[3] Tomas Mikolov, Wen-tau Yih, and Geoffrey Zweig. Linguistic Regularities in Continuous Space Word Representations. In Proceedings of NAACL HLT, 2013.

[4] Collobert R, Weston J, Bottou L, et al. Natural language processing (almost) from scratch[J]. The Journal of Machine Learning Research, 2011, 12: 2493-2537.

來源:http://www.cnblogs.com/hebin/p/3507609.html

轉載請註明:人人都是數據咖 ? 利用中文數據跑Google開源項目word2vec

利用中文數據跑Google開源項目word2vec