Einführung
Ich finde diese Frage wirklich interessant, ich gehe davon aus, dass jemand eine Zeitung darüber herausgebracht hat, aber es ist mein freier Tag, also möchte ich nicht nach Referenzen suchen.
Wir könnten es also als Repräsentation / Codierung der Ausgabe betrachten, was ich in dieser Antwort tue. Ich denke immer noch, dass es einen besseren Weg gibt, wo man einfach eine etwas andere Verlustfunktion verwenden kann. (Vielleicht Summe der quadratischen Differenzen mit Subtraktionsmodulo 2 ).π
Aber weiter mit der eigentlichen Antwort.
Methode
Ich schlage vor, dass ein Winkel als ein Wertepaar dargestellt wird, sein Sinus und sein Cosinus.θ
Die Codierungsfunktion lautet also:
und die Decodierungsfunktion lautet: Für arctan2 sind die inversen Tangenten, wobei die Richtung in allen Quadranten beibehalten wird.θ ↦ ( sin( θ ) , cos( θ ) )
( y1, y2) ↦ arctan2 ( y1, y2)
Theoretisch könnten Sie auch direkt mit den Winkeln arbeiten, wenn Ihr Werkzeug atan2
als Layer-Funktion unterstützt wird (genau 2 Eingaben nehmen und 1 Ausgabe erzeugen).
TensorFlow macht dies jetzt und unterstützt den Gradientenabstieg , obwohl es nicht für diese Verwendung vorgesehen ist. Ich habe out = atan2(sigmoid(ylogit), sigmoid(xlogit))
mit einer Verlustfunktion nachgeforscht min((pred - out)^2, (pred - out - 2pi)^2)
. Ich fand, dass es viel schlimmer trainierte als outs = tanh(ylogit), outc = tanh(xlogit))
mit einer Verlustfunktion 0.5((sin(pred) - outs)^2 + (cos(pred) - outc)^2
. Was meiner Meinung nach darauf zurückzuführen ist, dass der Gradient für unterbrochen istatan2
Mein Test hier führt es als Vorverarbeitungsfunktion aus
Um dies auszuwerten, habe ich eine Aufgabe definiert:
Bei einem Schwarzweißbild, das eine einzelne Linie auf einem leeren Hintergrund darstellt, wird ausgegeben, in welchem Winkel diese Linie zur "positiven x-Achse" liegt.
Ich habe eine Funktion implementiert, mit der diese Bilder zufällig mit Linien in zufälligen Winkeln erzeugt werden (Hinweis: In früheren Versionen dieses Beitrags wurden eher zufällige Neigungen als zufällige Winkel verwendet. Dank an @Ari Herman für den Hinweis. Es ist jetzt behoben). Ich habe mehrere neuronale Netze aufgebaut, um die Leistung für die Aufgabe zu bewerten. Die vollständigen Details der Implementierung finden Sie in diesem Jupyter-Notizbuch . Der Code ist alles in Julia und ich benutze die Mocha- Bibliothek für neuronale Netze.
Zum Vergleich stelle ich es den alternativen Skalierungsmethoden von 0,1 gegenüber. und in 500 Behälter zu setzen und Soft-Label-Softmax zu verwenden. Ich bin mit dem letzten nicht besonders glücklich und denke, ich muss es optimieren. Aus diesem Grund probiere ich es im Gegensatz zu den anderen nur für 1.000 Iterationen aus, im Gegensatz zu den beiden anderen, die für 1.000 und für 10.000 ausgeführt wurden
Versuchsaufbau
Die Bilder hatten eine Pixel, wobei die Linie in der Mitte beginnt und bis zum Rand reicht. Das Bild enthielt kein Rauschen usw., nur eine "schwarze" Linie auf weißem Hintergrund.101 × 101
Für jeden Trail wurden 1.000 Trainings- und 1.000 Testbilder zufällig generiert.
Das Bewertungsnetzwerk hatte eine einzige verborgene Schicht mit einer Breite von 500. Sigmoidneuronen wurden in der verborgenen Schicht verwendet.
Es wurde von Stochastic Gradient Decent mit einer festen Lernrate von 0,01 und einem festen Impuls von 0,9 trainiert.
Es wurde keine Regularisierung oder Dropout verwendet. Es gab auch keine Art von Faltung usw. Ein einfaches Netzwerk, von dem ich hoffe, dass sich diese Ergebnisse verallgemeinern lassen
Es ist sehr einfach , diese Parameter in dem zwicken Test - Code , und ich ermutige die Menschen , dies zu tun. (und suchen Sie nach Fehlern im Test).
Ergebnisse
Meine Ergebnisse sind wie folgt:
| | 500 bins | scaled to 0-1 | Sin/Cos | scaled to 0-1 | Sin/Cos |
| | 1,000 Iter | 1,000 Iter | 1,000 iter | 10,000 Iter | 10,000 iter |
|------------------------|--------------|----------------|--------------|----------------|--------------|
| mean_error | 0.4711263342 | 0.2225284486 | 2.099914718 | 0.1085846429 | 2.1036656318 |
| std(errors) | 1.1881991421 | 0.4878383767 | 1.485967909 | 0.2807570442 | 1.4891605068 |
| minimum(errors) | 1.83E-006 | 1.82E-005 | 9.66E-007 | 1.92E-006 | 5.82E-006 |
| median(errors) | 0.0512168533 | 0.1291033982 | 1.8440767072 | 0.0562908143 | 1.8491085947 |
| maximum(errors) | 6.0749693965 | 4.9283551248 | 6.2593307366 | 3.735884823 | 6.2704853962 |
| accurancy | 0.00% | 0.00% | 0.00% | 0.00% | 0.00% |
| accurancy_to_point001 | 2.10% | 0.30% | 3.70% | 0.80% | 12.80% |
| accurancy_to_point01 | 21.90% | 4.20% | 37.10% | 8.20% | 74.60% |
| accurancy_to_point1 | 59.60% | 35.90% | 98.90% | 72.50% | 99.90% |
Wo ich mich auf Fehler beziehe, ist dies der absolute Wert der Differenz zwischen dem vom neuronalen Netz ausgegebenen Winkel und dem wahren Winkel. So ist der mittlere Fehler (zum Beispiel) der Durchschnitt über die 1.000 Testfälle dieses Unterschieds usw. Ich bin nicht sicher, ob ich ihn nicht neu skalieren sollte, indem ich einen Fehler von say gleich mache auf einen Fehler von ). π7 π4π4
Ich präsentiere auch die Genauigkeit auf verschiedenen Ebenen der Granularität. Die Genauigkeit ist der Teil der Testfälle, die korreliert wurden. Das accuracy_to_point01
bedeutet, dass es als korrekt gezählt wurde, wenn die Ausgabe innerhalb von 0,01 des wahren Winkels lag. Keine der Darstellungen lieferte perfekte Ergebnisse, aber das ist angesichts der Funktionsweise der Gleitkomma-Mathematik keineswegs überraschend.
Wenn Sie sich den Verlauf dieses Beitrags ansehen, werden Sie feststellen, dass die Ergebnisse ein wenig verrauscht sind und sich jedes Mal geringfügig unterscheiden, wenn ich ihn erneut ausführe. Die allgemeine Reihenfolge und Skala der Werte bleibt jedoch gleich. So können wir einige Schlussfolgerungen ziehen.
Diskussion
Binning mit Softmax funktioniert bei weitem am schlechtesten, da ich nicht sicher bin, ob ich bei der Implementierung etwas falsch gemacht habe. Die Leistung liegt jedoch geringfügig über der Rate. Wenn wir nur raten würden, bekämen wir einen mittleren Fehler vonπ
Die Sin / Cos-Codierung ist wesentlich leistungsfähiger als die skalierte 0-1-Codierung. Die Verbesserung besteht darin, dass sin / cos bei 1.000 Trainingsiterationen bei den meisten Metriken etwa dreimal so gut abschneidet wie bei 10.000 Iterationen.
Ich denke, dies hängt zum Teil mit der Verbesserung der Verallgemeinerung zusammen, da beide einen relativ ähnlichen mittleren quadratischen Fehler im Trainingssatz aufwiesen und mindestens einmal 10.000 Iterationen ausgeführt wurden.
Es gibt sicherlich eine Obergrenze für die bestmögliche Leistung bei dieser Aufgabe, da der Winkel mehr oder weniger eine reelle Zahl sein kann, aber nicht alle derartigen Winkel erzeugen unterschiedliche Linien bei einer Auflösung von × Pixeln. Da zum Beispiel die Winkel 45.0 und 45.0000001 bei dieser Auflösung beide an dasselbe Bild gebunden sind, wird keine Methode jemals beide perfekt korrigieren.101 × 101
Es scheint auch wahrscheinlich, dass auf einer absoluten Skala, um über diese Leistung hinauszugehen, ein besseres neuronales Netzwerk benötigt wird. Anstatt der sehr einfachen, die oben im Versuchsaufbau beschrieben wurde.
Fazit.
Es scheint, dass die Sin / Cos-Darstellung bei weitem die beste der Darstellungen ist, die ich hier untersucht habe. Dies ist sinnvoll, da es einen glatten Wert hat, wenn Sie sich im Kreis bewegen. Ich mag es auch, dass das Umkehren mit arctan2 gemacht werden kann , was elegant ist.
Ich glaube, dass die vorgelegte Aufgabe ausreicht, um eine angemessene Herausforderung für das Netzwerk darzustellen. Obwohl ich wirklich denke, dass es nur darum geht, die Kurvenanpassung für es vielleicht zu einfach. Und vielleicht noch schlimmer, es könnte die gepaarte Darstellung begünstigen. Ich glaube nicht, dass es so ist, aber es wird spät hier, also habe ich vielleicht etwas verpasst, das ich Sie noch einmal einlade, meinen Code durchzusehen . Schlagen Sie Verbesserungen oder alternative Aufgaben vor.f( x ) = y1y2x