如何最佳地处理不在 word2vec 词汇表中的单词

How to handle words that are not in word2vec's vocab optimally

我有一个约 1000 万个句子的列表,其中每个句子最多包含 70 个单词。

我运行在每个单词上使用 gensim word2vec,然后对每个句子取简单平均值。问题是我用的是min_count=1000,所以很多词不在词汇表中。

为了解决这个问题,我将 vocab 数组(包含大约 10000 个单词)与每个句子相交,如果该交集中至少还剩下一个元素,则 returns 为简单平均值,否则,它 returns 一个零向量。

问题是当我 运行 在整个数据集上计算每个平均值需要很长时间,即使拆分成多个线程也是如此,我想得到一个更好的解决方案 运行 更快。

我运行在 EC2 r4.4xlarge 实例上安装它。

我已经尝试切换到 doc2vec,速度更快,但结果不如 word2vec 的简单平均值。

word2vec_aug_32x = Word2Vec(sentences=sentences, 
                        min_count=1000, 
                        size=32, 
                        window=2,
                        workers=16, 
                        sg=0)

vocab_arr = np.array(list(word2vec_aug_32x.wv.vocab.keys()))

def get_embedded_average(sentence):
    sentence = np.intersect1d(sentence, vocab_arr)
    if sentence.shape[0] > 0:
        return np.mean(word2vec_aug_32x[sentence], axis=0).tolist()
    else:
        return np.zeros(32).tolist()

pool = multiprocessing.Pool(processes=16)

w2v_averages = np.asarray(pool.map(get_embedded_average, np.asarray(sentences)))
pool.close()

如果您对具有相同句子嵌入目的的不同算法或技术有任何建议并且可以解决我的问题,我很乐意阅读。

您可以使用 FastText 而不是 Word2Vec。 FastText 能够通过查看子词信息(字符 ngram)嵌入词汇表外的词。 Gensim还有一个FastText实现,非常好用:

from gensim.models import FastText

model = FastText(sentences=training_data, size=128, ...)

word = 'hello' # can be out of vocabulary
embedding = model[word] # fetches the word embedding

通常 Doc2Vec 与普通的平均词向量相比,文本向量的有用性非常相似(或者在调整时更好一点)。 (毕竟,算法非常相似,处理相同数据的相同形式,并且创建的模型大小大致相同。)如果下降幅度很大,则您的 Doc2Vec 进程.

正如@AnnaKrogager 指出的那样,FastText 可以通过使用单词片段合成猜测向量来处理词汇表外的单词。 (这需要单词具有此类共享词根的语言。)向量可能不是很好,但通常比完全忽略未知单词或使用全零向量或随机插入向量要好。

在进程之间拆分它是否对运行时有帮助?因为在子进程之间发送批量工作会产生大量开销,而 Python 中的子进程会导致内存需求激增——而且这种开销甚至可能是虚拟内存交换都可能超过任何开销并行的其他好处。