用中文把玩Google開源的Deep-Learning項目word2vec


google最近新開放出word2vec項目,該項目使用deep-learning技術將term表示為向量,由此計算term之間的相似度,對term聚類等,該項目也支持phrase的自動識別,以及與term等同的計算。

word2vec項目首頁:https://code.google.com/p/word2vec/,文檔比較詳盡,很容易上手。可能對於不同的系統和gcc版本,需要稍微改一下代碼和makefile。具體到我的mac系統,源代碼中所有#include <malloc.h>的地方都需要改成#include <stdlib.h>,makefile編譯選項中的-Ofast要更改為-O2,-march=native -Wno-unused-result這兩個編譯選項都不認,使用予以刪除。直接make,按照它的文檔提示運行即可。

本文主要說說如何使用word2vec處理中文語料。首先我們打開demo-word.sh看看,腳本開始其實就是去下載語料並解壓成text8文件,這份文件約96M大小,less看看其實就是純文本的英文,每個單詞之間有空格隔開:

 anarchism originated as a term of abuse first used against early working class radicals including the diggers of the english revolution and the sans culottes of the french revolution whilst the term is still used in a pejorative way to describe any act that used violent means to destroy the organization of society it has also been taken up as a positive label by self defined anarchists the word anarchism is derived from the greek without archons ruler chief king anarchism as a political philosophy is the belief that rulers are unnecessary and should be abolished although there... 

所以如果我們有一份分過詞的中文語料,每個詞(term)之間用空格隔開,就可以用word2vec來處理了。

分詞我們使用開源的ansj_seg項目,該項目是用java實現中科院ictclas中的算法(下載ictclas沒有源碼,且linux 64bit的版本在64位mac下鏈接庫報錯,應該是不兼容,ictclas官方並未提供mac 64bit的版本)。ansj_seg的官方主頁在:https://github.com/ansjsun/ansj_seg,運行:

git clone https://github.com/ansjsun/ansj_seg

下載該項目會報類似下面的錯誤:

error: RPC failed; result=22, HTTP code = 413 | 116 KiB/s   
fatal: The remote end hung up unexpectedly
Writing objects: 100% (2504/2504), 449.61 MiB | 4.19 MiB/s, done.
Total 2504 (delta 1309), reused 2242 (delta 1216)
fatal: The remote end hung up unexpectedly

在stackoverflow上搜了下解決辦法,需要執行下面的命令,配置git的緩沖區大小:

git config --global http.postBuffer 524288000

如果仍然失敗的話,可以在ansj_seg主頁直接下載項目的.zip文件,解壓即可。

如果用eclipse打開該項目,還需要依賴一個tree-split-word的項目,這是一個Trie樹實現用來查詞表的項目,ansj_seg主頁目前給出的鏈接已經失效,在github搜索treesplitword可以找到這個項目,下載后打成jar包,加入到ansj_seg的項目中,發現仍然有錯,原因是當前的tree-split-word的很多接口都與ansj_seg中使用的不兼容了。

這時發現ansj_seg是一個maven項目,直接使用mvn compile命令編譯,會自動下載其所需依賴,整個編譯過程沒有報錯,最終取得成功。從中提取出項目使用的tree_split-1.0.1.jar,加入到eclipse項目中,重新build一下,eclipse中的紅叉消失。

到ansj_seg項目中的src/demo/java/下的org.ansj.demo包中跑一跑每一個demo文件,會遇到以下問題:

1. 報錯找不到library.properties文件,將項目根目錄下的library.properties.bak copy成library.properties,並注意添加eclipse項目中的classpath,可以解決這個問題;

2. 初始化詞典時會報找不到nature/nature.map文件(詞性映射文件,ansj_seg不僅有分詞的功能,還能詞性標注),find . -iname nature.map會發現其實這個文件是存在的,可以直接加eclipse的classpath指向ansj_seg/src/main/resources目錄即可;

3. 跑demo時可能會報OutOfMemory的錯誤,加載詞典可能超出了eclipse的默認jvm大小,可以在run as時,設定argument,-Xmx512M -Xms512M即可。

解決上述問題后,除了demo中需要讀文件的沒有,其他demo都能成功運行。ansj_seg的接口也非常簡潔易用,很容易編程讀取自己的語料文件進行分詞。

最后我們需要解決的就是語料問題。搜狗實驗室公布了許多有用的語料,我使用其中的全網新聞數據:http://www.sogou.com/labs/dl/ca.html,填寫姓名郵箱申請得到用戶名密碼,可以獲得一個ftp下載地址。首先下載一個迷你語料news_tensite_xml.smarty.tar.gz做做簡單實驗,解壓文件可以看到文本的格式,很容易理解,該文件是gbk編碼的,可以轉成utf-8編碼再進行處理。基於這個迷你語料和ansj_seg編程分詞,生成word2vec的輸入文件。代碼如下:

 1 package org.ansj.demo;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.FileOutputStream;
 5 import java.io.IOException;
 6 import java.io.PrintWriter;
 7 import java.io.OutputStreamWriter;
 8 import java.util.HashSet;
 9 import java.util.List;
10 import java.util.Set;
11 
12 import love.cq.util.IOUtil;
13 
14 import org.ansj.domain.Term;
15 import org.ansj.splitWord.analysis.ToAnalysis;
16 
17 public class MyFileDemo {
18     
19     public static final String TAG_START_CONTENT = "<content>";
20     public static final String TAG_END_CONTENT = "</content>";
21     
22     public static void main(String[] args) {
23         String temp = null ;
24         
25         BufferedReader reader = null;
26         PrintWriter pw = null;
27         try {
28             reader = IOUtil.getReader("corpus.txt", "UTF-8") ;
29             ToAnalysis.parse("test 123 孫") ;
30             pw = new PrintWriter(new OutputStreamWriter(new FileOutputStream
31                     ("resultbig.txt"), "UTF-8"), true);
32             long start = System.currentTimeMillis()  ;
33             int allCount =0 ;
34             int termcnt = 0;
35             Set<String> set = new HashSet<String>();
36             while((temp=reader.readLine())!=null){
37                 temp = temp.trim();
38                 if (temp.startsWith(TAG_START_CONTENT)) {
39                     int end = temp.indexOf(TAG_END_CONTENT);
40                     String content = temp.substring(TAG_START_CONTENT.length(), end);
41                     //System.out.println(content);
42                     if (content.length() > 0) {
43                         allCount += content.length() ;
44                         List<Term> result = ToAnalysis.parse(content);
45                         for (Term term: result) {
46                             String item = term.getName().trim();
47                             if (item.length() > 0) {
48                                 termcnt++;
49                                 pw.print(item.trim() + " ");
50                                 set.add(item);
51                             }
52                         }
53                         pw.println();
54                     }
55                 }
56             }
57             long end = System.currentTimeMillis() ;
58             System.out.println("共" + termcnt + "個term," + set.size() + "個不同的詞,共 "
59                     +allCount+" 個字符,每秒處理了:"+(allCount*1000.0/(end-start)));
60         } catch (IOException e) { 
61             e.printStackTrace();
62         } finally {
63             if (null != reader) {
64                 try {
65                     reader.close();
66                 } catch (IOException e) {
67                     e.printStackTrace();
68                 }
69             }
70             if (null != pw) {
71                 pw.close();
72             }
73         }
74     }
75 }

生成的resultbig.txt即為分好詞用空格隔開的語料,使用word2vec,運行:

./word2vec -train resultbig.txt -output vectors.bin -cbow 0 -size 200 -window 5 -negative 0 -hs 1 -sample 1e-3 -threads 12 -binary 1
./distance vectors.bin

vectors.bin是word2vec處理resultbig.txt生成的term的向量文件,./distance命令加載該文件計算term之間的距離。mini文件能夠跑通,但距離沒有什么意義,因為語料實在太少了(word2vec中說語料越多效果越好)。

這時可以放心的下載700+M的全網新聞語料了,最好做下預處理只取出有content的行並轉碼,限於本人的機器,我只取出前20W行進行分詞:

cat news_tensite_xml.dat | iconv -f gbk -t utf-8 -c | grep "<content>" | head -n 200000 > corpus.txt

corpus.txt大小是200+M,分詞后有4000W+的term,使用word2vec處理,最后得到的結果還有點意思:

 

 

 

200+M的語料,這個結果是不是相當湊合了?小伙伴們,快玩起來吧!剩下phrase,classify的功能各位可以自行探索:)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM