Почему мой парализованный цикл for намного медленнее? - PullRequest
2 голосов
/ 07 ноября 2019

Я попытался парализовать цикл for в Python, используя пакет многопроцессорной обработки. Эта функция, которую я хочу запустить в нескольких потоках, это

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

1 Ответ

0 голосов
/ 07 ноября 2019

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

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 секунд Параллельно -> 34,04 # фактически параллельной обработки не произошло

...