Обучение 4 моделей параллельно с 2 ядрами каждое медленнее, чем обучение моделей sklearn итеративно с 8 ядрами

#python #scikit-learn #multiprocessing #joblib

Вопрос:

Допустим, у меня есть простой способ обучить модель с N ядрами:

 def train(cores = 1):
    reg = RandomForestRegressor(n_jobs=cores).fit(X, y)
    return reg
 

и простой набор данных:

 X = np.random.random(size=[25_000, 10])
y = np.sum(X, axis = 1)
 

Обучение на 2 ядрах занимает 7,6 секунды, а на 8 ядрах-3,4 секунды. Поэтому, как и ожидалось, когда я тренирую модель 4 раза с 8 ядрами, это занимает 13,6 секунды:

 models = []
for i in range(4):
    models.append(train(8))
 

Однако, когда я пытаюсь обучить их одновременно с помощью ProcessPoolExecutor, это занимает 14,2 секунды (из которых 0,2 секунды-время отправки задания).:

 start = time()
models = []
with ProcessPoolExecutor(max_workers=4) as executor:
    for i in range(4):
        models.append(executor.submit(train, 2))
    print("Submission Time:", time() - start)
print(time() - start)
 

Я понимаю, что есть накладные расходы, и я потенциально мог бы попробовать использовать joblib или какой-либо другой способ распараллеливания моделей. Однако я ожидаю, что если на 2 ядра потребуется 7,6 секунды, то обучение 4 на 4 рабочих (на машине с 8 ядрами) займет менее 10 секунд, а не 14 секунд.

Действительно ли замедление связано с накладными расходами на обработку? Или есть какая-то избыточная подписка, которую я не замечаю? Или, возможно, возможно, что модели пытаются использовать одни и те же ядра (я использовал htop, и, похоже, все ядра максимальны). Я не совсем уверен, что здесь происходит и как это исправить или лучше обучать модели параллельно. Цель состоит в том, чтобы тренироваться на машинах с более чем 100 ядрами и более чем 100 моделями параллельно, это не будет работать при замедлениях такого масштаба.

Примечание Я также попробовал joblib, который также занял 14 секунд:

 start = time()
result = Parallel(n_jobs=4)(delayed(train)(2) for _ in range(4))
print(time() - start)
 

РЕДАКТИРОВАТЬ Вот еще один полный сценарий на этот раз 16 моделей либо по 1 модели на ядро, либо по 8 ядер на модель последовательно:

 import numpy as np
from time import time, sleep
from sklearn.ensemble import RandomForestRegressor
from concurrent.futures import ProcessPoolExecutor

X = np.random.random(size=[25_000, 10])
y = np.sum(X, axis=1)


def train(cores=1):
    reg = RandomForestRegressor(n_jobs=cores).fit(X, y)
    return reg


start = time()
models = []
with ProcessPoolExecutor(max_workers=8) as executor:
    for i in range(16):
        models.append(executor.submit(train, 1))
    print("Submission Time:", time() - start)
print(time() - start)

start = time()
models = []
for i in range(16):
    models.append(train(8))
print(time() - start)
 

Дальнейшее РЕДАКТИРОВАНИЕ:

Я также попробовал бэкэнд loky joblib:

 from joblib import parallel_backend, Parallel, delayed

start = time()
with parallel_backend("loky", n_jobs=4):
    Parallel()(delayed(train)(2, X.copy(), y.copy()) for _ in range(8))
print("joblib loky 8 Models:", time() - start)
 

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

1. размер=[25000, 10] ?

2. Случайный набор данных, который я сгенерировал, имеет размер 25 000 строк и 10 столбцов.

3. И как вы запускаете код?

4. В настоящее время я запускаю его на ipython, не совсем понимаю, что вы имеете в виду. Я могу запустить его где угодно.

5. В том-то и дело. Несколько процессов Python не могут работать в интерактивном режиме.

Ответ №1:

Чтобы разделить работу, необходимо потратить некоторое время на настройку отдельных процессов python. Я удивлен, что параллельное наказание не выше. Если ваша работа займет всего 14 секунд, вы не увидите преимуществ неловких параллельных вычислений.

Другой момент заключается в том, что ваши ядра, вероятно, переподписаны. Мы замечаем, что инструменты sklearn часто называют библиотеки многопроцессорной обработкой. Когда вы используете joblib, эти требования противоречат друг другу.

Возможно, sklearn parallel_backend-правильный инструмент для вас. https://scikit-learn.org/stable/modules/generated/sklearn.utils.parallel_backend.html