Forum: Digitale Signalverarbeitung / DSP / Machine Learning Matlab: warum dauert das so lange?


von Benni N. (benninori)


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?

von Walter T. (nicolas)


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.

von Sebastian (Gast)


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.

von Benni N. (benninori)


Lesenswert?

super, danke für die hilfe. das probier ich gleich aus.

von Andreas A. (Firma: Embedded Microtec) (andi) Flattr this


Lesenswert?

Generell sollte man in Matlab versuchen Schleifen so weit es geht zu 
vermeiden und Dinge anhand von Matrizenoperationen implementieren.

von Michael (Gast)


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?

von benninori (Gast)


Lesenswert?

ich benutze die letzten beiden versionen 2009 und 2010. bei beiden das 
gleiche problem: die for-schleife

von Anon N. (fuechslein)


Lesenswert?

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. ;)

von Michael (Gast)


Lesenswert?

Würd mich mal interessieren: Wieviel schneller ist denn jetzt die 
Version mit dem vektorisierten Code? (hab leider kein Matlab hier)

von Michael (Gast)


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.

von Benni N. (benninori)


Lesenswert?

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.

von Michael (Gast)


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.

von Karl (Gast)


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.

von Anon N. (fuechslein)


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.

von Karl (Gast)


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?)

von Anon N. (fuechslein)


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)."

von Purzel H. (hacky)


Lesenswert?

Ich wuerd mal auf eine ineffiziente Stringread- oder Stringconvert 
operation tippen...

von Karl (Gast)


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.

von Michael (Gast)


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.

von Fred (Gast)


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.

von Michael W. (Gast)


Lesenswert?

Das nenne ich mal einen guten Tipp!!

von Jan K. (jan_k)


Lesenswert?


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
Noch kein Account? Hier anmelden.