Почему я не могу использовать Pytorch для расчета расстояния нескольких мультивуд?(Ошибка инициализации по умолчанию и неправильные значения в fds_in_keep для порождения) - PullRequest
2 голосов
/ 14 мая 2019

Я использую 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), не будет ничего плохого?

...