Многопроцессорная обработка больших извилин с использованием Scipy не ускоряет - PullRequest
0 голосов
/ 27 февраля 2019

Я использую scipy.signal.correlate для выполнения больших 2D сверток.У меня есть большое количество массивов, с которыми я хочу работать, и поэтому естественно подумал, что multiprocessing.Pool может помочь.Однако использование следующей простой настройки (на 4-ядерном процессоре) не дает никаких преимуществ.

import multiprocessing as mp
import numpy as np
from scipy import signal

arrays = [np.ones([500, 500])] * 100
kernel = np.ones([30, 30])

def conv(array, kernel):
  return (array, kernel, signal.correlate(array, kernel, mode="valid", method="fft"))

pool = mp.Pool(processes=4)
results = [pool.apply(conv, args=(arr, kernel)) for arr in arrays]

Изменение счетчика процесса на {1, 2, 3, 4} происходит примерно в то же время (2,6 с +- .2).

Что может быть?

Ответы [ 2 ]

0 голосов
/ 27 февраля 2019

Я думаю, что проблема в этой строке:

results = [pool.apply(conv, args=(arr, kernel)) for arr in arrays]

Pool.apply - это операция блокировки, которая запускает conv для каждого элемента в массиве и ждет, прежде чем перейти кследующий элемент, так что, несмотря на многопроцессорность, на самом деле ничего не распространяется.Вместо этого вам нужно использовать pool.map, чтобы получить поведение, которое вы ищете:

from functools import partial
conv_partial = partial( conv, kernel=kernel )
results = pool.map( conv_partial, arrays )
0 голосов
/ 27 февраля 2019

Что может происходить?

Сначала я подумал, что причина в том, что базовая реализация FFT уже распараллелена.В то время как интерпретатор Python является однопоточным, код C, который может вызываться из Python, может полностью использовать ваш ЦП.

Тем не менее, базовая реализация scipy.correlate в FFT, по-видимому, представляет собой fftpack в NumPy (переведеноиз Fortran, который был написан в 1985 году), который выглядит как однопоточный по сравнению с тем, как он выглядит на странице fftpack .

Действительно, я запустил ваш скрипт и получил значительно более высокую загрузку ЦП.С четырьмя ядрами на моем компьютере и четырьмя процессами я получил ускорение ~ 2 (для массивов 2000x2000 и использования изменений кода с Raw Dawg ).

Затраты на создание процессов и обмен даннымис процессами съедает часть преимуществ более эффективного использования ЦП.

Вы все еще можете попытаться оптимизировать размеры массива или вычислить только небольшую часть корреляции (если вам все это не нужно)или если ядро ​​все время одинаково, вычислите FFT ядра только один раз и используйте его повторно (это потребует реализации части scipy.correlate самостоятельно), или попробуйте одинарную точность вместо двойной или выполните корреляцию на видеокарте сCUDA.

...