找到大向量矩阵的点积的最快方法

有翼的诺斯罗皮

我正在寻找有关解决以下问题的最有效方法的建议:

我有两个数组,分别称为A和B。它们的形状均为NxNx3。它们代表位置的两个2D矩阵,其中每个位置都是x,y和z坐标的向量。

我想创建一个形状为NxN的名为C的新数组,其中C [i,j]是向量A [i,j]和B [i,j]的点积。

这是到目前为止我提出的解决方案。第一个使用numpy的einsum函数(在此进行了详细介绍)。第二种使用numpy的广播规则及其sum函数。

>>> import numpy as np
>>> A = np.random.randint(0, 10, (100, 100, 3))
>>> B = np.random.randint(0, 10, (100, 100, 3))
>>> C = np.einsum("ijk,ijk->ij", A, B)
>>> D = np.sum(A * B, axis=2)
>>> np.allclose(C, D)
True

有没有更快的方法?我曾经听到过一些杂语,说numpy的tensordot函数可以快速发展,但我一直都很难理解它。使用numpy的点或内部函数呢?

在某些情况下,A和B数组通常具有100到1000个元素。

任何指导,不胜感激!

hpaulj

经过一些调整,我们可以使用matmul想法是将前两个维视为“批量”维,dot最后一个维视为

In [278]: E = A[...,None,:]@B[...,:,None]                                       
In [279]: E.shape                                                               
Out[279]: (100, 100, 1, 1)
In [280]: E = np.squeeze(A[...,None,:]@B[...,:,None])                           
In [281]: np.allclose(C,E)                                                      
Out[281]: True
In [282]: timeit E = np.squeeze(A[...,None,:]@B[...,:,None])                    
130 µs ± 2.01 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [283]: timeit C = np.einsum("ijk,ijk->ij", A, B)                             
90.2 µs ± 1.53 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

比较时间可能会有些棘手。在当前版本中,einsum可以根据尺寸采取不同的路线。在某些情况下,似乎将任务委托给了matmul(或至少与相同的底层BLAS类似代码)。虽然einsum在此测试中更快是很好的,但我不会对此进行概括。

tensordot只需调整数组的形状(并在需要时转置),以便可以应用普通的2d np.dot实际上,它在这里不起作用,因为您将前两个轴视为“批处理”,就像outer product在它们上那样。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章