尽管 `max_vocab_size` 设置,gensim word2vec 词汇量随着语料库的增长而上下波动

gensim word2vec vocabulary size fluctuates up & down as corpus grows despite `max_vocab_size` setting

我正在使用 gensim Word2Vec 模型训练词嵌入,该模型具有数百万句语料库,该语料库由 300 万个具有 max_vocab_size = 32_000 的独特标记组成。

即使我设置了 min_count = 1,模型创建的词汇量也远远少于 32_000。当我使用语料库的一个子集时,词汇量增加了!

为了解决问题,我设置了一个实验,我用不同大小的子语料库控制词汇量的大小。词汇量波动!

您可以使用以下代码重新制作:

import string
import numpy as np
from gensim.models import Word2Vec

letters = list(string.ascii_lowercase)

# creating toy sentences
sentences = []
number_of_sentences = 100_000

for _ in range(number_of_sentences):
    number_of_tokens = np.random.randint(1, 15, 1)[0]
    sentence = []
    for i in range(number_of_tokens):
        token = ""
        len_of_token = np.random.randint(1, 5, 1)[0]
        for j in range(len_of_token):
            token += np.random.choice(letters)
        sentence.append(token)
    sentences.append(sentence)

# Sanity check to ensure that input data is a list of list of strings(tokens)
for _ in range(4):
    print(np.random.choice(sentences))

# collecting some statistics about tokens
flattened = []
for sublist in sentences:
    for item in sublist:
        flattened.append(item)
        
unique_tokens = {}
for token in flattened:
    if token not in unique_tokens:
        unique_tokens[token] = len(unique_tokens)

print('Number of tokens:', f'{len(flattened):,}')
print('Number of unique tokens:', f'{len(unique_tokens):,}')


# gensim model
vocab_size = 32_000
min_count = 1
collected_data = []
for num_sentence in range(5_000, number_of_sentences + 5_000, 5_000):
    model = Word2Vec(min_count=min_count, max_vocab_size= vocab_size)
    model.build_vocab(sentences[:num_sentence])

    collected_data.append((num_sentence, len(model.wv.key_to_index)))

for duo in collected_data:
    print('Vocab size of', duo[1], 'for', duo[0], 'number of sentences!')

输出:

['cpi', 'bog', 'df', 'tgi', 'xck', 'kkh', 'ktw', 'ay']
['z', 'h', 'w', 'jek', 'w', 'dqm', 'wfb', 'agq', 'egrg']
['kgwb', 'lahf', 'kzx', 'd', 'qdok', 'xka', 'hbiz', 'bjo', 'fvk', 'j', 'hx']
['old', 'c', 'ik', 'n', 'e', 'n', 'o', 'r', 'ehx', 'dlud', 'd']

Number of tokens: 748,383
Number of unique tokens: 171,485

Vocab size of 16929 for 5000 number of sentences!
Vocab size of 30314 for 10000 number of sentences!
Vocab size of 19017 for 15000 number of sentences!
Vocab size of 31394 for 20000 number of sentences!
Vocab size of 19564 for 25000 number of sentences!
Vocab size of 31831 for 30000 number of sentences!
Vocab size of 19543 for 35000 number of sentences!
Vocab size of 31744 for 40000 number of sentences!
Vocab size of 19536 for 45000 number of sentences!
Vocab size of 31642 for 50000 number of sentences!
Vocab size of 18806 for 55000 number of sentences!
Vocab size of 31255 for 60000 number of sentences!
Vocab size of 18497 for 65000 number of sentences!
Vocab size of 31166 for 70000 number of sentences!
Vocab size of 18142 for 75000 number of sentences!
Vocab size of 30886 for 80000 number of sentences!
Vocab size of 17693 for 85000 number of sentences!
Vocab size of 30390 for 90000 number of sentences!
Vocab size of 17007 for 95000 number of sentences!
Vocab size of 30196 for 100000 number of sentences!

我尝试增加 min_count,但这对词汇量的这种波动没有帮助。我错过了什么?

在 Gensim 中,max_vocab_size 参数是一种非常 粗略的机制,用于在初始扫描训练语料库以发现词汇时限制 RAM 使用。只有当它是解决 RAM 问题的唯一方法时,才应使用此参数。

本质上:尝试不使用 max_vocab_size。如果您想控制保留哪些单词,请使用替代参数,例如 min_count(丢弃频率低于特定阈值的单词)或 max_final_vocab(不超过设定数量的最-常用词)。

当且仅当您遇到内存不足错误(或大量虚拟内存交换),然后考虑使用 max_vocab_size.

但即便如此,由于它的工作方式,您仍然不想将 max_vocab_size 设置为您想要的实际最终大小。相反,您应该将它设置为某个非常非常大的值 - 但小到足以不耗尽您的 RAM。

这允许在应用其他参数(如 min_countmax_final_vocab)之前 最准确的字数统计。

如果您改为使用较低的 max_vocab_size,则 运行 调查会在已知单词数量达到该值时过早 trim 计数。也就是说,一旦临时计数达到那么多条目,比如说 max_vocab_size=32000,许多最不频繁的计数就会被 遗忘 以限制内存使用(并且每次更多达到阈值)。

这使得所有最终计数都是近似值(基于术语错过截止值的频率),并且意味着完整调查中唯一标记的最终数量将是某个值甚至小于 max_vocab_size,有些武断基于最近一次遗忘-trim 被触发的时间。 (因此,有些随机,但总是低于 max_vocab_size,在您的实验输出中看到的计数。)

因此:max_vocab_size 不太可能按照大多数人的意愿行事,或者以可预测的方式行事。尽管如此,它仍然可以帮助完成极端语料库的模糊调查,否则唯一术语会溢出 RAM。

另外:min_count=1 在 word2vec 中通常是一个坏主意,因为缺乏足够多变用法示例的词本身不会获得好的词向量,而是将所有这些表示不佳的词留在训练数据中倾向于充当噪音,稀释(和延迟)可以从足够频繁的单词中学到什么。