【问题标题】:Poor numpy.cross() performancenumpy.cross() 性能不佳
【发布时间】:2010-12-31 13:54:32
【问题描述】:

我一直在做一些性能测试,以提高我正在编写的宠物项目的性能。这是一个数字运算密集型应用程序,所以我一直在使用 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 在这种情况下表现如此糟糕?
  • 有什么办法可以解决吗?

【问题讨论】:

    标签: python performance numpy


    【解决方案1】:

    优秀的帖子!我认为这种比较实际上并不公平。 Batch Cross Product 给出了一个包含所有向量叉积的数组,而 Python Cross Product 一次给出一个向量。如果您需要一次计算所有叉积当然 Batch 更好,但是如果您需要分别计算每个叉积,则应该包括访问数组的开销。此外,如果一个叉积是前一个叉积的函数,则应该修改 Batch 实现。

    【讨论】:

      【解决方案2】:

      为了减少 numpy 调用开销,您可以尝试使用 cython 作为中间体来调用 numpy 函数。

      详情请见Fast numerical computations with Cython (SciPy 2009)。

      【讨论】:

        【解决方案3】:

        您可以在这里自己查看源代码:http://www.google.com/codesearch/p?hl=en#5mAq98l-MUw/trunk/dnumpy/numpy/core/numeric.py&q=cross%20package:numpy&sa=N&cd=1&ct=rc

        numpy.cross 只处理很多案例并做一些额外的副本。

        一般来说,numpy 对于矩阵乘法或求逆之类的慢速操作来说足够快 - 但是像这样的小向量上的操作会产生很多开销。

        【讨论】:

          【解决方案4】:

          用更大的数组试试这个。我认为只是在这里调用numpy 的方法的成本超出了Python 版本所需的简单的几个列表访问。如果您处理更大的数组,我认为您会看到 numpy 的巨大胜利。

          【讨论】:

          • 在这种特殊情况下,3 个分量数组(x、y、z 坐标)是迄今为止最常见的情况。还有一点奇怪的是,即使从 numpy 数组中读取,python 代码仍然更快。如果是调用开销,我希望它比纯 NumPy 解决方案更慢。
          • @Adam:但是通过从 numpy 的数组中读取,您可以节省调用 cross 函数本身的开销,这是一个动态加载的扩展,因此它至少要经过几个指针。对于如此短的数组,将调用展开到cross 的微优化确实是有意义的
          • 我刚刚添加了一个测试用例,我将数组批处理在一起,并看到了相当大的性能提升。所以我会说开销理论是正确的。看起来如果我想使用 Numpy 来提高性能,我需要找到一种将这些操作批处理在一起的方法。
          猜你喜欢
          • 2011-01-03
          • 2016-11-06
          • 2019-06-15
          • 2013-06-11
          • 2012-01-25
          • 2021-12-15
          • 2011-02-13
          • 2011-01-14
          • 2016-12-24
          相关资源
          最近更新 更多