在大型数据集上训练词嵌入时如何处理内存问题?

数据挖掘 数据集 深度学习 词嵌入 火炬
2021-09-19 21:28:38

我想训练一个单词可预测性任务来生成单词嵌入。文档集合包含 243k 文档。代码实现在torch中。我正在努力应对庞大的数据集,并且需要有关如何在如此庞大的数据集上训练词嵌入的想法,该数据集包含 243,000 个完整的文章文档。研究计算资源是定时的,因此可以短时间访问 GPU 节点,因此选择了增量模型训练:

  1. 增量模型训练:对整个数据集进行训练的一种方法是使用增量模型训练,即在一块数据上训练模型并保存它。稍后选择相同的预训练模型并开始对其下一个数据块进行训练。我在这种方法中面临的问题是我如何维护单词的词汇/字典。在词嵌入方法中,字典/词汇起着重要的作用。我们扫描所有文档并创建计数大于最小设定频率的单词的词汇。现在,实际上这个词汇是一个哈希映射,它具有与每个单词相关联的索引,并且在训练样本中,为了模型的简单性,我们用词汇中的索引替换单词。在增量训练的情况下,如何增量创建字典?我是否必须最初在整个文档上创建词汇/字典,然后逐步训练?或者是一种在增量训练中扩展词汇的方法?
  2. 另一个问题是词汇数据结构大小的内存限制。我在基于 LUA 的 Torch 中实现我的模型。因此,LUA 对表格大小进行了限制,我无法在单个表格中加载整个文档的词汇。如何克服这样的记忆问题?
  3. 从手套向量中汲取灵感。在他们的论文中,他们说他们“我们在五个不同大小的语料库上训练了我们的模型:一个 2010 年的维基百科转储,包含 10 亿个令牌;2014 年 Wikipedia 转储,包含 16 亿个代币;Gigaword 5 拥有 43 亿个代币;Gigaword5 + Wikipedia2014 的组合,拥有 60 亿个代币;以及来自 Common Crawl5 的 420 亿个网络数据令牌。我们使用斯坦福分词器对每个语料库进行分词和小写,构建一个包含 400,000 个最常用词的词汇表,然后构建一个共现计数矩阵 X”。关于 Glove 向量如何在如此大的语料库和大词汇量上进行训练以及如何处理他们案例中的内存限制的任何想法?论文参考 - http://nlp.stanford.edu/pubs/glove.pdf
  4. 关于如何限制生成词嵌入的数据集大小的任何想法?随着文档数量的增加或减少,它将如何影响词嵌入的性能或覆盖率?使用采样技术从数据集中采样文档是个好主意吗?如果是,那么请建议一些采样技术。
2个回答

您可以使用 tds 库克服内置的内存限制,它允许您构建不受 Lua 内存上限限制的或多或少的等效结构。这对您的硬件限制没有帮助,但是您将能够拥有诸如大于 2 GB 的表之类的东西。

https://github.com/torch/tds

此外,如果所有其他方法都失败了,您可以考虑将您的词汇表划分为较小的表。然后,当您需要访问它时,您将拥有某种主表,您可以在其中查找要查找的元素的正确词汇表。这将需要对您的词汇进行排序,因此您仍然必须一次将所有内容都存储在内存中(或者我猜想实现您自己的狡猾的排序算法),但只要您的词汇量足够长,您只需要这样做一次保持不变。然后序列化所有词汇表并根据需要将它们从磁盘加载,这会很慢,但仍然比填满物理内存和占用交换空间要快。大概。

我对 Torch 不熟悉,但是由于基本上考虑了 word2vec 和 doc2vec,这些模型从每个句子中学习,因此不需要将所有句子都放在记忆中。您可以遍历语料库中的每个句子,并让模型从每个句子中学习。这可能就是人们在有或没有高计算机器的情况下在巨大的语料库上训练的方式。

python中的一个简短示例:

class SentenceIterator(object):
   def __iter__(file_name):
      for line in open(file_name)
         yield line

sentences = SentenceIterator("path/to/file")
for line in sentences:
    model.train(line)

这样,内存一次只加载一个句子,当它完成时,内存加载下一个。对于构建词汇表,您可以对所有文档进行整个迭代以首先构建词汇表,然后训练数据,具体取决于实现的词嵌入功能。