从 gensim word2vec 模型中删除旧 "words" 的最佳方法是什么?
What is the best way to drop old "words" from gensim word2vec model?
我有一个从项目-项目图构建的“语料库”,这意味着每个句子都是一个图行走路径,每个单词都是一个项目。我想在语料库上训练一个 word2vec 模型以获得项目的嵌入向量。该图每天更新,因此 word2vec 模型以增加的方式训练(使用 Word2Vec.save()
和 Word2Vec.load()
)以不断更新项目的向量。
与文字不同,我的语料库中的项目有其生命周期,每天都会添加新项目。为了防止模型大小不断增长,我需要丢弃达到其生命周期的项目,同时保持模型可训练。我读过类似的问题
here,但这个问题的答案与增加训练无关,而是基于 KeyedVectors
。我想出了下面的代码,但我不确定它是否正确:
from gensim.models import Word2Vec
import numpy as np
texts = [["a", "b", "c"], ["a", "h", "b"]]
m = Word2Vec(texts, size=5, window=5, min_count=1, workers=1)
print(m.wv.index2word)
print(m.wv.vectors)
# drop old words
wordsToDrop = ["b", "c"]
for w in wordsToDrop:
i = m.wv.index2word.index(w)
m.wv.index2word.pop(i)
m.wv.vectors = np.delete(m.wv.vectors, i, axis=0)
del m.wv.vocab[w]
print(m.wv.index2word)
print(m.wv.vectors)
m.save("m.model")
del m
# increased training
new = [["a", "e", "n"], ["r", "s"]]
m = Word2Vec.load("m.model")
m.build_vocab(new, update=True)
m.train(new, total_examples=m.corpus_count, epochs=2)
print(m.wv.index2word)
print(m.wv.vectors)
删除和增加训练后,m.wv.index2word
和m.wv.vectors
是否仍然是element-wise对应的?上面的代码有副作用吗?如果我的方法不好,有人可以给我一个例子来说明如何正确地删除旧的“单词”并保持模型的可训练性吗?
没有官方支持从 Gensim Word2Vec
模型中删除单词,一旦它们“切入”以包含在内。
甚至 添加 单词的能力也不是很好,因为该功能不是基于任何 proven/published 更新 [=12] 的方法=] 模型,并通过选择 learning-rate 或批次是否完全代表现有词汇表来掩盖 update-batches 如何影响模型的困难权衡。最安全的方法是定期 re-train 从头开始构建模型,使用完整的语料库,其中包含所有相关单词的足够示例。
因此,我的主要建议是定期将您的模型替换为经过所有 still-relevant 数据训练的新模型。这将确保它不再在过时的术语上浪费模型状态,并且所有 still-live 术语都接受了同等的交错训练。
在这样的重置之后,word-vectors 将无法与之前 'model era' 的 word-vectors 相提并论。 (同一个词,即使它的有形意义没有改变,也可能是一个任意不同的地方——但与其他向量的相对关系应该保持不变或更好。)但是,同样的 drift-out-of-comparison 是 也 发生在任何一组 small-batch 更新中,这些更新不会 'touch' 每个现有单词均等,只是以某种无法量化的速度。
OTOH,如果您认为需要保留此类增量更新,即使知道注意事项,您也可以 patch-up 模型结构尽可能多地保留旧模型并继续培训。
到目前为止,您的代码是一个合理的开始,缺少一些正确功能的重要注意事项:
- 因为删除 earlier-words 会更改 later-words 的索引位置,您需要更新每个幸存单词的
vocab[word].index
值,以匹配新的 index2word
订购。例如,在完成所有删除后,您可以这样做:
for i, word in enumerate(m.wv.index2word):
m.wv.vocab[word].index = i
因为在您的(默认 negative-sampling)Word2Vec
模型中,还有 另一个 per-word 权重数组与模型的输出层相关,也应该同步更新,以便每个单词检查正确的 output-values。粗略地说,每当您从 m.wv.vectors
中删除一行时,您应该从 m.traininables.syn1neg
.
中删除同一行
因为幸存的词汇有不同的相对 word-frequencies,negative-sampling 和下采样(由 sample
参数控制)功能应该不同 pre-calculated 结构来协助他们的选择。对于negative-sampling使用的cumulative-distributiontable,这很简单:
m.make_cum_table(m.wv)
对于下采样,您希望更新 .sample_int
值,类似于您可以在 https://github.com/RaRe-Technologies/gensim/blob/3.8.3/gensim/models/word2vec.py#L1534. (But, looking at that code now, I think it may be buggy 处查看代码的逻辑,因为它仅使用中的频率信息更新所有单词新字典,所以可能会污染 truly-frequent 单词的通常下采样,并且可能错误地对仅在新更新中频繁出现的单词进行下采样。)
如果这些内部结构与您现有的操作同步正确更新,模型可能处于一致状态以进行进一步训练。 (但请注意:这些结构在即将发布的 gensim-4.0.0
版本中发生了很大变化,因此在升级时需要更新任何自定义篡改。)
另一个效率注意事项:np.delete()
操作将创建一个新数组,即剩余数组的完整大小,并在每次调用时复制旧值。因此,使用它从 very-large 原始数组中一次删除许多行可能需要大量冗余 allocation/copying/garbage-collection。最后,您可以使用要删除的所有索引的列表调用它一次。
但实际上:更简单的 better-grounded 方法也可能产生更好的 continually-comparable 向量,只要有可能或发生大量变化,就用所有当前数据重新训练。
我有一个从项目-项目图构建的“语料库”,这意味着每个句子都是一个图行走路径,每个单词都是一个项目。我想在语料库上训练一个 word2vec 模型以获得项目的嵌入向量。该图每天更新,因此 word2vec 模型以增加的方式训练(使用 Word2Vec.save()
和 Word2Vec.load()
)以不断更新项目的向量。
与文字不同,我的语料库中的项目有其生命周期,每天都会添加新项目。为了防止模型大小不断增长,我需要丢弃达到其生命周期的项目,同时保持模型可训练。我读过类似的问题
here,但这个问题的答案与增加训练无关,而是基于 KeyedVectors
。我想出了下面的代码,但我不确定它是否正确:
from gensim.models import Word2Vec
import numpy as np
texts = [["a", "b", "c"], ["a", "h", "b"]]
m = Word2Vec(texts, size=5, window=5, min_count=1, workers=1)
print(m.wv.index2word)
print(m.wv.vectors)
# drop old words
wordsToDrop = ["b", "c"]
for w in wordsToDrop:
i = m.wv.index2word.index(w)
m.wv.index2word.pop(i)
m.wv.vectors = np.delete(m.wv.vectors, i, axis=0)
del m.wv.vocab[w]
print(m.wv.index2word)
print(m.wv.vectors)
m.save("m.model")
del m
# increased training
new = [["a", "e", "n"], ["r", "s"]]
m = Word2Vec.load("m.model")
m.build_vocab(new, update=True)
m.train(new, total_examples=m.corpus_count, epochs=2)
print(m.wv.index2word)
print(m.wv.vectors)
删除和增加训练后,m.wv.index2word
和m.wv.vectors
是否仍然是element-wise对应的?上面的代码有副作用吗?如果我的方法不好,有人可以给我一个例子来说明如何正确地删除旧的“单词”并保持模型的可训练性吗?
没有官方支持从 Gensim Word2Vec
模型中删除单词,一旦它们“切入”以包含在内。
甚至 添加 单词的能力也不是很好,因为该功能不是基于任何 proven/published 更新 [=12] 的方法=] 模型,并通过选择 learning-rate 或批次是否完全代表现有词汇表来掩盖 update-batches 如何影响模型的困难权衡。最安全的方法是定期 re-train 从头开始构建模型,使用完整的语料库,其中包含所有相关单词的足够示例。
因此,我的主要建议是定期将您的模型替换为经过所有 still-relevant 数据训练的新模型。这将确保它不再在过时的术语上浪费模型状态,并且所有 still-live 术语都接受了同等的交错训练。
在这样的重置之后,word-vectors 将无法与之前 'model era' 的 word-vectors 相提并论。 (同一个词,即使它的有形意义没有改变,也可能是一个任意不同的地方——但与其他向量的相对关系应该保持不变或更好。)但是,同样的 drift-out-of-comparison 是 也 发生在任何一组 small-batch 更新中,这些更新不会 'touch' 每个现有单词均等,只是以某种无法量化的速度。
OTOH,如果您认为需要保留此类增量更新,即使知道注意事项,您也可以 patch-up 模型结构尽可能多地保留旧模型并继续培训。
到目前为止,您的代码是一个合理的开始,缺少一些正确功能的重要注意事项:
- 因为删除 earlier-words 会更改 later-words 的索引位置,您需要更新每个幸存单词的
vocab[word].index
值,以匹配新的index2word
订购。例如,在完成所有删除后,您可以这样做:
for i, word in enumerate(m.wv.index2word):
m.wv.vocab[word].index = i
因为在您的(默认 negative-sampling)
中删除同一行Word2Vec
模型中,还有 另一个 per-word 权重数组与模型的输出层相关,也应该同步更新,以便每个单词检查正确的 output-values。粗略地说,每当您从m.wv.vectors
中删除一行时,您应该从m.traininables.syn1neg
.因为幸存的词汇有不同的相对 word-frequencies,negative-sampling 和下采样(由
sample
参数控制)功能应该不同 pre-calculated 结构来协助他们的选择。对于negative-sampling使用的cumulative-distributiontable,这很简单:
m.make_cum_table(m.wv)
对于下采样,您希望更新 .sample_int
值,类似于您可以在 https://github.com/RaRe-Technologies/gensim/blob/3.8.3/gensim/models/word2vec.py#L1534. (But, looking at that code now, I think it may be buggy 处查看代码的逻辑,因为它仅使用中的频率信息更新所有单词新字典,所以可能会污染 truly-frequent 单词的通常下采样,并且可能错误地对仅在新更新中频繁出现的单词进行下采样。)
如果这些内部结构与您现有的操作同步正确更新,模型可能处于一致状态以进行进一步训练。 (但请注意:这些结构在即将发布的 gensim-4.0.0
版本中发生了很大变化,因此在升级时需要更新任何自定义篡改。)
另一个效率注意事项:np.delete()
操作将创建一个新数组,即剩余数组的完整大小,并在每次调用时复制旧值。因此,使用它从 very-large 原始数组中一次删除许多行可能需要大量冗余 allocation/copying/garbage-collection。最后,您可以使用要删除的所有索引的列表调用它一次。
但实际上:更简单的 better-grounded 方法也可能产生更好的 continually-comparable 向量,只要有可能或发生大量变化,就用所有当前数据重新训练。