Алгебра NumPy Matrix или Python for-loop / list-compceptionsion автоматически использует многопроцессорность? - PullRequest
0 голосов
/ 29 января 2019

Я всегда думал, что для понимания списка Python неявно используется многопроцессорная обработка, и чтение вопросов в стеке (например, этот ) также произвело на меня такое же впечатление.Тем не менее, вот мой маленький эксперимент:

import numpy as np
import time

# some arbitrary data
n = 1000
p = 5
X = np.block([[np.eye(p)], [np.zeros((n-p, p))]])
y = np.sum(X, axis=1) + np.random.normal(0, 1, (n, ))
n_loop = 100000

# run linear regression using direct matrix algebra
def in_sample_error_algebra(X, y):
    beta_hat = np.linalg.inv(X.transpose()@X)@(X.transpose()@y)
    y_hat = X@beta_hat
    error = metrics.mean_squared_error(y, y_hat)
    return error


start = time.time()
errors = [in_sample_error_algebra(X, y) for _ in range(n_loop)]
print('run time =', round(time.time() - start, 2), 'seconds')

время выполнения = 19,68 секунд

Во время выполнения этого кода все 6 (физических) ядер моего процессора работалидо 100%

enter image description here

Что еще более волшебно, когда я перешел от понимания списка к циклу for, произошло то же самое.Я думал с .append, это должно было быть сделано последовательно.См. Ниже:

start = time.time()
errors = []
for _ in range(n_loop):
    errors.append(in_sample_error_algebra(X, y))
print('run time =', round(time.time() - start, 2), 'seconds')

время выполнения = 21,29 секунд

enter image description here

Любые теории?

Python 3.7.2, numpy 1.15.4

1 Ответ

0 голосов
/ 29 января 2019

Действительно, вычисления на чистом Python не выигрывают от многопоточности . глобальная блокировка интерпретатора (GIL) предотвращает одновременный доступ к интерпретатору со стороны нескольких потоков.

Однако многопроцессорная обработка возможна в Python, поскольку каждый процесс запускает свой собственныйэкземпляр интерпретатора Python.Это снижает производительность: инициализация и обмен данными не бесплатны между процессами.Зачастую это даже не стоит затраченных усилий.

История для NumPy отличается.Numpy в основном состоит из собственных функций, написанных на C. Когда на некоторое время код C не нуждается в интерпретаторе, он может освободить GIL и позволить одновременно запустить другой поток Python.Код C также может порождать «не-Python» потоки для распараллеливания вычислений.Это то, что происходит в numpy.

На самом деле, numpy сама по себе не порождает потоки (я думаю), но многие из процедур матрицы / вектора и линейной алгебры обращаются к библиотекам низкого уровня BLAS и LAPACK.Существуют различные реализации этих библиотек, и некоторые из них оптимизированы для многопоточности.Ваша версия numpy, очевидно, использует один из них.

В заключение, ни понимание внешнего списка, ни цикл for не выполняются параллельно, но np.linalg.inv, а также матричный продукт X @ beta_hat могут внутренне выполняться несколькопотоки.См. Параллельное программирование с numpy и scipy для получения дополнительной информации.

...