WICHTIG: Der Betrieb von goMatlab.de wird privat finanziert fortgesetzt. - Mehr Infos...

Mein MATLAB Forum - goMatlab.de

Mein MATLAB Forum

 
Gast > Registrieren       Autologin?   

Partner:




Forum
      Option
[Erweitert]
  • Diese Seite per Mail weiterempfehlen
     


Gehe zu:  
Neues Thema eröffnen Neue Antwort erstellen

efiizienterer Code -> Vektorisierung??

 

Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 29.09.2012, 14:35     Titel: efiizienterer Code -> Vektorisierung??
  Antworten mit Zitat      
Hallo,
ich bin neu hier im Forum. Ich habe schon vergeblich das Forum durchstöbert um Lösungen für mein Problem zu finden. Ich will meinen Code irgendwie effizienter machen, doch habe ich absolut keine Idee. Das Problem ist, dass ich in meiner Matlab Simulation mit ziemlich großen Daten umgehen muss... Bei meinem derzeitigen Stand braucht mein Programm mehrere Stunden bis es komplett duchgelaufen ist, der Grund hierfür liegt in dieser Funktion:

Code:

function [ y_predict ] = kernelregression( x_train,y_train,x_predict, h)
% REGRESSION construct regression estimate by using the Nadaraya Watson
% kernel estimate
%   We are using as a kernel function the Gaussian kernel with bandwidth h,
%   which is choosen datadependent by "Splitting the Sample"

SizeOfX = size(x_train,1);
n=size(x_predict,1);
d=size(x_predict,2);

% eigebtlich darf dass nur nx1 sein...
[y_predict]=ones(n,1);

% y_train ist immer Spaltenvektor, egal ob d=5 oder d=1!

if(d==1)
    for i=1:n
   
        %  copy every single entry of x_predict into an own vector for easier
        % handling
        x_predict_vector = repmat(x_predict(i,:),SizeOfX,1);
     
        % Kernel Function: Gaussian kernel
        K = exp((- norm((x_predict_vector - x_train)/ h).^2)/2);
                   
        % regression estimate y_predict is a vector in which every entry
        % represents a value of an estimate of the corresponding entry in
        % x_predict
        if (K==0)
            y_predict(i)=0;
        else
            y_predict(i) = sum(K.*y_train)/ K;
        end
    end
   
else
    K=0;
    for i=1:n
       
         x_predict_vector = repmat(x_predict(i,:),SizeOfX,1);
         A=(x_predict_vector - x_train)/ h;
         
        for j=1:SizeOfX
            % Kernel Function: Gaussian kernel
             K=K+exp((-norm(A(j,:)).^2)/2);
        end
       
        if (K==0)
            y_predict(i)=0;
        else
            y_predict(i) = sum(K.*y_train)/ K;
        end
       
    end


end
end
 


Gibt es hier eine Möglichkeit dies schneller zu bekommen, eventuel mit besserer Vektorisierung? Ich weiß leider nicht, wie ich diese for-Schleifen umgehen kann. Da ich leider ein absoluter Anfänger in Matlab bin, brauche ich dringend eure Hilfe...

Vielen dank schon einmal...


Harald
Forum-Meister

Forum-Meister


Beiträge: 24.501
Anmeldedatum: 26.03.09
Wohnort: Nähe München
Version: ab 2017b
     Beitrag Verfasst am: 29.09.2012, 15:44     Titel:
  Antworten mit Zitat      
Hallo,

kannst du einen Beispielaufruf posten? Benötigt ein einzelner Aufruf dieser Funktion so lange, oder wird sie sehr oft aufgerufen?

Mit dem Profiler solltest du zudem innerhalb der Funktion feststellen können, welcher Teil besonders lange dauert.

Ist das "k=0" an der richtigen Stelle, oder sollte das nicht eher innerhalb der i-Schleife sein?

Grüße,
Harald
Private Nachricht senden Benutzer-Profile anzeigen
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 29.09.2012, 16:11     Titel:
  Antworten mit Zitat      
Also K=0 müsste an der richtigen Stelle stehen, da ich es nur am Anfang einmal 0 setzten möchte, damit ich die Aufzählung K=K+... machen kann. Auch ein Beispielauffuf ist eher schwierig, da das ein Teil der Monte Carlo Simulation zur Bewertung von amerikanischen Optionen ist und aus 5 zusätzlichen Funktionen besteht. Die Funktion wird sehr oft aufgerufen. Also es ist schon normal, dass die komplette Auswertung so ca 20 Minuten dauern kann.

Ich kann dir aber gerne mal die Größe der Eingabevariablen geben:
x_predict ist entweder 12000x1 oder 12000x5 groß
x_train 2000x1 oder 2000x5
y_train 2000x1
h Skalar

Meine Frage ist, ob ich die for-Schleifen umgehen kann um das Ganze effizienter zu gestalten. Falls es etwas helfen sollte kann auch mal die anderen Funktionen posten oder dir zukommen lassen.
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 29.09.2012, 16:14     Titel:
  Antworten mit Zitat      
Christina hat Folgendes geschrieben:
Also es ist schon normal, dass die komplette Auswertung so ca 20 Minuten dauern kann.

Im besten Fall, aber so wie es hier ist, dauert es ca 1 stunde für den Fall d=1 (x_train und x_predict eindimensional) und für den Fall das d=5 dauert es mit Sicherheit um die 10Stunden...
Und ich glaube nicht, dass das normal ist und nicht schneller mit einer besseren Implementierung geht
 
Sirius3
Forum-Guru

Forum-Guru


Beiträge: 441
Anmeldedatum: 12.11.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 29.09.2012, 18:40     Titel:
  Antworten mit Zitat      
Hallo Christina,

wenn ich nur mal die for-Schleife für d=1 anschaue, versteh ich so einiges nicht:
Code:

        %  copy every single entry of x_predict into an own vector for easier
        % handling
        x_predict_vector = repmat(x_predict(i,:),SizeOfX,1);
%%% Warum soll x_prefict in einem Vektor stehen, mit einem Skalar läßt
%%% sich doch viel einfacher rechnen
     
        % Kernel Function: Gaussian kernel
        K = exp((- norm((x_predict_vector - x_train)/ h).^2)/2);
%%% norm ist schon die Wurzel der Summe aller quadrierten Vektorelemente
%%% h läßt sich auch ausklammern:
        x_predict_skalar = x_predict(i);
        K = exp(-(0.5/h)*sum((x_predict_skalar - x_train).^2));
                   
        % regression estimate y_predict is a vector in which every entry
        % represents a value of an estimate of the corresponding entry in
        % x_predict
        if (K==0)
            y_predict(i)=0;
        else
            y_predict(i) = sum(K.*y_train)/ K;
%%% Wozu das denn nun? K ist ein Skalar. Also läßt sich K wunderbar wegkürzen:
            y_predict(i) = sum(y_train);
        end
%%% Damit läßt sich die Frage ob K=0 ist viel einfacher beantworten:
%%% Genau dann wenn alle Elemente von x_train==x_predict_skalar sind.
 


Grüße
Sirius
Private Nachricht senden Benutzer-Profile anzeigen
 
Harald
Forum-Meister

Forum-Meister


Beiträge: 24.501
Anmeldedatum: 26.03.09
Wohnort: Nähe München
Version: ab 2017b
     Beitrag Verfasst am: 29.09.2012, 19:57     Titel:
  Antworten mit Zitat      
Hallo,

ich bekomme da Zweifel, dass der ursprüngliche Code stimmt.

Mal von dem K=0 abgesehen: wozu wird K berechnet, wenn es (wie von Sirius gesagt) gar nicht gebraucht wird?

Im zweiten Teil kann man die innere for-Schleife so weglassen:
Code:
K = K + sum(exp(-sum(A.^2,2))/2);


Grüße,
Harald
Private Nachricht senden Benutzer-Profile anzeigen
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 01.10.2012, 09:34     Titel:
  Antworten mit Zitat      
vielen Dank für eure Antworten. Also in dem zweiten Fall, wenn d=5 ist, soll quasi jede Zeile als einzelner Vektor genommen werden, davon dann die euklidische Länge berechnet und diese dann aufaddiert werden. Stimmt das dann damit überein:
Code:

K = K + sum(exp(-sum(A.^2,2))/2);

Klar müsste es ja eigentlich, denn ^2 hebt die Wurzel auf und somit bleibt nur übrog das jeder Eintrag quadiert wird, richtig?!

so wie es da steht stimmt es, dass k sich weg kürzt, das darf es aber eigentlich nicht, habe mir noch einmal meine ursprüngliche Gleichung angesehen und werde es noch einmal verändern müssen.

Sirius, also ich habe das Skalar deshalb in einen Vektor kopiert, weil ich dachte es macht den Umgang damit in Matlab schneller, und außerdem hatte ich zuerest vor zwischen d=1 und d=5 nicht zu unterscheiden, sondern den Code so zu schereiben, dass er mit beidem umgehen kann. Habe es aber dann doch erst einmal anders gemacht und somit ist das noch ein Überbleibsel.

Wenn ich im zweiten Teil die for Schleife weg lassen kann, dann brauch ich K auch nicht hochzählen und am Anfang Null setzten. Das stimmt doch so oder?
 
Harald
Forum-Meister

Forum-Meister


Beiträge: 24.501
Anmeldedatum: 26.03.09
Wohnort: Nähe München
Version: ab 2017b
     Beitrag Verfasst am: 01.10.2012, 10:37     Titel:
  Antworten mit Zitat      
Hallo,

Zitat:
Klar müsste es ja eigentlich, denn ^2 hebt die Wurzel auf und somit bleibt nur übrog das jeder Eintrag quadiert wird, richtig?!


Im Zweifelsfall würde ich das an einem Beispiel testen, ob (zumindest annähernd) das gleiche herauskommt.

Zitat:
ich habe das Skalar deshalb in einen Vektor kopiert, weil ich dachte es macht den Umgang damit in Matlab schneller,

Wäre mir neu Smile

Zitat:
Wenn ich im zweiten Teil die for Schleife weg lassen kann, dann brauch ich K auch nicht hochzählen und am Anfang Null setzten.

Das hängt davon ab, wo K auf 0 gesetzt wird.
So, wie der Code momentan dasteht, brauchst du das weiterhin.
Wenn K nur innerhalb der Schleife auf 0 gesetzt wird, brauchst du es nicht.

Grüße,
Harald
Private Nachricht senden Benutzer-Profile anzeigen
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 01.10.2012, 12:14     Titel:
  Antworten mit Zitat      
Zitat:
Code:
K = K + sum(exp(-sum(A.^2,2))/2);

Wenn ich aber anstatt dem, das schreibe:

Code:
K = sum(exp(-sum(A.^2,2))/2);


kann ich k=0 weglassen, denn ich muss es ja jetzt nicht mehr hoch zählen.

Ich habe aber mal mein Problem, dass sich k weg kürzt behoben:

Code:
x_predict_vector = x_predict(i);
     
        %compute the weights of y_i with the Gaussian Kernel Function

        for j=1:SizeOfX
            W(j)= (exp(-(0.5/h)*(x_predict_vector - x_train(j,:)).^2))/...
                sum(exp(-(0.5/h)*sum((x_predict_vector - x_train).^2,2)));
        end


        if (W==0)
            y_predict(i)=0;
        else
            y_predict(i) = sum(W.*y_train);
        end

 


habe vorher übersehen, dass k im bruch nciht die summe aller k ist, sondern nur k an der stelle x_i.

jedoch habe ich noch eine Frage,

es wurde ja geschrieben, weil h eine konstante ist, konne man es raus nehmen aus der norm, müsste es aber dann nicht quadiert sein, also müsste dann icht der term:

Code:
K = exp(-(0.5/h)*sum((x_predict_skalar - x_train).^2));

anstatt von (0.5/h) nicht (0.5/h^2) sein? denn ||h||^2= sqrt(h^2)^2 oder nicht?
 
Harald
Forum-Meister

Forum-Meister


Beiträge: 24.501
Anmeldedatum: 26.03.09
Wohnort: Nähe München
Version: ab 2017b
     Beitrag Verfasst am: 01.10.2012, 13:11     Titel:
  Antworten mit Zitat      
Hallo,

Zitat:
müsste dann icht der term anstatt von (0.5/h) nicht (0.5/h^2) sein?
ja, muss es wohl.

Solche Dinge lassen sich ja aber auch leicht überprüfen, indem man die Funktion für mehrere Code-Varianten durchlaufen lässt und die Ergebnisse vergleicht. Natürlich nicht unbedingt mit h = 1 Wink

Falls du noch irgendwo Hilfe brauchst, bitte genau angeben wo.

Grüße,
Harald
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 01.10.2012, 13:19     Titel:
  Antworten mit Zitat      
Hallo Christina,

Die konstanten Terme sollten unbedingt aus der Schleife gezogen werden:
Code:
x_predict_vector = x_predict(i);
c = sum(exp(-(0.5/h)*sum((x_predict_vector - x_train).^2, 2)));
for j=1:SizeOfX
   W(j)= exp((0.5/h)*(x_train(j,:) - x_predict_vector).^2) / c;
end

Nun kommt "if (W==0)", aber W ist ein Vektor. Meinst du "if all(W == 0)"?

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 01.10.2012, 13:52     Titel:
  Antworten mit Zitat      
Vielen Dank nochmal!

Ich habe jetzt den konstanten Term rausgezogen und das Problem mit der Abfrage W==0 gelöst. Es müsste wie folgt lauten:
Code:
for i=1:n
   
        %consider only the i-th entry (scalar or row vector) of x_predict
        x_predict_vector =  repmat(x_predict(i,:),SizeOfX,1);
     
        %compute the weights of y_i with the Gaussian Kernel Function
        k=sum(exp(-(0.5/h^2)*sum((x_predict_vector - x_train).^2,2)));
        if (k==0)
            y_predict(i)=0;
            break
        else
            for j=1:SizeOfX
                W(j)= (exp(-(0.5/h^2)*(x_predict_vector - x_train(j,:)).^2))/k;
            end
        end

        y_predict(i) = sum(W.*y_train);
        end
 



hierzu noch eine Frage, mit dem Befehl break, beende ich doch jetzt nur den Durchlauf i=1 z.b oder? beende ich damit die for-schleife komplett? Falls dies der Fall sein sollte, wie kann ich dann nur die eine Iteration der for-Schleife beenden?
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 01.10.2012, 13:57     Titel:
  Antworten mit Zitat      
ich habe
Code:
x_predict_vector =  repmat(x_predict(i,:),SizeOfX,1);
nur wieder mit aufgenommen, da ich jetzt den Code ohne vorherige if Abfrage geschrieben habe, dass also beide Fälle d=1 und d=5 gleich behandelt werden, da ja das Verfaren das selbe ist und auch in der Abänderung
Code:
k=sum(exp(-(0.5/h^2)*sum(x_predict_vector - x_train).^2,2)));
das richtige rauskommt, auch wenn (x_predict_vector - x_train) nur ein eindimensionaler vektor ist, dass ist zwar sum(...,2) unnötig aber es erlaubt mir die gleiche behandlung beider fälle.
 
Christina

Gast


Beiträge: ---
Anmeldedatum: ---
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 02.10.2012, 18:38     Titel:
  Antworten mit Zitat      
Hallo,

ich bin es noch einmal. Ich habe jetzt meinen Code komplett überarbeitet, so dass er sowohl mathematisch korrekt ist, tatsächlich das richtige berechnet und sowohl für den eindimsionalen als auch für den mehrdimensional Fall verwendbar ist. Jetzt ist er nur wirklich ziemlich ziemlich langsam. Er berechnet nun seit 11 Stunden und hat nicht einmal ansatzweise die Hälfte aller Wiederholungen geschafft und es ist der eindimensional Fall...
Könntet ihr vielleicht noch einmal drüber schauen und mir sagen ob ihr auf dem ersten Blick etwas seht um die Laufzeit zu verkürzen?

Code:
function [y_predict] = kregression(x_train,y_train, x_predict, h)
%REGRESSION construct regression estimate by using the Nadaraya Watson
%kernel estimate
%   We are using as a kernel function the Gaussian kernel with bandwidth h,
%   which is choosen data dependent by "Splitting the Sample"

SizeOfX = size(x_train,1);
n=size(x_predict,1);

[y_predict]=ones(n,1);
[W]=ones(SizeOfX,1);
K=0;

%Variante ohne Vektorisieren des Ganzen
for i=1:n
   
    %compute the weights of y_i with the Gaussian Kernel Function:
   
    for j=1:SizeOfX
        K=K+ exp(-sum((x_predict(i,:)-x_train(j,:)).^2)/(2*h^2));
    end

    if (K==0)
        y_predict(i)=0;
        continue
    else
        for j=1:SizeOfX
            W(j)=exp(-sum((x_predict(i,:)-x_train(j,:)).^2)/(2*h^2))/K;
        end
    end
    y_predict(i)=sum(W.*y_train);
end

end
 


Die Regressionsfunktion wird von einer zweiten von mir implementierten Funktion aufgerufen:

Code:

function [y_predict] = smoothingParameter(x_train,y_train, x_predict)
   
n=size(x_train,1);
nl= ceil(n/2);

[x_learning] = x_train(1:nl,:);
[y_learning] = y_train(1:nl,:);
[x_testing] = x_train((nl+1):n,:);
[y_testing] = y_train((nl+1):n,:);

nt=size(x_testing,1);


[y_predict_t] =ones(nt,1);
[y_h]= ones(nt,2);
s=1;

for k=(-10):10
    %set bandwidth
    hi=2^k;
   
    %compute regression estimate with learning sample, and use X-values
    %of testing sample for the empirical error
    y_predict_t(:,:)= kregression(x_learning,y_learning,x_testing,hi);
   
    %compute the empirical error mit Y-values of the testing sample, save
    %the result and the corresponding bandwidth in a 2-dim. matrice
    y_h(s,1)= (1/(nt))* sum((y_predict_t - y_testing).^2);
    y_h(s,2)=hi;
   
    %raise the counter +1
    s=s+1;
end

% determine the minimal empirical L2 risk and remember the position
[c,i]=min(y_h);
% bandwidth is the value on the position i in the second column
h= y_h(i(1),2);
% now do regression estimate again with the predicted x-values
y_predict=kregression(x_learning,y_learning,x_predict,h);  
end


Gibt es hier eine Möglichkeit für eine for Schleife zweit Counter zu verwenden? Oder kann ich mir auf irgendeine Weise den Counter s sparen? Auch hier noch einmal die gleiche Frage, gibt es hier eine Möglichkeit die Laufzeit zu verkürzen?
Vielen Dank schon einmal im Vorraus.

Christina
 
Harald
Forum-Meister

Forum-Meister


Beiträge: 24.501
Anmeldedatum: 26.03.09
Wohnort: Nähe München
Version: ab 2017b
     Beitrag Verfasst am: 02.10.2012, 20:46     Titel:
  Antworten mit Zitat      
Hallo,

das wäre doch etwas mehr Arbeit und ich bin müde ;) , also an der Stelle ein paar Vorschläge:

Zitat:
Oder kann ich mir auf irgendeine Weise den Counter s sparen?

Ja, mit
Code:
k = -10:10;
for s = 1:length(k)
% in der Schleife wird k(s) verwendet
end


Das wird aber der Laufzeit nicht viel helfen.

In den for-Schleifen in kregression berechnest du zwei Mal sehr ähnliche Dinge.

Du könntest die W(j) am Anfang berechnen und sie dann in der Schleife verwenden. Der Fall K == 0 wird ja eher die Ausnahme sein, und nur auftreten, wenn im Exponentialterm extrem große Werte vorkommen.

Die Berechnung der W(j) ist für verschiedene h sehr ähnlich. Es wäre also wohl möglich, dass kregression einen Vektor von h's entgegennimmt und das ganze sp effizienter abgearbeitet wird.

Schließlich kann man wohl noch bsxfun verwenden, um x_predict(i,:)-x_train(j,:) für festes i effizienter zu berechnen. Zusammen mit dem Trick von zuvor sollte die for-Schleife dann wegfallen.

Insgesamt würde ich einen Beschleunigungsfaktor von min. 20 erwarten, vermutlich deutlich mehr.

Wichtig: immer wieder (z.B. an kleinen Testfällen) überprüfen, ob nach wie vor das richtige gemacht wird - nicht dass man da irgendwo Fehler einbaut.

Wenn die Parallel Computing Toolbox vorhanden ist und du auf einem Rechner mit mehreren Kernen arbeitest, kann man am Ende noch eine for-Schleife parallelisieren (der Aufwand dazu ist meist sehr gering) und auch so nochmal was rausholen. Am Anfang sollte aber wirklich stehen, den existierenden Code zu optimieren.

Grüße,
Harald
Private Nachricht senden Benutzer-Profile anzeigen
 
Neues Thema eröffnen Neue Antwort erstellen

Gehe zu Seite 1, 2, 3  Weiter

Einstellungen und Berechtigungen
Beiträge der letzten Zeit anzeigen:

Du kannst Beiträge in dieses Forum schreiben.
Du kannst auf Beiträge in diesem Forum antworten.
Du kannst deine Beiträge in diesem Forum nicht bearbeiten.
Du kannst deine Beiträge in diesem Forum nicht löschen.
Du kannst an Umfragen in diesem Forum nicht mitmachen.
Du kannst Dateien in diesem Forum posten
Du kannst Dateien in diesem Forum herunterladen
.





 Impressum  | Nutzungsbedingungen  | Datenschutz | FAQ | goMatlab RSS Button RSS

Hosted by:


Copyright © 2007 - 2025 goMatlab.de | Dies ist keine offizielle Website der Firma The Mathworks

MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.