【问题标题】:Speed Up Gensim's Word2vec for a Massive Dataset为海量数据集加速 Gensim 的 Word2vec
【发布时间】:2020-05-12 03:21:04
【问题描述】:

我正在尝试使用 Gensim 在由 1000 个文件组成的海量数据集上构建 Word2vec(或 FastText)模型,每个文件包含约 210,000 个句子,每个句子包含约 1000 个单词。培训是在 185gb RAM、36 核机器上进行的。 我验证了这一点

gensim.models.word2vec.FAST_VERSION == 1

首先,我尝试了以下方法:

files = gensim.models.word2vec.PathLineSentences('path/to/files')
model = gensim.models.word2vec.Word2Vec(files, workers=-1)

但 13 小时后,我认为它运行时间过长并停止了它。

然后我尝试基于单个文件构建词汇表,并基于所有 1000 个文件进行如下训练:

files = os.listdir['path/to/files']
model = gensim.models.word2vec.Word2Vec(min_count=1, workers=-1)
model.build_vocab(corpus_file=files[0])
for file in files:
    model.train(corpus_file=file, total_words=model.corpus_total_words, epochs=1)

但是我检查了训练前后的词向量样本,没有任何变化,这意味着没有进行实际的训练。

我可以就如何快速成功地运行它提出一些建议。谢谢!

更新 #1:

这是检查向量更新的代码:

file = 'path/to/single/gziped/file'
total_words = 197264406 # number of words in 'file'
total_examples = 209718 # number of records in 'file'
model = gensim.models.word2vec.Word2Vec(iter=5, workers=12)
model.build_vocab(corpus_file=file)
wv_before = model.wv['9995']
model.train(corpus_file=file, total_words=total_words, total_examples=total_examples, epochs=5)
wv_after = model.wv['9995']

所以向量:wv_beforewv_after 完全相同

【问题讨论】:

    标签: gensim word2vec fasttext


    【解决方案1】:

    gensimWord2Vec 中没有工具可以接受workers 值。 (你从哪里得到有意义的想法?)

    因此,很有可能这会破坏某些东西,甚至可能会阻止任何训练的尝试。

    是否有合理的日志输出(INFO 级别)表明在您的试运行中正在进行训练,无论是针对 PathLineSentences 还是您的第二次尝试? top 之类的实用程序是否显示繁忙的线程?输出是否建议了特定的进度并让您预测可能的完成时间?

    我建议使用积极的workers 值并观察INFO 级别的日志记录,以更好地了解正在发生的事情。

    不幸的是,即使有 36 个内核,使用语料库可迭代序列(如 PathLineSentences)将 gensim Word2Vec 放入模型中,如果 workers 值在 8-16 范围内,您可能会获得最大吞吐量,使用的线程远远少于您的所有线程。但它会在任何大小的语料库上做正确的事情,即使它是由可迭代序列即时组装的。

    使用corpus_file 模式可以使更多内核饱和,但您仍应指定要使用的实际工作线程数 - 在您的情况下,workers=36 - 它旨在从单个文件处理所有数据。

    您的代码尝试使用train() 多次使用corpus_file 有很多问题,我想不出一种方法来调整corpus_file 模式以处理您的许多文件。一些问题包括:

    • 您只是从第一个文件中构建词汇表,这意味着仅出现在其他文件中的任何单词都将是未知和忽略的,Word2Vec 算法的任何词频驱动部分可能正在从事不具代表性的工作

    • 模型从build_vocab() 步骤构建其对预期语料库大小的估计(例如:model.corpus_total_words),因此每个train() 在其进程中都会表现得好像该大小是总语料库大小-报告和管理内部alpha 学习率衰减。因此,这些日志将是错误的,alpha 将在每个train() 的新衰减中被管理不善,从而导致所有文件的alpha 上下拼图。

    • 您只对每个文件的内容进行一次迭代,这并不常见。 (不过,如果每个文件的文本均等且随机地代表该域,那么在 2100 亿字的巨大语料库中这可能是合理的。在这种情况下,完整的语料库一次可能与迭代 1/5 的语料库一样好大小是 5 倍。但如果某些单词/使用模式都聚集在某些文件中,那将是一个问题 - 最好的训练在每个时期和所有时期中交错对比示例。)

    • min_count=1 使用这种算法几乎总是不明智的,尤其是在具有典型自然语言词频的大型语料库中。稀有词,尤其是那些只出现一次或几次的词,会使模型变得巨大,但这些词不会得到好的词向量,并且将它们保持在干扰其他更常见词的改进的行为中。

    我推荐:

    尝试语料库可迭代序列模式,使用日志记录和合理的workers 值,至少可以准确读取可能需要多长时间。 (最长的步骤将是初始词汇扫描,它本质上是单线程的,并且必须访问所有数据。但是您可以在该步骤之后.save()模型,然后再重新.load()它,修改设置,然后尝试不同的train() 方法,而无需重复缓慢的词汇调查。)

    尝试使用更高的 min_count 值(丢弃更多稀有词以获得更小的模型和更快的训练)。也许还可以尝试使用更小的sample 值(如1e-051e-06 等)来丢弃大部分最常见的词,以加快训练速度,同时通常也提高整体词向量质量(通过花费相对较少的单词要付出更多的努力)。

    如果仍然太慢,请考虑是否可以使用较小的语料库子样本就足够了。

    如果您可以将大部分或全部数据滚动到所需的单个文件中,请考虑使用corpus_file 方法。

    【讨论】:

    • 感谢您的详细回复。在 uber 文件上实施之前,我在单个文件上测试了您的建议:将 workers=8epochs=5min_count=5 和日志级别设置为 INFO。进度日志显示正在进行培训,top 也显示了繁忙的线程。训练前后的词向量仍然保持不变...
    • 如上所述,如果您使用单个文件(和corpus_file),您不妨使用workers=36。您如何检查词向量是否保持不变? (注意使用类似most_similar() 检查的任何东西,因为这可能会导致使用缓存的单位长度归一化向量集,经过更多训练后不一定会改变。)
    • 我在调用实例化模型并运行model.build_vocab 之后检查了一个单词样本,然后在运行model.train 之后再次检查。
    • 如果日志显示正在发生耗时的训练,那么单词应该会发生变化——因此您检查单词向量样本的方式可能有问题。如果您(在您的答案中)显示您用来检查的代码,问题可能会变得清晰。
    • wv_before = model.wv['9995'] 这样对底层numpy 数组的简单访问通常会在该行上创建一个新的“视图”,而不是一个独立的副本。所以最后,是的,wv_before == wv.after 将是True——但那是因为wv_before 一直在跟上变化。如果您在之前/之后注意到您的示例项目,您应该会看到更改 - 或者您可以使用 wv_before = model.wv['9995'].copy() 确保单独的副本。
    猜你喜欢
    • 1970-01-01
    • 2019-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-15
    • 1970-01-01
    • 2019-07-01
    • 2019-05-26
    相关资源
    最近更新 更多