如何解决从gensim word2vec模型中删除旧“单词”的最佳方法是什么?
我有一个从项目-项目图构建的“语料库”,这意味着每个句子都是一个图行走路径,每个单词都是一个项目。我想在语料库上训练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
仍在元素方面相对应吗?上面的代码有副作用吗?如果我的方法不好,有人可以给我举个例子,说明如何正确删除旧的“单词”并使模型易于训练吗?
解决方法
一旦他们“切入”包含在内,就没有官方支持从Gensim Word2Vec
模型中删除单词。
即使添加字词的能力也不是很好,因为该功能不是基于任何已证明/已发布的更新Word2Vec
模型的方法,并且会掩盖通过选择学习率或批次是否完全代表现有词汇,在更新批次如何影响模型方面进行了艰难的权衡。最安全的方法是定期从头开始重新训练模型,并使用完整的语料库以及所有相关单词的充分示例。
因此,我的主要建议是定期使用经过培训且仍具有所有相关数据的新模型定期替换您的模型。这样可以确保它不再浪费过时的模型状态,并且所有仍然有效的术语都经过了同等的,交错的训练。
这样的重置后,字向量将无法与之前的“模型时代”中的字向量相提并论。 (即使它的有形含义没有改变,相同的词也可能是一个任意不同的地方-但与其他向量的相对关系应保持相同或更好。)但是,这种类型的比较偏离 也发生在任何小批量更新中,这些更新不会以某种无法量化的速度平等地“接触”每个现有单词。
OTOH,如果您认为需要保留此类增量更新,甚至知道警告,那么可以修补模型结构以保留旧模型中尽可能多的内容,并继续进行培训。
>到目前为止,您的代码是一个合理的开始,但缺少一些有关正常功能的重要注意事项:
- 由于删除前一个单词会更改后一个单词的索引位置,因此您需要为每个尚存的单词更新
vocab[word].index
值,以匹配新的index2word
顺序。例如,完成所有删除后,您可以这样做:
for i,word in enumerate(m.wv.index2word):
m.wv.vocab[word].index = i
-
因为(默认的负采样)
Word2Vec
模型中,还存在 与该模型的输出层相关的每字权重的另一个数组,该数组也应为同步更新,以便每个单词检查正确的输出值。粗略地说,无论何时从m.wv.vectors
删除一行,都应从m.traininables.syn1neg
删除同一行。 -
由于尚存的词汇具有不同的相对词频,因此负采样和降采样(受
sample
参数控制)功能均应采用不同的预先计算结构来辅助选择。对于负采样所使用的累积分布表,这非常简单:
m.make_cum_table(m.wv)
对于下采样,您希望更新.sample_int
的值,类似于可以在https://github.com/RaRe-Technologies/gensim/blob/3.8.3/gensim/models/word2vec.py#L1534的代码周围查看的逻辑。 (但是,现在看一下这段代码,我想可能是buggy,因为它只是用新字典中的频率信息来更新所有单词,因此可能会破坏通常对真正频繁单词的下采样,并且可能会错误地对仅在新更新中经常出现的单词进行降采样。)
如果与您的现有操作同步地正确更新了这些内部结构,则该模型可能处于一致状态,以进行进一步的培训。 (但请注意:这些结构在即将发布的gensim-4.0.0
版本中发生了很大变化,因此在升级时,任何自定义篡改都需要更新。)
另一个效率注意事项:np.delete()
操作将创建一个新数组,该数组将保留整个数组的大小,并在每次调用时复制旧值。因此,使用它从非常大的原始阵列中一次删除许多行可能需要大量冗余分配/复制/垃圾收集。最后,您也许可以调用一次,并列出所有要删除的索引。
但是实际上:更简单,更扎实的方法(可能还会产生更好的可连续比较的向量)将是在可能或发生大量更改的情况下使用所有当前数据进行重新训练。