Für das populäre Deep -Lernen ist es notwendig, den Geist des Lernens aufrechtzuerhalten - Programmierer, insbesondere Architekten, müssen sich immer über Kerntechnologien und wichtige Algorithmen besorgt machen, und wenn dies erforderlich ist, müssen Sie es schreiben und beherrschen. Es ist mir egal, wann man es benutzt - ob es ein politisches Problem ist oder ob es ein technisches Problem ist, genau wie Soldaten kümmern sich nicht darum, ob Sie kämpfen möchten oder nicht, sondern wie Sie gewinnen sollen.
Wie Programmierer maschinelles Lernen lernen
Für Programmierer hat maschinelles Lernen einen bestimmten Schwellenwert (dieser Schwellenwert ist auch die Kernwettbewerbsfähigkeit). Ich glaube, dass viele Menschen Kopfschmerzen für englische Papiere voller mathematischer Formeln haben, wenn sie maschinelles Lernen lernen, und sogar aufgeben können. Tatsächlich ist das Implementierungsprogramm für maschinelles Lernalgorithmus jedoch nicht schwer zu schreiben. Das Folgende ist der Reverse Multi-Layer (BP) Neural Network Algorithmus, der durch 70 Codezeilen implementiert ist, dh Deep Learning. Tatsächlich sind es nicht nur neuronale Netzwerke, sondern die meisten Algorithmen für maschinelles Lernen wie logistische Regression, Entscheidungsbaum C45/ID3, Zufallswald, Bayesian, kollaborative Filterung, Graph Computing, Kmeans, Pageank usw. können in 100 Reihen von Stand-Alon-Programmen implementiert werden (in Betrachtlichkeit später).
Die wirkliche Schwierigkeit des maschinellen Lernens liegt darin, warum es so berechnet wird, was ist das mathematische Prinzip dahinter und wie man die Formel abgeleitet hat. Die meisten Informationen im Internet führen diesen Teil des theoretischen Wissens ein, erzählen jedoch selten, wie der Berechnungsprozess und die Programmimplementierung des Algorithmus sind. Für Programmierer müssen Sie nur technische Anwendungen tun und keine neue mathematische Berechnungsmethode beweisen. Tatsächlich verwenden die meisten Ingenieure für maschinelles Lernen Open -Source -Pakete oder Toolsoftware, die von anderen geschrieben wurden, um Daten einzugeben und die Berechnungskoeffizienten anzupassen, um die Ergebnisse zu trainieren, und den Algorithmusprozess selten selbst implementieren. Es ist jedoch immer noch sehr wichtig, den Berechnungsprozess jedes Algorithmus zu beherrschen, sodass Sie verstehen können, was der Algorithmus verändert und welche Daten der Algorithmus zur Erreichung dient.
Dieser Artikel konzentriert sich auf die Implementierung von Einzelmaschinen von umgekehrten neuronalen Netzwerken. In Bezug auf die Mehrmaschine-Parallelisierung neuronaler Netzwerke bietet Fourinone ein sehr flexibles und vollständiges Parallel-Computer-Framework. Wir müssen nur die Implementierung des eigenständigen Programms verstehen, um eine verteilte Parallelisierungslösung zu konzipieren und zu entwerfen. Wenn wir den Algorithmusberechnungsprozess nicht verstehen, können nicht alle Ideen erweitert werden. Darüber hinaus gibt es auch ein Faltungs -neuronales Netzwerk, das hauptsächlich eine Dimensionsreduktionsidee darstellt, die für die Bildverarbeitung verwendet wird und nicht im Rahmen dieses Artikels liegt.
Prozessbeschreibung des neuronalen Netzwerks:
Erstens ist es wichtig zu sein, dass das neuronale Netzwerk Vorhersageaufgaben ausführt. Ich glaube, Sie erinnern sich an die Methode der kleinsten Quadrate, die Sie in der High School gelernt haben. Wir können dies verwenden, um eine weniger strenge, aber intuitivere Analogie zu erstellen:
Erstens möchten wir die Markierungen eines Datensatzes und eines Datensatzes erhalten (in der Methode der kleinsten Quadrate erhalten wir auch eine Reihe von Werten von x und y).
Der Algorithmus passt zu einem Funktionsparameter, der diesen Datensatz basierend auf diesem Datensatz und den entsprechenden Markierungen ausdrücken kann (dh der Formel, die A und B in der Methode der kleinsten Quadrate berechnet, aber diese Formel kann nicht direkt im neuronalen Netzwerk erhalten werden)
Wir erhalten die angepasste Funktion (dh die angepasste Linie y^= ax+b in der Methode der kleinsten Quadrate)
Nach dem Einbringen neuer Daten kann der entsprechende vorhergesagte Wert y^generiert werden (in der Methode der kleinsten Quadrate soll Y^= Ax+B einbringen, um die vorhergesagte y^zu erhalten, ebenso wie der Algorithmus für neuronale Netzwerk, aber die erhaltene Funktion ist viel komplexer als die Methode der kleinsten Quadrate).
Der Berechnungsprozess von neuronalen Netzwerken
Die Struktur des neuronalen Netzwerks ist in der folgenden Abbildung dargestellt. Die Eingangsschicht ist die Eingangsschicht, das rechts ist die Ausgangsschicht und die Mitte ist mehrere versteckte Schichten. Jeder neuronale Knoten der versteckten Schicht und die Ausgangsschicht wird durch Multiplizieren des vorherigen Schichtknotens mit ihrem Gewicht akkumuliert. Der mit "+1" gekennzeichnete Kreis ist der Intercept -Begriff b. Für jeden Knoten außerhalb der Eingangsschicht: y = w0*x0+w1*x1+…+wn*xn+b können wir wissen, dass das neuronale Netzwerk einer mehrschichtigen logistischen Regressionsstruktur entspricht.
Der Algorithmusberechnungsprozess: Die Eingangsschicht startet, berechnet von links nach rechts und geht für Schicht vorwärts, bis die Ausgangsschicht das Ergebnis erzeugt. Wenn es eine Differenz zwischen dem Ergebniswert und dem Zielwert gibt, berechnen Sie von rechts nach links, berechnen Sie den Fehler jeder Knotenschicht für Schicht und passen Sie alle Gewichte jedes Knotens an. Berechnen Sie sie nach dem Erreichen der Eingangsschicht umgekehrt erneut vor und iterieren Sie die obigen Schritte, bis alle Gewichtsparameter zu einem vernünftigen Wert konvergieren. Da Computerprogramme Gleichungsparameter und mathematische Methoden unterscheiden, wählen sie normalerweise zuerst Parameter aus und passen dann die Parameter ständig an, um den Fehler zu reduzieren, bis der richtige Wert angezeigt wird. Das meiste maschinelle Lernen ist ständig iteratives Training. Schauen wir uns die Implementierung dieses Prozesses aus dem Programm genauer an.
Implementierung des Algorithmusprogramms von neuronalem Netzwerk
Die Implementierung des Algorithmusprogramms von neuronalen Netzwerken ist in drei Prozesse unterteilt: Initialisierung, Vorwärtsberechnungsergebnisse und umgekehrte Modifikation von Gewichten.
1. Initialisierungsprozess
Da es sich um ein neuronales N-Layer-Netzwerk handelt, verwenden wir eine zweidimensionale Array-Schicht, um den Knotenwert aufzuzeichnen. Die erste Dimension ist die Anzahl der Schichten, die zweite Dimension ist die Knotenposition der Schicht, und der Wert des Arrays ist der Knotenwert; In ähnlicher Weise wird auch der Knotenfehler -Wert LayerErerr auf ähnliche Weise aufgezeichnet. Verwenden Sie das dreidimensionale Array Layer_gewicht, um die Gewichte jedes Knotens aufzuzeichnen. Die erste Dimension ist die Anzahl der Schichten, die zweite Dimension ist die Knotenposition der Schicht, die dritte Dimension ist die Position des unteren Schichtknotens, der Wert des Arrays ist der Gewichtswert eines Knotens, der eine niedrigere Schicht erreicht, und der Anfangswert ist eine Zufallszahl zwischen 0-1. Um die Konvergenzgeschwindigkeit zu optimieren, wird hier die Einstellung der Impulsmethode gewichtet. Es ist erforderlich, die letzte Gewichtsanpassungsmenge aufzuzeichnen und die dreidimensionale Array-Layer_weight_delta zu verwenden. Abfangen Term Processing: Das Programm legt den Wert des Abschnitts auf 1 fest, so dass es nur sein Gewicht berechnen muss.
2. Berechnen Sie die Ergebnisse vorwärts
Die S-Funktion 1/(1+math.exp (-z)) wird verwendet, um den Wert jedes Knotens zwischen 0-1 zu vereinen und ihn dann für Schicht bis zur Ausgangsschicht zu berechnen. Für die Ausgangsschicht besteht tatsächlich keine Notwendigkeit, die S -Funktion zu verwenden. Wir betrachten das Ausgangsergebnis als Wahrscheinlichkeitswert zwischen 0 und 1, sodass auch die S -Funktion verwendet wird, was auch für die Gleichmäßigkeit des Programms förderlich ist.
3.. Umgekehrt das Gewicht umgekehrt zu ändern
So berechnen Sie Fehler in neuronalen Netzwerken im Allgemeinen für die Quadratfehlerfunktion E wie folgt:
Das heißt, die Quadrate der Fehler mehrerer Ausgangsbegriffe und entsprechender Zielwerte werden durch 2 gesammelt und geteilt. Tatsächlich ist dies die Fehlerfunktion der logistischen Regression. Wenn diese Funktion verwendet wird, um den Fehler zu berechnen, was ist die mathematische Rationalität und wie sie erhalten wird, schlage ich vor, dass Programmierer keine Mathematiker sein wollen. Gehen Sie also nicht ausführlich darauf ein. Was wir jetzt tun müssen, ist, wie Sie den Mindestwert des Fehlers dieser Funktion E übernehmen und ihn abgeben müssen. Wenn es einige Grundlagen der derivativen Mathematik gibt, können Sie versuchen, die folgende Formel aus den abgeleiteten Funktionsgewichten E zu erhalten:
Es spielt keine Rolle, ob wir es nicht ableiten können. Wir müssen nur die Ergebnisformel verwenden. In unserem Programm verwenden wir LayerErR, um den minimierten Fehler nach E -Gewichtsableitung aufzuzeichnen und dann das Gewicht entsprechend dem minimierten Fehler anzupassen.
Beachten Sie, dass die Impulsmethode hier verwendet wird, um die Erfahrung der vorherigen Anpassung zu berücksichtigen, um nicht in den lokalen Mindestwert zu fallen. Das folgende K repräsentiert die Anzahl der Iterationen, Mobp ist der Impulsbegriff und die Rate ist der Lernschritt:
ΔW (K+1) = MOBP*ΔW (K)+Rate*Err*-Schicht
Im Folgenden werden auch viele Formeln verwendet, und der Unterschied ist nicht zu groß:
ΔW (K+1) = MOBP*ΔW (K)+(1-MOBP) Rate*Err*-Schicht
Um die Leistung zu verbessern, beachten Sie, dass die Programmimplementierung den Fehler berechnet und das Gewicht in einer Weile anpassen soll. Positionieren Sie zuerst die Position auf der zweiten bis letzt -Schicht (dh der letzten versteckten Schicht) und stellen Sie dann die Gewichtsschicht in umgekehrte Schicht ein. Passen Sie das Gewicht der L -Schicht gemäß dem durch L+1 -Schicht berechneten Fehler an und berechnen Sie den Fehler der L -Schicht und berechnen Sie das Gewicht beim nächsten Mal, um das Gewicht bis zum Ende der ersten Schicht (Eingangsschicht) zu berechnen.
Zusammenfassung
Während des gesamten Berechnungsprozesses ändert sich der Wert des Knotens jedes Mal, wenn er berechnet wird und muss nicht gespeichert werden. Die Gewichtsparameter und Fehlerparameter müssen gespeichert werden und unterstützen die nächste Iteration. Wenn wir daher eine verteilte Multi-Machine-Parallel-Computerlösung konzipieren, können wir verstehen, warum es in anderen Frameworks ein Konzept des Parameterservers gibt.
Vollständige Programmimplementierung des neuronalen Netzwerks mit mehreren Schichten
Das folgende Implementierungsprogramm BPDeep.java kann direkt verwendet werden und es ist auch einfach, es für jede andere Sprachimplementierung wie C, C#, Python usw. zu ändern, da es sich um alle grundlegenden Anweisungen handelt und keine anderen Java -Bibliotheken (außer zufälligen Funktionen).
import Java.util.random; öffentliche Klasse BPDeep {public double [] [] layer; // NEURAL NETZNEHME PUBLIC DOUBLE [] [] LAYEERERR; // NEURNELNEHMENSCHAFTEN NODE ERROR PUBLIC DOUBLE [] [] [] layer_gewicht; // Neural Layer Node Gewicht Public Double [] [] [] Layer_Weighta; // // NEURAL LADE NOTE WORDE WOLLEM IMPERT; Rate; // Lernkoeffizient öffentlich BPDeep (int [] layernum, doppelte Rate, Doppelmobp) {this.mobp = mobp; this.rate = rate; Layer = neues Double [Layernum.Length] []; LayerErr = New Double [Layernum.Length] []; Layer_weight = New Double [Layernum.Length] [] []; layer_weight_delta = new Double [layernum.length] [] []; Random random = new random (); für (int l = 0; l <layernum.length; l ++) {Layer [l] = neues double [layernum [l]]; layererr [l] = neues double [layernum [l]]; if (l+1 <layernum.length) {layer_weight [l] = neues double [layernum [l] +1] [layernum [l+1]]; layer_weight_delta [l] = neues double [layernum [l] +1] [layernum [l+1]]; for(int j=0;j<layernum[l]+1;j++) for(int i=0;i<layernum[l+1];i++) layer_weight[l][j][i]=random.nextDouble();//Random initialization weight} } } //Compute the output layer by layer public double[] computeOut(double[] in){ for(int l = 1; l <Layer.Length; l ++) {für (int j = 0; j <layer [l] .Length; j ++) {double z = layer_weight [l-1] [Layer [l-1] .Länge] [j]; für (int i = 0; i <layer [l-1] .Length; i ++) {Layer [l-1] [i] = l == 1? In [i]: layer [l-1] [i]; z+= layer_weight [l-1] [i] [j]*layer [l-1] [i]; } Layer [l] [j] = 1/(1+math.exp (-z)); }} Rückgabeschicht [Layer.Length-1]; } // Berechnen Sie die Fehlerschicht für Schicht umgekehrt und ändern Sie das Gewicht Public void UpdateWeight (double [] tar) {int l = Layer.Length-1; für (int j = 0; j <layererr [l] .Length; j ++) layererr [l] [j] = layer [l] [j]*(1-layer [l] [j])*(tar [j] -layer [l] [j]); while (l-> 0) {für (int j = 0; j <layererr [l] .Length; j ++) {double z = 0,0; für (int i = 0; i <layererr [l+1] .Length; i ++) {z = z+l> 0? layererr [l+1] [i]*layer_weight [l] [j] [i]: 0; layer_weight_delta [l] [j] [i] = mobp*layer_weight_delta [l] [j] [i]+rate*layererr [l+1] [i]*layer [l] [j]; // Implant Layer -Impuls -Einstellungsschiebung Layer_gewicht [l] [j] [i]+= laywighthighthelta [l] [j] [i]; if (j == layererr [l] .Length-1) {layer_weight_delta [l] [j+1] [i] = mobp*layer_weight_delta [l] [j+1] [i]+rate*layererr [l+1] [i]; // Die Impulsanpassung angreifen Layer_weight [l] [j+1] [i]+= layer_weight_delta [l] [j+1] [i]; // Schnittgewichtsanpassung}} Layererr [l] [j] = z*layer [l] [j]*(1-layer [l] [j]); // DOUBLE}}}}}} usw. out void-Zug (double [] in, double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double [] double; Berechnung (in); UpdateWeight (TAR); }}Ein Beispiel für die Verwendung neuronaler Netzwerke
Lassen Sie uns schließlich ein einfaches Beispiel finden, um die magischen Auswirkungen neuronaler Netzwerke zu sehen. Um die Beobachtung der Datenverteilung zu erleichtern, wählen wir zweidimensionale Koordinatendaten. Es finden Sie 4 Daten unten. Der Block repräsentiert die Art der Daten ist 1, und das Dreieck repräsentiert die Art der Daten ist 0. Sie können sehen, dass die zum Blocktyp gehörenden Daten (1, 2) und (2, 1) und die Daten, die zum Dreieckstyp gehören, (1, 1), (2, 2) sind. Das Problem ist nun, dass wir die 4 Daten in 1 und 0 in der Ebene unterteilen und diese verwenden müssen, um die Art der neuen Daten vorherzusagen.
Wir können einen logistischen Regressionsalgorithmus verwenden, um das obige Klassifizierungsproblem zu lösen, aber die logistische Regression erhält eine lineare gerade Linie als Trennlinie. Sie können sehen, dass egal wie die rote Linie oben platziert ist, eine Probe immer fälschlicherweise in verschiedene Typen unterteilt ist. Daher kann für die obigen Daten nur eine gerade Linie ihre Klassifizierung nicht korrekt teilen. Wenn wir den neuronalen Netzwerkalgorithmus verwenden, können wir den Klassifizierungseffekt der folgenden Abbildung erzielen, was dem Auffinden der Vereinigung mehrerer gerader Linien entspricht, um den Raum zu teilen, der die Genauigkeit höher ist.
Hier ist der Quellcode dieses Testprogramms bpdeepest.java:
Import Java.util.Arrays; öffentliche Klasse BPDeepTest {public static void main (String [] args) {// Initialisieren Sie die grundlegende Konfiguration des neuronalen Netzwerks // Der erste Parameter ist ein ganzzahliges Array, das die Anzahl der Schichten des neuralen Netzwerks und die Anzahl der Knoten pro Schicht darstellt. For example, {3, 10, 10, 10, 10, 2} means that the input layer is 3 nodes, the output layer is 2 nodes, and there are 4 hidden layers in the middle, and 10 nodes per layer //The second parameter is the learning step size, and the third parameter is the momentum coefficient BpDeep bp = new BpDeep(new int[]{2, 10, 2}, 0.15, 0.8); // Setzen Sie die Beispieldaten, die dem obigen 4 zweidimensionalen Koordinatendaten double [] [] data = new Double [] [] [] {{1,2}, {2,2}, {1,1}, {2,1}} entsprechen; // Die Zieldaten festlegen, entsprechend der Klassifizierung von 4 Koordinatendaten double [] [] target = new Double [] [] {{1,0}, {0,1}, {0,1}, {1,0}}; // iteratives Training 5000 -mal für (int n = 0; n <5000; n ++) für (int i = 0; i <data.length; i ++) Bp.Train (Daten [i], Ziel [i]); // Beispieldaten basierend auf den Trainingsergebnissen für (int j = 0; j <data.length; j ++) {double [] result = bp.computeout (Daten [j]); System.out.println (Arrays.toString (Daten [j])+":"+arrays.toString (Ergebnis)); } // Die Klassifizierung neuer Daten basierend auf den Trainingsergebnissen double [] x = new Double [] {3,1}; double [] result = bp.computeout (x); System.out.println (Arrays.toString (x)+":"+arrays.toString (Ergebnis)); }} Zusammenfassung
Das obige Testprogramm zeigt, dass neuronale Netze magische Klassifizierungseffekte haben. Tatsächlich haben neuronale Netze bestimmte Vorteile, sind jedoch keine universellen Algorithmen nahe dem menschlichen Gehirn. Oft kann es uns enttäuschen. Wir müssen auch viele Daten aus verschiedenen Szenarien verwenden, um die Auswirkungen zu beobachten. Wir können die versteckte 1-Schicht-versteckte Schicht in N-Schicht ändern und die Anzahl der Knoten, Iterationen, Lernschrittgröße und Impulskoeffizienten pro Schicht anpassen, um ein optimiertes Ergebnis zu erzielen. In vielen Fällen ist die Wirkung der versteckten N-Schicht-Schicht jedoch nicht signifikant verbessert als die von Schicht 1. Stattdessen ist die Berechnung komplexer und zeitaufwändiger. Unser Verständnis von neuronalen Netzwerken erfordert mehr Übung und Erfahrung.
Das obige Inhalt ist in diesem Artikel über die Implementierung von tiefen neuronalen Netzwerkalgorithmen mit 70 Zeilen Java -Code. Ich hoffe, es wird für alle hilfreich sein. Wenn es Mängel gibt, hinterlassen Sie bitte eine Nachricht, um darauf hinzuweisen.