开发者

Poor numpy.cross() performance

开发者 https://www.devze.com 2022-12-15 09:32 出处:网络
I\'ve been doing some performance testing in order to improve the performance of a pet project I\'m writing. It\'s a very number-crunching intensive application, so I\'ve been playing with Numpy as a

I've been doing some performance testing in order to improve the performance of a pet project I'm writing. It's a very number-crunching intensive application, so I've been playing with Numpy as a way of improving computational performance.

However, the result from the following performance tests were quite surprising....

Test Source Code (Updated with test cases for hoisting and batch submission)

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) 

Original Results

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

Final Results

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 

Needless to say, this wasn't the result I expected. The pure Python version performs almost 30x faster than Numpy. Numpy performance in other tests has been better than the Python equivalent (which was the expected result).

So, I've got two related questions:

  • Can anyone explain why NumPy is performing so poorly in this case?开发者_JS百科
  • Is there something I can do to fix it?


Try this with larger arrays. I think that just the cost of calling the methods of numpy here overruns the simple several list accesses required by the Python version. If you deal with larger arrays, I think you'll see large wins for numpy.


You can see the source code yourself here: 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 just handles lots of cases and does some extra copies.

In general, numpy is going to be plenty fast enough for slow things like matrix multiplication or inversion - but operations on small vectors like that have a lot of overhead.


To reduce the numpy calling overhead, you might try using cython as an intermediate to call into the numpy functions.

See Fast numerical computations with Cython (SciPy 2009) for details.


Excellent post! I think that the comparison is not actually fair. Batch Cross Product gives an array containing the cross products of all vectors while Python Cross Product gives one vector at a time. If you need to compute all cross products at once of course Batch is better, but if you need to compute every cross product separately you should include the overhead of accessing the array. Also, if a cross product if a function of the previous cross product the Batch implementation should be modified.

0

精彩评论

暂无评论...
验证码 换一张
取 消