Неожиданное поведение Pytorch после форка ⇐ Python
Неожиданное поведение Pytorch после форка
У меня есть приложение с PyTorch и Gunicorn. Сначала я создаю модели (модули факелов) в Gunicorn Master Worker, а затем Gunicorn разветвляет процесс, создает рабочих и обслуживает запросы. Все вычисления выполняются на ЦП.
Новая функция — параллельные вычисления для каждого запроса, поэтому я еще раз разветвляю рабочие процессы Gunicorn, чтобы добиться параллелизма на уровне рабочих процессов Gunciorn. Вот как я создаю новые процессы (поскольку я читаю, что метод fork используется по умолчанию при использовании .start()):
class Worker(multiprocessing.get_context('fork').Process): Он используется следующим образом:
Worker().start() Внутри нового процесса я получаю доступ к вычислительному конвейеру через глобальную переменную.
Как я читал в документации, после fork внутреннее состояние факела должно оставаться неизменным, если вы его не изменяете, из-за кэша страниц и природы fork (и это ).
Но. Иногда в среде докера происходит странное поведение: данные в state_dict неверны (отличаются от родительского процесса), в результате чего выходной вектор неверен. Например, ожидаемый вектор — это [0,0001, 0,3, 0,1], но я получаю: [112, 4, 43], разница видна невооруженным глазом. Это происходит только в среде докера и в очень редком случае, поэтому мне трудно это исправить. Возможно каждый 30 старт с этим багом. Мне не удалось создать минимальный пример кода с повторяющимися ошибками.
Что я пробовал:
[*]https://github.com/pytorch/pytorch/blob ... e.py#L2465 Вызов этого метода share_memory() в родительском процессе (главный рабочий) . [*]torch.multiprocessing.set_start_method('fork', Force=True) явно задает метод запуска. [*]multiprocessing.set_start_method('fork',force=True) явно задает метод запуска. [*]Увеличение общей памяти в докере: --shm-size=4G [*]torch.multiprocessing.set_sharing_strategy(new_strategy) попробовал обе стратегии file_system и file_descriptor (прежде чем я увеличил разрешенное количество открытых FD на процесс ).
Что я еще не пробовал
[*]Отправка адресов общего состояния через очередь дочерним процессам, как показано здесь https://pytorch.org/docs/stable/multiprocessing.html в разделе CUDA. (Поскольку я пока не использую графический процессор, я думаю, что fork будет достаточно) [*]Вызов метода Share_memory() в дочерних процессах.
torch.set_num_threads() — в моем приложении установлено значение 1.
Мне приходится использовать вилку ради экономии оперативной памяти. При таком поведении у меня не заканчивается оперативная память.
Имейте в виду, что все работало правильно, когда у меня только были рабочие Gunicorn, внутри Gunicorn они используют метод os.fork() для разветвления. Но я проверил, что Process.start() и os.fork() идентичны.
Я не изменяю/обновляю какие-либо данные после разветвления, поэтому невозможно, чтобы я испортил состояние факела.
Я прочитал много предупреждений, например: Если вы хотите, чтобы PyTorch работал правильно, просто не разветвляйте процессы. К сожалению, для меня это не вариант.
Я использую Ubuntu 20 в Docker и Python 3.9. Состояние Pytorch загружается из git lfs через load_state_dict().
Пожалуйста, если вы столкнулись с таким поведением, поделитесь со мной информацией.
У меня есть приложение с PyTorch и Gunicorn. Сначала я создаю модели (модули факелов) в Gunicorn Master Worker, а затем Gunicorn разветвляет процесс, создает рабочих и обслуживает запросы. Все вычисления выполняются на ЦП.
Новая функция — параллельные вычисления для каждого запроса, поэтому я еще раз разветвляю рабочие процессы Gunicorn, чтобы добиться параллелизма на уровне рабочих процессов Gunciorn. Вот как я создаю новые процессы (поскольку я читаю, что метод fork используется по умолчанию при использовании .start()):
class Worker(multiprocessing.get_context('fork').Process): Он используется следующим образом:
Worker().start() Внутри нового процесса я получаю доступ к вычислительному конвейеру через глобальную переменную.
Как я читал в документации, после fork внутреннее состояние факела должно оставаться неизменным, если вы его не изменяете, из-за кэша страниц и природы fork (и это ).
Но. Иногда в среде докера происходит странное поведение: данные в state_dict неверны (отличаются от родительского процесса), в результате чего выходной вектор неверен. Например, ожидаемый вектор — это [0,0001, 0,3, 0,1], но я получаю: [112, 4, 43], разница видна невооруженным глазом. Это происходит только в среде докера и в очень редком случае, поэтому мне трудно это исправить. Возможно каждый 30 старт с этим багом. Мне не удалось создать минимальный пример кода с повторяющимися ошибками.
Что я пробовал:
[*]https://github.com/pytorch/pytorch/blob ... e.py#L2465 Вызов этого метода share_memory() в родительском процессе (главный рабочий) . [*]torch.multiprocessing.set_start_method('fork', Force=True) явно задает метод запуска. [*]multiprocessing.set_start_method('fork',force=True) явно задает метод запуска. [*]Увеличение общей памяти в докере: --shm-size=4G [*]torch.multiprocessing.set_sharing_strategy(new_strategy) попробовал обе стратегии file_system и file_descriptor (прежде чем я увеличил разрешенное количество открытых FD на процесс ).
Что я еще не пробовал
[*]Отправка адресов общего состояния через очередь дочерним процессам, как показано здесь https://pytorch.org/docs/stable/multiprocessing.html в разделе CUDA. (Поскольку я пока не использую графический процессор, я думаю, что fork будет достаточно) [*]Вызов метода Share_memory() в дочерних процессах.
torch.set_num_threads() — в моем приложении установлено значение 1.
Мне приходится использовать вилку ради экономии оперативной памяти. При таком поведении у меня не заканчивается оперативная память.
Имейте в виду, что все работало правильно, когда у меня только были рабочие Gunicorn, внутри Gunicorn они используют метод os.fork() для разветвления. Но я проверил, что Process.start() и os.fork() идентичны.
Я не изменяю/обновляю какие-либо данные после разветвления, поэтому невозможно, чтобы я испортил состояние факела.
Я прочитал много предупреждений, например: Если вы хотите, чтобы PyTorch работал правильно, просто не разветвляйте процессы. К сожалению, для меня это не вариант.
Я использую Ubuntu 20 в Docker и Python 3.9. Состояние Pytorch загружается из git lfs через load_state_dict().
Пожалуйста, если вы столкнулись с таким поведением, поделитесь со мной информацией.
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение