Я использую pytorch не для сети, а только для вычисления матрицы расстояний на GPU.Когда я просто использую один графический процессор, все идет отлично;но когда дело доходит до нескольких графических процессоров, возникает ошибка.
Во-первых, я получил RuntimeError: CUDA error: initialization error
, и погуглил эту ошибку и нашел решение: добавьте mp.set_start_method('spawn')
.Но произошла новая ошибка, на этот раз ошибка была ValueError: bad value(s) in fds_to_keep
, и я не нашел способа ее исправить.
Теперь я запутался и не знаю, как ее решить.
Я использую Ubuntu 16.04, Python 3.6.8 и pytorch 1.0.0.
Если нет mp.set_start_method('spawn')
, общий объем трассировки:
Traceback (most recent call last):
File "/home/mc/anaconda3/envs/Lab/lib/python3.6/multiprocessing/process.py", line 258, in _bootstrap
self.run()
File "/home/mc/anaconda3/envs/Lab/lib/python3.6/multiprocessing/process.py", line 93, in run
self._target(*self._args, **self._kwargs)
File "/home/mc/nfs/Project/Polaris_Toolkit/src/density.py", line 288, in run_kernel
d_ts = gpr.pairwise_distance(data_i, data_j, device=device)
File "/home/mc/nfs/Project/Polaris_Toolkit/src/gpr.py", line 126, in pairwise_distance
data1, data2 = data1.cuda(device), data2.cuda(device)
RuntimeError: CUDA error: initialization error
Здесь device
является индексом графического процессора.
А для mp.set_start_method('spawn')
трассировка:
~/nfs/Project/Polaris_Toolkit/src/density.py in multi_gpu_density(trans_matrix, mmd, device, workers, threshold_coe, p, batch_size)
438 param = (data, indice, threshold, d, d_ma_row, d_ma_col, p)
439 pr = mp.Process(target=run_kernel, args=param)
--> 440 pr.start()
441 jobs.append(pr)
442 for job in jobs:
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/process.py in start(self)
103 'daemonic processes are not allowed to have children'
104 _cleanup()
--> 105 self._popen = self._Popen(self)
106 self._sentinel = self._popen.sentinel
107 # Avoid a refcycle if the target function holds an indirect
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/context.py in _Popen(process_obj)
221 @staticmethod
222 def _Popen(process_obj):
--> 223 return _default_context.get_context().Process._Popen(process_obj)
224
225 class DefaultContext(BaseContext):
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/context.py in _Popen(process_obj)
282 def _Popen(process_obj):
283 from .popen_spawn_posix import Popen
--> 284 return Popen(process_obj)
285
286 class ForkServerProcess(process.BaseProcess):
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/popen_spawn_posix.py in __init__(self, process_obj)
30 def __init__(self, process_obj):
31 self._fds = []
---> 32 super().__init__(process_obj)
33
34 def duplicate_for_child(self, fd):
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/popen_fork.py in __init__(self, process_obj)
17 util._flush_std_streams()
18 self.returncode = None
---> 19 self._launch(process_obj)
20
21 def duplicate_for_child(self, fd):
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/popen_spawn_posix.py in _launch(self, process_obj)
57 self._fds.extend([child_r, child_w])
58 self.pid = util.spawnv_passfds(spawn.get_executable(),
---> 59 cmd, self._fds)
60 self.sentinel = parent_r
61 with open(parent_w, 'wb', closefd=False) as f:
~/anaconda3/envs/Lab/lib/python3.6/multiprocessing/util.py in spawnv_passfds(path, args, passfds)
415 args, [os.fsencode(path)], True, passfds, None, None,
416 -1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
--> 417 False, False, None)
418 finally:
419 os.close(errpipe_read)
ValueError: bad value(s) in fds_to_keep
Теперь я знаю, что в контексте fork
cuda не должен быть инициализирован до multiprocessing
, но я не могу понять ошибку в spawn
.На самом деле я попытался найти ключевое слово fds_to_keep
в исходном коде multiprocessing
и torch.multiprocessing
, но в обоих исходных кодах нет fds_to_keep
.
Так что я хотел бы знатькак решить эту проблему и почему set_start_method('spawn')
не работает, что такое fds_to_keep
, где находится это ключевое слово.
update
Я обнаружил fds_to_keep
ошибку в _posixsubprocess.c
, и я посмотрел _sanity_check_python_fd_sequence
, я понял, iter_fd
может вызвать ошибку.Итак, я перешел к multiprocessing/util.py
, в функции spawnv_passfds
я печатаю переменную passfds
до и после сортировки.
оригинальный код:
# multiprocessing/util.py
def spawnv_passfds(path, args, passfds):
import _posixsubprocess
passfds = tuple(sorted(map(int, passfds)))
errpipe_read, errpipe_write = os.pipe()
try:
return _posixsubprocess.fork_exec(
args, [os.fsencode(path)], True, passfds, None, None,
-1, -1, -1, -1, -1, -1, errpipe_read, errpipe_write,
False, False, None)
finally:
os.close(errpipe_read)
os.close(errpipe_write)
изменение:
def spawnv_passfds(path, args, passfds):
print('before', passfds)
import _posixsubprocess
passfds = tuple(sorted(map(int, passfds)))
print('after', passfds)
errpipe_read, errpipe_write = os.pipe()
...
passfds
не изменилось, потому что это кортеж, который не может быть отсортирован.
Затем я изменил passfds = tuple(sorted(map(int, passfds)))
на passfds = tuple(sorted(map(int, list(passfds))))
, на этот раз результат passfds
равен:
before [77]
after (77,)
before [78, 76, 80, 79]
after (76, 78, 79, 80)
before [78, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 80, 79]
after (75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 78, 79, 80)
Очевидно, что в 3-м passfds
слишком много 75-х, поэтому должно появиться iter_fd <= prev_fd
и произойдет ошибка.
Итак, теперь мой вопрос:почему возникает этот феномен и почему при использовании fork
(если я не использую gpu до multiprocessing
), не будет ничего плохого?