Leitfaden zur Optimierung von MATLAB-Code

8

Ich habe viele individuelle Fragen zu SO bemerkt, aber keine gute Anleitung zur MATLAB-Optimierung.

Häufige Fragen:

  • Optimiere diesen Code für mich
  • Wie vektorisiere ich das?

Ich glaube nicht, dass diese Fragen aufhören werden, aber ich hoffe, dass die hier vorgestellten Ideen ihnen etwas Zentrales an die Hand geben werden.

Die Optimierung von Matlab-Code ist eine Art Schwarzkunst, es gibt immer einen besseren Weg, dies zu tun. Und manchmal ist es einfach unmöglich, Ihren Code zu vektorisieren.

Meine Frage ist also: Wenn die Vektorisierung unmöglich oder extrem kompliziert ist, was sind Ihre Tipps und Tricks, um den MATLAB-Code zu optimieren? Auch wenn Sie irgendwelche üblichen Vektorisierungstricks haben, hätte ich nichts dagegen, sie zu sehen.

    
Samuel O'Malley 01.11.2013, 07:20
quelle

1 Antwort

14

Vorwort

Alle diese Tests werden auf einer Maschine ausgeführt, die mit anderen geteilt wird, so dass es keine vollkommen saubere Umgebung ist. Zwischen den einzelnen Tests lösche ich den Arbeitsbereich, um Speicher freizugeben.

Bitte achten Sie nicht auf die einzelnen Zahlen, schauen Sie sich nur die Unterschiede zwischen den Vorher- und Nachheroptimierungszeiten an.

Hinweis: Die Aufrufe von tic und toc , die ich in den Code eingegeben habe, zeigen an, wo ich die Zeit gemessen habe.

Vorbelegung

Die einfache Vorbelegung von Arrays in Matlab kann einen enormen Geschwindigkeitsvorteil bieten.

%Vor%

Dies dauert 47 Sekunden

%Vor%

Dies dauert 0.1018 Sekunden

47 Sekunden bis 0,1 Sekunden für eine einzelne hinzugefügte Codezeile ist eine erstaunliche Verbesserung. Offensichtlich in diesem einfachen Beispiel könnten Sie es in my_array = 5 * 1:100000 vektorisieren (das 0,000423 Sekunden nahm), aber ich versuche, die komplizierteren Zeiten darzustellen, als Vektorisierung keine Wahl ist.

Ich habe kürzlich festgestellt, dass die Nullenfunktion (und andere der gleichen Art) bei der Vorbelegung nicht so schnell sind wie einfach den letzten Wert auf 0 setzen:

%Vor%

Dies dauert 0.0991 Sekunden

Offensichtlich beweist dieser kleine Unterschied nicht viel, aber Sie müssen mir über eine große Datei glauben, mit vielen dieser Optimierungen wird der Unterschied viel offensichtlicher.

Warum funktioniert das?

Die Methoden vor der Zuweisung weisen Ihnen einen Teil des Arbeitsspeichers zu, mit dem Sie arbeiten können. Dieser Speicher ist zusammenhängend und kann wie ein Array in C ++ oder Java vorab abgerufen werden. Wenn Sie jedoch keine Vorbelegung vornehmen, muss MATLAB dynamisch mehr Speicher für die Verwendung finden. Wie ich es verstehe, verhält sich das anders als eine Java ArrayList und ähnelt mehr einer LinkedList, bei der verschiedene Teile des Arrays überall im Speicher aufgeteilt sind.

Das ist nicht nur langsamer, wenn Sie Daten darauf schreiben (47 Sekunden!), sondern es ist auch langsamer, wenn Sie von nun an darauf zugreifen. In der Tat, wenn Sie absolut nicht vor-reservieren können, dann ist es immer noch sinnvoll, Ihre Matrix auf eine neue vor-zugewiesenen zu kopieren, bevor Sie es verwenden.

Was passiert, wenn ich nicht weiß, wie viel Speicherplatz zuzuweisen ist?

Dies ist eine häufige Frage und es gibt ein paar verschiedene Lösungen:

  1. Überschätzung - Es ist besser, die Größe Ihrer Matrix grob zu überschätzen und zu viel Speicherplatz zuzuweisen, als Speicherplatz zu unterzuordnen.
  2. Behandle es und repariere es später - Ich habe das oft gesehen, wo der Entwickler die langsame Populationszeit in Kauf genommen hat, und dann die Matrix in einen neuen vorher zugewiesenen Bereich kopiert. Normalerweise wird dies als .mat -Datei oder ähnlich gespeichert, damit es zu einem späteren Zeitpunkt schnell gelesen werden kann.

Wie ordne ich eine komplizierte Struktur vorab zu?

Die Zuweisung von Speicherplatz für einfache Datentypen ist einfach, wie wir bereits gesehen haben, aber was ist, wenn es sich um einen sehr komplexen Datentyp handelt, wie zum Beispiel eine Struktur von Strukturen?

Ich könnte nie daran arbeiten, diese explizit vorzubelegen (ich hoffe, dass jemand eine bessere Methode vorschlagen kann), also kam ich auf diesen einfachen Hack:

%Vor%

Dies dauert 1,5 Minuten

%Vor%

Dies dauert 6 Sekunden

Dies ist offensichtlich keine perfekte Vorbelegung, und es dauert eine Weile, das Array danach umzudrehen, aber die Zeitverbesserungen sprechen für sich. Ich hoffe, dass jemand einen besseren Weg hat, dies zu tun, aber das ist in der Zwischenzeit ein ziemlich guter Hack.

Datenstrukturen

In Bezug auf die Speichernutzung ist ein Array von Structs um Größenordnungen schlechter als ein Struct of Arrays:

%Vor%

Verwendet 624 Bytes

%Vor%

Verwendet 384 Bytes

Wie Sie sehen, verwendet das Array of Structs selbst in diesem einfachen / kleinen Beispiel viel mehr Speicher als das Struct of Arrays. Auch das Struct of Arrays ist in einem nützlicheren Format, wenn Sie die Daten plotten möchten.

Jedes Struct hat einen großen Header, und wie Sie sehen können, wiederholt ein Array von Strukturen diesen Header mehrfach, wobei die Struktur von Arrays nur den einen Header hat und daher weniger Platz benötigt. Dieser Unterschied ist bei größeren Arrays offensichtlich.

Datei liest

Je weniger freads (oder ein anderer Systemaufruf) in Ihrem Code hat, desto besser.

%Vor%

Der vorherige Code ist viel langsamer als der folgende:

%Vor%

Sie denken vielleicht, dass das offensichtlich ist, aber das gleiche Prinzip kann auf kompliziertere Fälle angewendet werden:

%Vor%

Dieses Problem ist nicht mehr so ​​einfach, weil die Floats im Speicher so dargestellt werden:

%Vor%

Sie können jedoch den Wert skip von fread verwenden, um die gleichen Optimierungen wie zuvor zu erreichen:

%Vor%

Also wurde das Lesen dieser Datei mit zwei fread s anstelle von 200 durchgeführt, eine massive Verbesserung.

Funktionsaufrufe

Ich habe kürzlich an Code gearbeitet, der viele Funktionsaufrufe verwendet hat, die alle in separaten Dateien gespeichert waren. Also sagen wir, es gab 100 verschiedene Dateien, die sich gegenseitig angerufen haben. Indem ich diesen Code in eine Funktion "einfügte", sah ich eine 20% ige Verbesserung der Ausführungsgeschwindigkeit von 9 Sekunden.

Natürlich würden Sie das nicht auf Kosten der Wiederverwendbarkeit tun, aber in meinem Fall wurden die Funktionen automatisch generiert und überhaupt nicht wiederverwendet. Aber wir können immer noch daraus lernen und übermäßige Funktionsaufrufe vermeiden, wo sie nicht wirklich gebraucht werden.

Externe MEX-Funktionen verursachen einen Overhead für den Aufruf. Daher ist ein Aufruf an eine große MEX-Funktion viel effizienter als viele Aufrufe an kleinere MEX-Funktionen.

Plotten vieler getrennter Linien

Wenn Sie getrennte Daten wie eine Reihe von vertikalen Linien zeichnen, besteht die traditionelle Vorgehensweise in Matlab darin, mehrere Aufrufe an line oder plot mit hold on zu wiederholen. Wenn Sie jedoch eine große Anzahl einzelner Linien zeichnen müssen, wird dies sehr langsam.

Die Technik, die ich gefunden habe, verwendet die Tatsache, dass Sie NaN -Werte in die zu plottenden Daten einfügen können und es zu einem Bruch in den Daten kommt.

Das unten beschriebene Beispiel konvertiert eine Menge von x_values, y1_values ​​und y2_values ​​(wobei die Zeile von [x, y1] zu [x, y2] ist) in ein Format, das für einen einzelnen Aufruf von plot geeignet ist.

Beispiel:

%Vor%

Ich habe diese Methode verwendet, um Tausende winziger Linien zu drucken, und die Leistungsverbesserungen waren immens. Nicht nur im ersten Plot, sondern auch in der Durchführung nachfolgender Manipulationen wie Zoom- oder Pan-Operationen.

    
Samuel O'Malley 06.10.2017, 05:17
quelle

Tags und Links