【问题标题】:Scikit-learn out-of-core text classification memory consumptionScikit-learn 核外文本分类内存消耗
【发布时间】:2017-08-05 00:56:31
【问题描述】:

我正在尝试使用 scikit-learn 对大量文本文档进行分类,尽管我使用的是核心功能(SGDClassifierHashingVectorizer),但该程序似乎消耗了很多内存 (>10GB)。在此之前,我执行了词形还原并从文本数据中删除了停用词。我觉得我在这里错过了一些重要的东西。你能在我的代码中发现一个错误吗?

非常感谢您的任何建议!

这是我的python代码:

import time
import numpy as np
import os
import re
import pyprind
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.linear_model import SGDClassifier
from sklearn.naive_bayes import MultinomialNB
from sklearn import metrics

directory = "mydirectory"
batch_size = 1000
n_batches = 44
pbar = pyprind.ProgBar(n_batches)

class Doc_Iterable:
    def __init__(self, file):
        self.file = file
    def __iter__(self):
        for line in self.file:
            line = re.sub('[^\w\s]|(.\d{1,4}[\./]\d{1,2}[\./]\d{1,4})|(\s\d{1,})', '', line)
            yield line


def stream_docs(path, texts_file, labels_file):
    with open(path + texts_file, 'r') as fX, open(path + labels_file, 'r') as fy:
        for text in fX:
            label = next(fy)
            text = re.sub('[^\w\s]|(.\d{1,4}[\./]\d{1,2}[\./]\d{1,4})|(\s\d{1,})', '', text)
            yield text, label

def get_minibatch(doc_stream, size):
    X, y = [], []
    for _ in range(size):
        text, label = next(doc_stream)
        X.append(text)
        y.append(label)
    return X, y


classes = set()
for label in open(directory + 'y_train', 'r'):
    classes.add(label)
for label in open(directory + 'y_test', 'r'):
    classes.add(label)
classes = list(classes)

validation_scores = []
training_set_size = []

h_vectorizer = HashingVectorizer(lowercase=True, ngram_range=(1,1))
clf = SGDClassifier(loss='hinge', n_iter=5, alpha=1e-4, shuffle=True)

doc_stream = stream_docs(path=directory, texts_file='X_train', labels_file='y_train')
n_samples = 0
iteration = 0

for _ in range(n_batches):
    print("Training with batch nr.", iteration)
    iteration += 1

    X_train, y_train = get_minibatch(doc_stream, size=batch_size)

    n_samples += len(X_train)

    X_train = h_vectorizer.transform(X_train)

    clf.partial_fit(X_train, y_train, classes=classes)

    pbar.update()


del X_train
del y_train
print("Training complete. Classifier trained with " + str(n_samples) + " samples.")
print()
print("Testing...")
print()
X_test = h_vectorizer.transform(Doc_Iterable(open(directory + 'X_test')))
y_test = np.genfromtxt(directory + 'y_test', dtype=None, delimiter='|').astype(str)
prediction = clf.predict(X_test)
score = metrics.accuracy_score(y_test, prediction)
print("Accuracy: ", score)
print()

【问题讨论】:

  • 您的数据集的总大小是多少:44000 个文档?您是否尝试过将 HashingVectorizer 应用于完整数据集?根据我的经验,从 700000 封文本电子邮件中提取特征而不使用核心方法需要不到 16GB 的 RAM,所以你的数字非常大。除非文件很长。减少特征的数量无论如何都不会显着改变它,因为它是稀疏数组,几乎没有哈希冲突(我不同意下面的回复)。
  • 谢谢。我有 300 万份文档,我可能需要在预处理方面做更多工作以减少特征数量/词汇量。使用 Tf-idf 似乎可以很好地处理最多 1GB 的文本文件的子集作为输入。我也将尝试使用HashingVectorizer 而不进行核外学习...
  • 300 万个文档相当大。您应该使用memory_profiler 进行逐行分析,以了解内存分配(或未释放)的位置。如果是脚本,用python -m memory_profiler 运行就足够了……

标签: python scikit-learn text-classification


【解决方案1】:

尝试在HashingVectorizer中调整n_features,例如:

h_vectorizer = HashingVectorizer(n_features=10000, lowercase=True, ngram_range=(1,1))

使用默认参数 (n_features=1048576),您可以期望转换后的矩阵具有:

1048576(features) x 1000(mini batch size) x 8 bytes = 8.4 GB

由于稀疏性会小于这个值,但是分类器的系数会加起来:

1048576(features) x len(classes) * 8 bytes

这样可以解释您当前的内存使用情况。

【讨论】:

  • 谢谢!我认为功能的数量确实是我的问题,我必须通过某种预处理来限制它。如果实际数量超过n_features,HashingVectorizer如何选择特征?
  • 如果功能多于n_features,那么您将发生冲突,并且两个功能可能会合并为一个。但这在实践中并没有那么糟糕,因为大多数单词从未被使用过(齐夫定律)。您可以通过使用不同的n_features 测量您的 CV 分数并与 tf-idf 进行比较来确保是这种情况。您可以查看here 了解哈希技巧的工作原理,以便获得更好的图片。
  • 是的,here 是关于减小散列表大小如何降低文本分类准确性的一些更实用的基准。我猜对于 1e4-1e5 功能,应该几乎没有影响..
【解决方案2】:

这可能不是一个答案(抱歉,由于声誉问题我无法发表评论),但我从事图像分类项目。

根据我的经验,使用 scikit-learn 进行训练非常慢(在我的例子中,我使用了大约 30 张图像,训练分类器花了我将近 2-6 分钟)。当我切换到 OpenCV-python 时,我只需要大约一分钟或更短的时间来训练相同的分类器,同时使用相同数量的训练数据。

【讨论】:

  • 这里的问题完全不同,因为文本文档被向量化为稀疏数组,这与密集数组表示的图像不同(OpenCV 可能确实更优化)。
猜你喜欢
  • 2018-07-03
  • 2018-02-11
  • 2014-12-31
  • 2016-05-16
  • 2012-09-18
  • 2013-07-21
  • 2014-06-28
  • 1970-01-01
  • 2016-04-24
相关资源
最近更新 更多