Adam Luchjenbroers
Adam Luchjenbroers

Reputation: 5019

Poor numpy.cross() performance

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:

Upvotes: 9

Views: 3840

Answers (4)

nodarkside
nodarkside

Reputation: 182

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.

Upvotes: 0

Ryan Ginstrom
Ryan Ginstrom

Reputation: 14121

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.

Upvotes: 1

dmazzoni
dmazzoni

Reputation: 13236

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.

Upvotes: 6

Eli Bendersky
Eli Bendersky

Reputation: 273486

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.

Upvotes: 6

Related Questions