2016-05-04 14 views
3

Ich muss ein Stück MATLAB Code optimieren. Der Code ist einfach, aber er ist Teil einer Berechnungseinheit, die ihn ~ 8000 mal aufruft (ohne Redundanz) (Diese Berechnungseinheit wird in realen Fällen ~ 10-20K mal verwendet). Der gesamte MATLAB-Code ist ziemlich lang und komplex (für einen Physiker, wie ich), aber MATLAB Profiler behauptet, dass das folgende Segment für fast die Hälfte der Laufzeit (!) Verantwortlich ist.MATLAB Matrix Element weise Multiplikationsoptimierung

Der Code multipliziert grundsätzlich elementar jede Permutation von 3 Matrizen aus 3 Gruppen (A, B, C) und summiert sie mit einer gewissen Gewichtung. Gruppe A hat eine einzige Matrix, Gruppe B hat 4 Matrizen und Gruppe C hat 7.

Ich habe versucht, einige Vektorisierungstechniken * noch bestenfalls die gleiche Laufzeit zu bekommen.

Mit dem MATLAB Profiler habe ich die Gesamtzeit überprüft, die für jede Zeile aufgewendet wurde (für alle 8000 Aufrufe) - ich habe diese in Kommentare geschrieben.

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 

Ende

Vorkenntnissen -
A_MAT ist 1024x1024 komplexe Doppel konstante Matrix ouside der Schleife
B_MAT definiert ist 1024x1024 Doppelmatrix, im wesentlichen sparse (nur 0 und 1-Werte, sind solche, ~ 5 % von gesamt-Elemente)
C_MAT ist 1024x1024 komplexe Doppel

Sum_x/Sum_y/Sum_z richtig
initiiert wurden Coeff_X/Coeff_y/Coeff_z sind Doppelskalare
p1, p2, p3 sind Parameter (Konstante für dieses Codesegment)

Weiß jemand, warum die aufwendigste Operation ist variable Zuweisung? (Ich habe versucht, die Zuordnung zu überspringen und ersetzen C_MAT direkt mit seinem Ausdruck, aber es verschlechtert die Leistung)


Vektorisierung Versuch
Die techique I versuchte Katze zu verwenden, neu zu gestalten und repmat 3 zu erstellen Riese 2D-Matrizen, multipliziere diese elementweise und lege dann alles (mit Umformen) übereinander und summiere über die relevante Dimension. Die erste Matrix war A wiederholt 4 · 7 = 28 mal, die zweite war die 4 B-Matrizen, die 7 mal wiederholt wurden und die dritte war alle C-Matrizen überspannt (= 28 Matrizen).


Probeneingang
der Code auf den folgenden link erzeugen Probeneingabedateien. Die Laufzeit mit diesen Variablen (auf meinem Computer) ist ~ 0,38 sec (der ursprüngliche Code + Variablen ~ 0,42, der Unterschied ist meiner Meinung nach, weil der echte C-Cell-Container sehr groß ist, so dauert die Extraktion mehr Zeit)

+4

'*' Betrieb kommutativ (im Gegensatz zu '*' Matrix multiplizieren), so dass man 'A_MAT * B_MAT' außerhalb der inneren Schleife durchführen kann. –

+0

@BenVoigt ändert sich nicht viel die Leistung. – Alexander

+0

Sie verweisen auf Vektorisierungstechniken in Ihrer Frage, was haben Sie versucht? – BillBokeey

Antwort

2

Vorausgesetzt, dass die Arrays in den Eingangszellenarrays identische Größen haben, könnte es eine bessere Idee sein, die Eingänge als mehrdimensionale Arrays anstelle von Zellenarrays zu speichern, um die vektorisierten Techniken von MATLAB zu nutzen, die in diesem Fall zum Extrahieren indexing10 wären Elemente und matrix-multiplication für die Summenreduktion. Wenn wir also die Eingänge bilden, könnten wir nach mehrdimensionalen Feldern suchen, die den Eingaben entsprechen: , C_Container_Cell, 10, Coeff_y_Cell und Coeff_z_Cell.Nun sind dies 1D Zellenarrays mit B_Container_Cell, die 2D Arrays und Rest 3D Arrays enthalten. Somit würden wir bei Verwendung von mehrdimensionalen Arrays diese als eine zusätzliche Dimension haben, d. H. Sie wären bzw. 4D Arrays.

Um ihre mehrdimensionale Array-Formate zu simulieren, lassen Sie uns die gegebenen Zellenanordnungen mit Verkettung, wie so mit cat entlang ihrer last+1 Dimension konvertieren -

Bm = cat(3,B_Container_Cell{:}); 
Cm = cat(4,C_Container_Cell{:}); 

Cx = cat(4,Coeff_x_Cell{:}); 
Cy = cat(4,Coeff_y_Cell{:}); 
Cz = cat(4,Coeff_z_Cell{:}); 

Schließlich ist die vektorisiert Lösung zu verwenden, um diese multidimensionalen Arrays und erhalten die gewünschten Ausgänge -

%// Get ACB across all iterations and reshaped into (Nx28) shaped array 
Ar = reshape(bsxfun(@times,bsxfun(@times,Cm,permute(Bm,[1,2,4,3])),A_MAT),[],28); 

%// Use matrix-multiplication to sum reduce sliced versions of Cx, Cy and 
%// Cz, to get respectived summed outputs 
sz = size(A_MAT); %// Output array size 
Sum_x_out = reshape(Ar*reshape(Cx(p1,p2,:,:),[],1),sz); 
Sum_y_out = reshape(Ar*reshape(Cy(p1,p2,:,:),[],1),sz); 
Sum_z_out = reshape(Ar*reshape(Cz(p1,p2,:,:),[],1),sz); 

Bitte beachten sie, dass es nicht wie der Parameter sieht p3 verwendet wurde.

Runtime Testergebnisse (für gelistete Probeneingänge) -.

--------------------------------- With Original Approach 
Elapsed time is 2.412417 seconds. 
--------------------------------- With Proposed Approach 
Elapsed time is 1.572035 seconds. 
+0

Das Speichern der Matrizen in multidimensionalen Arrays hat viel Zeit gespart (selbst bei doppelter Schleifenstruktur). Ich werde auch die Vektorisierung versuchen, obwohl Sie zu Recht das Kopfgeld verdient haben (ich kann es noch nicht vergeben, bis vor 24 Stunden, nachdem ich das Kopfgeld eingestellt habe) – Alexander

+0

@Alexander Keine Eile. Stellen Sie sicher, dass es funktioniert und effizient genug für Sie ist. Außerdem würde ich gerne von den Laufzeitnummern des vektorisierten Ansatzes gegen die Doppelschleifenstruktur hören. – Divakar

+0

Es ist ziemlich witzig, dass jede vektorisierte Version immer mindestens 20% langsamer ist. Auch nach mehr Änderung der Struktur der Variablen zur Optimierung der Speicherauslastung für bsxfun - es war noch langsamer. Dieses Stück Code sollte doppelt geloopt werden. – Alexander