改进 Gensim Doc2vec 结果

Improving Gensim Doc2vec results

我尝试在 600000 行句子上应用 doc2vec:代码如下:

from gensim import models
model = models.Doc2Vec(alpha=.025, min_alpha=.025, min_count=1, workers = 5)
model.build_vocab(res)
token_count = sum([len(sentence) for sentence in res])
token_count

%%time
for epoch in range(100):
    #print ('iteration:'+str(epoch+1))
    #model.train(sentences)
    model.train(res, total_examples = token_count,epochs = model.iter)
    model.alpha -= 0.0001  # decrease the learning rate`
    model.min_alpha = model.alpha  # fix the learning rate, no decay

我在上面的实现中得到的结果很差。 除了教程中建议的内容外,我所做的更改是更改以下行:

  model.train(sentences)

作为:

 token_count = sum([len(sentence) for sentence in res])
model.train(res, total_examples = token_count,epochs = model.iter)

不幸的是,您的代码是错误做法的荒谬组合。因此,不要 遵循您所遵循的任何在线示例!

按照问题的顺序,从上到下:

不要 使 min_alphaalpha 相同。随机梯度下降优化过程需要在看到许多不同示例的过程中从较大的 alpha 学习率逐渐下降,并且通常应该以可忽略不计的接近零的值结束。 (代码试图以这种方式显式递减 alpha 还有其他问题,我们将在下面进行介绍。)只有已经有了有效设置、很好地理解算法并正在进行实验性调整的专家用户应该更改 alpha/min_alpha 默认值。

不要设置min_count=1。只出现一次或几次的稀有词通常 对 Word2Vec/Doc2Vec 训练没有帮助。它们出现的次数少意味着它们自己对应的模型权重没有得到太多训练,并且与对应词的真实含义相比,出现次数少的次数更有可能不具有代表性(可能会反映在测试数据或后来的生产数据中)。因此,模型对这些个别稀有词的表示不太可能变得非常好。但总的来说,所有这些稀有词与 do 有机会变得有意义的其他词竞争很多——所以 'rough' 稀有词主要是对其他词的随机干扰。或者,这些词可能意味着额外的模型词汇参数,这有助于模型在训练数据上变得表面上更好,因为在那里记住了不可泛化的特质,但在未来的 test/production 数据上更糟。因此,min_count 是另一个默认值 (5),只有在您拥有工作基线后才应更改它 - 如果您稍后严格元优化此参数,在一个大小适中的数据集(如您的 600K 文档)上,您很可能会发现 更高 min_count 而不是 更低 可以改善最终结果。

为什么要做token_count?没有以后需要总令牌计数的地方。 total_examples 参数稍后需要文本示例的计数——即单个 documents/sentences 的数量 – 而不是 总单词数。通过提供(更大的)字数,train() 将无法正确管理 alpha 或估计记录输出的进度。

不要 在一个循环中多次调用 train() 并使用您自己的显式 alpha 管理,除非您确定自己知道自己在做什么正在做。大多数人都弄错了。通过在此处提供默认 model.iter(值为 5)作为参数,您实际上对语料库执行了 500 次总传递,这不太可能是您想要的。通过在 100 次循环中将初始 0.025 alpha 值递减 0.0001,最终 alpha 为 0.015 - 小于起始值的一半。相反,使用正确的 total_examples 和精心选择的 epochs 值(在 Doc2Vec 发表的作品中通常使用 10 到 20)只调用一次 train()。然后它将进行精确的显式迭代次数,并智能地管理 alpha,并在日志记录中打印准确的进度估计。

最后,接下来的事情不一定是你的代码中的问题,因为你没有展示你的语料库 res 是如何构建的,但有一个常见的错误需要注意:确保你的语料库可以迭代多次(就好像它是一个内存列表,或者一个可重新启动的 iterable 对象来自 IO 的东西)。通常人们会提供一个一次性的 iterator,在一次通过后(如 build_vocab())returns 没有别的 - 导致即时训练和无用的 -仍然是随机和未经训练的模型。 (如果您启用了日志记录,并注意记录的输出和每个步骤的时间,那么这是否是一个问题会很明显。)