2013-05-14 2 views
12

Le code ci-dessous reproduit le problème que je l'ai rencontré dans l'algorithme je met actuellement en œuvre:Pourquoi la multiplication de tableaux itératifs par éléments ralentit-elle en numpy?

import numpy.random as rand 
import time 

x = rand.normal(size=(300,50000)) 
y = rand.normal(size=(300,50000)) 

for i in range(1000): 
    t0 = time.time() 
    y *= x 
    print "%.4f" % (time.time()-t0) 
    y /= y.max() #to prevent overflows 

Le problème est que, après un certain nombre d'itérations, les choses commencent à se progressivement plus lentement jusqu'à une itération prend plusieurs fois plus temps que initialement.

Une parcelle du ralentissement enter image description here

utilisation du processeur par le processus Python est stable autour de 17-18% tout le temps.

J'utilise:

  • Python 2.7.4 version 32 bits;
  • Numpy 1.7.1 avec MKL;
  • Windows 8.
+0

Je ne pense pas que je vois ce comportement avec python-2.7.4 sous Linux. –

+9

C'est probablement dû à des nombres dénormaux: http://stackoverflow.com/a/9314926/226621 –

+4

Dans mon test, dès qu'il a commencé à ralentir, je l'ai interrompu et j'ai fait 'print numpy.amin (numpy.abs (y [y! = 0])) 'et obtenu' 4.9406564584124654e-324', donc je pense que les nombres dénormaux sont votre réponse. Je ne sais pas comment vider les dénormaux de zéro à partir de Python autre que de créer une extension C si ... –

Répondre

3

Comme @Alok souligné, cela semble être causé par denormal numbers affecter les performances. J'ai couru sur mon système OSX et confirmé le problème. Je ne connais pas de moyen de vider les dénormatifs à zéro en numpy. Je voudrais essayer de contourner ce problème dans l'algorithme en évitant les très petits nombres: avez-vous vraiment besoin de diviser y jusqu'à ce qu'il descende au niveau 1.e-324?

Si vous évitez les nombres faibles, par ex. en ajoutant la ligne suivante dans votre boucle:

y += 1e-100 

alors vous aurez une constante de temps par itération (quoique plus lente en raison de l'opération supplémentaire). Une autre solution consiste à utiliser une arithmétique de plus haute précision, par ex.

x = rand.normal(size=(300,50000)).astype('longdouble') 
y = rand.normal(size=(300,50000)).astype('longdouble') 

Cela rendra chacune de vos étapes plus coûteuse, mais chaque étape prendra à peu près le même temps.

Voir la comparaison suivante dans mon système: enter image description here

+0

_> avez-vous vraiment besoin de diviser y jusqu'à ce qu'il descende au niveau 1.e-324? _ Oui, sinon les valeurs débordent à environ 400 itérations. J'ai essayé "d'ajouter la petite solution constante" dans mon algorithme (le code donné dans la question est juste un simple testcode) et il a résolu le problème du ralentissement. Merci à tous pour votre aide! (en particulier @Alok et @tiago) – Ottokar

Questions connexes