Numpy Performance - внешнее произведение вектора с его транспонированием
Насколько я понимаю, Внешнее Произведение вектора с его транспозицией симметрично по значению.
Принимает ли это во внимание Numpy, чтобы выполнять умножения только для верхней части треугольника выходных данных, или он рассчитывает всю выходную матрицу (даже если она симметрична, а время + память могут быть потрачены впустую?)
1 ответ
Изучение некоторых альтернатив:
In [162]: x=np.arange(100)
In [163]: np.outer(x,x)
Out[163]:
array([[ 0, 0, 0, ..., 0, 0, 0],
[ 0, 1, 2, ..., 97, 98, 99],
[ 0, 2, 4, ..., 194, 196, 198],
...,
[ 0, 97, 194, ..., 9409, 9506, 9603],
[ 0, 98, 196, ..., 9506, 9604, 9702],
[ 0, 99, 198, ..., 9603, 9702, 9801]])
In [164]: x1=x[:,None]
In [165]: x1*x1.T
Out[165]:
array([[ 0, 0, 0, ..., 0, 0, 0],
[ 0, 1, 2, ..., 97, 98, 99],
[ 0, 2, 4, ..., 194, 196, 198],
...,
[ 0, 97, 194, ..., 9409, 9506, 9603],
[ 0, 98, 196, ..., 9506, 9604, 9702],
[ 0, 99, 198, ..., 9603, 9702, 9801]])
In [166]: np.dot(x1,x1.T)
Out[166]:
array([[ 0, 0, 0, ..., 0, 0, 0],
[ 0, 1, 2, ..., 97, 98, 99],
[ 0, 2, 4, ..., 194, 196, 198],
...,
[ 0, 97, 194, ..., 9409, 9506, 9603],
[ 0, 98, 196, ..., 9506, 9604, 9702],
[ 0, 99, 198, ..., 9603, 9702, 9801]])
Сравнивая их времена:
In [167]: timeit np.outer(x,x)
40.8 µs ± 63.1 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [168]: timeit x1*x1.T
36.3 µs ± 22 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [169]: timeit np.dot(x1,x1.T)
60.7 µs ± 6.86 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Является dot
используя транспонированный короткий путь? Я так не думаю, или если это так, это не поможет в этом случае. Я немного удивлен, что dot
медленнее.
In [170]: x2=x1.T
In [171]: timeit np.dot(x1,x2)
61.1 µs ± 30 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Другой метод
In [172]: timeit np.einsum('i,j',x,x)
28.3 µs ± 19.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
einsum
с x1
а также x2
имеет такие же времена.
Интересно что matmul
делает так же, как einsum
в этом случае (возможно einsum
делегирует matmul
?)
In [178]: timeit x1@x2
27.3 µs ± 1.09 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [179]: timeit x1@x1.T
27.2 µs ± 14.2 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Самоумножение эффективной матрицы (умножение на грамм) демонстрирует, как dot
можно сэкономить время, будучи умным (для массива 1000x1000).
Как обсуждалось в ссылках, dot
может определять, когда один аргумент является транспонированным для другого (возможно, путем проверки указателя буфера данных, его формы и шагов), и может использовать функцию BLAS, оптимизированную для симметричных вычислений. Но я не вижу доказательств outer
делая это. И вряд ли трансляция умножения сделает такой шаг.