前几天看论文,忽然看到了一个跟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) + "
")
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 + "
")
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