16

I am running Python 2.7 (64-bit) on a Windows 8 64-bit system with 24GB memory. When doing the fitting of the usual Sklearn.linear_models.Ridge, the code runs fine.

Problem: However when using Sklearn.linear_models.RidgeCV(alphas=alphas) for the fitting, I run into the MemoryError error shown below on the line rr.fit(X_train, y_train) that executes the fitting procedure.

How can I prevent this error?

Code snippet

def fit(X_train, y_train):
    alphas = [1e-3, 1e-2, 1e-1, 1e0, 1e1]

    rr = RidgeCV(alphas=alphas)
    rr.fit(X_train, y_train)

    return rr


rr = fit(X_train, y_train)

Error

MemoryError                               Traceback (most recent call last)
<ipython-input-41-a433716e7179> in <module>()
      1 # Fit Training set
----> 2 rr = fit(X_train, y_train)

<ipython-input-35-9650bd58e76c> in fit(X_train, y_train)
      3 
      4     rr = RidgeCV(alphas=alphas)
----> 5     rr.fit(X_train, y_train)
      6 
      7     return rr

C:\Python27\lib\site-packages\sklearn\linear_model\ridge.pyc in fit(self, X, y, sample_weight)
    696                                   gcv_mode=self.gcv_mode,
    697                                   store_cv_values=self.store_cv_values)
--> 698             estimator.fit(X, y, sample_weight=sample_weight)
    699             self.alpha_ = estimator.alpha_
    700             if self.store_cv_values:

C:\Python27\lib\site-packages\sklearn\linear_model\ridge.pyc in fit(self, X, y, sample_weight)
    608             raise ValueError('bad gcv_mode "%s"' % gcv_mode)
    609 
--> 610         v, Q, QT_y = _pre_compute(X, y)
    611         n_y = 1 if len(y.shape) == 1 else y.shape[1]
    612         cv_values = np.zeros((n_samples * n_y, len(self.alphas)))

C:\Python27\lib\site-packages\sklearn\linear_model\ridge.pyc in _pre_compute_svd(self, X, y)
    531     def _pre_compute_svd(self, X, y):
    532         if sparse.issparse(X) and hasattr(X, 'toarray'):
--> 533             X = X.toarray()
    534         U, s, _ = np.linalg.svd(X, full_matrices=0)
    535         v = s ** 2

C:\Python27\lib\site-packages\scipy\sparse\compressed.pyc in toarray(self, order, out)
    559     def toarray(self, order=None, out=None):
    560         """See the docstring for `spmatrix.toarray`."""
--> 561         return self.tocoo(copy=False).toarray(order=order, out=out)
    562 
    563     ##############################################################

C:\Python27\lib\site-packages\scipy\sparse\coo.pyc in toarray(self, order, out)
    236     def toarray(self, order=None, out=None):
    237         """See the docstring for `spmatrix.toarray`."""
--> 238         B = self._process_toarray_args(order, out)
    239         fortran = int(B.flags.f_contiguous)
    240         if not fortran and not B.flags.c_contiguous:

C:\Python27\lib\site-packages\scipy\sparse\base.pyc in _process_toarray_args(self, order, out)
    633             return out
    634         else:
--> 635             return np.zeros(self.shape, dtype=self.dtype, order=order)
    636 
    637 

MemoryError: 

Code

print type(X_train)
print X_train.shape

Result

<class 'scipy.sparse.csr.csr_matrix'>
(183576, 101507)
4

2 回答 2

19

查看堆栈跟踪的这一部分:

    531     def _pre_compute_svd(self, X, y):
    532         if sparse.issparse(X) and hasattr(X, 'toarray'):
--> 533             X = X.toarray()
    534         U, s, _ = np.linalg.svd(X, full_matrices=0)
    535         v = s ** 2

您使用的算法依赖于 numpy 的线性代数例程来执行 SVD。但是那些不能处理稀疏矩阵,所以作者简单地将它们转换为常规的非稀疏数组。为此必须发生的第一件事是分配一个全零数组,然后用稀疏存储在稀疏矩阵中的值填充适当的位置。听起来很容易,但让我们算一下。一个 float64(默认 dtype,如果您不知道自己在使用什么,您可能会使用它)元素占用 8 个字节。因此,根据您提供的数组形状,新的零填充数组将是:

183576 * 101507 * 8 = 149,073,992,256 ~= 150 gigabytes

您系统的内存管理器可能看了一眼该分配请求并自杀了。但是你能做些什么呢?

首先,这看起来是相当荒谬的功能数量。我对您的问题领域或您的功能一无所知,但我的直觉反应是您需要在这里进行一些降维。

其次,您可以尝试修复算法对稀疏矩阵的错误处理。它在这里窒息numpy.linalg.svd,所以你可以用它scipy.sparse.linalg.svds来代替。我不知道有问题的算法,但它可能不适用于稀疏矩阵。即使您使用适当的稀疏线性代数例程,它也可能会生成(或在内部使用)一些大小与您的数据相似的非稀疏矩阵。使用稀疏矩阵表示来表示非稀疏数据只会导致使用比原来更多的空间,因此这种方法可能不起作用。谨慎行事。

于 2013-05-03T03:51:45.987 回答
6

这里的相关选项是 gcv_mode。它可以取 3 个值:“auto”、“svd”和“eigen”。默认情况下,它设置为“auto”,具有以下行为:如果 n_samples > n_features 使用 svd 模式,否则使用 eigen 模式。

由于在您的情况下 n_samples > n_features,因此选择了 svd 模式。但是,svd 模式目前不能正确处理稀疏数据。scikit-learn 应该被修复为使用适当的稀疏 SVD 而不是密集 SVD。

作为一种解决方法,我会通过 gcv_mode="eigen" 强制使用特征模式,因为这种模式应该正确处理稀疏数据。但是,在您的情况下, n_samples 非常大。由于本征模式构建了一个内核矩阵(因此具有 n_samples ** 2 内存复杂度),内核矩阵可能不适合内存。在这种情况下,我只会减少样本的数量(尽管本征模式可以毫无问题地处理大量特征)。

在任何情况下,由于 n_samples 和 n_features 都非常大,因此您正在将此实现推向其极限(即使使用适当的稀疏 SVD)。

另见https://github.com/scikit-learn/scikit-learn/issues/1921

于 2013-05-03T10:07:19.080 回答