ANN-Regression, Approximation linearer Funktionen

8

Ich habe ein reguläres ANN-BP-Setup mit einer Einheit auf der Eingangs- und Ausgangsebene und vier Knoten mit Sigmoid versteckt aufgebaut. Es ist eine einfache Aufgabe, die lineare f(n) = n mit n im Bereich 0-100 anzunähern.

PROBLEM : Ungeachtet der Anzahl der Ebenen, der Einheiten in der ausgeblendeten Ebene oder unabhängig davon, ob ich die Knotenwerte binäre Werte verwende oder nicht, lernt man f (n) = Durchschnitt (Datensatz) wie folgt:

Code ist in JavaScript als Proof of Concept geschrieben. Ich habe drei Klassen definiert: Net, Layer und Connection, wobei Layer ein Array von Input-, Bias- und Output-Werten ist. Connection ist ein 2D-Array aus Gewichten und Delta-Gewichten. Hier ist der Layer-Code, in dem alle wichtigen Berechnungen stattfinden:

%Vor%

Die Hauptfunktionen feedForward und backProp sind wie folgt definiert:

%Vor%

Der Verbindungscode ist ziemlich einfach:

%Vor%

Und meine Aktivierungsfunktionen und Derivate sind wie folgt definiert:

%Vor%

Und Konfiguration JSON für das Netzwerk ist wie folgt:

%Vor%

Vielleicht kann Ihr erfahrenes Auge das Problem mit meinen Berechnungen erkennen?

Siehe Beispiel in JSFiddle

    
Division by Zero 08.11.2016, 16:21
quelle

2 Antworten

2

Ich habe den Code nicht ausgiebig angeschaut (weil es viel Code zum Anschauen gibt, müsste später dafür mehr Zeit brauchen und ich bin nicht 100% ig mit JavaScript vertraut). Wie auch immer, ich glaube, Stephen hat einige Änderungen an der Berechnung der Gewichte vorgenommen, und sein Code scheint korrekte Ergebnisse zu liefern, also würde ich empfehlen, sich das anzusehen.

Hier sind ein paar Punkte, die nicht unbedingt die Korrektheit von Berechnungen betreffen, aber trotzdem helfen können:

  • Wie viele Beispiele zeigen Sie das Netzwerk für das Training? Zeigen Sie den gleichen Eingang mehrmals? Sie sollten jedes Beispiel, das Sie haben, (Eingaben) mehrmals zeigen; jedes Beispiel nur einmal zu zeigen ist nicht ausreichend für Algorithmen, die auf Gradientenabstieg basieren, da sie sich jedes Mal nur ein wenig in die richtige Richtung bewegen. Es ist möglich, dass Ihr gesamter Code korrekt ist, aber Sie müssen ihm einfach etwas mehr Zeit zum Trainieren geben.
  • Die Einführung von mehr versteckten Schichten wie Stephen könnte helfen, das Training zu beschleunigen, oder es könnte schädlich sein. Dies ist normalerweise etwas, mit dem Sie in Ihrem speziellen Fall experimentieren möchten. Für dieses einfache Problem sollte es jedoch nicht unbedingt notwendig sein. Ich vermute, ein wichtigerer Unterschied zwischen Ihrer Konfiguration und Stephens Konfiguration könnte die Aktivierungsfunktion sein, die in den versteckten Ebenen verwendet wird. Sie haben ein Sigmoid verwendet, was bedeutet, dass alle Eingabewerte in der ausgeblendeten Ebene unter 1,0 gequetscht werden und Sie dann sehr große Gewichte benötigen, um diese Zahlen zurück in die gewünschte Ausgabe zu transformieren (was bis zu einem Wert von 100). Stephen verwendete lineare Aktivierungsfunktionen für alle Schichten, was in diesem speziellen Fall das Training wahrscheinlich erleichtert, weil Sie tatsächlich versuchen, eine lineare Funktion zu lernen. In vielen anderen Fällen wäre es jedoch wünschenswert, Nichtlinearitäten einzuführen.
  • Es kann vorteilhaft sein, sowohl Ihre Eingabe als auch Ihre gewünschte Ausgabe in [0, 1] anstatt in [0, 100] zu transformieren (normalisieren). Dies würde es wahrscheinlicher machen, dass Ihre Sigmoidschicht gute Ergebnisse erzielt (obwohl ich mir immer noch nicht sicher bin, ob es ausreichen würde, weil Sie immer noch eine Nichtlinearität in einem Fall einführen, in dem Sie eine lineare Funktion lernen wollen und Sie benötigt möglicherweise mehr versteckte Knoten, um das zu korrigieren). In "realen" Fällen, in denen Sie mehrere verschiedene Eingabevariablen haben, wird dies in der Regel ebenfalls durchgeführt, da sichergestellt wird, dass alle Eingabevariablen anfangs als gleich wichtig behandelt werden. Sie könnten immer einen Vorverarbeitungsschritt ausführen, in dem Sie die Eingabe zu [0, 1] normalisieren, dem Netzwerk als Eingabe übergeben, es zur Ausgabe in [0, 1] erstellen und dann einen Nachverarbeitungsschritt hinzufügen, in dem Sie die Ausgabe transformieren zurück zum ursprünglichen Bereich.
Dennis Soemers 17.11.2016 11:16
quelle
1

Erstens ... Ich mag diesen Code wirklich. Ich weiß sehr wenig über NNs (gerade erst angefangen) so entschuldigen Sie meine fehlende wenn überhaupt.

Hier ist eine Zusammenfassung der Änderungen, die ich vorgenommen habe:

%Vor%

Der Konfigurationsabschnitt sieht jetzt so aus:

%Vor%

    
Stephen Mathews 15.11.2016 14:09
quelle