IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Sommes - Optimisation


Sujet :

Python

  1. #1
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 656
    Points : 1 153
    Points
    1 153
    Par défaut Sommes - Optimisation
    Bonjour,

    J'ai hésité à placer ce post dans la section 'Calcul Scientique', mais je pense que le problème est plus général.

    L'intitulé n'est pas très explicite... Je cherche à générer une 'time serie' (ou encore un signal temporel) polychromatique (plusieurs fréquences) comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    F(t) = Somme(Ai*cos(wi*t+Phii))
    J'ai un certain nombre de "composantes" à mon signal (les indices i) sur une certaine plage de temps. Le résutat est sous forme de liste (un élément par pas de temps t).

    Mon problème vient du temps d'éxécution. Beaucoup trop long je trouve (une dizaine de secondes quand même), je pense donc que ma méthode n'est pas optimale.

    Voici une version épurée de mon code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    # -*- coding:Utf-8 -*-
     
     
    #-----------------------------------------------------------------------
    #			        MODULE IMPORTATION
    #-----------------------------------------------------------------------
     
    import numpy as np
    from math import cos
    import random
    import time
     
    #-----------------------------------------------------------------------
    #			        SPECTRUM DEFINITIONS
    #-----------------------------------------------------------------------
     
     
    def HarrisDNV(meanSpeed, Wmin, Wmax, N):
        """ Harris - DNV Spectrum """
     
        # Frequencies in rad/s
        W = linspace(Wmin,Wmax,N)
     
        # Surface drag coefficient  	
        C = 0.0015 
     
        # Spectrum					
        Spectrum = [(7200/(2*np.pi))*C*meanSpeed*(2+(286.0*W[i]/meanSpeed)**2)**(-5.0/6.0) for i in range(len(W))]
     
        return W,Spectrum
     
     
     
    #-----------------------------------------------------------------------
    #			       RANDOM TIME SERIE GENERATOR
    #-----------------------------------------------------------------------
     
    def WindGen(Npoints, SampleTime, MaxFreq, Nlags, meanSpeed, Spec=2, Seed=None):
        """ Build a time serie of the wind velocity 
        
        This function generate a random time serie of wind speed based on 
        the following wind spectrum:
            1- Ochi-Shin
            2- Harris-DNV (default)
            3- Wills or Modified Harris
            4- API
            5- NPD
        
        --------------------------------------------------------------------
        INPUTS:
        --------------------------------------------------------------------
            Npoints     : Number of points in the time serie (integer)
            SampleTime  : Sample time (sec) (integer)
            MaxFreq     : Max frequency for spectrum (float)
            Nlags       : Number of random phases (integer)
            meanSpeed   : Mean wind velocity (float)
            Spec        : Spectrum type (integer)
            
        --------------------------------------------------------------------
        OUTPUTS
        --------------------------------------------------------------------
            liste containing:
                - time
                - wind velocities
        """
     
        #
        # GENERATING WIND SPECTRUM
        #
        if Spec == 1:
            print 'OchiShin'
            W,S = OchiShin(meanSpeed, Wmin=0., Wmax=MaxFreq, N=Nlags)
        elif Spec == 2:
            print 'HarrisDNV'
            W,S = HarrisDNV(meanSpeed, Wmin=0., Wmax=MaxFreq, N=Nlags)
        elif Spec == 3:
            print 'Wills'
            W,S = Wills(meanSpeed, Wmin=0., Wmax=MaxFreq, N=Nlags)
        elif Spec == 4:
            print 'API'
            W,S = API(meanSpeed, Wmin=0., Wmax=MaxFreq, N=Nlags)
        elif Spec == 5:
            print 'NPD'
            W,S = NPD(meanSpeed, Wmin=0., Wmax=MaxFreq, N=Nlags)
        else:
            print 'Unvalide choice, default spectrum have been selected (Harris)'
            print 'The following spectrum are available:'
            print '\t' + '1- Ochi-Shin'
            print '\t' + '2- Harris-DNV (default)'
            print '\t' + '3- Wills or Modified Harris'
            print '\t' + '4- API'
            print '\t' + '5- NPD'
            print ''
            W,S = HarrisDNV(meanSpeed, Wmin=0., Wmax=MaxFreq, N=Nlags)
     
        #           
        # GENERATING TIME SERIES
        #
        if Seed: random.seed(Seed)
     
        T = [t for t in range(Npoints)]
        A = [(2*(S[i+1]+S[i])/2*(W[i+1]-W[i]))**0.5 for i in range(Nlags-1)]
        A.append(0.0)
        P = [random.uniform(0.0,2*np.pi) for i in range(Nlags)]
     
        t0 = time.clock()
        WindVelocities = [sum([A[i]*cos(W[i]*t + P[i]) for i in range(Nlags)]) + meanSpeed for t in range(Npoints)]
        print 'Time serie generated in ' + str(round(time.clock()-t0,4)) + 's'
     
        return T, WindVelocities
     
     
     
    if __name__=="__main__":
     
        import numpy as np
        from pylab import *	
        from math import cos
        import random
        import time
     
        t, WindVelocities = WindGen(Npoints = 3600, 
                                       SampleTime = 1, 
                                       MaxFreq = 2*np.pi/4, 
                                       Nlags = 1000, 
                                       meanSpeed = 1.0, 
                                       Spec=2, 
                                       Seed=145468)
     
     
        plot(t[100:300],WindVelocities[100:300],'blue')
        legend(('Random Wind velocities'),'best')
        ylabel('Wind Velocity in m/s')
        xlabel('Time in s')
        tight_layout()
        show()

    La création de la liste 'WindVelocities' prend chez moi plus de 10s... Est-ce que la liste compréhension n'est pas adapté, ou est-ce la fonction 'sum' qui prend autant de temps?



    Ju

  2. #2
    Invité
    Invité(e)
    Par défaut
    Salut,

    Tu peux utiliser le module cProfile pour voir où ton script passe le plus de temps.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    python -m cProfile [-o output_file] [-s sort_order] myscript.py

  3. #3
    Membre éclairé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Janvier 2013
    Messages
    388
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2013
    Messages : 388
    Points : 692
    Points
    692
    Par défaut
    Salut,
    En prenant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    WindVelocities = np.array([ np.sum(A*np.cos(W*t+P)) + meanSpeed for t in np.arange(Npoints)])
    l'exécution passe de 23s à 2s sur ma machine.

  4. #4
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 656
    Points : 1 153
    Points
    1 153
    Par défaut
    Salut Mygale1978,

    Je me méfie des profilers, il m'est déjà arrivé d'obtenir des résultats aberrants. Toujours est-il voici le profile de l'appel à ma fonction 'WindGen' (obtenu avec le module cProfile):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
      3631141 function calls in 17.759 seconds
     
       Ordered by: standard name
     
       ncalls  tottime  percall  cumtime  percall filename:lineno(function)
            1    0.000    0.000   17.759   17.759 <string>:1(<module>)
            1    0.009    0.009    0.009    0.009 WindSim.py:124(HarrisDNV)
            1   16.760   16.760   17.759   17.759 WindSim.py:197(WindGen)
         3600    0.020    0.000    0.529    0.000 fromnumeric.py:1379(sum)
         3600    0.014    0.000    0.506    0.000 fromnumeric.py:32(_wrapit)
            1    0.000    0.000    0.000    0.000 function_base.py:6(linspace)
         3600    0.004    0.000    0.471    0.000 numeric.py:167(asarray)
            1    0.000    0.000    0.000    0.000 random.py:100(seed)
         1000    0.000    0.000    0.000    0.000 random.py:355(uniform)
           35    0.000    0.000    0.000    0.000 rpc.py:149(debug)
            5    0.000    0.000    0.006    0.001 rpc.py:208(remotecall)
            5    0.000    0.000    0.001    0.000 rpc.py:218(asynccall)
            5    0.000    0.000    0.005    0.001 rpc.py:238(asyncreturn)
            5    0.000    0.000    0.000    0.000 rpc.py:244(decoderesponse)
            5    0.000    0.000    0.005    0.001 rpc.py:279(getresponse)
            5    0.000    0.000    0.000    0.000 rpc.py:287(_proxify)
            5    0.000    0.000    0.005    0.001 rpc.py:295(_getresponse)
            5    0.000    0.000    0.000    0.000 rpc.py:317(newseq)
            5    0.000    0.000    0.000    0.000 rpc.py:321(putmessage)
            5    0.000    0.000    0.000    0.000 rpc.py:546(__getattr__)
            4    0.000    0.000    0.000    0.000 rpc.py:589(__init__)
            4    0.000    0.000    0.005    0.001 rpc.py:594(__call__)
            5    0.000    0.000    0.000    0.000 socket.py:223(meth)
            5    0.000    0.000    0.000    0.000 threading.py:101(RLock)
            5    0.000    0.000    0.000    0.000 threading.py:106(__init__)
            5    0.000    0.000    0.000    0.000 threading.py:121(acquire)
            5    0.000    0.000    0.000    0.000 threading.py:141(release)
            5    0.000    0.000    0.000    0.000 threading.py:159(_acquire_restore)
            5    0.000    0.000    0.000    0.000 threading.py:167(_release_save)
            5    0.000    0.000    0.000    0.000 threading.py:177(_is_owned)
            5    0.000    0.000    0.000    0.000 threading.py:181(Condition)
            5    0.000    0.000    0.000    0.000 threading.py:186(__init__)
            5    0.000    0.000    0.005    0.001 threading.py:235(wait)
           10    0.000    0.000    0.000    0.000 threading.py:58(__init__)
           25    0.000    0.000    0.000    0.000 threading.py:63(_note)
           10    0.000    0.000    0.000    0.000 threading.py:826(currentThread)
            5    0.000    0.000    0.000    0.000 {_struct.pack}
            5    0.000    0.000    0.000    0.000 {cPickle.dumps}
            1    0.000    0.000    0.000    0.000 {function seed at 0x0296D270}
         3605    0.001    0.000    0.001    0.000 {getattr}
         3610    0.004    0.000    0.004    0.000 {isinstance}
           16    0.000    0.000    0.000    0.000 {len}
      3600000    0.432    0.000    0.432    0.000 {math.cos}
           20    0.005    0.000    0.005    0.000 {method 'acquire' of 'thread.lock' objects}
            6    0.000    0.000    0.000    0.000 {method 'append' of 'list' objects}
            1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
            5    0.000    0.000    0.000    0.000 {method 'fileno' of '_socket.socket' objects}
            5    0.000    0.000    0.000    0.000 {method 'get' of 'dict' objects}
         1000    0.000    0.000    0.000    0.000 {method 'random' of '_random.Random' objects}
           10    0.000    0.000    0.000    0.000 {method 'release' of 'thread.lock' objects}
            5    0.000    0.000    0.000    0.000 {method 'send' of '_socket.socket' objects}
         3600    0.019    0.000    0.019    0.000 {method 'sum' of 'numpy.ndarray' objects}
            1    0.000    0.000    0.000    0.000 {numpy.core.multiarray.arange}
         3600    0.468    0.000    0.468    0.000 {numpy.core.multiarray.array}
         3605    0.022    0.000    0.022    0.000 {range}
            1    0.000    0.000    0.000    0.000 {round}
            5    0.000    0.000    0.000    0.000 {select.select}
           10    0.000    0.000    0.000    0.000 {thread.allocate_lock}
           25    0.000    0.000    0.000    0.000 {thread.get_ident}
            2    0.000    0.000    0.000    0.000 {time.clock}
    Il y a 3600 pas de temps avec 1000 composantes (ouais c'est pas mal), d'où les 3 600 000 appels à la fonction cosinus.

    Je dois bien avoué que ça ne m'aide pas trop. Je ne cherche pas à faire quelque chose de très rapide, mon interrogation est : est-ce normal ou on peut mieux faire?

    Merci

    EDIT:

    Je viens de voir ton message _Dardamos_. Effectivement avec ton changement le temps calcul est radicalement plus faible!

    Pour ma culture, est-ce que tu saurais pour quelle raison exactement? Sont-ce mes appels aux listes (avec A[i], W[i]...) qui prenaient du temps?

    Merci beaucoup.

    Ju

  5. #5
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 656
    Points : 1 153
    Points
    1 153
    Par défaut
    Le sujet a été abordé ici:

    http://stackoverflow.com/questions/1...mpys-numpy-sum

    Apparement il y a un gain non négligeable à prendre la méthode sum de numpy associée avec un np.array (et non une liste de python). J'ai remplacé dans mon code la construction des amplitudes et phases sur le même principe, et je gagne encore du temps calculs.

    Intéressant.

    Merci beaucoup,

    Ju

  6. #6
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Mars 2007
    Messages
    941
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Mars 2007
    Messages : 941
    Points : 1 384
    Points
    1 384
    Par défaut
    Avec numpy, il faut penser "vectorisation". C'est comme avec Matlab: les boucles explicites sont lentes, les opérations vectorielles sont rapides.

    Avec le code de Dardanos, par exemple, au lieu de 3 600 000 appels à math.cos avec un argument scalaire, il n'y a plus que 3600 appels à np.cos avec un argument vectoriel de taille 1000.

    on peut aller encore plus loin dans la vectorisation:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        if Seed: np.random.seed(Seed)
        T = np.arange(Npoints)
        A = np.array([(2*(S[i+1]+S[i])/2*(W[i+1]-W[i]))**0.5 for i in range(Nlags-1)] + [0.0])
        P = np.random.rand(Nlags) * 2 * np.pi
     
        Wt = np.arange(Npoints).reshape((-1,1)) * W # Wt.shape = (Npoints,Nlags)
        WindVelocities = np.sum(A*np.cos(Wt + P), axis=1) + meanSpeed
    Il n'y a ici qu'un seul appel à np.cos sur un tableau de 3600 x 1000 éléments.

  7. #7
    Membre éprouvé

    Homme Profil pro
    Ingénieur
    Inscrit en
    Août 2010
    Messages
    656
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2010
    Messages : 656
    Points : 1 153
    Points
    1 153
    Par défaut
    Merci beaucoup pour ces précisions dividee.

    Je n'avais jamais songé à ce problème jusqu'à présent, mais je vois déjà de nombreux bouts de codes que je vais pouvoir optimiser.

    Je vois également que tu as opté pour la méthode random de numpy à la place de celle de random, est-ce uniquement afin d'éviter l'importation de deux modules au lieu d'un seul, ou est-ce dans un soucis de compatibilité optimale?


    Merci encore,


    Ju

  8. #8
    Expert éminent
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    3 824
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 3 824
    Points : 7 120
    Points
    7 120
    Par défaut
    Numpy optimise quasiment toutes les fonctions mathématiques, tableaux, ...

    Si tu cherches la vitesse, autant utiliser numpy à toutes les sauces, ça n'en sera que plus efficace.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 4
    Dernier message: 18/11/2010, 20h16
  2. Optimisation de code - somme
    Par Loïc B. dans le forum Fortran
    Réponses: 3
    Dernier message: 20/02/2009, 00h05
  3. Optimiser calcul de somme
    Par Margatthieu dans le forum Langage SQL
    Réponses: 2
    Dernier message: 28/04/2008, 17h56
  4. Optimisation de somme
    Par jeffciara dans le forum Algorithmes et structures de données
    Réponses: 13
    Dernier message: 13/08/2007, 09h27
  5. Réponses: 2
    Dernier message: 25/11/2005, 13h07

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo