Nano Hash - криптовалюты, майнинг, программирование

Почему мой парализованный цикл for работает намного медленнее?

Я попытался распараллелить цикл for в Python с помощью пакета multiprocessing. Функция, которую я хочу запустить в нескольких потоках, - это

def regression_loss(W, k, x, y):
    U = expit(x.dot(W[k].T)) - y
    return np.sum(U*U)

который вычисляет ошибку задачи регрессии с несколькими классами для нескольких точек данных x. W — весовая матрица, а y — цель.

В настоящее время парализованный цикл for примерно в 200 раз медленнее. Я хотел бы знать, почему и что я могу сделать, чтобы сделать параллельный цикл for намного быстрее, чем цикл for seriell.

Вот мой код, где я сравниваю стандартный цикл for и распараллеленный с использованием модуля многопроцессорности.

import time
import numpy as np
import multiprocessing as mp
from scipy.special import expit

def regression_loss(W, k, x, y):
    U = expit(x.dot(W[k].T)) - y
    return np.sum(U*U)

def optimizer_seriell(p_size, n_classes, n_input, batch_size, W):
    loss = np.zeros((p_size))
    x, y = np.random.rand(batch_size, n_input), np.random.rand(batch_size, n_classes) 
    for k in range(p_size):
        loss[k] = regression_loss(W, k, x, y)

def optimizer_parallel(p_size, n_classes, n_input, batch_size, W):
    pool = mp.Pool(processes = 4)
    x, y = np.random.rand(batch_size, n_input), np.random.rand(batch_size, n_classes) 
    loss = [pool.apply(regression_loss, args=(W, k, x, y)) for k in range(p_size)]

if __name__ == "__main__":
    p_size = 32
    n_classes = 10
    n_input = 1000
    batch_size = 8
    W = [np.random.rand(n_classes, n_input) for k in range(p_size)]

    t0 = time.time()
    optimizer_seriell(p_size, n_classes, n_input, batch_size, W)
    print(time.time()-t0) # 0.00186 on my machine

    t0 = time.time()
    optimizer_parallel(p_size, n_classes, n_input, batch_size, W)
    print(time.time()-t0) # 0.20029 on my machine

  • apply блокирует. Используйте apply_async. 07.11.2019
  • @AlexR apply_async все еще заказан? 07.11.2019
  • Что вы имеете в виду под заказанным? 07.11.2019
  • Стоит отметить, что даже после того, как вы сделаете этот код неблокирующим, он все равно может работать медленнее. Причина в том, что создание нового процесса сопряжено со значительными накладными расходами, а объем обработки, выполняемой в каждом цикле, на самом деле не так уж велик. 07.11.2019
  • Есть ли причина, по которой вы собираетесь использовать многопроцессорность? Я не думаю, что при таком коротком времени обработки многоцелевая обработка имеет большое значение. Вы должны подумать, лучше ли это, учитывая накладные расходы на многопроцессорную обработку, т. Е. Раскрутку памяти. И сколько ядер у вашего компа? если ncores ‹ процессы. Будет конкуренция и значительное замедление. 07.11.2019
  • @Turksarama Есть ли другой способ уменьшить накладные расходы? 07.11.2019
  • @JasonChia Настоящая проблема намного больше, и я показываю здесь лишь минимальный рабочий пример. 07.11.2019
  • @Samuel, возможно, вы захотите разделить свой процесс на 4 (или сколько у вас ядер) и заставить каждый процесс выполнять одну четверть всего, а затем соединить их вместе в конце. Таким образом, вы запускаете только 4 процесса вместо 32. 07.11.2019
  • @AlexR Я имею в виду, если разные потери все еще в том же порядке, что и в последовательном подходе for-loop. 07.11.2019
  • @Turksarama Хотя я делал это, используя pool = mp.Pool(processes = 4). Что мне тогда менять? 07.11.2019
  • @Samuel Самуэль А, на самом деле ты прав, это означает, что у тебя будет только 4 процесса. На самом деле это означает, что ваша проблема хуже, потому что это ускорение вам недоступно. Вы должны попробовать это с n > 1000, а не с 32, чтобы увидеть, как работает ускорение для действительно большого количества вычислений. 07.11.2019
  • @Samuel Настоящая проблема намного больше Насколько больше? Имейте в виду, что multiprocessing фактически должен копировать данные в и из процессов обратно в основной процесс. Ускорение вычислений всего в 4 раза бесполезно, если копирование занимает всего в 3 раза больше времени, чем вычисление (и, вероятно, это занимает намного больше времени). 07.11.2019
  • @MisterMiyagi Под большим я подразумеваю, что p_size находится в порядке 100 или 1000. Есть ли другой подход, который я мог бы использовать? 07.11.2019

Ответы:


1

Я сделал несколько собственных тестов и вот результаты. Я думаю, вам нужен pool.map вместо apply, особенно если вы хотите поддерживать порядок.

import time
import numpy as np
import multiprocessing as mp
from scipy.special import expit

def regression_loss(test):#a little lazy to work out how to pass multiple variables
    W = test[0]
    k = test[1]
    x = test[2]
    y = test[3]
    U = expit(x.dot(W[k].T)) - y
    time.sleep(1) #simulate lots of hard work
    return np.sum(U*U)

def optimizer_seriell(x,y,p_size, n_classes, n_input, batch_size, W):
    loss = np.zeros((p_size))

    for k in range(p_size):
        loss[k] = regression_loss((W, k, x, y))



def optimizer_parallel(x,y,p_size, n_classes, n_input, batch_size, W):
    with mp.Pool(processes = 4) as pool:

        loss = [pool.map(regression_loss,[(W,k,x,y) for k in range(p_size)])]

if __name__ == "__main__":
    p_size = 32
    n_classes = 10
    n_input = 1000
    batch_size = 8
    W = [np.random.rand(n_classes, n_input) for k in range(p_size)]
    x, y = np.random.rand(batch_size, n_input), np.random.rand(batch_size, n_classes) 
    t0 = time.time()
    optimizer_seriell(x,y,p_size, n_classes, n_input, batch_size, W)
    print(time.time()-t0) 

    t0 = time.time()
    optimizer_parallel(x,y,p_size, n_classes, n_input, batch_size, W)
    print(time.time()-t0) 

это приводит к: 32.018938064575195 для последовательного 9.142435073852539 для параллельного (очевидная экономия времени, если каждый цикл занимает 1 секунду для обработки)

Когда я попробовал это с применением, как вы, времени вообще не было. Это связано с тем, что применение блокируется даже в итерируемом объекте. т.е. на самом деле никакой параллельной обработки не происходит.

То, что вы показываете, на самом деле не является проблемой многопроцессорной обработки, но накладные расходы затмевают преимущества.

РЕДАКТИРОВАТЬ: С применением SErial -> 32,02 секунды Parallel -> 34,04 # на самом деле параллельной обработки не произошло

07.11.2019
  • @ Самуэль, ты когда-нибудь решал проблему? Я думаю, что этот ответ как бы показывает, что общее время обработки 0,018 секунды незначительно для фактического раздела обработки. Возможно, вы захотите профилировать свой код и посмотреть, где он занимает больше всего времени, а затем определить, может ли вам помочь многопроцессорность. Попробуйте cprofile и снейквиз 11.11.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..