Word2Vec 食用指南-应用篇(一)
Table of Contents
准备数据
使用 gensim 生成 word2vec 需要输入为一个可迭代的序列。每个句子为词组成的 list(utf-8 编码)。
# import modules & set up logging
import gensim, logging
logging.basicConfig(format='%(asctime)s: %(levelname)s : %(message)s', level=logging.INFO)
sentences = [['first', 'sentence'], ['second', 'sentence']]
model = gensim.models.Word2Vec(sentences, min_count=1)
使用 Python 原生的 list 非常的方便,但当输入非常大的时候内存就可能不够用了,所以一个好的方法是使用生成器(区别迭代器和生成器)来做。
例如,如果我们的输入是磁盘的多个文件(文件每一行,为一个句子),我们可以一行行的处理,而不是把所有的都加载到内存中。
class MySentences(object):
def __init__(self, dirname):
self.dirname = dirname
def __iter__(self):
for fname in os.listdir(self.dirname):
for line in open(os.path.join(self.dirname, fname)):
yield line.split()
sentences = MySentences('/some/directory')
model = gensim.models.Word2Vec(sentences)
如果我们想更进一步的对文本进行编码、大小写、移除数字或者提取实体等等都可以在 MySentences 里面来做,这些都是对 word2vec 透明的操作。
对于高级用户来说需要了解,Word2Vec(sentences, iter=1) 会执行两轮迭代 (更加准确的说法是 iter+1 轮,默认 iter=5)。第一轮,会获取词频,然后构建内部的树字典结构。第二以及随后的迭代会训练模型。在有些情况,数据可能不能重复迭代,你可以手动的初始化第一轮的词典:
model = gensim.models.Word2Vec(iter=1) # an empty model, no training yet
model.build_vocab(some_sentences) # can be a non-repeatable, 1-pass generator
model.train(other_sentences) # can be a non-repeatable, 1-pass generator
为了能够深入的理解 iterators, iterables, generates,我们可以看这个教程:Data Streaming in Python
训练
Word2Vec 的训练参数对训练的速度和结果的质量有非常大的影响。
其中之一是对内部词典的过滤,也就是在成千上百万的词中,仅仅出现一次二次的,很有可能是拼写错误或者没意义的词,对于它们训练没有太大的意义,最好的方式就是忽略掉这种词。
model = Word2Vec(sentences, min_count=10) # default value is 5
对于 min_count 一个合理的大小是 0-100,取决于语料的大小。
另外一个重要的参数是训练的层数,它和训练的自由度相关
model = Word2Vec(sentences, size=100) # default value is 100
更大的值同样需要跟多的语料,同时也会得到一个更加准确,表现更好的模型。合理的大小是 几十到几百之间。
最后一个非常重要的参数会影响训练的速度,也就是 worker 的个数
model = Word2Vec(sentences, worker=100) # default value is 1, worker no parallelization
如果你没有安装 Cython, 因为 GIL 的原因,这个参数设置不会生效,只能使用单核。
内存
说起内存占用,word2vec 模型参数是以 numpy arrays 来存储的。假设单词数 n=100000, size=200(size 参数),存储的类型为无符号浮点型(float)(假设占用 4B)。
内存中存储 3 个这样的矩阵参数,所以最终的内存占用为:
\[3 * 100000 * 200 * 4B = \sim 229M\]
另外,大部分情况仅仅需要少量的空间来存储词典树(100000 个词大约需要几 M),除非你的词都是非常非常长的字符串。
测评
Word2vec 训练是非监督学习,没有非常客观的方法来评价这个结果。 Google 放出了大约 20000 个的测试集,测试“A 相对于 B 类似于 C 相对于 D”的任务。 questions-words
Gensim 支持同样的操作,
model.accuracy('questions-words.txt')
再次强调一下,在测试集上好的表现未必在你的应用上工作的很好。
存储和加载模型
你可以使用标准的方法来存储和加载 w2v 模型:
model.save('/tmp/mymodel')
new_model = gensim.models.Word2Vec.load('/tmp/mymodel')
这个内部实现其实是使用了 pickle。
另外,你可以加载通过 C 语言工具生成的模型
model = Word2Vec.load_word2vec_format('/tmp/vectors.txt', binary=False)
# using gzipped/bz2 input works too, no need to unzip:
model = Word2Vec.load_word2vec_format('/tmp/vectors.bin.gz', binary=True)
或者可以这样:
model = word2vec.Word2Vec(sentences, min_count=1)
model.wv.save_word2vec_format('mymodel.bin', binary=True)
new_model = KeyedVectors.load_word2vec_format(
'mymodel.bin', binary=True)
在线训练/持续训练?(Online training/Resuming training)
高级用户可以加载模型,然后通过更多语句来进一步的训练:
model = gensim.models.Word2Vec.load('/tmp/mymodel')
model.train(more_sentences)
你或许需要微调一下 train() 的 total_words 参数。
需要注意的是,如果模型是通过二进制文件存储的,则无法进行持续训练,因为训练相关的重要信息丢失了。
如何使用模型
Word2vec 支持多种相似度的使用方式:
model.most_similar(positive=['woman', 'king'], negative=['man'], topn=1)
[('queen', 0.50882536)]
model.doesnt_match("breakfast cereal dinner lunch";.split())
'cereal'
model.similarity('woman', 'man')
0.73723527
如果想获取原生的向量输出,可以直接这样:
model['computer'] # raw NumPy vector of a word
array([-0.00449447, -0.00310097, 0.02421786, ...], dtype=float32)
Bonus App
TODO <github>