Kopierteres, verwiesenes Array verschwindet nach For-Loop

 
Hey, habe mehrere loops in einem Neuronalen Netz Prototyp:
void simple_looped_nn_calc(int n_layers,double& X[], double& h[],/*double &w[]*/double& w_L1[],double& w_L2[],double& w_L3[],double& w_L4[],double& w_L5[], double b)
   { 
   double Input[];

   for(int l=0;l<n_layers;l++)
      {
      if (l+1 == 1)
         {ArrayResize(Input,ArraySize(X)); ArrayCopy(Input,X); Print(ArraySize(X)); Print(X[1]);Print(Input[1]);}
      else if (l+1 >1)
         {ArrayResize(Input,ArraySize(h)); ArrayCopy(Input,h);}

      double w_l[]; int next_l_Size = 0;   
      
      
      
      if     (l==1){ArrayResize(w_l,ArraySize(w_L1)); ArrayCopy(w_l,w_L1); next_l_Size = ArraySize(w_L2);} 
      else if(l==2){ArrayResize(w_l,ArraySize(w_L2)); ArrayCopy(w_l,w_L2); next_l_Size = ArraySize(w_L3);}
      else if(l==3){ArrayResize(w_l,ArraySize(w_L3)); ArrayCopy(w_l,w_L3); next_l_Size = ArraySize(w_L4);}
      else if(l==4){ArrayResize(w_l,ArraySize(w_L4)); ArrayCopy(w_l,w_L4); next_l_Size = ArraySize(w_L5);}
      else if(l==5){ArrayResize(w_l,ArraySize(w_L5)); ArrayCopy(w_l,w_L5); next_l_Size =               1;}
      else if (l>5){Alert("ERROR ... wrong layer size");}
      
      ArrayResize(h,ArraySize(w_l));
      
      Print("______HIER IST ES NOCH DA_____",Input[1]);

         for (int i=0; i< next_l_Size; i++)
            {
            Print("____AB HIER IST INPUT NICHT MEHR ADRESSIERBAR______",Input[1]);

            double f_sum =0;

            for (int j=0; next_l_Size*i+j< ArraySize(w_l); j++)
               {
               f_sum += w_l[next_l_Size*i+j] * Input[j];
               }

            f_sum += b_L1;   
            h[i] = ActivateNeuron(f_sum);   
            }  
      }

Das Array Input , welches eine Kopie von X ist lässt sich ab dem Loop nicht mehr adressieren? Jemand nh idee warum und wie ich das umgehen kann?

 

Bringst du auch immer ein Kolben aus deinem Auto zum KFZ-Fachmann und fragst warum der Motor nicht läuft ?


Mach ein Skript mit DEINEN Input-Daten der Funktion.

Schau dir auf GitHub die Issues von großen Projekten an.

 
Bayne:
Das Array Input , welches eine Kopie von X ist lässt sich ab dem Loop nicht mehr adressieren? Jemand nh idee warum und wie ich das umgehen kann?

Das sollte es nicht geben, das Array sollte auch von der Schleife aus adressierbar sein. Der Fehler liegt irgendwo anders. Bei Dir fehlt übrigens eine schließende Klammer am Ende.

Ach ja, könnte sein, dass das ArrayResize Dein Input auf Länge 0 setzt warum auch immer.

 
static datetime lastBar;

input uint b_L1=-1, 
           b_L2=-1, 
           b_L3 = -1, 
           b_L4 = -1, 
           b_L5=-1;

input bool testen = true;

input int Layers = 4; //Layers inkl Inp- % Outp-Layer
int NeuronenArray[]; //Neuronenarray NUR soviele Layer wie auch neuronen deklariert
double weight_L1[],weight_L2[],weight_L3[],weight_L4[],weight_L5[];

//Layer L0 = InputLayer
input int Neuronen_L1 = 6; 
input int Neuronen_L2 = 6;
input int Neuronen_L3 = 6;
input int Neuronen_L4 = 3;
input int Neuronen_L5 = 0;

double RSI[]; 

string            my_symbol;    // variable for storing the symbol
ENUM_TIMEFRAMES   my_timeframe; // variable for storing the time frame

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- save the current chart symbol for further operation of the EA on this very symbol
   my_symbol=Symbol();
//--- save the current time frame of the chart for further operation of the EA on this very time frame
   my_timeframe=PERIOD_CURRENT;
//--- save the minimum lot of the transaction to be performed
//   lot_size=SymbolInfoDouble(my_symbol,SYMBOL_VOLUME_MIN);
   
ArraySetAsSeries(RSI,true);    
  
ArrayResize(NeuronenArray,Layers);   

for (int i=0;i<Layers;i++)
   {                                               //--- preparation for placing weights into the array
   if (i+1 == 1){NeuronenArray[i] = Neuronen_L1;   ArrayResize(weight_L1,NeuronenArray[0]);/*Print(weight_L1[0]);Print(weight_L1[1]);Print(weight_L1[2]);Print(weight_L1[3]);Print(weight_L1[4]);*/}
   if (i+1 == 2){NeuronenArray[i] = Neuronen_L2;   ArrayResize(weight_L2,NeuronenArray[1]);}
   if (i+1 == 3){NeuronenArray[i] = Neuronen_L3;   ArrayResize(weight_L3,NeuronenArray[2]);}
   if (i+1 == 4){NeuronenArray[i] = Neuronen_L4;   ArrayResize(weight_L4,NeuronenArray[3]);}
   if (i+1 == 5){NeuronenArray[i] = Neuronen_L5;   ArrayResize(weight_L5,NeuronenArray[4]);}  
   
   if (i+1 == Layers) 
                  {NeuronenArray[i] = 3; // Letzter Layer MUSS 3 haben-> weil 1 = Buy, 0 = hold , -1 = sell
                   break;} // weil ist ja der letzte 
   }

if (testen == true)
   {
   for (int i=0;i<Layers;i++)
      { int Neuronen = 0;
      if (i+1 == 1)
      {Neuronen = NeuronenArray[i]; ArrayFill(weight_L1,0,Neuronen,0.5);/*Print(weight_L1[0]);Print(weight_L1[1]);Print(weight_L1[2]);Print(weight_L1[3]);Print(weight_L1[4])*/;}
      if (i+1 == 2)
      {Neuronen = NeuronenArray[i]; ArrayFill(weight_L2,0,Neuronen,0.5);}
      if (i+1 == 3)
      {Neuronen = NeuronenArray[i]; ArrayFill(weight_L3,0,Neuronen,0.5);}
      if (i+1 == 4)
      {Neuronen = NeuronenArray[i]; ArrayFill(weight_L4,0,Neuronen,0.5);}
      if (i+1 == 5)
      {Neuronen = NeuronenArray[i]; ArrayFill(weight_L5,0,Neuronen,0.5);}
      }   
   }
//--- return 0, initialization complete
   lastBar = iTime(_Symbol,my_timeframe,0);
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
  double h[]; // outputarray of NN
  double X[]; // Vorerst: [0] = Closeprice(stationarized),[1] = Closepricebefore (stationarized), [2] = Closeprice(stationarized), [3] = DayOfWeek, [4] = Hour, [5] = RSI
  //ArraySetAsSeries(X,true);
  ArrayResize(X,6); 
  int rsi_handle = iRSI(my_symbol,my_timeframe,10,PRICE_CLOSE);  CopyBuffer(rsi_handle,0,1,0,RSI);
  
  // Neue Bar -> set X -> calculate NN -> h == buy/sell/hold
  datetime newBar = iTime(my_symbol,my_timeframe,0);
  if(lastBar < newBar)
  { lastBar = newBar;
      X[0]=iClose(my_symbol,my_timeframe,2) - iClose(my_symbol,my_timeframe,1);
      X[1]=iClose(my_symbol,my_timeframe,3) - iClose(my_symbol,my_timeframe,2);
      X[2]=iClose(my_symbol,my_timeframe,4) - iClose(my_symbol,my_timeframe,3);
      X[3]= DayOfWeek();
      X[4]= Hour();
      X[5]= rsi_handle; // ja ich weiß, ist nicht die richtige lösung aber mit buffer scheint es probleme zu geben die ich später lösen werde
      //Print (X[0],X[1],X[2],X[3],X[4],X[5]);
      
      for (int i=0;i<ArraySize(h);i++)
         {Print(h[i]);}
         
      simple_looped_nn_calc(Layers,X,h, weight_L1,weight_L2,weight_L3,weight_L4,weight_L5,b_L1);
  }
  

 //... ... ...

}
//+------------------------------------------------------------------+
//|   Neuron calculation function                                    |
//+------------------------------------------------------------------+
double CalculateNeuron(double &x[],double &w[])
  {
//--- variable for storing the weighted sum of inputs
   double NET=0.0;
//--- Using a loop we obtain the weighted sum of inputs based on the number of inputs
   for(int n=0;n<ArraySize(x);n++)
     {
      NET+=x[n]*w[n];
     }
//--- multiply the weighted sum of inputs by the additional coefficient
   NET*=0.4;
//--- send the weighted sum of inputs to the activation function and return its value
   return(ActivateNeuron(NET));
  }
//+------------------------------------------------------------------+
//|   Activation function                                            |
//+------------------------------------------------------------------+
double ActivateNeuron(double x)
  {
//--- variable for storing the activation function results
   double Out;
//--- sigmoid
   Out=1/(1+exp(-x));
//--- return the activation function value
   return(Out);
  }
//+------------------------------------------------------------------+

void simple_looped_nn_calc(int n_layers,double& X[], double& h[],/*double &w[]*/double& w_L1[],double& w_L2[],double& w_L3[],double& w_L4[],double& w_L5[], double b)//b muss als array umgestaltet werden
   { double Input[];
     //double h[]; <---- das hier muss ausserhalb deklariert werden
   for(int l=0;l<n_layers;l++)
      {
      if (l+1 == 1)
         {ArrayResize(Input,ArraySize(X)); ArrayCopy(Input,X); Print(ArraySize(X)); Print(X[1]);Print(Input[1]);}
      else if (l+1 >1)
         {ArrayResize(Input,ArraySize(h)); ArrayCopy(Input,h);}
      double w_l[]; int next_l_Size = 0;   
      
      
      
      if     (l==1){ArrayResize(w_l,ArraySize(w_L1)); ArrayCopy(w_l,w_L1); next_l_Size = ArraySize(w_L2);} 
      else if(l==2){ArrayResize(w_l,ArraySize(w_L2)); ArrayCopy(w_l,w_L2); next_l_Size = ArraySize(w_L3);}
      else if(l==3){ArrayResize(w_l,ArraySize(w_L3)); ArrayCopy(w_l,w_L3); next_l_Size = ArraySize(w_L4);}
      else if(l==4){ArrayResize(w_l,ArraySize(w_L4)); ArrayCopy(w_l,w_L4); next_l_Size = ArraySize(w_L5);}
      else if(l==5){ArrayResize(w_l,ArraySize(w_L5)); ArrayCopy(w_l,w_L5); next_l_Size =               1;}
      else if (l>5){Alert("ERROR ... wrong layer size");}
      
      ArrayResize(h,ArraySize(w_l));
      
      //for(int i=0;i<ArraySize(w_l);i++)
      //   {
      Print("____bis hier hin läuft es top_____",Input[1]);
         for (int i=0; i< next_l_Size; i++)
            {Print("____ab dem loop ist das Input Array wieder leer____",Input[1]);
            double f_sum =0;
            for (int j=0; next_l_Size*i+j< ArraySize(w_l); j++)
               {
               f_sum += w_l[next_l_Size*i+j] * Input[j];
               }
            f_sum += b_L1;   
            h[i] = ActivateNeuron(f_sum);   
            } 
      }
}
   
int  DayOfWeek()
      {
      MqlDateTime tm;
      TimeCurrent(tm);
      return(tm.day_of_week);
      }
int  Hour()
      {
      MqlDateTime tm;
      TimeCurrent(tm);
      return(tm.hour);
      }      

ist wie gesagt nur der prototyp (nur halb fertig). Inputs und alles was notwendig ist, ist drin (habe bereits nahezu alles überflüssige gestrichen).

Aber wie erwähnt taucht das problem nur bis zum (mit Prints) markierten loop auf. danach ist es futsch.


Das Resize() soll die größe des original Input Arrays (X oder h, wobei es sich um den input einer vorherigen Neuronenschicht handelt)  auf Input[] übertragen und anschließend , damit dieses eine exakte kopie darstellt mit dessen werten befüllen.

 
Bayne:

ist wie gesagt nur der prototyp (nur halb fertig). Inputs und alles was notwendig ist, ist drin (habe bereits nahezu alles überflüssige gestrichen).

Aber wie erwähnt taucht das problem nur bis zum (mit Prints) markierten loop auf. danach ist es futsch.


Das Resize() soll die größe des original Input Arrays (X oder h, wobei es sich um den input einer vorherigen Neuronenschicht handelt)  auf Input[] übertragen und anschließend , damit dieses eine exakte kopie darstellt mit dessen werten befüllen.

Dein Input wird im 2. loop der Schleife wo der Blaue Punkt ist überschrieben mit dem Array h was LEER ist.

Gewollt oder nicht musst du selber entscheiden.

Du siehst auch wie man einen Breakpoint mit Bedingung setzen kann um ein ganz bestimmten Zeitpunkt im Programm zu finden 

      if (ArraySize(Input) < 6)
        {
          DebugBreak();
        }


Unten rechst siehst du die Variablem zu dem "Fehlerzeitpunk" und kannst selbst nachvollziehen warum danach das Input Array leer ist.


ArrayCopy(Input,h)
h ist leer und macht Input somit auch leer
 

Bayne,

Ich durchblicke den Code nicht so auf die Schnelle, daher nur Dinge, die mir auf den ersten Blick auffallen:

1. Bist Du sicher, dass das mit den Gewichten so funktioniert und dass diese Arrays nicht mindestens zweidimensional sein müssten? Aus den Array-Koordinaten muss doch hervorgehen, welches Neuron mit welchem verbunden ist ("Stichwort fully connected NN"). Oder halt dreimeinsional, wenn Du es flexibler halten möchtest und das Bezugslayer enthalten sein soll (also statt W1[][], W2[][]... usw. einfach W[layer][][]. Beispiel: W[3][9][7] könnte dann das Gewicht sein, das Neuron9 aus Layer 3 mit dem Neuron7 aus dem Folgelayer(3+1=4) verbindet.

2. Warum schreibst Du die Bedingung l+1=1? Diese Bedingung ist nur <true> wenn l==0, also könntest Du auch gleich schreiben if (l==0){}.

   Genauso: if (l+1>1){} ist das Gleiche wie if (l>1){}. So wie Du es schreibst ist es nicht intuitiv.

3. Die Funktionen am Ende gehen viel knapper mit z.B.

globale Variable 

MqlDateTime tm;

und dann nur einmal in OnTick

TimeToStruct(TimeCurrent(),tm);

dann wäre z.B. "hour_of_day" schlicht tm.hour; es gibt keinen Grund, die Zeit pro Tick mehrmals (=über Deine separate Funktionen) auszulesen. Das sind die kleinen Details, von denen sich am Ende ein paar hundert summieren und ein Programm langsam machen.

4. Ich würde später mit unterschiedlichen Aktivierungsfunktionen experimentieren (tanh, ReLu, ELu...). Außerdem einen NaN-Error-Schutz in die Funktion einbauen mittels if (!MathIsValidNumber(Out)){....

 

Danke Christian, aber das hätte man doch ganz leicht mit dem Debugger selbst herausfinden können!

Wie heißt es so schön: Hilf Dir selbst, dann hilft Dir Gott!

 
      if     (l==1){ArrayResize(w_l,ArraySize(w_L1)); ArrayCopy(w_l,w_L1); next_l_Size = ArraySize(w_L2);} 
      else if(l==2){ArrayResize(w_l,ArraySize(w_L2)); ArrayCopy(w_l,w_L2); next_l_Size = ArraySize(w_L3);}
      else if(l==3){ArrayResize(w_l,ArraySize(w_L3)); ArrayCopy(w_l,w_L3); next_l_Size = ArraySize(w_L4);}
      else if(l==4){ArrayResize(w_l,ArraySize(w_L4)); ArrayCopy(w_l,w_L4); next_l_Size = ArraySize(w_L5);}
      else if(l==5){ArrayResize(w_l,ArraySize(w_L5)); ArrayCopy(w_l,w_L5); next_l_Size =               1;}
      else if (l>5){Alert("ERROR ... wrong layer size");}

hieran lag es schlussendlich, falls es einer auch gefunden habe: es hätte mit  if (l == 0){ArrayResize(...)... anfangen müssen.

Danke euch dennoch


@Carl Schreiber: Ich war heute nacht nach 2 stunden debuggen so blind und habe dauerhaft an der falschen stelle gesucht.

Ich debugge selbstverständlich erstmal selber und frage idr nur im forum, wenn ich selbst nicht weiter weiß, also keine Sorge, dennoch danke euch für euer geschultes Adlerauge :)


PS: keine sorge die 2d Arrays kommen noch, ich musste erstmal nur einen einstieg finden  was in die Arrays reingehört.


@Chris70 kannst du mir sagen wie ich ein 2d array Resizen kann? Die 2. Dimension meine ich. Lese überall das geht nicht. ( Die Anzahlen der Neuronen in diesem NN sind je nach layer unterschiedlich groß und variieren, denn ich will die layeranzahl als Input in den Strategy Tester packen (momentan sind es halt 5 manuell geschriebene), Multi arrays wären also platzsparender)

 


@Chris70 kannst du mir sagen wie ich ein 2d array Resizen kann? Die 2. Dimension meine ich. Lese überall das geht nicht. ( Die Anzahlen der Neuronen in diesem NN sind je nach layer unterschiedlich groß und variieren)

Absolut korrekt. Du wirst daher also praktisch nicht darum herumkommen, überzudimensionieren auf ein Niveau, das realistischerweise nicht überschritten wird. Irgendwo musss man da einen Kompromiss machen. Wenn für die einzelnen Dimensionen mit unterschiedlichen Größen gerechnet wird, macht es natürlich Sinn, nur die kleineren Größen statisch festzulegen und die potentiell größte Dimension an die dynamische erste Position zu legen. Wenn Du dann mal "Glück" hast und dieese Dimenson doch nciht so groß ist, hat man dann nicht so viele unnötige / überzählige Elemente. Am Beispiel der Gewichte könnte man also z.B. postulieren, dass die Anzahl der Neuronen pro Layer potentiell deutlich größer sein kann als die Zahl der Layer, insofern ist Dein Einwand gut: die Reihenfolge Weight[Senderneuron][Empfängerneuron][Senderlayer] kann so Vorteile haben (gegenüber Senderlayer auf der ersten/dynamischen Position). Da definierst Du z.B. double W[][200][10];. Vergiss übrigens die Bias-Neuronen nicht - oder handhabe einfach das nullte Neuron pro Layer als Bias; dann aber bei der Gewichtsvernetzung daran denken, dass die Bias-Neuronen nur Ausgangs-Gewichte haben, aber keine Eingangsgewichte.

edit: noch eine Sache: warum kopierst Du überhaupt das X-Array auf das erste Layer? Wo ist der Vorteil anstelle der Konvention "der cell-state von Layer 0 IST mein X-Vektor"? Der einzige Unterschied zwischen Eingang und Folgelayers ist, dass die Backpropagation am Eingangslayer beendet ist und dass das Einganglayer halt nur Ausgangsgewichte hat. Das kann man aber alles über for-loops regeln.

Nächste Schriite für Dich sind dann wahrscheinlich die Input-Normalisierung und die Funktionen für random-Initialisierung, Laden und Speichern der Gewichts-Matrix, oder? Und dann halt die Backpropagation... Viel Spaß!

 
Carl Schreiber:

Danke Christian, aber das hätte man doch ganz leicht mit dem Debugger selbst herausfinden können!

Ab und zu gebe ich noch gerne mal eine Hilfestellung,ohne mich in den Code einzuarbeiten.

Das können gerne andere machen, das Rad erfinde ich nicht neu :-)

 
Chris70:

Absolut korrekt. Du wirst daher also praktisch nicht darum herumkommen, überzudimensionieren auf ein Niveau, das realistischerweise nicht überschritten wird. Irgendwo musss man da einen Kompromiss machen. Wenn für die einzelnen Dimensionen mit unterschiedlichen Größen gerechnet wird, macht es natürlich Sinn, nur die kleineren Größen statisch festzulegen und die potentiell größte Dimension an die dynamische erste Position zu legen. Wenn Du dann mal "Glück" hast und dieese Dimenson doch nciht so groß ist, hat man dann nicht so viele unnötige / überzählige Elemente. Am Beispiel der Gewichte könnte man also z.B. postulieren, dass die Anzahl der Neuronen pro Layer potentiell deutlich größer sein kann als die Zahl der Layer, insofern ist Dein Einwand gut: die Reihenfolge Weight[Senderneuron][Empfängerneuron][Senderlayer] kann so Vorteile haben (gegenüber Senderlayer auf der ersten/dynamischen Position). Da definierst Du z.B. double W[][200][10];. Vergiss übrigens die Bias-Neuronen nicht - oder handhabe einfach das nullte Neuron pro Layer als Bias; dann aber bei der Gewichtsvernetzung daran denken, dass die Bias-Neuronen nur Ausgangs-Gewichte haben, aber keine Eingangsgewichte.

edit: noch eine Sache: warum kopierst Du überhaupt das X-Array auf das erste Layer? Wo ist der Vorteil anstelle der Konvention "der cell-state von Layer 0 IST mein X-Vektor"? Der einzige Unterschied zwischen Eingang und Folgelayers ist, dass die Backpropagation am Eingangslayer beendet ist und dass das Einganglayer halt nur Ausgangsgewichte hat. Das kann man aber alles über for-loops regeln.

Nächste Schriite für Dich sind dann wahrscheinlich die Input-Normalisierung und die Funktionen für random-Initialisierung, Laden und Speichern der Gewichts-Matrix, oder? Und dann halt die Backpropagation... Viel Spaß!

Wie willst du denn backpropagation in MQL5 anwenden bzw integrieren( hatte die diese Frage bereits antwortlose im Forum gestellt) 

hatte bisher nur NNs in der Codebase gefunden die einfach den strategy optimizer dazu nutzen...

Die Frage nach dem X-Inputarray kann ich dir noch nicht ganz beantworten, denn ich orientiere mich soweit noch an einem extrem simplen Modell aus Python Code, bei dem "h" am Ende ausgegeben wird.

Sag Mal... Dauert die Optimierung eines NNs mit W[SendeNeuron][Empfängerneuron][layer] nicht unendlich lange?(oder wie kannst du aus persönlicher Erfahrung berichten)

Grund der Beschwerde: