Поигрался с этим и нашел inner1d
самый быстрый. Однако эта функция является внутренней, поэтому более надежным подходом является использование
numpy.einsum("ij,ij->i", a, b)
Еще лучше выровнять свою память так, чтобы суммирование происходило в первом измерении, например,
a = numpy.random.rand(3, n)
b = numpy.random.rand(3, n)
numpy.einsum("ij,ij->j", a, b)
Для 10 ** 3 <= n <= 10 ** 6
это самый быстрый метод и почти вдвое быстрее, чем его нетранспонированный эквивалент. Максимум происходит, когда кеш уровня 2 исчерпан, примерно на 2 * 10 ** 4
.
Также обратите внимание, что транспонированная sum
обработка выполняется намного быстрее, чем ее нетранспонированный эквивалент.
Сюжет был создан с помощью perfplot (мой небольшой проект)
import numpy
from numpy.core.umath_tests import inner1d
import perfplot
def setup(n):
a = numpy.random.rand(n, 3)
b = numpy.random.rand(n, 3)
aT = numpy.ascontiguousarray(a.T)
bT = numpy.ascontiguousarray(b.T)
return (a, b), (aT, bT)
b = perfplot.bench(
setup=setup,
n_range=[2 ** k for k in range(1, 25)],
kernels=[
lambda data: numpy.sum(data[0][0] * data[0][1], axis=1),
lambda data: numpy.einsum("ij, ij->i", data[0][0], data[0][1]),
lambda data: numpy.sum(data[1][0] * data[1][1], axis=0),
lambda data: numpy.einsum("ij, ij->j", data[1][0], data[1][1]),
lambda data: inner1d(data[0][0], data[0][1]),
],
labels=["sum", "einsum", "sum.T", "einsum.T", "inner1d"],
xlabel="len(a), len(b)",
)
b.save("out1.png")
b.save("out2.png", relative_to=3)
person
Nico Schlömer
schedule
23.09.2016