Matlab: warum dauert das so lange?

OP #1707220
Lesenswert?

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?
#1707224
Lesenswert?

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.
Gast #1707237
Lesenswert?

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.
Gast #1707863
Lesenswert?

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?
Gast #1708292
Lesenswert?

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.
Gast #1709305
Lesenswert?

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.
Gast #1710539
Lesenswert?

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.
#1710917
Lesenswert?

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.
Gast #1710933
Lesenswert?

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?)
#1711157
Lesenswert?

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)."
Gast #1711702
Lesenswert?

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.
Gast #1712316
Lesenswert?

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.
Gast #4829992
Lesenswert?

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.
#4843584
Lesenswert?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren