Несколько вызовов Python из Bash, но без ускорения - PullRequest
0 голосов
/ 24 августа 2018

Я хочу запустить процесс Python3 несколько раз с разными гиперпараметрами. Чтобы полностью использовать доступные процессоры, я хочу запустить процесс несколько раз. Однако я практически не наблюдаю никакого ускорения на практике. Ниже я воспроизведу небольшой тест, иллюстрирующий эффект.

Сначала тестовый скрипт Python:

(speed_test.py)

import numpy as np
import time

now = time.time()
for i in range(50):
   np.matmul(np.random.rand(1000,1000),np.random.rand(1000,1000))
print(round(time.time()-now,1))

Один вызов : python3 speed_test.py отпечатки 10.0 секунд .

Однако, когда я пытаюсь запустить 2 процесса параллельно :

  • python3 speed_test.py & python3 speed_test.py & wait отпечатки 18.6 18.9.
  • parallel python3 speed_test.py ::: {1..2} отпечатков 18.3 18.7.

Кажется, что распараллеливание вряд ли что-то меня здесь покупает (два выполнения почти вдвое). Я знаю, что не могу ожидать линейного ускорения, но это, кажется, очень небольшая разница. Моя система имеет 1 сокет с 2 ядрами на сокет и 2 потоками на ядро ​​(всего 4 процессора). Я вижу тот же эффект на экземпляре Google Cloud с 8 процессорами. Примерно, вычислительное время улучшается не более чем на ~ 10-20% на процесс при параллельной работе.

Наконец, закрепление процессоров на процессах тоже мало помогает:

  • taskset -c 0-1 python3 speed_test.py & taskset -c 2-3 python3 speed_test.py & wait отпечатков 17.1 17.8

Я думал, что каждый процесс Python может использовать только 1 процессор из-за Глобальной блокировки интерпретатора. Есть ли способ ускорить мой код?

1 Ответ

0 голосов
/ 24 августа 2018

Спасибо за ответ @TomFenech, я должен был действительно добавить информацию об использовании процессора:

  • Локальный (4 ВЦП): один вызов = ~ 390%, двойной вызов ~ 190-200% каждый
  • Кластер Google (8 виртуальных ЦП): один вызов ~ 400%, двойной вызов ~ 400% каждый (как и ожидалось)

Вывод из игрушечного примера :Вы правы.Когда я звоню htop, я на самом деле вижу 4 процесса на запущенное задание, а не 1. Так что задание распределяется внутри себя.Я думаю это связано, распределение происходит для (матричного) умножения на BLAS / MKL.

Продолжение настоящей работы : Итак, вышеприведенный пример с игрушкой был на самом деле более сложным и не идеальным случаем для моего настоящего сценария.Мой настоящий (машинное обучение) сценарий только частично полагается на Numpy (не для умножения матриц), но большинство тяжелых вычислений выполняется в PyTorch.Когда я вызываю мой скрипт локально (4 vCPU), он использует ~ 220% CPU.Когда я вызываю этот сценарий в кластере Google Cloud (8 vCPU), он, что удивительно, достигает даже ~ 700% (htop действительно показывает 7-8 процессов).Таким образом, PyTorch, кажется, делает еще лучшую работу по распространению себя.(Версию Numpy BLAS можно получить с помощью np.__config__.show(). Мой локальный Numpy использует OpenBlas , кластер Google использует MKL (установка Conda). Я не могу найти аналогичную команду дляпроверьте версию PyTorch для BLAS, но предположите, что она использует то же самое.)

В общем, кажется, что как Numpy, так и сам PyTorch уже заботятся о распределении кода, когда дело доходит до умножения матриц (и все процессоры видны локально, то есть без настройки кластера / сервера).Поэтому, если большая часть вашего сценария является матричным умножением, то есть меньше причин, чем (по крайней мере, я), чтобы распространять сценарии самостоятельно.

Однако не весь мой код является матричным умножением.Следовательно, теоретически я все еще должен быть в состоянии ускорить параллельные процессы.Я написал новый тест с 50/50 кодом линейного и матричного умножения:

(speed_test2.py)

import time
import torch
import random

now = time.time()
for i in range(12000):
    [random.random() for k in range(10000)]

print('Linear time',round(time.time()-now,1))
now = time.time()

for j in range(350):
    torch.matmul(torch.rand(1000,1000),torch.rand(1000,1000))

print('Matrix time',round(time.time()-now,1))

Запуск этого в Google Cloud (8 vCPU):

  • Один процесс дает Линейное время 12,6, матричное время 9,2 .(ЦП во время первой части 100%, вторая часть 500%)
  • Параллельный процесс python3 speed_test2.py & python3 speed_test2.py дает Линейное время 12,6, Матричное время 15,4 для обоих процессов.
  • Добавление третьего процесса дает Линейное время ~ 12,7, Матричное время 25,2

Заключение : Хотя здесь имеется 8 vCPU,Pytorch / матричная (вторая) часть кода на самом деле становится медленнее с более чем 2 процессами.Линейная часть кода, конечно, увеличивается (до 8 параллельных процессов).Я думаю, что это в целом объясняет, почему на практике код Numpy / PyTorch может не показать такого большого улучшения, когда вы запускаете несколько параллельных процессов.И что не всегда полезно наивно запускать 8 процессов, когда вы видите 8 виртуальных ЦП.Пожалуйста, поправьте меня, если я ошибаюсь где-то здесь.

...