2010-01-01 6 views
4

J'ai fait quelques tests de performance afin d'améliorer les performances d'un projet d'animal de compagnie que j'écris. C'est une application très intensive en nombre, donc j'ai joué avec Numpy comme un moyen d'améliorer la performance computationnelle.Mauvaise performance de numpy.cross()

Cependant, le résultat des tests de performance suivants ont été tout à fait surprenant ....

test code source(Mise à jour avec des cas de test pour le levage et la soumission par lots)

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) 

Résultats d'origine

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

Résultats finaux

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 

Inutile de dire que ce ne fut pas le résultat que je m'y attendais. La version Python pure est presque 30 fois plus rapide que Numpy. La performance de Numpy dans d'autres tests a été meilleure que l'équivalent Python (qui était le résultat attendu).

Donc, j'ai deux questions connexes:

  • Quelqu'un peut-il expliquer pourquoi NumPy effectue si mal dans ce cas?
  • Y at-il quelque chose que je peux faire pour le réparer?

Répondre

6

Essayez ceci avec des réseaux plus grands. Je pense que juste le coût d'appeler les méthodes de numpy dépasse ici les simples accès à plusieurs listes requis par la version Python. Si vous traitez avec des tableaux plus grands, je pense que vous verrez de grandes victoires pour numpy.

+0

Dans ce cas particulier, les tableaux à 3 composantes (coordonnées x, y, z) sont de loin les plus courants. Ce qui est aussi un peu bizarre, c'est que même en lisant des tableaux numpy, le code python est encore plus rapide. S'il s'agissait d'une surcharge, je m'attendrais à ce que cela ralentisse encore plus que la simple solution NumPy. –

+0

@Adam: mais en lisant les tableaux de numpy, vous économisez la surcharge de l'appel de la fonction 'cross' elle-même, qui est une extension chargée dynamiquement donc elle traverse au moins quelques pointeurs. Pour de tels tableaux courts, il est logique de procéder à une micro-optimisation pour dérouler l'appel à "cross" –

+0

Je viens d'ajouter un cas de test où j'ai regroupé les tableaux ensemble, et vu une amélioration considérable des performances. Donc, je dirais que la théorie des frais généraux est correcte. On dirait que si je veux utiliser Numpy pour un coup de pouce de performance, je vais devoir trouver un moyen de regrouper ces opérations ensemble. –

5

Vous pouvez voir le code source vous-même ici: 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 gère juste beaucoup de cas et fait quelques copies supplémentaires.

En général, numpy va être suffisamment rapide pour les choses lentes comme la multiplication ou l'inversion de la matrice - mais les opérations sur de petits vecteurs comme celui-ci ont beaucoup de surcharge.

0

Excellent post! Je pense que la comparaison n'est pas juste. Batch Cross Product donne un tableau contenant les produits croisés de tous les vecteurs tandis que Python Cross Product donne un vecteur à la fois. Si vous avez besoin de calculer tous les produits croisés à la fois, bien sûr, Batch est meilleur, mais si vous devez calculer chaque produit croisé séparément, vous devez inclure le temps d'accès au tableau. De même, si un produit croisé est une fonction du produit croisé précédent, l'implémentation du lot doit être modifiée.

Questions connexes