Numpy 性能 - 向量的外积及其转置
Numpy Performance - Outer Product of a vector with its transpose
据我了解,向量及其转置的外积在值上是对称的。
Numpy 是否考虑到这一点只对输出的上三角部分进行乘法运算,或者它是否计算整个输出矩阵(即使它是对称的并且时间 + 内存可能会浪费?)
探索一些替代方案:
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
这样做的证据。而且广播乘法不太可能采取这样的步骤。
据我了解,向量及其转置的外积在值上是对称的。
Numpy 是否考虑到这一点只对输出的上三角部分进行乘法运算,或者它是否计算整个输出矩阵(即使它是对称的并且时间 + 内存可能会浪费?)
探索一些替代方案:
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
这样做的证据。而且广播乘法不太可能采取这样的步骤。