Gensim 中 word2vec 函数的使用

144
作者 chen_h
2017.08.09 16:22 字数 1327

Gensim 是我比较常用的一个 NLP 工具包,特别是其中的 word2vec 模块,它的具体 API 如下:

class gensim.models.word2vec.Word2Vec(
            sentences=None, 
            size=100, 
            alpha=0.025, 
            window=5, 
            min_count=5, 
            max_vocab_size=None, 
            sample=0.001, 
            seed=1, 
            workers=3, 
            min_alpha=0.0001, 
            sg=0, 
            hs=0, 
            negative=5, 
            cbow_mean=1, 
            hashfxn=<built-in function hash>, 
            iter=5, 
            null_word=0, 
            trim_rule=None, 
            sorted_vocab=1, 
            batch_words=10000, 
            compute_loss=False)

模型创建

Gensim 中 word2vec 模型的输入是经过分词的句子列表,即是某个二位数组。但由于中文没有像英文那么自带天然的分词,所有这里我们简单采用 jieba 来进行分词处理。

# 引入 word2vec
from gensim.models import word2vec

# 引入日志配置
import logging

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)

# 引入分词工具
import jieba

# 引入数据集
raw_sentences = ["但由于中文没有像英文那么自带天然的分词","所以我们第一步采用分词"]

# 切分词汇
sentences = []
for s in raw_sentences:
    tmp = []
    for item in jieba.cut(s):
        tmp.append(item)
    sentences.append(tmp)
# print(sentences)
# 构建模型
model = word2vec.Word2Vec(sentences, min_count=1)

# 进行词向量输出
model['中文']

但这种方法在数据集比较大的情况下会占用大量的 RAM,Gensim 本身只是要求能够迭代的有序句子列表,因此在工程实践中我们可以使用一些自定义的生成器,只在内存中保存单条语句,并且在导入内存之前进行分词操作。

Word2Vec 参数

from gensim.models.word2vec import LineSentence
from gensim.models.word2vec import Text8Corpus

sentences = LineSentence('a.txt')
sentences = Text8Corpus('a.txt')
  • size: 词向量的维度。
  • alpha: 模型初始的学习率。
  • window: 表示在一个句子中,当前词于预测词在一个句子中的最大距离。
  • min_count: 用于过滤操作,词频少于 min_count 次数的单词会被丢弃掉,默认值为 5。
  • max_vocab_size: 设置词向量构建期间的 RAM 限制。如果所有的独立单词数超过这个限定词,那么就删除掉其中词频最低的那个。根据统计,每一千万个单词大概需要 1GB 的RAM。如果我们把该值设置为 None ,则没有限制。
  • sample: 高频词汇的随机降采样的配置阈值,默认为 1e-3,范围是 (0, 1e-5)。
  • seed: 用于随机数发生器。与词向量的初始化有关。
  • workers: 控制训练的并行数量。
  • min_alpha: 随着训练进行,alpha 线性下降到 min_alpha。
  • sg: 用于设置训练算法。当 sg=0,使用 CBOW 算法来进行训练;当 sg=1,使用 skip-gram 算法来进行训练。
  • hs: 如果设置为 1 ,那么系统会采用 hierarchica softmax 技巧。如果设置为 0(默认情况),则系统会采用 negative samping 技巧。
  • negative: 如果这个值大于 0,那么 negative samping 会被使用。该值表示 “noise words” 的数量,一般这个值是 5 - 20,默认是 5。如果这个值设置为 0,那么 negative samping 没有使用。
  • cbow_mean: 如果这个值设置为 0,那么就采用上下文词向量的总和。如果这个值设置为 1 (默认情况下),那么我们就采用均值。但这个值只有在使用 CBOW 的时候才起作用。
  • hashfxn: hash函数用来初始化权重,默认情况下使用 Python 自带的 hash 函数。
  • iter: 算法迭代次数,默认为 5。
  • trim_rule: 用于设置词汇表的整理规则,用来指定哪些词需要被剔除,哪些词需要保留。默认情况下,如果 word count < min_count,那么该词被剔除。这个参数也可以被设置为 None,这种情况下 min_count 会被使用。
  • sorted_vocab: 如果这个值设置为 1(默认情况下),则在分配 word index 的时候会先对单词基于频率降序排序。
  • batch_words: 每次批处理给线程传递的单词的数量,默认是 10000。

内存

word2vec 参数模型保存在 NumPy 矩阵中。矩阵中的每一行是单词的向量,这个向量用浮点数(单精度,也称为 4 字节)表示。

假设三个这样的矩阵同时保存在 RAM 中(如果是矩阵正在工作中,那么该数量应该减少到两个,甚至一个)。因为,如果你输入的单词量是 100000 个,词向量你要求长度为 200 ,那么模型所占的内存为 100000 * 200 * 4 * 3 =~ 229 MB。

大型语料库

在真实的训练环境中,我们面对的都是比较大型的语料库,在这里我们以 word2vec 官方的 text8 为例子,具体如下:

sentences = word2vec.Text8Corpus('text8')
model = word2vec.Word2Vec(sentences, size=10)

我们在前面也提到了,如果是对大量的输入语聊集或者需要整合磁盘上多个文件夹中的数据,那么我们可以使用迭代器的方式来读取数据,而不是一次性的将全部内容读取到内存中,从而来节省 RAM 空间,具体如下:

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') # a memory-friendly iterator
model = gensim.models.Word2Vec(sentences)

模型的保存与读取

model.save('text8.model')

2017-08-09 14:48:50,382 : INFO : saving Word2Vec object under text8.model, separately None
2017-08-09 14:48:50,384 : INFO : not storing attribute syn0norm
2017-08-09 14:48:50,386 : INFO : not storing attribute cum_table
2017-08-09 14:48:50,765 : INFO : saved text8.model

model1=word2vec.Word2Vec.load('text8.model')

2017-08-09 14:49:14,599 : INFO : loading Word2Vec object from text8.model
2017-08-09 14:49:14,977 : INFO : loading wv recursively from text8.model.wv.* with mmap=None
2017-08-09 14:49:14,978 : INFO : setting ignored attribute syn0norm to None
2017-08-09 14:49:14,980 : INFO : setting ignored attribute cum_table to None
2017-08-09 14:49:14,981 : INFO : loaded text8.model

model1.wv.save_word2vec_format('text.model.bin', binary=True)

2017-08-09 14:51:27,198 : INFO : storing 71290x10 projection weights into text.model.bin

model2=gensim.models.KeyedVectors.load_word2vec_format('text.model.bin', binary=True)

2017-08-09 14:52:09,296 : INFO : loading projection weights from text.model.bin
2017-08-09 14:52:10,273 : INFO : loaded (71290, 10) matrix from text.model.bin

模型预测

Word2Vec 模块还可以进行一些语义相似度推算,比如:

model.most_similar(positive=['woman', 'king'], negative=['man'], topn=5)

[('queen', 0.6658061742782593),
 ('elizabeth', 0.6245918273925781),
 ('emperor', 0.5999430418014526),
 ('isabella', 0.5808215737342834),
 ('prince', 0.5779752731323242)]

model.wv.doesnt_match("breakfast cereal dinner lunch".split())

'cereal'

model.wv.similarity('woman', 'man')

0.7129250672362295

model.most_similar(['man'])

[('woman', 0.7129250168800354),
 ('girl', 0.6310214996337891),
 ('creature', 0.6019233465194702),
 ('god', 0.5626420974731445),
 ('boy', 0.5613292455673218),
 ('person', 0.5532713532447815),
 ('beast', 0.5510985851287842),
 ('evil', 0.5497387647628784),
 ('stranger', 0.5446441173553467),
 ('soul', 0.5437164306640625)]

如果我们希望直接获取某个单词的词向量,我们可以直接以下标的方式进行访问:

model['computer']
array([-0.12038743, -0.30791789, ..., 0.83891463, -2.07493448], dtype=float32)

模型评估

Word2Vec 的训练属于无监督模型。Google 之前公开了一个 20000 条左右的语法与语义化训练样本,每一条都遵循 A is to B as C is to D 这个格式,下载地址在这里

model.accuracy('questions-words.txt')
2017-08-09 15:34:12,000 : INFO : capital-common-countries: 28.5% (144/506)
2017-08-09 15:34:17,410 : INFO : capital-world: 15.8% (229/1452)
2017-08-09 15:34:18,435 : INFO : currency: 9.3% (25/268)
2017-08-09 15:34:24,265 : INFO : city-in-state: 9.7% (152/1571)
2017-08-09 15:34:25,410 : INFO : family: 73.2% (224/306)
2017-08-09 15:34:28,215 : INFO : gram1-adjective-to-adverb: 10.7% (81/756)
2017-08-09 15:34:29,363 : INFO : gram2-opposite: 17.6% (54/306)
2017-08-09 15:34:34,015 : INFO : gram3-comparative: 54.4% (686/1260)
2017-08-09 15:34:35,898 : INFO : gram4-superlative: 34.2% (173/506)
2017-08-09 15:34:39,558 : INFO : gram5-present-participle: 28.3% (281/992)
2017-08-09 15:34:44,608 : INFO : gram6-nationality-adjective: 49.2% (675/1371)
2017-08-09 15:34:49,570 : INFO : gram7-past-tense: 25.0% (333/1332)
2017-08-09 15:34:53,265 : INFO : gram8-plural: 41.8% (415/992)
2017-08-09 15:34:55,699 : INFO : gram9-plural-verbs: 30.2% (196/650)
2017-08-09 15:34:55,700 : INFO : total: 29.9% (3668/12268)

来源:

  1. CSDN
  2. gensim
  3. Word2vec Tutorial
  4. segmentfault
NLP