即使使用稀疏矩阵,scikit也出现MemoryError

0 投票
1 回答
2442 浏览
提问于 2025-04-18 16:20

我正在运行(或者说试图运行)一个脚本来对文档进行分类。出错的代码是:

X = df['text'].values
Y = np.asarray(df['label'], dtype=np.dtype(int))

text_clf = Pipeline([('vect', HashingVectorizer(ngram_range=(1,3), preprocessor=neg_preprocess, n_features=10000000)),
                     ('tfidf', TfidfTransformer()),
                     ('clf', SGDClassifier(loss='log', n_jobs=-1, penalty='elasticnet'))])

text_clf.fit(X, Y)

为了了解 HashingVectorizer 产生了什么:

<375175x10000000 sparse matrix of type '<type 'numpy.float64'>'
    with 56324335 stored elements in Compressed Sparse Row format>

完整的错误信息和追踪记录是:

---------------------------------------------------------------------------
MemoryError                               Traceback (most recent call last)
<ipython-input-15-09ad11dfb82b> in <module>()
  7                      ('clf', SGDClassifier(loss='log', n_jobs=-1, penalty='elasticnet'))])
  8 
----> 9 text_clf.fit(X, Y)
 10 
 11 print datetime.now()-startTime

D:\Users\DB\Anaconda\lib\site-packages\sklearn\pipeline.pyc in fit(self, X, y, **fit_params)
129         """
130         Xt, fit_params = self._pre_transform(X, y, **fit_params)
--> 131         self.steps[-1][-1].fit(Xt, y, **fit_params)
132         return self
133 

D:\Users\DB\Anaconda\lib\site-packages\sklearn\linear_model\stochastic_gradient.pyc in fit(self, X, y, coef_init, intercept_init, class_weight, sample_weight)
517                          coef_init=coef_init, intercept_init=intercept_init,
518                          class_weight=class_weight,
--> 519                          sample_weight=sample_weight)
520 
521 

D:\Users\DB\Anaconda\lib\site-packages\sklearn\linear_model\stochastic_gradient.pyc in _fit(self, X, y, alpha, C, loss, learning_rate, coef_init, intercept_init, class_weight, sample_weight)
416 
417         self._partial_fit(X, y, alpha, C, loss, learning_rate, self.n_iter,
--> 418                           classes, sample_weight, coef_init, intercept_init)
419 
420         # fitting is over, we can now transform coef_ to fortran order

D:\Users\DB\Anaconda\lib\site-packages\sklearn\linear_model\stochastic_gradient.pyc in _partial_fit(self, X, y, alpha, C, loss, learning_rate, n_iter, classes, sample_weight, coef_init, intercept_init)
359         if self.coef_ is None or coef_init is not None:
360             self._allocate_parameter_mem(n_classes, n_features,
--> 361                                          coef_init, intercept_init)
362 
363         self.loss_function = self._get_loss_function(loss)

D:\Users\DB\Anaconda\lib\site-packages\sklearn\linear_model\stochastic_gradient.pyc in _allocate_parameter_mem(self, n_classes, n_features, coef_init, intercept_init)
187             else:
188                 self.coef_ = np.zeros((n_classes, n_features),
--> 189                                       dtype=np.float64, order="C")
190 
191             # allocate intercept_ for multi-class

MemoryError: 

整个训练集的特征向量大小相当大,但每个文档都很短(大约 200 个词),特征集也很小。我想稀疏矩阵应该能处理这些数据,但也许我完全错了?我监控了我电脑的资源使用情况,当出错时还有很多内存剩余。

代码中有没有什么地方导致了这个错误?我觉得可能是 TfidfTransformer() 引起的,因为它会导致状态保持,但我把它从流程中去掉后,还是出现了同样的错误。如果是特征向量大小的问题,肯定有办法处理大量数据……

我使用的是 ipython notebook 和 python 2.7.6 的 Anaconda 版本。如果需要更多信息来帮助解决问题,请告诉我。

提前谢谢你。

1 个回答

4

我觉得问题不在于向量化器,因为错误信息显示它在以下这行代码出错:

self.coef_ = np.zeros((n_classes, n_features), dtype=np.float64, order="C")

这行代码分配了一个稠密的numpy数组,这会占用很多内存。它的形状是(n_classes, n_features),而n_features就是你传给向量化器的那个参数,10M!你在数据集中有多少个类别呢?

一个简单的解决办法是减少n_features的值。或者,你可以尝试其他分类器,这些分类器不会把输入转换成稠密数组。不过我不太清楚sklearn中哪些分类器是这样做的。


附注 这个问题展示了如何确定一个矩阵在内存中实际占用的大小。你可以验证一下,问题不是出在向量化器或tfidf转换器上。

撰写回答