numpy.cross() 性能差

8

我一直在进行性能测试,以提高我正在编写的小项目的性能。这是一个非常计算密集型的应用程序,因此我一直在尝试使用Numpy来提高计算性能。

然而,以下性能测试的结果相当令人惊讶...

测试源代码 (更新了变量提升和批量提交的测试用例)

import timeit

numpySetup = """
import numpy
left = numpy.array([1.0,0.0,0.0])
right = numpy.array([0.0,1.0,0.0])
"""

hoistSetup = numpySetup +'hoist = numpy.cross\n'

pythonSetup = """
left = [1.0,0.0,0.0]
right = [0.0,1.0,0.0]
"""

numpyBatchSetup = """
import numpy

l = numpy.array([1.0,0.0,0.0])
left = numpy.array([l]*10000)

r = numpy.array([0.0,1.0,0.0])
right = numpy.array([r]*10000)
"""

pythonCrossCode = """
x = ((left[1] * right[2]) - (left[2] * right[1]))
y = ((left[2] * right[0]) - (left[0] * right[2]))
z = ((left[0] * right[1]) - (left[1] * right[0]))
"""

pythonCross = timeit.Timer(pythonCrossCode, pythonSetup)
numpyCross = timeit.Timer ('numpy.cross(left, right)' , numpySetup)
hybridCross = timeit.Timer(pythonCrossCode, numpySetup)
hoistCross = timeit.Timer('hoist(left, right)', hoistSetup)
batchCross = timeit.Timer('numpy.cross(left, right)', numpyBatchSetup) 

print 'Python Cross Product : %4.6f ' % pythonCross.timeit(1000000)
print 'Numpy Cross Product  : %4.6f ' % numpyCross.timeit(1000000) 
print 'Hybrid Cross Product : %4.6f ' % hybridCross.timeit(1000000) 
print 'Hoist Cross Product  : %4.6f ' % hoistCross.timeit(1000000) 
# 100 batches of 10000 each is equivalent to 1000000
print 'Batch Cross Product  : %4.6f ' % batchCross.timeit(100) 

原始结果

Python Cross Product : 0.754945 
Numpy Cross Product  : 20.752983 
Hybrid Cross Product : 4.467417 

最终结果

Python Cross Product : 0.894334 
Numpy Cross Product  : 21.099040 
Hybrid Cross Product : 4.467194 
Hoist Cross Product  : 20.896225 
Batch Cross Product  : 0.262964 

不用说,这不是我预期的结果。纯Python版本的执行速度比Numpy快了近30倍。在其他测试中,Numpy的性能比Python等效版本更好(这是预期的结果)。

所以,我有两个相关的问题:

  • 有人能解释为什么NumPy在这种情况下的表现如此糟糕吗?
  • 我该做些什么来修复它?
4个回答

6

尝试在更大的数组上使用此方法。我认为,仅调用numpy方法的成本就超过了Python版本所需的几个简单列表访问。如果您处理更大的数组,我认为您将看到numpy的巨大优势。


在这种情况下,三个组件数组(x、y、z坐标)是迄今为止最常见的情况。更奇怪的是,即使从numpy数组中读取,Python代码仍然更快。如果是调用开销,我会预计它比纯NumPy解决方案更慢。 - Adam Luchjenbroers
@Adam:但是通过从numpy的数组中读取,您可以节省调用cross函数本身的开销,因为它是一个动态加载的扩展,所以至少要经过几个指针。对于这样短的数组,将调用cross展开作为微小优化确实是有意义的。 - Eli Bendersky
我刚刚添加了一个测试用例,其中我将数组批处理在一起,并看到了显着的性能提升。所以我想开销理论是正确的。看起来如果我想使用Numpy来提高性能,我需要找到一种将这些操作批处理在一起的方法。 - Adam Luchjenbroers

5

1

0

非常好的文章!我认为这个比较并不公平。批量叉积给出包含所有向量叉积的数组,而Python叉积一次只给出一个向量。如果您需要一次计算所有叉积,当然批处理更好,但如果您需要单独计算每个叉积,则应包括访问数组的开销。此外,如果叉积是前一个叉积的函数,则批处理实现应进行修改。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接