Hi, ich importiere meine Messungen, csv mit einigen Milionen Zeilen, in Matlab. So weit so gut. Um die Messwerte durch einen Filter zu jagen muss ich vorher noch die Zeit "zurechtrücken" und die "messwerte" auf die drei Phasen aufteilen. Das mache ich wie folgt: messwerte = csvread('blabla'); schritte = size(messwerte); null = messwerte(1,1); for i:1:1:schritte(1,1) u(i,1) = messwerte(i,1) - null; u(i,2) = messwerte(i,2); v(i,1) = messwerte(i,1) - null; v(i,2) = messwerte(i,3); w(i,1) = messwerte(i,1) - null; w(i,2) = messwerte(i,4); end; Es klappt alles wunderbar, nur dauert dieses verschieben, die for-Schleife, richtig ewig. Ich kann mir das nicht so ganz erklären. Gibt es da einen Trick wie das schneller geht oder mach ich sogar was falsch?
Das wird schonmal schneller gehen:
1 | for i = schritte(1,1):-1:1 |
2 | u(i,1) = messwerte(i,1) - null; |
3 | u(i,2) = messwerte(i,2); |
4 | v(i,1) = messwerte(i,1) - null; |
5 | v(i,2) = messwerte(i,3); |
6 | w(i,1) = messwerte(i,1) - null; |
7 | w(i,2) = messwerte(i,4); |
8 | end; |
Ansonsten: Bitte richtiges Codebeispiel posten! Das, was dort oben steht wird nicht laufen.
Kopier es ohne Schleife: u = zeros(schritte(1,1), 2); v = zeros(schritte(1,1), 2); w = zeros(schritte(1,1), 2); u(:,1) = messwerte(:,1) - null; u(:,2) = messwerte(:,2); v(:,1) = messwerte(:,1) - null; v(:,2) = messwerte(:,3); w(:,1) = messwerte(:,1) - null; w(:,2) = messwerte(:,4); Wenn null ein Skalar ist, wird dieser automatisch auf einen Vektor erweitert.
Generell sollte man in Matlab versuchen Schleifen so weit es geht zu vermeiden und Dinge anhand von Matrizenoperationen implementieren.
Was für ein Matlab (welches Jahr) benutzt Du eigentlich? Dass Schleifen langsamer laufen als vektorisierter Code konnte ich schon seit ein paar Jahren nicht mehr feststellen. Was genau dauert eigentlich so lange an Deinem Code? Die for-Schleife oder der Aufruf von csvread?
ich benutze die letzten beiden versionen 2009 und 2010. bei beiden das gleiche problem: die for-schleife
profile on; .. dein code .. profile off; profile viewer; Das erste was ich mach wenn was langsam is. Aber stimm natuerlich: Die for Schleife is natuerlich sehr langsam. ;)
Würd mich mal interessieren: Wieviel schneller ist denn jetzt die Version mit dem vektorisierten Code? (hab leider kein Matlab hier)
Ich habs jetzt mal ausprobiert. Vektorisierter Code: %messwerte = csvread('blabla'); Nx = 3000000; messwerte = rand(Nx,4); schritte = size(messwerte); null = messwerte(1,1); u = zeros(Nx,2); v = zeros(Nx,2); w = zeros(Nx,2); tic u(:,1) = messwerte(:,1) - null; u(:,2) = messwerte(:,2); v(:,1) = messwerte(:,1) - null; v(:,2) = messwerte(:,3); w(:,1) = messwerte(:,1) - null; w(:,2) = messwerte(:,4); toc % Elapsed time is 0.149645 seconds. Und der nicht-vektorisierte Code (mit for-Schleife): %messwerte = csvread('blabla'); Nx = 3000000; messwerte = rand(Nx,4); schritte = size(messwerte); null = messwerte(1,1); u = zeros(Nx,2); v = zeros(Nx,2); w = zeros(Nx,2); tic for i=1:1:Nx u(i,1) = messwerte(i,1) - null; u(i,2) = messwerte(i,2); v(i,1) = messwerte(i,1) - null; v(i,2) = messwerte(i,3); w(i,1) = messwerte(i,1) - null; w(i,2) = messwerte(i,4); end; toc % Elapsed time is 0.517368 seconds. Der vektorisierte Code läuft (unter Matlab 2007) also wirklich etwas schneller (immerhin Faktor drei). Hierbei ist mir aufgefallen, dass die Definition von Nx und die Benutzung von Nx als obere Grenze der for-Schleife das Ganze etwa doppelt so schnell laufen lässt, als wenn ich schritte(1,1) also obere Grenze setze. Wichtig ist auf jeden Fall bei for-loops, dass die Matrizen u,v,w vorher mit der entsprechenden Größe angelegt werden. Wenn nicht, wachsen die mit jeder Interation der Loop, und es muss ständig neuer Speicher allokiert werden (mit der entsprechenden Größe), was natürlich sehr lange dauert. Aber gut: Ich hätte nicht gedacht, dass die vektorisierte Form überhaupt nennenswert (>10% oder so) schneller läuft.
Bei meinen auswertungen hat sich mächtig was getan. während es vorher kaum machbar war, tage und wochen. sind die meißten auswertungen jetzt in ein paar stunden erledigt. habe halt richtig viele messwerte, einige millionen.
Einige Millionen sind eigentlich nicht wirklich viel. Falls Du feststellen solltest, dass bei Deinen Berechnungen die Festplatte heftig rattert, bedeutet das, dass Du nicht genug Speicher hast, um alles gleichzeitig zu laden (die Festplatte swappt). Dann solltest Du nach Möglichkeit scheibchenweise vorgehen, also z.B. eine Million Daten nach der anderen prozessieren. Tage und Wochen sollten so nicht vorkommen.
Auch eine gaaanz böse Falle bei Matlab: Vektoren dynamisch wachsen lassen. Dabei muss jedesmal der Speicher freigegeben werden und neu allokiert werden. Wenn das mal in den MiB-Bereich geht, wirds extrem langsam! deshalb immer mit x = zeros() vorbelegen, wenn möglich.
Nananan jetzt nicht gleich den Teufel an die Wand malen. Jedesmal speicher allokieren und dann wieder frei geben is auch nicht rightig. Jemand der ne Algorithmenvorlesung besucht hat weis das man normal den Speicher immer verdoppelt um eine Amortisierte Laufzeit von O(1) zu bekommen. So ist es AFAIK auch in der STL implementiert. Klar is das allokierten davor um Welten besser allerding ist es jetzt nicht so das eine Element jedes mal ein realloc triggert.
Wir reden hier nicht von C oder C++, sondern von Matlab! Das Vorbelegen ist explizit in der Doku erwähnt und bei größeren Datensätzen kann man sonst wirklich zuschauen, wie lange ein Schleifendurchlauf braucht! (Nein, ich habe keine Algorithmenvorlesung besucht: Was ist einen "Amortisierte Laufzeit" und wie passt das mit O(1) zusammen?)
MATLAB ist aber in C/C++ implementiert. (Auser der GUI die ist in Java...) http://en.wikipedia.org/wiki/Amortized_analysis "As a simple example, in a specific implementation of the dynamic array, we double the size of the array each time it fills up. Because of this, array reallocation may be required, and in the worst case an insertion may require O(n). However, a sequence of n insertions can always be done in O(n) time, because the rest of the insertions are done in constant time, so n insertions can be completed in O(n) time. The amortized time per operation is therefore O(n) / n = O(1)."
Ich wuerd mal auf eine ineffiziente Stringread- oder Stringconvert operation tippen...
Wie dem auch sei, die messbare Performance sagt (mit Matlab 2006b), dass dieser Algorithmus nicht zum Einsatz kommt und ein initiales Anlegen des Arrays richtig was bringt. So gesehen bin ich froh, diese Vorlesung nicht besucht zu haben, weil dann wäre ich der Meinung, dass dynamische Arrays quasi nichts kosten.
Der Zusammenhang mit dem Matlab-internen Just-In-Time-Compiler, der Matlab-Code seit einigen Jahren gerade auch bei for-Schleifen beschleunigt, ist auch etwas schwierig. Scheinbar wird der JIT-Compiler bei solchen for-loops nur angeworfen, wenn die for-loop in einer Matlab-Function auftaucht, oder wenn sie eben keine dynamisch wachsenden Arrays hat. Siehe z.B. http://www.scholarpedia.org/article/MATLAB unter dem Abschnitt "Interpretation, just-in-time compilation, and performance". Hier wird eine for-Schleife gezeigt, die 1.5*0.018469s (etwa 0.025s) braucht, wenn sie in einem m-file steht und in der keine dynamischen Arrays auftauchen, gegenüber einer for-Schleife, die 34.178847s braucht, in der dynamische Arrays drinstehen. Also ein Unterschied vom Faktor 1000. Mag aber immer noch O(1) (auch wenn ich es nicht glaube) sein - der Zusammenhang mit der Größe des Arrays wurde nicht untersucht.
Auch wenn diese Frage schon uralt ist, falls einer das selbe Problem hat, dann liegt das einfach daran, dass die Vektoren u, v, w vom Fragensteller nicht initialisiert wurden! Bei einigen der gegebenen Antworten aber schon! Wenn man bspw. den Vektor u nicht initialisiert, so wird intern u beim ersten Schleifendurchgang als Skalar betrachtet, beim zweiten Durchgang wird dann u zu einem Vektor mit 2 Einträgen. Damit dies aber funktioniert wird Matlab neuen Speicher anfordern, das alte u in das neue u kopieren und zusätzlich den neuen Messwert ablegen. Jetzt kann man sich denken, dass genau dieser Prozess des Speicher anforderns, alten Vektor kopieren und neuen Messwert ablegen bei hohen Schleifendurchgängen immens dauern wird. Das wird das Problem gewesen sein, dem der Fragensteller gegenüber gestanden hat. Also: u,v,w mit den Dimensionen der Messwerte initialisieren! Dann wird von vorn herein der richtige Speicherbedarf bereitgestellt und es müssen nur noch die Werte reingeschrieben werden. Kein Anfragen nach neuem Speicher und auch kein rumkopieren des alten Vektors in den aktuellen.
Das sagt einem doch sogar der Editor (gelbe Dreiecke mit entsprechenden Tips). Generell siehe Matlab Best practices: http://blogs.mathworks.com/loren/2012/01/13/best-practices-for-programming-matlab/ und https://www.google.at/url?sa=t&source=web&rct=j&url=https://www.kellogg.northwestern.edu/rc/docs/gmpp.pdf&ved=0ahUKEwiVyPfVrpfRAhURYFAKHVy6CRAQFggaMAA&usg=AFQjCNGkFhdnNthrDrJXJQoD-bLAjNxMyw
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.