【问题标题】:Gensim Doc2vec finalize_vocab Memory ErrorGensim Doc2vec finalize_vocab 内存错误
【发布时间】:2017-08-29 16:13:47
【问题描述】:

我正在尝试使用 gensim 训练一个 Doc2Vec 模型,该模型具有 114M 唯一文档/标签和大约 3M 唯一单词的词汇量。我在 Azure 上有 115GB Ram linux 机器。 当我运行 build_vocab 时,迭代器会解析所有文件,然后抛出如下所示的内存错误。

    Traceback (most recent call last):
  File "doc_2_vec.py", line 63, in <module>
    model.build_vocab(sentences.to_array())
  File "/home/meghana/.local/lib/python2.7/site-packages/gensim/models/word2vec.py", line 579, in build_vocab
    self.finalize_vocab(update=update)  # build tables & arrays
  File "/home/meghana/.local/lib/python2.7/site-packages/gensim/models/word2vec.py", line 752, in finalize_vocab
    self.reset_weights()
  File "/home/meghana/.local/lib/python2.7/site-packages/gensim/models/doc2vec.py", line 662, in reset_weights
    self.docvecs.reset_weights(self)
  File "/home/meghana/.local/lib/python2.7/site-packages/gensim/models/doc2vec.py", line 390, in reset_weights
    self.doctag_syn0 = empty((length, model.vector_size), dtype=REAL)
MemoryError

我的代码-

import parquet
import json
import collections
import multiprocessing


# gensim modules
from gensim import utils
from gensim.models.doc2vec import LabeledSentence
from gensim.models import Doc2Vec

class LabeledLineSentence(object):
    def __init__(self, sources):
        self.sources = sources   
        flipped = {}

    def __iter__(self):
        for src in self.sources:
            with open(src) as fo:
               for row in parquet.DictReader(fo, columns=['Id','tokens']):
                    yield LabeledSentence(utils.to_unicode(row['tokens']).split('\x01'), [row['Id']])

## list of files to be open ##
sources =  glob.glob("/data/meghana_home/data/*")
sentences = LabeledLineSentence(sources)

#pre = Doc2Vec(min_count=0)
#pre.scan_vocab(sentences)
"""
for num in range(0, 20):
    print('min_count: {}, size of vocab: '.format(num), pre.scale_vocab(min_count=num, dry_run=True)['memory']['vocab']/700)
    print("done")
"""

NUM_WORKERS = multiprocessing.cpu_count()
NUM_VECTORS = 300
model = Doc2Vec(alpha=0.025, min_alpha=0.0001,min_count=15, window=3, size=NUM_VECTORS, sample=1e-4, negative=10, workers=NUM_WORKERS) 
model.build_vocab(sentences)
print("built vocab.......")
model.train(sentences,total_examples=model.corpus_count, epochs=10)

按照顶部的内存使用情况是-

谁能告诉我预期的内存是多少?什么是更好的选择 - 添加交换空间并减慢进程或添加更多内存,以便集群成本最终可能相等。 gensim 将哪些向量存储在内存中?我为内存有效使用而缺少的任何标志。

【问题讨论】:

    标签: python nlp gensim doc2vec


    【解决方案1】:

    1.14 亿个文档标签至少需要 114,000,000 doctags * 300 dimensions * 4 bytes/float = 136GB 才能在训练期间存储原始文档标签向量。

    (如果 doctag 键 row['Id'] 是字符串,那么记住 string-to-int-index 映射字典会有额外的开销。如果 doctag 键是从 0 到 1.14 亿的原始整数,那将避免填充那个 dict。如果 doctag 键是原始 int,但包含任何大于 1.14 亿的 int,则模型将尝试分配一个足够大的数组以包含最大 int 的行——即使许多其​​他较低的 int 未使用。)

    原始词向量和模型输出层 (model.syn1) 将需要大约另外 8GB,词汇字典需要另外几 GB。

    因此,理想情况下,您需要更多的可寻址内存,或者更小的文档标签集。

    您提到了“集群”,但 gensim Doc2Vec 不支持多机分发。

    对于这些算法来说,使用交换空间通常不是一个好主意,它可能涉及大量随机访问,因此在交换过程中会变得非常慢。但是对于 Doc2Vec,您可以使用Doc2Vec.__init__() 可选参数docvecs_mapfile 将其doctags 数组设置为由内存映射文件提供服务。在每个文档都有一个标签的情况下,并且这些标签在每次重复扫描训练文本时以相同的升序出现,性能可能是可以接受的。

    分别:

    您对训练迭代和alpha 学习率的管理有问题。即使每个 train() 调用尝试默认的 5 次传递,但随后仅从不可重新启动的 sentences.to_array() 对象中获取单次迭代,您在 alpha 值分别为 0.025 和 0.023 处实现了 2 次传递。

    您应该瞄准更多的通道,用更少的代码行来管理 alpha 从它的初始高到默认的最终微小 min_alpha 值。您只需拨打train() 一次,除非您绝对确定需要在多次通话之间执行额外步骤。 (此处显示的内容都不需要。)

    通过将to_array() 更改为__iter__(),然后将sentences(而不是sentences.to_array())单独(而不是sentences.to_array())传递给模型,使您的sentences 对象成为可以多次迭代的真正可迭代对象。

    然后用这个可多次迭代的对象调用train() 一次,让它执行指定次数的迭代,从高到低平滑地更新alpha。 (从Word2Vec 继承的默认值为 5 次迭代,但在已发布的Doc2Vec 工作中更常用的是 10 到 20。默认的 min_alpha 的 0.0001 几乎永远不会更改。)

    【讨论】:

    • 根据后面的建议修改了代码。我希望它现在很好。谢谢。
    • 感谢您的回答。关于“docvecs_mapfile”参数,我将阅读它是如何工作的。您能否参考一些资料来阅读各种参数的工作原理或通过 gensim Doc2vec 代码就足够了?
    • DocvecsArray 类的源代码和文档注释 - github.com/RaRe-Technologies/gensim/blob/… - 可能会有所帮助。它是model.docvecs 中对象的类。您可能还想搜索项目讨论列表 - groups.google.com/forum/#!forum/gensim - 以获取之前提到的 docvecs_mapfile
    • 代码更改以使您的 LabeledLineSentence 类成为真正的可迭代对象,然后让对 train() 的一次调用管理时期和平滑 alpha-decay,看起来不错。另一个注意事项 - 如果您的核心数量超过 8 个,您可能无法在 workers 数量等于核心的情况下获得更高的吞吐量。在 Python (GIL) 和这个 gensim 实现中仍然存在一些固有的多线程瓶颈,因此训练吞吐量(以训练的每秒语料库单词为单位)通常会在 16 个线程低于处达到最大值。
    猜你喜欢
    • 1970-01-01
    • 2015-08-09
    • 2017-02-12
    • 2018-07-21
    • 2016-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-11
    相关资源
    最近更新 更多