numpy中的大点阵矩阵乘法

时间:2015-10-02 04:11:16

标签: python arrays numpy

给出两个大的numpy数组,一个用于3D点列表,另一个用于转换矩阵列表。假设两个列表之间存在1对1的对应关系,我正在寻找计算由其相应矩阵转换的每个点的结果数组的最佳方法。

我这样做的解决方案是使用切片(参见下面的示例代码中的“test4”),它适用于小型数组,但由于我的方法浪费多少而导致大型数组失败:)

import numpy as np
COUNT    = 100
matrix   = np.random.random_sample((3,3,))   # A single matrix
matrices = np.random.random_sample((COUNT,3,3,)) # Many matrices
point    = np.random.random_sample((3,))     # A single point
points   = np.random.random_sample((COUNT,3,)) # Many points

# Test 1, result of a single point multiplied by a single matrix
# This is as easy as it gets
test1 = np.dot(point,matrix)
print 'done'

# Test 2, result of a single point multiplied by many matrices
# This works well and returns a transformed point for each matrix
test2 = np.dot(point,matrices)
print 'done'

# Test 3, result of many points multiplied by a single matrix
# This works also just fine
test3 = np.dot(points,matrix)
print 'done'

# Test 4, this is the case i'm trying to solve. Assuming there's a 1-1
# correspondence between the point and matrix arrays, the result i want
# is an array of points, where each point has been transformed by it's
# corresponding matrix
test4 = np.zeros((COUNT,3))
for i in xrange(COUNT):
    test4[i] = np.dot(points[i],matrices[i])
print 'done' 

使用小数组,这很好用。对于大型数组,(COUNT = 1000000)测试#4有效,但速度相当慢。

有没有办法让测试#4更快?假设不使用循环?

2 个答案:

答案 0 :(得分:2)

您可以使用numpy.einsum。这是一个包含5个矩阵和5个点的例子:

In [49]: matrices.shape
Out[49]: (5, 3, 3)

In [50]: points.shape
Out[50]: (5, 3)

In [51]: p = np.einsum('ijk,ik->ij', matrices, points)

In [52]: p[0]
Out[52]: array([ 1.16532051,  0.95155227,  1.5130032 ])

In [53]: matrices[0].dot(points[0])
Out[53]: array([ 1.16532051,  0.95155227,  1.5130032 ])

In [54]: p[1]
Out[54]: array([ 0.79929572,  0.32048587,  0.81462493])

In [55]: matrices[1].dot(points[1])
Out[55]: array([ 0.79929572,  0.32048587,  0.81462493])

上面的内容正在matrix[i] * points[i](即在右侧相乘),但我只是重新阅读了问题,发现您的代码使用了points[i] * matrix[i]。您可以通过切换einsum

的索引和参数来实现
In [76]: lp = np.einsum('ij,ijk->ik', points, matrices)

In [77]: lp[0]
Out[77]: array([ 1.39510822,  1.12011057,  1.05704609])

In [78]: points[0].dot(matrices[0])
Out[78]: array([ 1.39510822,  1.12011057,  1.05704609])

In [79]: lp[1]
Out[79]: array([ 0.49750324,  0.70664634,  0.7142573 ])

In [80]: points[1].dot(matrices[1])
Out[80]: array([ 0.49750324,  0.70664634,  0.7142573 ])

答案 1 :(得分:0)

拥有多个变换矩阵没有多大意义。您可以像this question中一样组合转换矩阵:

如果我想应用矩阵A,那么B,然后是C,我将以相反的顺序乘以矩阵np.dot(C,np.dot(B,A))

因此,您可以通过预先计算该矩阵来节省一些内存空间。然后应该将一堆矢量应用于一个变换矩阵应该很容易处理( in reason )。

我不知道为什么你需要在一百万个载体上进行一百万次转换,但我建议购买更大的RAM。

修改 没有办法减少操作,没有。除非您的转换矩阵具有特定属性,例如稀疏性,对角性等,否则您将不得不运行所有乘法和求和。但是,处理这些操作的方式可以跨核心和/或使用GPU上的向量操作进行优化。

另外,python显然很慢。您可以尝试使用NumExpr在您的核心之间拆分numpy。或者也许在C ++上使用BLAS框架(特别是快速;))