Gensim Word2Vec从预训练模型中选择少量的词向量

8
我有一个在gensim中训练好的大型Word2Vec模型,我想使用预训练的词向量作为我的Keras模型嵌入层。但是问题是嵌入层的大小很大,而且我不需要大部分的单词向量(因为我知道哪些单词可以作为输入)。所以我想通过白名单来筛选掉不需要的单词向量,从而减小嵌入层的大小。请问是否有一种方法只保留所需的单词向量(包括对应的索引)?
3个回答

14

感谢这个答案(我稍微修改了代码使其更好)。你可以使用这段代码来解决你的问题。

我们将所有小词汇放在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), ('拉格啤酒', 0.7733745574951172), ('Beer', 0.71753990650177), ('饮料', 0.668931245803833), ('拉格', 0.6570086479187012), ('Yuengling_Lager', 0.655455470085144), ('精酿啤酒', 0.6534324884414673), ('Brooklyn_Lager', 0.6501551866531372), ('泡沫', 0.6497018337249756), ('酿造啤酒', 0.6490240097045898)]
restricted_word_set = {"beer", "wine", "computer", "python", "bash", "lagers"}
restrict_w2v(w2v, restricted_word_set)
w2v.most_similar("beer")

这段内容的翻译如下:

[('lagers', 0.6570085287094116),
('wine', 0.6217695474624634),
('bash', 0.20583480596542358),
('computer', 0.06677375733852386),
('python', 0.005948573350906372)]

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


2
非常有帮助,需要注意的是,index2entity和index2word的类型似乎是列表而不是ndarray(当您随后调用其他函数如w2v.add()时会出现问题)。 - ciri

0

虽然没有内置功能可以做到这一点,但是不需要太多的代码,可以参考现有的gensim代码进行建模。以下是几种可能的替代策略:

加载完整的词向量,然后以易于解析的格式保存 - 例如通过 .save_word2vec_format(..., binary=False)。这种格式几乎是自说明的;编写你自己的代码从该文件中删除不在你的白名单上的所有行(确保更新入口计数的前导行声明)。load_word2vec_format()save_word2vec_format() 的现有源代码可能会起到指导作用。然后你就拥有了一个子集文件。
或者,假设你要使用感兴趣的语料库(仅包含有趣的单词)训练一个新的 Word2Vec 模型。但是,只需创建模型并执行 build_vocab() 步骤。现在,你拥有一个未经训练的模型,具有随机向量,但是拥有正确的词汇表。获取模型的 wv 属性 - 具有正确词汇表的 KeyedVectors 实例。然后分别加载超大的向量集,并为右尺寸的每个单词在 KeyedVectors 中,复制来自更大集合的实际向量。然后保存正确大小的子集。
或者,查看 Word2Vec 上可能已经损坏的(自 gensim-3.4 以来)方法 intersect_word2vec_format()。它更或多或少地尝试执行上述(2)中描述的操作:使用具有所需词汇表的内存模型,在磁盘上的另一个 word2vec 格式集合中仅合并重叠单词。它要么工作,要么提供你想要做的模板。

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或其他工具为未知单词生成嵌入。

该软件包有详细的文档和测试。还有示例展示如何与Keras一起使用

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接