Großartiges und nützliches Artikelmaterial
Ich danke Ihnen!
Ja, das ist geplant :)
Dmitry, bitte, ich habe zuerst nicht verstanden, warum Sinus und Kosinus zu den Eingabewerten hinzugefügt werden.
neuron.setOutputVal(inputVals.At(i)+(i%2==0 ? sin(i) : cos(i)) );
Ich brauche auch einen Rat - sollte ich versuchen, die Eingabedaten für meine Aufgaben in irgendeiner Weise zu normalisieren?
In den Beispielen wird, so wie ich es verstehe, alles "wie es ist" angegeben. Aber selbst in den Beispielen mit Fraktalen liegen einige Oszillatoren zwischen 0 und 1, und die Preise können je nach Instrument viel höher als 1 sein.
Entsteht dadurch nicht eine anfängliche Verzerrung beim Training mit nicht normalisierten Eingaben?
Dmitry, bitte erklären Sie mir, warum Sinus und Kosinus zu den Eingabewerten addiert werden.
Ich brauche auch einen Rat - sollte ich versuchen, die Eingabedaten für meine Aufgaben irgendwie zu normalisieren?
In den Beispielen wird, so wie ich es verstehe, alles "so wie es ist" angegeben. Aber selbst in den Beispielen mit Fraktalen liegen einige Oszillatoren zwischen 0 und 1, und die Preise können je nach Instrument viel höher als 1 sein.
Entsteht dadurch nicht eine anfängliche Verzerrung beim Training auf nicht normalisierte Eingaben?
Dies ist für die zeitliche Einbettung. Ich werde im nächsten Artikel mehr ins Detail gehen.
Ich gebe mir Mühe, die Bedeutung zu verstehen)
Eingabewerte werden arithmetisch an eine konstante Matrix von 0 bis 1 angepasst, unabhängig davon, wie die Eingabedaten aussehen und welche absoluten Werte sie haben.
Time-Embedding verstehe ich in diesem Sinne so, dass man eine Zeitreihe mit einer Sinuswelle überlagert, so dass die Bedeutung vergangener Kerzen in der Zeit schwankt.
Ok, das ist klar, anscheinend spielt es keine Rolle, dass die Schwankungen der Eingangsdaten jedes Balkens eine andere Phase haben, oder es ist ein Merkmal.
Aber dann wird die Frage nach der Normalisierung erst recht relevant. Die Bedeutung ist z.B. für EURUSD und SP500 recht unterschiedlich.
Und offenbar ist es richtig, diese Zeiteinbettung von der Bibel auf die Train-Funktion zu übertragen.
@Dmitriy Gizlyk, die Frage stellte sich beim Studieren und Arbeiten mit der Bibliothek:
In der Methode zur Berechnung des Gradienten für versteckte Schichten fügen Sie outputVal
hinzu, um dessen Wert später in der calcOutputGradients-Methode für die Universalität zu kompensieren, richtig?
Sie haben auch eine Gradienten-Normalisierung hinzugefügt.
bool CNeuron::calcHiddenGradients(CLayer *&nextLayer) { double targetVal=sumDOW(nextLayer)+outputVal; return calcOutputGradients(targetVal); } //+------------------------------------------------------------------+ bool CNeuron::calcOutputGradients(double targetVal) { double delta=(targetVal>1 ? 1 : targetVal<-1 ? -1 : targetVal)-outputVal; gradient=(delta!=0 ? delta*activationFunctionDerivative(outputVal) : 0); return true; }
Die Frage ist, ob es richtiger wäre, nicht das Ziel, sondern das endgültige Delta sozu normalisieren.
double delta=targetVal-outputVal; delta=delta>1?1:delta<-1?-1:delta;
Warum? Beispiel: Wenn outputVal nahe bei 1 liegt und der gesamte gewichtete Gradient der nächsten Schicht ebenfalls hoch und positiv ist, erhalten wir nun ein Enddelta nahe bei Null, was falsch erscheint.
Schließlich sollte das Delta des Gradienten proportional zum Fehler der nächsten Schicht sein, d.h. mit anderen Worten, wenn das effektive Gewicht eines Neurons negativ ist (und möglicherweise in einigen anderen Fällen), wird das Neuron für einen Fehler weniger bestraft als bei einem positiven Gewicht. Ich habe es vielleicht etwas kurz erklärt, aber ich hoffe, dass diejenigen, die sich mit dem Thema beschäftigen, die Idee verstehen :) Vielleicht ist Ihnen dieser Punkt bereits aufgefallen und Sie haben eine solche Entscheidung getroffen, es wäre interessant, die Gründe dafür zu erfahren.
Der gleiche Punkt gilt auch für OCL-Code
__kernel void CalcHiddenGradient(__global double *matrix_w, __global double *matrix_g, __global double *matrix_o, __global double *matrix_ig, int outputs, int activation) { .............. switch(activation) { case 0: sum=clamp(sum+out,-1.0,1.0)-out; sum=sum*(1-pow(out==1 || out==-1 ? 0.99999999 : out,2));
@Dmitriy Gizlyk, die Frage stellte sich während des Studiums und der Arbeit in der Bibliothek:
In der Methode der Gradientenberechnung für versteckte Schichten fügen Sie outputVal
hinzu, um den Wert in der calcOutputGradients-Methode für die Universalität weiter zu kompensieren, richtig?
Sie haben auch eine Gradienten-Normalisierung hinzugefügt
Die Frage ist, ob es nicht korrekter wäre, nicht das Ziel, sondern das endgültige Delta wie folgtzu normalisieren
warum? Beispiel: Wenn outputVal nahe bei 1 liegt und der gewichtete Gesamtgradient der nächsten Schicht ebenfalls hoch und positiv ist, dann erhalten wir jetzt ein Enddelta nahe bei Null, was falsch erscheint.
Schließlich sollte das Delta des Gradienten proportional zum Fehler der nächsten Schicht sein, d.h. mit anderen Worten, wenn das effektive Gewicht eines Neurons negativ ist (und möglicherweise in einigen anderen Fällen), wird das Neuron für einen Fehler weniger bestraft als bei einem positiven Gewicht. Ich habe es vielleicht etwas kurz erklärt, aber ich hoffe, dass diejenigen, die sich mit dem Thema beschäftigen, die Idee verstehen :) Vielleicht ist Ihnen dieser Punkt bereits aufgefallen und Sie haben eine solche Entscheidung getroffen, es wäre interessant, die Gründe dafür zu erfahren.
Der gleiche Punkt gilt auch für OCL-Code
Nicht wirklich. Wir überprüfen die Zielwerte, genau wie bei versteckten Schichten, wo wir outpuVal zum Gradienten hinzufügen, um das Ziel zu erhalten und dessen Wert zu überprüfen. Der Punkt ist, dass Sigmoid einen begrenzten Bereich von Ergebnissen hat: logistische Funktion von 0 bis 1, tanh - von -1 bis 1. Wenn wir das Neuron für die Abweichung bestrafen und den Gewichtskoeffizienten unendlich erhöhen, werden wir zum Gewichtsüberlauf kommen. Denn wenn der Wert eines Neurons gleich 1 ist und die nachfolgende Schicht einen Fehler meldet, sollten wir den Wert auf 1,5 erhöhen. Das Neuron wird bei jeder Iteration gehorsam die Gewichte erhöhen, und die Aktivierungsfunktion wird die Werte auf dem Niveau von 1 abschneiden. Deshalb beschränke ich die Werte des Ziels auf die Bereiche der akzeptablen Werte der Aktivierungsfunktion. Und die Anpassung außerhalb des Bereichs überlasse ich den Gewichten der nachfolgenden Schicht.
Nicht wirklich. Wir überprüfen die Werte des Ziels, genau wie bei versteckten Schichten addieren wir outpuVal zum Gradienten, um das Ziel zu erhalten und seinen Wert zu überprüfen. Der Punkt ist, dass Sigmoid einen begrenzten Bereich von Ergebnissen hat: logistische Funktion von 0 bis 1, tanh - von -1 bis 1. Wenn wir das Neuron für die Abweichung bestrafen und den Gewichtungsfaktor unendlich erhöhen, werden wir zu einem Gewichtsüberlauf kommen. Wenn nämlich der Wert eines Neurons gleich 1 ist und die nachfolgende Schicht, die einen Fehler sendet, sagt, dass wir den Wert auf 1,5 erhöhen sollten. Das Neuron wird bei jeder Iteration gehorsam die Gewichte erhöhen, und die Aktivierungsfunktion wird die Werte auf dem Niveau von 1 abschneiden. Deshalb beschränke ich die Werte des Ziels auf die Bereiche der akzeptablen Werte der Aktivierungsfunktion. Und die Anpassung außerhalb des Bereichs überlasse ich den Gewichten der nachfolgenden Schicht.
Ich glaube, ich habe es geschafft. Aber ich frage mich immer noch, ob das der richtige Ansatz ist, ein Beispiel wie dieses:
Wenn das Netzwerk einen Fehler macht, indem es 0 angibt, obwohl es eigentlich 1 ist. Von der letzten Schicht kommt dann der Gradient, der auf der vorherigen Schicht gewichtet wurde (höchstwahrscheinlich, wie ich verstehe) positiv und kann mehr als 1 sein, sagen wir 1,6.
Nehmen wir an, es gibt ein Neuron in der vorherigen Schicht, das +0,6 produziert hat, d.h. es hat den richtigen Wert produziert - sein Gewicht sollte im Plus zunehmen. Und mit dieser Normalisierung schneiden wir die Veränderung seines Gewichts ab.
Das Ergebnis ist norm(1,6)=1. 1-0,6=0,4, und wenn wir es normalisieren, wie ich vorgeschlagen habe, wird es 1 sein. In diesem Fall verlangsamen wir die Verstärkung des richtigen Neurons.
Was meinen Sie dazu?
Was die unendliche Erhöhung der Gewichte angeht, so habe ich gehört, dass dies im Falle einer "schlechten Fehlerfunktion" passiert, wenn es viele lokale Minima gibt und keine ausgedrückten globalen, oder die Funktion nicht konvex ist, so etwas in der Art, ich bin kein Superexperte, ich glaube nur, dass man mit unendlichen Gewichten und anderen Methoden kämpfen kann und sollte.
Ich bitte um ein Experiment, um beide Varianten zu testen. Wenn ich mir überlege, wie ich den Test formulieren soll )
- Freie Handelsapplikationen
- Über 8.000 Signale zum Kopieren
- Wirtschaftsnachrichten für die Lage an den Finanzmärkte
Sie stimmen der Website-Richtlinie und den Nutzungsbedingungen zu.
Neuer Artikel Neuronale Netze leicht gemacht (Teil 9): Dokumentation der Arbeit :
Wir haben schon einen langen Weg hinter uns und der Code in unserer Bibliothek wird immer umfangreicher. Das macht es schwierig, den Überblick über alle Verbindungen und Abhängigkeiten zu behalten. Daher schlage ich vor, eine Dokumentation für den früher erstellten Code zu erstellen und diese mit jedem neuen Schritt zu aktualisieren. Eine gut vorbereitete Dokumentation wird uns helfen, die Integrität unserer Arbeit zu erkennen.
Sobald das Programm abgeschlossen ist, erhalten Sie eine fertige Dokumentation. Einige Screenshots sind unten abgebildet. Die vollständige Dokumentation finden Sie im Anhang.
Autor: Dmitriy Gizlyk