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

25

我正在使用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
谢谢@sascha,我将只尝试一个进程。如果tmpfs是临时分区(我认为是吗?)那么它是1.6GB。这可能是问题吗?如果是,有没有解决方法? - machaerus
7个回答

36

使用LatentDirichletAllocation时也遇到了同样的问题。看起来你的共享内存(/dev/shm)不足,可以通过运行df -h来检查。尝试将JOBLIB_TEMP_FOLDER环境变量设置为其他路径,例如/tmp,这在我的情况下已经解决了该问题。

如果你有权限,则可以增加共享内存的大小,直接在训练LDA的机器上进行操作。


15
这对我很有用。在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就解决了问题。 - Kallin Nagelberg

10

当共享内存被消耗且没有I/O操作时,会出现此问题。这是一个令大多数Kaggle用户感到沮丧的问题,而在拟合机器学习模型时经常发生。

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

%env JOBLIB_TEMP_FOLDER=/tmp

3

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

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

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

1
自从joblib 1.3版本以后,你可以使用parallel_config来设置临时文件夹。
from joblib.parallel import parallel_config
with parallel_config(backend='threading', temp_folder='/tmp'):
   pass

0

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

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

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


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

0
我在Docker中运行时遇到了同样的问题。花了几个小时试图解决这个问题,结果发现缺少对NAS服务器的权限。
以下是你可以尝试的几件事情:
- 减小批处理大小 - 增加内存 - 检查对内存的访问权限
顺便说一下,如果你在Docker上运行,默认的共享内存空间是64MB,你需要在运行时指定空间。
将以下内容添加到你的docker run命令中:--shm-size=64g
例如:sudo docker run --gpus all --cpuset-cpus 0-63 --shm-size=64g -it YOUR_IMAGE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接