Extremlange Zahlen Normalisieren nicht möglich !? (wissenschaftliche Schreibweise)

Einloggen oder registrieren, um einen Kommentar zu schreiben
Bayne
1009
Bayne  
   double the_x = 9.9310486084873392E+249;
   double old_x = the_x;
   the_x =NormalizeDouble(the_x,10);


Rückgabewert ist bei beidem "9.9310486084873399E+249"


wie auch immer vielleicht verstehe ich Die Funktion Normalize Double auch totalfalsch, aber wie komme ich denn auf ein Ergebnis das in einem Zug lesbar ist ?

(Ziel: Vermeidung von inf oder -inf Werten, wenn auf funktionen wie exp() oder tanh() angewandt)

Carl Schreiber
Moderator
9934
Carl Schreiber  

Lies mal: https://www.mql5.com/de/articles/1561

Aber, dass die Zahl ("9.9310486084873399E+249") so groß (nicht lang!) ist liegt an Deinem Code, wahsch. eine Division fast durch Null!

Arbeiten mit Doubles in MQL4
Arbeiten mit Doubles in MQL4
  • www.mql5.com
Die MQL Programmierung eröffnet neue Möglichkeiten für das automatisierte Trading, viele Menschen auf der ganzen Welt schätzen es bereits. Wenn wir einen Expert Advisor für das Trading schreiben, müssen wir sicher sein, dass er korrekt arbeitet. Viele Neulinge haben oft ein paar Fragen, wenn die Ergebnisse einiger mathematischer Berechnungen...
Christian
3200
Christian  
Bayne:

(Ziel: Vermeidung von inf oder -inf Werten, wenn auf funktionen wie exp() oder tanh() angewandt)

Nochmal Bayne:

Du musst die Arrays VOR der ersten Benutzung Initialisieren.

In deinem Code passiert das wenig bis garnicht.

Auszug:

int MyOnInit()
   {
       
   ArrayResize(Input_Types,0);
   CheckWhichInputsWeNeed(Input_Types);
         
   ArrayResize(NeuronenArray,Layers); 
   
   
if (training == true)
   {
   
   for (int i=0;i<Layers;i++)
   {                                                   //--- place weights into the array
   if (i == 0){NeuronenArray[i] = ArraySize(Input_Types);}                               //--- place weights into the array
   else if (i == 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]);*/}
   else if (i == 2){NeuronenArray[i] = Neuronen_L2;   /*ArrayResize(weight_L2,NeuronenArray[1]);*/}
   else if (i == 3){NeuronenArray[i] = Neuronen_L3;   /*ArrayResize(weight_L3,NeuronenArray[2]);*/}
   else if (i == 4){NeuronenArray[i] = Neuronen_L4;   /*ArrayResize(weight_L4,NeuronenArray[3]);*/}
   else if (i == 5){NeuronenArray[i] = Neuronen_L5;   /*ArrayResize(weight_L5,NeuronenArray[4]);*/}  
   else if (i == 6){NeuronenArray[1] = Neuronen_L6;   /*ArrayResize(weight_L5,NeuronenArray[4]);*/}  
   else if (i == 7){NeuronenArray[i] = Neuronen_L7;   /*ArrayResize(weight_L5,NeuronenArray[4]);*/}  
   else if (i == 8){NeuronenArray[i] = Neuronen_L8;   /*ArrayResize(weight_L5,NeuronenArray[4]);*/}  
   else if (i == 9){NeuronenArray[i] = Neuronen_L9;   /*ArrayResize(weight_L5,NeuronenArray[4]);*/}  
   else if (i == 10){NeuronenArray[i] = Neuronen_L10;   /*ArrayResize(weight_L5,NeuronenArray[4]);*/}  
Input_Types ?
NeuronenArray ?

Beide nicht Initialisiert.

int  ArrayInitialize(
   double  array[],     // initialisiertes array
   double  value        // der zu gestellte wert
   );

Ohne das wirst du immer Berechnungsfehler haben.

Siehe hier -> https://www.mql5.com/de/docs/array/arrayinitialize

Dokumentation zu MQL5: Operationen mit Arrays / ArrayInitialize
Dokumentation zu MQL5: Operationen mit Arrays / ArrayInitialize
  • www.mql5.com
Die Funktion ArrayResize() erlaubt die Größe für ein Array mit einem Reserve vorzugeben, damit es größer wird ohne physische Umverteilung des Speichers. Das wird für Operationsgeschwindigkeit gemacht, denn Operationen der Speicherverteilung sind langsam genug. (array, init_val) bedeutet nicht die Initialisierung durch denselben Wert der...
Chris70
543
Chris70  

ach.. das hatten wir doch alles schon;

Das Problem entsteht ja nicht durch das "wissenschaftliche" Zahlenformat, sondern durch die Größe der Zahl an sich. Ich gebe Christian natürlich absolut Recht was das konsequente Initialisieren angeht. Trotzdem wird der Fehler da nicht alleine liegen. Das Entstehen sehr großer und sehr kleiner Zwischenergebnisse ist ein spezifisches Problem neuronaler Netze, das sich aber vermeiden lässt durch ein paar Vorüberlegungen zu den Eingabedaten und der Netzarchitektur.

Du hast eigentlich schon sämtliche nötige Hilfe bekommen, sie aber ignoriert und machst einen neuen Thread auf. Dass die Normalize-Double-Methode für diesen Zweck Quatsch ist, sagte ich bereits. Du willst es trotzdem.

Was ich für unverzichtbar halte (sagte ich auch schon...):

- verstehen, was eine Gleitkommazahl ist: https://de.m.wikipedia.org/wiki/Gleitkommazahl

- konsequent initialisieren

- Datenvorbehandlung, Normalisieren der Inputs (damit meine ich NICHT NormalizeDouble, sondern homogenisieren durch skalieren, Nullpunktverschiebung und Umgang mit Extremwerten)

Gleitkommazahl – Wikipedia
Gleitkommazahl – Wikipedia
  • de.m.wikipedia.org
Alle (mechanischen oder elektronischen) Rechenhilfsmittel vom Abakus bis zum Computer verwenden als einfachste Form der Zahldarstellung Festkommazahlen. Dabei wird eine meistens begrenzte Ziffernfolge gespeichert und an festgelegter Stelle das Komma angenommen. Bei größeren Rechnungen treten unweigerlich Überläufe auf, die eine Skalierung der...
Bayne
1009
Bayne  
Christian:

Nochmal Bayne:

Du musst die Arrays VOR der ersten Benutzung Initialisieren.

In deinem Code passiert das wenig bis garnicht.

Auszug:

Beide nicht Initialisiert.

Ohne das wirst du immer Berechnungsfehler haben.

Siehe hier -> https://www.mql5.com/de/docs/array/arrayinitialize

Christian:

Nochmal Bayne:

Du musst die Arrays VOR der ersten Benutzung Initialisieren.

In deinem Code passiert das wenig bis garnicht.

Auszug:

Beide nicht Initialisiert.

Ohne das wirst du immer Berechnungsfehler haben.

Siehe hier -> https://www.mql5.com/de/docs/array/arrayinitialize

Dort liegt nicht das Problem, kriege ja die richtigen werte..., die probleme kommen später bei der berechnung in den knoten des Neuronalen Netzes auf, also eine Multiplikation mit einem entweder riesigen oder sehr sehr kleinen wert wie carl schon sagte (aber falls ich falsch liege: Reicht es nicht was in CheckWichInputsWeNeed()? und "NeuronenArray[i] = Neuronen_L1;" initialisiert doch den inputwert wieviele Neuronen und layer wir brauchen .... Was macht array initialize denn anderes als meine geannte initialisierung ? die vorher bestehenden exponentiellen zahlen werden durch den gewünschten wert erstetzt )

void CheckWhichInputsWeNeed(int &Input_Types[])
   { int s = 0;
   if(inp_Close1before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=1; if(LatestBarBack<2){LatestBarBack=2;}} //latestBarback is+1 because of stationarizing
   if(inp_Close2before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=2; if(LatestBarBack<3){LatestBarBack=3;}}
   if(inp_Close3before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=3; if(LatestBarBack<4){LatestBarBack=4;}}
   if(inp_Close4before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=4; if(LatestBarBack<5){LatestBarBack=5;}}
   if(inp_Close5before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=5; if(LatestBarBack<6){LatestBarBack=6;}}
   if(inp_Close6before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=6; if(LatestBarBack<7){LatestBarBack=7;}}
   if(inp_Close7before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=7; if(LatestBarBack<8){LatestBarBack=8;}}
   if(inp_Close8before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=8; if(LatestBarBack<9){LatestBarBack=9;}}
   if(inp_Close9before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=9; if(LatestBarBack<10){LatestBarBack=10;}}
   if(inp_Close10before){s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=10; if(LatestBarBack<11){LatestBarBack=11;}}
   if(inp_Close11before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=11; if(LatestBarBack<12){LatestBarBack=12;}} //latestBarback is+1 because of stationarizing
   if(inp_Close12before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=12; if(LatestBarBack<13){LatestBarBack=13;}}
   if(inp_Close13before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=13; if(LatestBarBack<14){LatestBarBack=14;}}
   if(inp_Close14before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=14; if(LatestBarBack<15){LatestBarBack=15;}}
   if(inp_Close15before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=15; if(LatestBarBack<16){LatestBarBack=16;}}
   if(inp_Close16before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=16; if(LatestBarBack<17){LatestBarBack=17;}}
   if(inp_Close17before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=17; if(LatestBarBack<18){LatestBarBack=18;}}
   if(inp_Close18before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=18; if(LatestBarBack<19){LatestBarBack=19;}}
   if(inp_Close19before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=19; if(LatestBarBack<20){LatestBarBack=20;}}
   if(inp_Close20before) {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=20; if(LatestBarBack<21){LatestBarBack=21;}}
   
   if(inp_DayOfWeek)    {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=21;}
   if(inp_DayOfMonth)   {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=22;}
   if(inp_Month)        {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=23;}
   if(inp_Hour)         {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=24;}
   if(inp_RSI)          {s= ArraySize(Input_Types);ArrayResize(Input_Types,s+1);Input_Types[s]=25; if(LatestBarBack<inp_RSIperiod){LatestBarBack=inp_RSIperiod+3 ;}} //3 because we need RSI[2]-RSI[1)
   }

es geht mir mehr darum wie ich mit Gewichten oder Neuronenwerten umgehen soll, die größer als 247483647 oder kleiner als 0.1E-308 (schätze das waren die maxi- und minimal möglichen Werte für MQL).

Also... was tun? (in Neuronalen Netzen)

@Carl Schreiber
Chris70
543
Chris70  

Was direkt auffällt:

Close-Preise und RSI-Werte sind z.B. völlig unterschiedlich skaliert. Mit so heterogenen Inputs kommt kein NN zurecht. Transformiere die Daten so, dass sie z.B. zwischen -1 und 1 oder 0 und 1 liegen. Dafür musst Du Minimal- und Maximalwerte des Inputs entweder kennen oder im Laufe der ersten Iterationen automatisch erfassen lassen, in einer Variablen hinterlegen und updaten (edit: separate Skalierungswerte für jedes Input einzeln; die Skalierungsdaten sind also ebenfalls Arrays). Die automatische Erfassung führt bei den ersten Iterationen zu Fehlern weil die Skalierung zunächst nur sehr grob ist, was aber egal ist, da ja eh etliche tausend bis Millionen Iterationen anstehen. Du musst außerdem entscheiden, ob Du Extremausreißer ignorierst oder mit Deinem Skalierungs-Minimum/Maximum gleichsetzt oder ob Du sie relativierst durch z.B. logarithmische Skalierung (funktioniert aber nur für positive Werte, Logarithmus einer negativen Zahl ergibt Error, daher Tricks mit z.B. MathAbs() nötig).

Wochentage, Tage des Monats usw. als einzelne Inputs zu nehmen wird nichts bringen weil z.B. jeder Wochentag eine separate Eigenschaft ist und keine stetige Rangabfolge vorliegt. Das ist kein kleiner/größer-Problem sondern ein "oder"-Problem. Ein Preis kann z.B. höher oder tiefer sein. Aber was ist Freitag mehr als Donnerstag (außer näher am Wochenende)? Und wie erklärt man sich dann den Sprung von 6 zu 0 für direkt benachbarte Wochentage oder von 23 zu 0 für direkt benachbarte Stunden? Das ist also "garbage in". Wenn Du z.B. wirklich wissen willst, ob andere Handelstage zu anderen Ergebnissen führen, dann ist jeder Wochentag ein separater Input, der dann eine 1 oder 0 erhält, je nachdem ob der aktuelle Tag das Kriterium erfüllt.

Christian
3200
Christian  
Bayne:

 (aber falls ich falsch liege: Reicht es nicht was in CheckWichInputsWeNeed()? und "NeuronenArray[i] = Neuronen_L1;" initialisiert doch den inputwert wieviele Neuronen und layer wir brauchen .... Was macht array initialize denn anderes als meine geannte initialisierung ?

Wenn du dein Projekt soweit überblicken kannst brauchst du das nicht machen.Ja das reicht.

Ich gehe nicht davon aus.

Sieh es als ESP(Auto) an . Schummi brauchte es nicht .

Es sind einfach wichtige Grundlagen um Fehler zu vermeiden.

Bayne
1009
Bayne  
Chris70:

Was direkt auffällt:

Close-Preise und RSI-Werte sind z.B. völlig unterschiedlich skaliert. Mit so heterogenen Inputs kommt kein NN zurecht. Transformiere die Daten so, dass sie z.B. zwischen -1 und 1 oder 0 und 1 liegen. Dafür musst Du Minimal- und Maximalwerte des Inputs entweder kennen oder im Laufe der ersten Iterationen automatisch erfassen lassen, in einer Variablen hinterlegen und updaten (edit: separate Skalierungswerte für jedes Input einzeln; die Skalierungsdaten sind also ebenfalls Arrays). Die automatische Erfassung führt bei den ersten Iterationen zu Fehlern weil die Skalierung zunächst nur sehr grob ist, was aber egal ist, da ja eh etliche tausend bis Millionen Iterationen anstehen. Du musst außerdem entscheiden, ob Du Extremausreißer ignorierst oder mit Deinem Skalierungs-Minimum/Maximum gleichsetzt oder ob Du sie relativierst durch z.B. logarithmische Skalierung (funktioniert aber nur für positive Werte, Logarithmus einer negativen Zahl ergibt Error, daher Tricks mit z.B. MathAbs() nötig).

Wochentage, Tage des Monats usw. als einzelne Inputs zu nehmen wird nichts bringen weil z.B. jeder Wochentag eine separate Eigenschaft ist und keine stetige Rangabfolge vorliegt. Das ist kein kleiner/größer-Problem sondern ein "oder"-Problem. Ein Preis kann z.B. höher oder tiefer sein. Aber was ist Freitag mehr als Donnerstag (außer näher am Wochenende)? Und wie erklärt man sich dann den Sprung von 6 zu 0 für direkt benachbarte Wochentage oder von 23 zu 0 für direkt benachbarte Stunden? Das ist also "garbage in". Wenn Du z.B. wirklich wissen willst, ob andere Handelstage zu anderen Ergebnissen führen, dann ist jeder Wochentag ein separater Input, der dann eine 1 oder 0 erhält, je nachdem ob der aktuelle Tag das Kriterium erfüllt.

Stimmt danke, hab den Normalisierungsprozess voll aus den augen verloren und dachte ich hätte ihn bereits geschrieben ...

Bei der Normalisierung der Eingangsdaten:

Macht es sinn über die kompletten Trainingsdaten (alle samples komplett) drüber zu iterieren um das Maximum und Minimum zu finden

oder ist es ausreichend, nur das maximum und minimum des jeweiligen trainingsamples zu verwenden? (wenn ich mich nicht irre dürfte es aufgrund prozentualer relativeriung keinen unterschied bei den Gewichten machen, aber bei den Biases bin ich nicht sicher)

Chris70
543
Chris70  

Erst einmal über alle Trainingsdaten zu gehen und die Minima/Maxima zu finden wäre sicherliche EINE Möglichkeit, zu skalieren. Doch was machst Du dann wenn im Gegensatz zu den Trainingsdaten später in der Echtzeit-Anwendung des trainierten Netzes Inputs vorkommen, die jenseits dieser Minimal/Maxima liegen? Da brauchst Du dann trotzdem eine Regel. Du kannst diese Werte natürlich dann einfach als Extremausreißer handhaben und mit Deinem Minimum/Maximum gleichsetzen. Andere Möglichkeit: Du legst während des Trainings z.B. fest, dass Anpassungen der Skalierung nur erlaubt sind bis z.B. zur tausendsten Iteration (=dass also die Skalierung bis dahin "gelernt" wird). Alles was später außerhalb liegt wird als synonym mit dem Skalenende gehandhabt. Da ist Deiner Kreativität keine Grenze gesetzt.

Und nackte Close-Preise würde ich sowieso nicht als Input nehmen, auch nicht mit Skalierung, denn die Skalierung wäre aufgrund langfristiger Trends jeden Monat eine andere. Du brauchst irgendeinen Bezugspreis, also Preise relativ zum Vortages-Close, zum 200er Moving Average, zum aktuellen Close.... je nachdem was Dein Netzwerk lernen soll kann das unterschiedlich sein, jedoch Absolutpreise sind keine gute Idee. Was heute ein hoher Preis ist, wäre vielleicht vor 1 Monat ein sehr niedriger Preis gewesen.

Bayne
1009
Bayne  
Chris70:

Erst einmal über alle Trainingsdaten zu gehen und die Minima/Maxima zu finden wäre sicherliche EINE Möglichkeit, zu skalieren. Doch was machst Du dann wenn im Gegensatz zu den Trainingsdaten später in der Echtzeit-Anwendung des trainierten Netzes Inputs vorkommen, die jenseits dieser Minimal/Maxima liegen? Da brauchst Du dann trotzdem eine Regel. Du kannst diese Werte natürlich dann einfach als Extremausreißer handhaben und mit Deinem Minimum/Maximum gleichsetzen. Andere Möglichkeit: Du legst während des Trainings z.B. fest, dass Anpassungen der Skalierung nur erlaubt sind bis z.B. zur tausendsten Iteration (=dass also die Skalierung bis dahin "gelernt" wird). Alles was später außerhalb liegt wird als synonym mit dem Skalenende gehandhabt. Da ist Deiner Kreativität keine Grenze gesetzt.

Und nackte Close-Preise würde ich sowieso nicht als Input nehmen, auch nicht mit Skalierung, denn die Skalierung wäre aufgrund langfristiger Trends jeden Monat eine andere. Du brauchst irgendeinen Bezugspreis, also Preise relativ zum Vortages-Close, zum 200er Moving Average, zum aktuellen Close.... je nachdem was Dein Netzwerk lernen soll kann das unterschiedlich sein, jedoch Absolutpreise sind keine gute Idee. Was heute ein hoher Preis ist, wäre vielleicht vor 1 Monat ein sehr niedriger Preis gewesen.

im code der den inputtyp in die Trainingsdaten initialisiert, nutze ich bereits die stationarisierung zum Closepreis davor(also nur die preisveränderung von bar zu bar).

also soll die skalierung innerhalb der ersten 1000 Iterationen in den trainingsdaten "erlernt werden" (verstehe deine beschreibnung noch nicht ganz) (und danach auf die folgenden weiterangewandt), wobei in der Live anwendung keine skalierungsänderung erfolgen soll...

oder mein anderer Ansatz es zu verstehen: im Training die komplette skalierung lernen und danach im live trading über die ersten z.B. 1000 bars die skalierung anpassen und danach nicht mehr rumschrauben


allerdings wenn in den livetrading bars signifikant größere Werte auftauchen und die skalierung angepasst wird, besteht doch die gefahr, dass die Gewichte und Bars zu niedrig angewandt werden oder nicht?

Carl Schreiber
Moderator
9934
Carl Schreiber  

Bayne, Du verschwendest viel Zeit für etwas was Du wahrscheinlich nur kopieren müsstest!

Kennst Du diese Artikel bzw. CodeBase:

https://www.mql5.com/en/articles/4228
https://www.mql5.com/en/forum/317110
https://www.mql5.com/en/articles/1482
https://www.mql5.com/en/articles/497
https://www.mql5.com/en/articles/1562
https://www.mql5.com/en/code/8499
https://www.mql5.com/en/code/8479
https://www.mql5.com/en/code/8514
https://www.mql5.com/en/code/1649


Er allein hat 12 Artikel über das Thema geschrieben:

https://www.mql5.com/en/users/vlad1949/publications

(Hinweis: wenn Du /en/ in den Links durch /de/ ersetzt, kriegst Du die deutsche Übersetzung (außer bei dem Forum, natürlich)

Deep Neural Networks (Part VII). Ensemble of neural networks: stacking
Deep Neural Networks (Part VII). Ensemble of neural networks: stacking
  • www.mql5.com
Contents Introduction Models of the base level of the ensemble (individual classifiers) are trained on a full set. Then the metamodel is trained on the ensemble outputs obtained during the prediction based on the testing set. In this case, the outputs of the ensemble's base classifiers become the input data for the new trained classifier...
12
Einloggen oder registrieren, um einen Kommentar zu schreiben