python-3.x - joblib 转储时出现内存错误

标签 python-3.x scikit-learn out-of-memory joblib

我运行以下代码片段来训练文本分类模型。我对它进行了相当多的优化,它运行得相当顺利,但它仍然使用大量内存。我们的数据集非常庞大(1300 万个文档 + 1800 万个词汇表),但在我看来,执行时抛出错误的点非常奇怪。脚本:

encoder = LabelEncoder()
y = encoder.fit_transform(categories)
classes = list(range(0, len(encoder.classes_)))

vectorizer = CountVectorizer(vocabulary=vocabulary,
                             binary=True,
                             dtype=numpy.int8)

classifier = SGDClassifier(loss='modified_huber',
                           n_jobs=-1,
                           average=True,
                           random_state=1)

tokenpath = modelpath.joinpath("tokens")
for i in range(0, len(batches)):
    token_matrix = joblib.load(
        tokenpath.joinpath("{}.pickle".format(i)))
    batchsize = len(token_matrix)
    classifier.partial_fit(
        vectorizer.transform(token_matrix),
        y[i * batchsize:(i + 1) * batchsize],
        classes=classes
    )

joblib.dump(classifier, modelpath.joinpath('classifier.pickle'))
joblib.dump(vectorizer, modelpath.joinpath('vectorizer.pickle'))
joblib.dump(encoder, modelpath.joinpath('category_encoder.pickle'))
joblib.dump(options, modelpath.joinpath('extraction_options.pickle'))

我在这一行遇到了 MemoryError:

joblib.dump(vectorizer, modelpath.joinpath('vectorizer.pickle'))

在执行过程中,训练已经完成并且分类器已经被转储。如果需要更多内存,它应该由垃圾收集器收集。除此之外,如果joblib连compressing the data都没有的话为什么要分配这么多内存呢? 。

我对Python垃圾收集器的内部工作原理没有深入的了解。我应该强制 gc.collect() 还是使用“del”语句来释放那些不再需要的对象?

更新:

我尝试过使用 HashingVectorizer,尽管它大大减少了内存使用量,但矢量化速度却慢得多,使其不是一个很好的替代方案。

我必须对矢量化器进行pickle,以便稍后在分类过程中使用它,这样我就可以生成提交给分类器的稀疏矩阵。我将在这里发布我的分类代码:

extracted_features = joblib.Parallel(n_jobs=-1)(
    joblib.delayed(features.extractor) (d, extraction_options) for d in documents)

probabilities = classifier.predict_proba(
    vectorizer.transform(extracted_features))

predictions = category_encoder.inverse_transform(
    probabilities.argmax(axis=1))

trust = probabilities.max(axis=1)

最佳答案

如果您向 CountVectorizer 提供自定义词汇表,则稍后在分类期间重新创建它应该不成问题。当您提供一组字符串而不是映射时,您可能希望使用已解析的词汇表,您可以通过以下方式访问:

parsed_vocabulary = vectorizer.vocabulary_
joblib.dump(parsed_vocabulary, modelpath.joinpath('vocabulary.pickle'))

然后加载它并用于重新创建CountVectorizer:

vectorizer = CountVectorizer(
    vocabulary=parsed_vocabulary,
    binary=True,
    dtype=numpy.int8
)

注意,这里不需要使用joblib;标准泡菜应该具有相同的性能;使用任何可用的替代方案,您可能会获得更好的结果,其中 PyTables 值得一提。

如果这也占用了大量内存,您应该尝试使用原始词汇表来重新创建矢量化器;目前,当提供一组字符串作为词汇表时,矢量化器只是将集合转换为排序列表,因此您不需要担心再现性(尽管在生产中使用之前我会仔细检查)。或者您可以自行将集合转换为列表。

综上所述:因为您没有 fit() Vectorizer,所以使用 CountVectorizer 的全部附加值(value)在于它的 transform()方法;由于所需的全部数据是词汇表(和参数),因此您可以减少仅对词汇表进行腌制的内存消耗,无论是否已处理。

当您要求从官方来源获取答案时,我想向您指出:https://github.com/scikit-learn/scikit-learn/issues/3844其中 scikit-learn 的所有者和贡献者提到重新创建一个 CountVectorizer,尽管是为了其他目的。您可能会更幸运地在链接的存储库中报告您的问题,但请确保包含导致过多内存使用问题的数据集,以使其可重现。

最后,您可以使用前面评论中提到的HashingVectorizer

PS:关于 gc.collect() 的使用 - 在这种情况下我会尝试一下;关于技术细节,您会发现很多关于解决此问题的问题。

关于python-3.x - joblib 转储时出现内存错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49497864/

相关文章:

python-3.x - BERT文件嵌入

python - Scikit-learn分类测试,ValueError : setting an array element with a sequence

Php laravel内存限制错误

python - 使用机器学习进行简单的机器人控制

java - StringBuilder.append() 中的 OutOfMemoryError 即使有足够的内存

c# - .Net 处理非托管内存的方式是否不同于 C++ 运行时/二进制可执行文件?

python - 如何在Python中并排打印两个计数器?

python - 替换在 Python 3 中不起作用的字节

python - 如何使用 Python 3 查找/替换不可打印/非 ASCII 字符?

python - 参数 num_class 的 xgboost sklearn 包装器值 0 应大于等于 1