我正在尝试使用 sklearn 0.11 的 LogisticRegression 对象来拟合具有大约 80,000 个特征的 200,000 个观测值的模型。目标是将短文本描述分类为 800 个类中的 1 个。
当我尝试拟合分类器 pythonw 时.exe给了我:
应用程序错误"指令在...引用内存在0x00000000"。内存无法写入"。
这些功能非常稀疏,每个观察大约 10 个,并且是二进制的(1 或 0),所以根据我的信封计算,我的 4 GB RAM 应该能够处理内存要求,但事实似乎并非如此。仅当我使用较少的观测值和/或较少的特征时,模型才适合。
如果有的话,我想使用更多的观察和功能。我天真的理解是,在幕后运行事物的 liblinear 库能够支持这一点。关于我如何挤出更多观察结果的任何想法?
我的代码如下所示:
y_vectorizer = LabelVectorizer(y) # my custom vectorizer for labels
y = y_vectorizer.fit_transform(y)
x_vectorizer = CountVectorizer(binary = True, analyzer = features)
x = x_vectorizer.fit_transform(x)
clf = LogisticRegression()
clf.fit(x, y)
我传递给分析器的 features() 函数只返回一个字符串列表,指示在每个观察中检测到的特征。
我使用的是Python 2.7,sklearn 0.11,Windows XP和4 GB RAM。
liblinear(sklearn.linear_model.LogisticRegression
的后备实现)将托管自己的数据副本,因为它是一个C++库,其内部存储器布局不能直接映射到Sipy中预先分配的稀疏矩阵上,例如scipy.sparse.csr_matrix
或scipy.sparse.csc_matrix
。
在您的情况下,我建议您将数据作为scipy.sparse.csr_matrix
加载并将其提供给sklearn.linear_model.SGDClassifier
(如果您想要逻辑回归模型和调用 predict_proba
方法的能力,请使用loss='log'
)。 如果输入数据已在使用scipy.sparse.csr_matrix
内存布局,则SGDClassifier
不会复制输入数据。
期望它在内存中分配 800 * (80000 + 1) * 8/(1024 ** 2) = 488MB 的密集模型(除了输入数据集的大小)。
编辑:如何优化数据集的内存访问
要在提取数据集后释放内存,您可以:
x_vectorizer = CountVectorizer(binary = True, analyzer = features)
x = x_vectorizer.fit_transform(x)
from sklearn.externals import joblib
joblib.dump(x.tocsr(), 'dataset.joblib')
然后退出这个 python 进程(强制完全释放内存)并在一个新进程中:
x_csr = joblib.load('dataset.joblib')
在 linux/OSX 下,您可以通过以下方式更有效地进行内存映射:
x_csr = joblib.load('dataset.joblib', mmap_mode='c')