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?
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. –
@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" –
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. –