Gensim Word2Vec从预训练模型中选择一组较小的单词向量

时间:2018-06-18 17:32:33

标签: python keras word2vec gensim word-embedding

我在gensim中有一个大型的预训练Word2Vec模型,我希望在我的Keras模型中使用预训练的单词向量作为嵌入层。

问题是嵌入大小是巨大的,我不需要大多数单词向量(因为我知道哪些单词可以作为输入出现)。所以我想摆脱它们以减小嵌入层的大小。

是否有办法根据单词白名单保留所需的wordvectors(包括相应的索引!)?

3 个答案:

答案 0 :(得分:1)

感谢this answer(我对代码进行了一些更改以使其变得更好)。您可以使用此代码解决问题。

我们在restricted_word_set中有所有次要的单词集(可以是列表的也可以是集合),w2v是我们的模型,所以这里是函数:

import numpy as np

def restrict_w2v(w2v, restricted_word_set):
    new_vectors = []
    new_vocab = {}
    new_index2entity = []
    new_vectors_norm = []

    for i in range(len(w2v.vocab)):
        word = w2v.index2entity[i]
        vec = w2v.vectors[i]
        vocab = w2v.vocab[word]
        vec_norm = w2v.vectors_norm[i]
        if word in restricted_word_set:
            vocab.index = len(new_index2entity)
            new_index2entity.append(word)
            new_vocab[word] = vocab
            new_vectors.append(vec)
            new_vectors_norm.append(vec_norm)

    w2v.vocab = new_vocab
    w2v.vectors = np.array(new_vectors)
    w2v.index2entity = np.array(new_index2entity)
    w2v.index2word = np.array(new_index2entity)
    w2v.vectors_norm = np.array(new_vectors_norm)
  

警告:当您首次创建模型时,vectors_norm == None   如果在此使用此功能,则会出现错误。 vectors_norm   首次使用后将获得numpy.ndarray类型的值。所以   在使用该功能之前,请尝试类似most_similar("cat")这样的操作   vectors_norm不等于None

它基于Word2VecKeyedVectors重写与单词相关的所有变量。

用法:

w2v = KeyedVectors.load_word2vec_format("GoogleNews-vectors-negative300.bin.gz", binary=True)
w2v.most_similar("beer")
  

[('啤酒',0.8409687876701355),
   ('lager',0.7733745574951172),
   (“啤酒”,0.71753990650177),
   ('drinks',0.668931245803833),
   (“ lagers”,0.6570086479187012),
   ('Yuengling_Lager',0.655455470085144),
   ('microbrew',0.6534324884414673),
   ('Brooklyn_Lager',0.6501551866531372),
   ('suds',0.6497018337249756),
   (“ brewed_beer”,0.6490240097045898)

restricted_word_set = {"beer", "wine", "computer", "python", "bash", "lagers"}
restrict_w2v(w2v, restricted_word_set)
w2v.most_similar("beer")
  

[('lagers',0.6570085287094116),
   (“葡萄酒”,0.6217695474624634),
   (“ bash”,0.20583480596542358),
   (“计算机”,0.06677375733852386),
   ('python',0.005948573350906372)]

它也可以用于删除一些单词。

答案 1 :(得分:0)

没有内置功能可以做到这一点,但它不需要太多代码,并且可以在现有的gensim代码上建模。一些可能的替代策略:

  1. 加载完整的向量,然后以易于解析的格式保存 - 例如通过.save_word2vec_format(..., binary=False)。这种格式几乎是不言自明的;编写自己的代码以从该文件中删除不在白名单中的所有行(确保更新entry-count的前导行声明)。 load_word2vec_format()&的现有源代码save_word2vec_format()可能具有指导意义。然后,您将拥有一个子集文件。

  2. 或者,假装你要使用你感兴趣的语料库(只有有趣的单词)训练一个新的Word2Vec模型。但是,只创建模型并执行build_vocab()步骤。现在,你有未经训练的模型,有随机向量,但只有正确的词汇。使用正确的词汇表抓取模型的wv属性 - KeyedVectors实例。然后分别加载超大矢量集,对于右侧大小KeyedVectors中的每个单词,复制​​较大集合中的实际矢量。然后保存正确大小的子集。

  3. 或者,请查看Word2Vec intersect_word2vec_format()上的(可能已损坏的自gensim-3.4)方法。它或多或少地试图做上面(2)中描述的内容:使用具有所需词汇的内存模型,仅合并来自磁盘上另一个word2vec格式的重叠单词。它既可以工作,也可以提供你想要做的模板。

答案 2 :(得分:0)

几年前,我编写了一个名为 embfile 的实用程序包,用于处理“嵌入文件”(但我仅在 2020 年发布)。它支持多种格式:

  • .txt(带或不带“标题行”)
  • .bin,Google Word2Vec 格式
  • .vvm,我使用的自定义格式(它只是一个 TAR 文件,在单独的文件中包含词汇表、向量和元数据,因此可以在几分之一秒内完全读取词汇表,并且可以随机访问向量)。

我想介绍的用例是创建一个预训练的嵌入矩阵来初始化一个 Embedding 层。我想通过尽可能快地加载我需要的词向量来做到这一点。

import embfile

with embfile.open(EMBEDDING_FILE_PATH) as f:

    emb_matrix, word2index, missing_words = embfile.build_matrix(
        f, 
        words=vocab,     # this could also be a word2index dictionary as well
        start_index=1,   # leave the first row to zeros 
    )

该函数还处理文件词汇表之外的单词的初始化。默认情况下,它在找到的向量上拟合正态分布,并使用它来生成新的随机向量(这就是 AllenNLP 所做的)。我不确定这个功能是否仍然相关:现在您可以使用 FastText 或其他工具为未知单词生成嵌入。

该包是 extensively documented 并经过测试。还有examples that show how to use it with Keras

请记住,txt 和 bin 文件本质上是顺序文件,需要进行全面扫描(除非您在最后找到要查找的所有单词)。这就是我使用 vvm 文件的原因,它为向量提供随机访问。一个人可以通过索引顺序文件来解决这个问题,但是 embfile 没有这个功能。尽管如此,您可以将顺序文件转换为 vvm(这类似于创建索引并将所有内容打包到一个文件中)。