Gensim Word2Vec select 来自预训练模型的少量词向量集
Gensim Word2Vec select minor set of word vectors from pretrained model
我在 gensim 中有一个大型的预训练 Word2Vec 模型,我想将预训练的词向量用于我的 Keras 模型中的嵌入层。
问题是嵌入的大小很大,我不需要大部分的词向量(因为我知道哪些词可以作为输入出现)。所以我想去掉它们以减小嵌入层的大小。
有没有办法根据单词白名单只保留所需的单词向量(包括相应的索引!)?
没有内置功能可以完全做到这一点,但它不需要太多代码,并且可以在现有 gensim
代码的基础上建模。一些可能的替代策略:
加载完整向量,然后以易于解析的格式保存 - 例如通过 .save_word2vec_format(..., binary=False)
。这种格式几乎是不言自明的;编写您自己的代码以从该文件中删除所有不在您的白名单中的行(确保更新条目计数的前导行声明)。 load_word2vec_format()
& save_word2vec_format()
的现有源代码可能具有指导意义。然后您将拥有一个子集文件。
或者,假设您要使用您感兴趣的语料库(只包含有趣的词)来训练一个新的 Word2Vec 模型。但是,只创建模型并执行 build_vocab()
步骤。现在,您拥有未经训练的模型,带有随机向量,但只有正确的词汇表。获取模型的 wv
属性 - 具有正确词汇表的 KeyedVectors
实例。然后分别加载超大向量集,并针对大小合适 KeyedVectors
中的每个单词,从更大的集合中复制实际向量。然后保存大小合适的子集。
或者,看看 Word2Vec intersect_word2vec_format()
上的 (possibly-broken-since-gensim-3.4) 方法。它或多或少地尝试执行上面 (2) 中描述的操作:使用具有您想要的词汇表的内存模型,合并来自磁盘上另一个 word2vec 格式集的重叠单词。它要么有效,要么为您想要执行的操作提供模板。
感谢 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)
WARNING: when you first create the model the vectors_norm == None
so
you will get an error if you use this function there. vectors_norm
will get a value of the type numpy.ndarray
after the first use. so
before using the function try something like most_similar("cat")
so
that vectors_norm
not be equal to None
.
重写所有与单词相关的变量
用法:
w2v = KeyedVectors.load_word2vec_format("GoogleNews-vectors-negative300.bin.gz", binary=True)
w2v.most_similar("beer")
[('beers', 0.8409687876701355),
('lager', 0.7733745574951172),
('Beer', 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),
('wine', 0.6217695474624634),
('bash', 0.20583480596542358),
('computer', 0.06677375733852386),
('python', 0.005948573350906372)]
它也可以用于删除一些单词。
几年前,我写了一个名为 embfile 的实用程序包来处理“嵌入文件”(但我只在 2020 年发布了它)。它支持多种格式:
- .txt(有或没有“header行”)
- .bin, Google Word2Vec 格式
- .vvm,我使用的自定义格式(它只是一个 TAR 文件,词汇表、向量和元数据在单独的文件中,因此词汇表可以在几分之一秒内完全读取,向量可以随机已访问)。
我想介绍的用例是创建 pre-trained 嵌入矩阵来初始化 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 and tested. There are also examples that show how to use it with Keras。
请记住,txt 和 bin 文件本质上是顺序文件,需要进行全面扫描(除非您在结束前找到所有要查找的词)。这就是我使用 vvm 文件的原因,它提供对矢量的随机访问。可以通过索引顺序文件来解决问题,但 embfile 没有此功能。尽管如此,您可以将顺序文件转换为 vvm(这类似于创建索引并将所有内容打包到一个文件中)。
我在 gensim 中有一个大型的预训练 Word2Vec 模型,我想将预训练的词向量用于我的 Keras 模型中的嵌入层。
问题是嵌入的大小很大,我不需要大部分的词向量(因为我知道哪些词可以作为输入出现)。所以我想去掉它们以减小嵌入层的大小。
有没有办法根据单词白名单只保留所需的单词向量(包括相应的索引!)?
没有内置功能可以完全做到这一点,但它不需要太多代码,并且可以在现有 gensim
代码的基础上建模。一些可能的替代策略:
加载完整向量,然后以易于解析的格式保存 - 例如通过
.save_word2vec_format(..., binary=False)
。这种格式几乎是不言自明的;编写您自己的代码以从该文件中删除所有不在您的白名单中的行(确保更新条目计数的前导行声明)。load_word2vec_format()
&save_word2vec_format()
的现有源代码可能具有指导意义。然后您将拥有一个子集文件。或者,假设您要使用您感兴趣的语料库(只包含有趣的词)来训练一个新的 Word2Vec 模型。但是,只创建模型并执行
build_vocab()
步骤。现在,您拥有未经训练的模型,带有随机向量,但只有正确的词汇表。获取模型的wv
属性 - 具有正确词汇表的KeyedVectors
实例。然后分别加载超大向量集,并针对大小合适KeyedVectors
中的每个单词,从更大的集合中复制实际向量。然后保存大小合适的子集。或者,看看 Word2Vec
intersect_word2vec_format()
上的 (possibly-broken-since-gensim-3.4) 方法。它或多或少地尝试执行上面 (2) 中描述的操作:使用具有您想要的词汇表的内存模型,合并来自磁盘上另一个 word2vec 格式集的重叠单词。它要么有效,要么为您想要执行的操作提供模板。
感谢 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)
重写所有与单词相关的变量WARNING: when you first create the model the
vectors_norm == None
so you will get an error if you use this function there.vectors_norm
will get a value of the typenumpy.ndarray
after the first use. so before using the function try something likemost_similar("cat")
so thatvectors_norm
not be equal toNone
.
用法:
w2v = KeyedVectors.load_word2vec_format("GoogleNews-vectors-negative300.bin.gz", binary=True)
w2v.most_similar("beer")
[('beers', 0.8409687876701355),
('lager', 0.7733745574951172),
('Beer', 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),
('wine', 0.6217695474624634),
('bash', 0.20583480596542358),
('computer', 0.06677375733852386),
('python', 0.005948573350906372)]
它也可以用于删除一些单词。
几年前,我写了一个名为 embfile 的实用程序包来处理“嵌入文件”(但我只在 2020 年发布了它)。它支持多种格式:
- .txt(有或没有“header行”)
- .bin, Google Word2Vec 格式
- .vvm,我使用的自定义格式(它只是一个 TAR 文件,词汇表、向量和元数据在单独的文件中,因此词汇表可以在几分之一秒内完全读取,向量可以随机已访问)。
我想介绍的用例是创建 pre-trained 嵌入矩阵来初始化 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 and tested. There are also examples that show how to use it with Keras。
请记住,txt 和 bin 文件本质上是顺序文件,需要进行全面扫描(除非您在结束前找到所有要查找的词)。这就是我使用 vvm 文件的原因,它提供对矢量的随机访问。可以通过索引顺序文件来解决问题,但 embfile 没有此功能。尽管如此,您可以将顺序文件转换为 vvm(这类似于创建索引并将所有内容打包到一个文件中)。