前几天看论文,忽然看到了一个跟word2vec并列的词向量工具,这么厉害?还能跟word2vec相提并论?

果断需要试试。

GloVe 

它来自斯坦福的一篇论文,GloVe全称应该是  Global  Vectors for Word Representation

官网在此  http://nlp.stanford.edu/projects/glove/

大概长这样,上面还有训练好的模型可以下载


下面开始动手。

官方的代码的GitHub在此 :  https://github.com/stanfordnlp/GloVe


可以看到,这是个c的版本,并且跑在linux下。

毕竟最爱的是python,首先想,有没有python版本的,GitHub上其实还真搜到了一个,不过看了一下,应该是哪个小伙伴自己写的,试了一下,发现一百句话的语料它的速度就已经慢得不能忍受了。我们是要面对至少几百M几个G的语料,显然这个是不能接受的。所以就不放链接了。

那就只能用C的代码训练,然后再用python来处理结果。让人欣喜的是,GloVe训练的结果,是可以用gensim里面word2vec的load直接加载并且使用的,那就简单了。

首先,找到一个linux系统的机器,把上面GitHub上的代码down下来。

进入glove目录下,首先先参考README.txt,里面主要介绍这个程序包含了四部分子程序,按步骤分别是vocab_count、cooccur、shuffle、glove:

1.vocab_count:用于计算原文本的单词统计(生成vocab.txt,每一行为:单词  词频)

2.cooccur:用于统计词与词的共现,目测类似与word2vec的窗口内的任意两个词(生成的是cooccurrence.bin,二进制文件,呵呵)

3. shuffle:对于2中的共现结果重新整理(一看到shuffle瞬间想到Hadoop,生成的也是二进制文件cooccurrence.shuf.bin)

4.glove:glove算法的训练模型,会运用到之前生成的相关文件(1&3),最终会输出vectors.txt和vectors.bin(前者直接可以打开,下文主要针对它做研究,后者还是二进制文件)

上面已经介绍了这个程序的执行流程,下面就具体训练出这个vectors.txt。

首先二话不说,直接makefile,

make

就会多出来一个build文件夹

然后再执行sh demo.sh就行了:

sh demo.sh

其中,可以再demo.sh里面,设置训练语料路径(默认是从网上下载一个语料,把这段删了,改成自己的语料路径就行了),还可以设置迭代次数,向量的维度等等,自己随便折腾就行了

经历漫长的等待之后(取决于你的语料有多大,当然了,中文的话,记得分词)

现在,得到了vectors.txt,这就是训练出来的词向量的结果。下面,我们看看怎么用python来加载并使用它。

首先,默认已经装好python+gensim了,并且已经会用word2vec了。

其实,只需要在vectors.txt这个文件的最开头,加上两个数,第一个数指明一共有多少个向量,第二个数指明每个向量有多少维,就能直接用word2vec的load函数加载了

假设你已经加上这两个数了,那么直接

# Demo: Loads the newly created glove_model.txt into gensim API.
model=gensim.models.Word2Vec.load_word2vec_format(' vectors.txt',binary=False) #GloVe Model

就行了,剩下的操作就跟word2vec一样了

下面附上 这一段的完整代码(包括把 vectors.txt改成能load的格式,和加载模型)

def load(filename):

# Input: GloVe Model File
# More models can be downloaded from http://nlp.stanford.edu/projects/glove/
# glove_file="glove.840B.300d.txt"
glove_file = filename

dimensions = 300

num_lines = getFileLineNums(filename)
# num_lines = check_num_lines_in_glove(glove_file)
# dims = int(dimensions[:-1])
dims = 300

print num_lines
#
# # Output: Gensim Model text format.
gensim_file='glove_model.txt'
gensim_first_line = "{} {}".format(num_lines, dims)
#
# # Prepends the line.
if platform == "linux" or platform == "linux2":
prepend_line(glove_file, gensim_file, gensim_first_line)
else:
prepend_slow(glove_file, gensim_file, gensim_first_line)

# Demo: Loads the newly created glove_model.txt into gensim API.
model=gensim.models.Word2Vec.load_word2vec_format(gensim_file,binary=False) #GloVe Model

model_name = filename[5:-4]

model.save('model\\' + model_name)

return model

def getFileLineNums(filename):
f = open(filename,'r')
count = 0

for line in f:

count += 1
return count

def prepend_line(infile, outfile, line):
"""
Function use to prepend lines using bash utilities in Linux.
(source: http://stackoverflow.com/a/10850588/610569)
"""
with open(infile, 'r') as old:
with open(outfile, 'w') as new:
new.write(str(line) + "\n")
shutil.copyfileobj(old, new)

def prepend_slow(infile, outfile, line):
"""
Slower way to prepend the line by re-creating the inputfile.
"""
with open(infile, 'r') as fin:
with open(outfile, 'w') as fout:
fout.write(line + "\n")
for line in fin:
fout.write(line)

这是一段加载模型之后使用的例子,当然了,这个就跟word2vec一样了

def load_model_and_use(model_name):
model = gensim.models.Word2Vec.load('model/'+model_name)
print len(model.vocab)
word_list = [u'发烧',u'流感']

for word in word_list:
print word,'--'
for i in model.most_similar(word, topn=10):
print i[0],i[1]
print ''

结果如下

83078
发烧 --
瘟疠 0.561131298542
多无发 0.438511788845
感冒 0.423784643412
寒战 0.41094905138
发冷 0.400202810764
肌肉酸痛 0.394035518169
畏寒 0.391746163368
头痛 0.390283048153
恶寒 0.387357711792
石岐 0.385719358921


流感 --
芭比 0.693880617619
嗜血 0.660785496235
H1N1 0.543790698051
肺炎 0.520848989487
流行性感冒 0.517322063446
副流感 0.51515519619
甲型 0.495822429657
肺炎球菌 0.491611480713
H10N8 0.490446418524
H3N2 0.486712753773


这个是经典的那个 man - king, women -? 的例子

for i in w2v_model.most_similar(positive=['肺炎', '肺'], negative=['胃炎']):
print i[0],i[1]

肺部 0.662135243416
肺门区 0.556283473969
通气 0.548550665379
肺泡 0.529182732105
肺气肿 0.525536477566
慢阻 0.512038588524
胸片 0.503533244133
萎陷 0.502206265926
肺透明膜病 0.498196214437
肺段 0.492621898651

可见,效果不太好,可能是语料太少的原因。

关于word2vec模型的格式的探究,可见:
http://blog.csdn.net/sscssz/article/details/51921392