拟合 Sklearn 模型时出现“设备上没有剩余空间”错误

Posted

技术标签:

【中文标题】拟合 Sklearn 模型时出现“设备上没有剩余空间”错误【英文标题】:"No space left on device" error while fitting Sklearn model 【发布时间】:2017-02-28 03:05:27 【问题描述】:

我正在使用 scikit-learn 拟合包含大量数据的 LDA 模型。相关代码如下:

lda = LatentDirichletAllocation(n_topics = n_topics, 
                                max_iter = iters,
                                learning_method = 'online',
                                learning_offset = offset,
                                random_state = 0,
                                evaluate_every = 5,
                                n_jobs = 3,
                                verbose = 0)
lda.fit(X)

(我想这里唯一可能相关的细节是我正在使用多个作业。)

一段时间后,我收到“设备上没有剩余空间”错误,即使磁盘上有足够的空间和大量可用内存。我在两台不同的计算机上(在我的本地计算机和远程服务器上)尝试了多次相同的代码,首先使用 python3,然后使用 python2,每次都以同样的错误结束。

如果我在较小的数据样本上运行相同的代码,一切正常。

整个堆栈跟踪:

Failed to save <type 'numpy.ndarray'> to .npy file:
Traceback (most recent call last):
  File "/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/numpy_pickle.py", line 271, in save
    obj, filename = self._write_array(obj, filename)
  File "/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/numpy_pickle.py", line 231, in _write_array
    self.np.save(filename, array)
  File "/home/ubuntu/anaconda2/lib/python2.7/site-packages/numpy/lib/npyio.py", line 491, in save
    pickle_kwargs=pickle_kwargs)
  File "/home/ubuntu/anaconda2/lib/python2.7/site-packages/numpy/lib/format.py", line 584, in write_array
    array.tofile(fp)
IOError: 275500 requested and 210934 written


IOErrorTraceback (most recent call last)
<ipython-input-7-6af7e7c9845f> in <module>()
      7                                 n_jobs = 3,
      8                                 verbose = 0)
----> 9 lda.fit(X)

/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/decomposition/online_lda.pyc in fit(self, X, y)
    509                     for idx_slice in gen_batches(n_samples, batch_size):
    510                         self._em_step(X[idx_slice, :], total_samples=n_samples,
--> 511                                       batch_update=False, parallel=parallel)
    512                 else:
    513                     # batch update

/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/decomposition/online_lda.pyc in _em_step(self, X, total_samples, batch_update, parallel)
    403         # E-step
    404         _, suff_stats = self._e_step(X, cal_sstats=True, random_init=True,
--> 405                                      parallel=parallel)
    406 
    407         # M-step

/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/decomposition/online_lda.pyc in _e_step(self, X, cal_sstats, random_init, parallel)
    356                                               self.mean_change_tol, cal_sstats,
    357                                               random_state)
--> 358             for idx_slice in gen_even_slices(X.shape[0], n_jobs))
    359 
    360         # merge result

/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.pyc in __call__(self, iterable)
    808                 # consumption.
    809                 self._iterating = False
--> 810             self.retrieve()
    811             # Make sure that we get a last message telling us we are done
    812             elapsed_time = time.time() - self._start_time

/home/ubuntu/anaconda2/lib/python2.7/site-packages/sklearn/externals/joblib/parallel.pyc in retrieve(self)
    725                 job = self._jobs.pop(0)
    726             try:
--> 727                 self._output.extend(job.get())
    728             except tuple(self.exceptions) as exception:
    729                 # Stop dispatching any new job in the async callback thread

/home/ubuntu/anaconda2/lib/python2.7/multiprocessing/pool.pyc in get(self, timeout)
    565             return self._value
    566         else:
--> 567             raise self._value
    568 
    569     def _set(self, i, obj):

IOError: [Errno 28] No space left on device

【问题讨论】:

它可能会在没有多处理的情况下工作 (n_jobs=1)。我不确定,scikit-learn 将哪个路径用于某些临时数据。你的 tmp 分区有多大? 谢谢@sascha,我将只尝试一个进程。如果tmpfs 是 tmp 分区(我认为是?)那么它是 1.6GB。这可能是问题吗?如果是这样,是否有任何解决方法? 【参考方案1】:

@silterser 的解决方案为我解决了问题。

如果您想在代码中设置环境变量,请执行以下操作:

import os
os.environ['JOBLIB_TEMP_FOLDER'] = '/tmp'

【讨论】:

【参考方案2】:

我知道有点晚了,但我通过设置learning_method = 'batch' 解决了这个问题。

这可能会带来其他问题,例如延长训练时间,但它缓解了共享内存空间不足的问题。

或者可以设置一个更小的batch_size。虽然我自己没有测试过。

【讨论】:

【参考方案3】:

当共享内存被消耗并且不允许任何 I/O 操作时会出现此问题。这是大多数 Kaggle 用户在拟合机器学习模型时遇到的令人沮丧的问题。

我通过使用以下代码设置 JOBLIB_TEMP_FOLDER 变量克服了这个问题。

%env JOBLIB_TEMP_FOLDER=/tmp

【讨论】:

【参考方案4】:

这是因为您设置了 n_jobs=3。您可以将其设置为 1,则不会使用共享内存,即使学习需要更长的时间。您可以根据上述答案选择一个 joblib 缓存目录,但请记住,此缓存也可以快速填满您的磁盘,具体取决于数据集?并且磁盘事务会减慢您的工作速度。

【讨论】:

【参考方案5】:

LatentDirichletAllocation 也有同样的问题。看来,您的共享内存已用完(运行df -h 时的/dev/shm)。尝试将JOBLIB_TEMP_FOLDER 环境变量设置为不同的值:例如,设置为/tmp。就我而言,它已经解决了问题。

或者只是增加共享内存的大小,如果您对正在训练 LDA 的机器拥有适当的权限。

【讨论】:

这对我有用。在 docker 容器中使用 iPython,尝试验证模型,例如:best_knn_clf = KNeighborsClassifier(weights='distance', n_neighbors=4, n_jobs=-1) scores = cross_val_score(best_knn_clf, X_train_expanded, y_train_expanded, cv=3, n_jobs=-1, verbose=3)。在笔记本中添加 %env JOBLIB_TEMP_FOLDER=/tmp 就可以了。

以上是关于拟合 Sklearn 模型时出现“设备上没有剩余空间”错误的主要内容,如果未能解决你的问题,请参考以下文章

将 sklearn 的 BaggingClassifier 与 GridSearchCV 一起使用时出现 ZeroDivisionError

重新加载腌制的 sklearn 管道时出现问题。未导入计数向量分析器功能

sklearn - 模型一直过拟合

拟合 sklearn GridSearchCV 模型

Python中浮点错误的无效文字

Python Sklearn 逻辑回归模型拟合不正确