Je dois optimiser un morceau de code MATLAB. Le code est simple, mais il fait partie d'une unité de calcul, qui l'appelle ~8000 fois (sans redondance) (cette unité de calcul est utilisée ~10-20K fois dans des cas réels). L'ensemble du code MATLAB est assez long et complexe (pour un physicien comme moi), mais le profileur MATLAB affirme que le segment suivant est responsable de près de la moitié du temps d'exécution ( !).
Le code consiste essentiellement à multiplier par élément chaque permutation de 3 matrices de 3 groupes (A, B, C) et à les additionner avec une certaine pondération. Le groupe A a une seule matrice, le groupe B a 4 matrices et le groupe C en a 7.
J'ai essayé quelques techniques de vectorisation* mais j'ai obtenu au mieux le même temps d'exécution.
À l'aide du profileur MATLAB, j'ai vérifié le temps total passé à chaque ligne (pour les 8 000 appels) - je l'ai écrit dans les commentaires.
for idx_b = 1:4
B_MAT=B_Container_Cell{idx_b};
for idx_c = 1:7
C_MAT = C_Container_Cell{idx_b}(:,:,idx_c); % 60 sec
ACB=A_MAT.*C_MAT.*B_MAT; % 20 sec
Coeff_x = Coeff_x_Cell{idx_b}(p1,p2,idx_c,p3);
Coeff_y = Coeff_y_Cell{idx_b}(p1,p2,idx_c,p3);
Coeff_z = Coeff_z_Cell{idx_b}(p1,p2,idx_c,p3);
Sum_x = Sum_x+Coeff_x.*ACB; % 15 sec
Sum_y = Sum_y+Coeff_y.*ACB; % 15 sec
Sum_z = Sum_z+Coeff_z.*ACB; % 15 sec
end
fin
Quelques connaissances préalables -
A_MAT est une matrice complexe double constante de 1024x1024 définie à l'extérieur de la boucle.
B_MAT est une matrice double de 1024x1024, essentiellement clairsemée (seulement des valeurs 0 et 1, les valeurs 1 représentent ~5% du total des éléments).
C_MAT est un double complexe de 1024x1024
Sum_x/ Sum_y / Sum_z ont été correctement initiés
Coeff_X / Coeff_y / Coeff_z sont des doubles scalaires
p1,p2,p3 sont des paramètres (constants pour ce segment de code)
Quelqu'un sait-il pourquoi l'opération la plus coûteuse est l'affectation des variables ? (J'ai essayé de sauter l'affectation et de remplacer C_MAT directement par son expression, mais cela aggrave les performances).
Tentative de vectorisation
La technique que j'ai essayé est d'utiliser cat, reshape et repmat pour créer 3 matrices 2D géantes, de les multiplier par élément, puis de les superposer (avec reshape) et de les additionner via la dimension correspondante. La première matrice était A répétée 4*7=28 fois, la deuxième était les 4 matrices B répétées 7 fois et la troisième était toutes les matrices C réparties (=28 matrices).
Exemple d'entrée
Le code sur les points suivants enlace génère des exemples de fichiers d'entrée. Le temps d'exécution avec ces variables (sur mon ordinateur) est de ~0.38 sec (le code original+variables ~0.42, la différence à mon avis est due au fait que le conteneur C Cell réel est très grand, donc l'extraction prend plus de temps).