Ошибка «Не осталось места на устройстве» при подгонке модели Sklearn

#python #multithreading #scikit-learn #ioerror

#python #многопоточность #scikit-learn #ioerror

Вопрос:

Я устанавливаю модель LDA с большим количеством данных, используя scikit-learn. Соответствующий фрагмент кода выглядит следующим образом:

 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
  

Комментарии:

1. Вероятно, это будет работать без многопроцессорной обработки ( n_jobs=1 ). Я не уверен, какой путь scikit-learn использует для некоторых временных данных. Насколько велик ваш раздел tmp?

2. Спасибо @sascha, я попробую только с одним процессом. Если tmpfs это раздел tmp (я думаю, что это так?), То это 1,6 ГБ. Может ли это быть проблемой? Если да, есть ли какой-либо обходной путь для этого?

Ответ №1:

Была такая же проблема с LatentDirichletAllocation . Кажется, что у вас заканчивается общая память ( /dev/shm при запуске df -h ). Попробуйте установить JOBLIB_TEMP_FOLDER переменную среды на что-то другое: например, на /tmp . В моем случае это решило проблему.

Или просто увеличьте размер общей памяти, если у вас есть соответствующие права для машины, на которой вы обучаете LDA.

Комментарии:

1. У меня это сработало. Используя IPython в контейнере docker, пытаюсь проверить модель, подобную: 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 в notebook сделал свое дело.

Ответ №2:

Эта проблема возникает, когда используется общая память и операции ввода-вывода недопустимы. Это неприятная проблема, которая возникает у большинства пользователей Kaggle при установке моделей машинного обучения.

Я преодолел эту проблему, установив переменную JOBLIB_TEMP_FOLDER, используя следующий код.

 %env JOBLIB_TEMP_FOLDER=/tmp
  

Ответ №3:

Решение @silterser решило проблему для меня.

Если вы хотите установить переменную среды в коде, сделайте это:

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

Ответ №4:

Это потому, что вы установили n_jobs=3. Вы могли бы установить его равным 1, тогда общая память не будет использоваться, даже если обучение займет больше времени. Вы можете выбрать каталог кэша joblib в соответствии с приведенным выше ответом, но имейте в виду, что этот кеш также может быстро заполнить ваш диск, в зависимости от набора данных? и дисковые транзакции могут замедлить вашу работу.

Ответ №5:

Я знаю, что уже немного поздно, но я справился с этой проблемой, установив learning_method = 'batch' .

Это могло привести к другим проблемам, таким как увеличение времени обучения, но это решило проблему нехватки места в общей памяти.

Или, может быть, можно установить меньшее batch_size значение. Хотя я сам этого не тестировал.