Sommaire
Dans les exemples suivants, nous allons voir l’intérêt de passer par des bibliothèques préconçues, notamment en terme de temps de calcul.
Cas des vecteurs
Pour cet exemple, nous allons nous baser sur les vecteurs suivants :
import numpy as np v_time = np.linspace(0,1,4000) f0 = 100 v_signal = np.sin(2 * np.pi * f0 * v_time)
Ce code génère deux vecteurs v_time et v_signal de 4000 échantillons chacun.
Par le suite, on va chercher à copier une partie des données (les 400 premiers échantillons) vers un autre vecteur.
n_max = 400 v_time_imp = np.zeros(n_max) v_time_mat = np.zeros(n_max)
On définit alors deux nouveaux vecteurs de 400 éléments remplis de 0.
Afin de pouvoir mesurer le temps d’exécution des programmes réalisés, nous allons nous appuyer sur la bibliothèque time de Python. Afin de pouvoir mesurer des temps faibles d’exécution, nous allons réaliser l’opération un certains nombres de fois.
Calcul itératif en Python
On réalise ici l’opération 100 fois.
import time start1 = time.time() for k in range(100): for i in range(n_max): v_time_imp[i] = v_time[i] end1 = time.time() elapsed1 = end1 - start1 print(f'Temps d\'exécution (100 exécutions) : {elapsed1:.8}ms')
Utilisation de la bibliothèque Numpy
On réalise ici l’opération 10 000 fois.
start2 = time.time() for k in range(int(1e4)): v_time_mat[0:n_max] = v_time[0:n_max] end2 = time.time() elapsed2 = end2 - start2 print(f'Temps d\'exécution (10^4 executions) : {elapsed2:.8}ms')
Comparaison
Les deux codes précédents fournissent le résultat suivant (avec un processeur Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz, 32 Go de RAM et sous Windows 10) :
Temps d'exécution (100 exécutions) : 0.0079784393ms Temps d'exécution (10^4 executions) : 0.0069489479ms
On s’aperçoit sur cet exemple simple que le calcul matriciel est environ 100 fois plus performant en terme de temps de calcul (100 exécutions pour le calcul itératif contre 10 000 exécutions pour le calcul matriciel donnant un temps d’exécution entre 7 et 8 us).
Autre exemple / Utilisation d’un meshgrid
Un autre exemple basé sur l’utilisation d’un meshgrid pour la génération de matrices permet d’aboutir à des conclusions similaires.
L’utilisation de boucles en Python (langage interprété) est souvent plus couteux en temps de calcul, contrairement à l’utilisation de bibliothèques (de type Numpy) qui se basent sur des instructions pré-compilées en langage C/C++. L’exécution se base également sur des boucles mais dans un langage compilé et donc plus rapide à l’exécution.
import numpy as np import time N = 2000 sum = 0 x = np.linspace(1,N,N) start_time = time.time() for i in range(1,N): for j in range(1,N): sum = sum + i time_spent_sum_loop = 1000*(time.time() - start_time) XX,XX = np.meshgrid(x,x) start_time = time.time() sum = np.sum(XX) time_spent_sum_np = 1000*(time.time() - start_time) print(f"Loop: {time_spent_sum_loop} ms \nNumPy {time_spent_sum_np} ms") print(f"Numpy is {round(time_spent_sum_loop/time_spent_sum_np)} times faster") start_time = time.time() XX2 = np.zeros((N, N)) for i in range(1,N): for j in range(1,N): XX2[i,j] = XX[i,j]*XX[i,j] time_spent_product_loop = 1000*(time.time() - start_time) start_time = time.time() XX2 = XX*XX time_spent_product_np = 1000*(time.time() - start_time) print(f"Loop: {time_spent_product_loop} ms \nNumPy {time_spent_product_np} ms") print(f"Numpy is {round(time_spent_product_loop/time_spent_product_np)} times faster")