Inhaltsverzeichnis[Ausblenden][Zeigen]
Das Gehirn ist vergleichbar mit neuronalen Netzen. Dies ist die Analogie, die normalerweise verwendet wird, um jemandem, der sich mit dem Thema noch nicht auskennt, dabei zu helfen, die Ideen hinter maschinellem Lernen und künstlichen neuronalen Netzen zu verstehen.
Da hinter den Kulissen mehrere Ebenen mathematischer und statistischer Berechnungen ablaufen, ist die Definition dieser Netzwerke als mathematische Funktion eine fortgeschrittenere Methode.
Dies ist für die Leute, die sich tatsächlich für maschinelles Lernen interessieren und sehen möchten, wie der Code für neuronale Python-Netzwerke geschrieben wird.
In diesem Artikel zeigen wir, wie Sie ein vollständig verbundenes tiefes neuronales Netzwerk (DNN) von Grund auf neu erstellen Python 3.
Ein Überblick über die Dateistruktur für unseren Python Neural Network Code
Hier werden drei Dateien erstellt. Die erste ist die einfache nn.py-Datei, die in „Hilfsfunktionen einrichten“ und „Neuronales Netzwerk von Grund auf neu aufbauen“ besprochen wird.
Wir werden auch eine Datei namens mnist loader.py haben, um die Testdaten zu laden, wie in „Laden von MNIST-Daten“ beschrieben.
Schließlich haben wir eine Datei namens test.py, die im Terminal gestartet wird, um unser neuronales Netzwerk zu testen.
Diese Datei wird ausführlich unter „Ausführen von Tests“ beschrieben.
Installation
Die NumPy-Python-Bibliothek muss heruntergeladen werden, um diesem Tutorial folgen zu können. Sie können dies erreichen, indem Sie den folgenden Befehl auf dem Terminal verwenden:
Importieren von Modulen und Einrichten der Hilfsfunktion
Die einzigen zwei Bibliotheken, die wir benötigen, sind random und NumPy, die wir sofort importieren werden. Für die anfänglichen Gewichtungen unseres neuronalen Netzwerks mischen wir sie mithilfe der Zufallsbibliothek.
Um unsere Berechnungen zu beschleunigen, verwenden wir NumPy oder np (konventionell wird es oft als np importiert). Unsere beiden Hilfsfunktionen werden nach unseren Importen erstellt. Zwei Sigmoid-Funktionen: Eins und Sigmoid-Primzahl.
Die logistische Regression klassifiziert Daten mithilfe der Sigmoid-Funktion, während die Backpropagation das Delta oder den Gradienten mithilfe der Sigmoid-Primzahl-Funktion berechnet.
Netzwerkklasse erstellen
Der Aufbau eines vollständig verknüpften neuronalen Netzes ist der einzige Schwerpunkt dieses Abschnitts. Die Netzwerkklasse umfasst alle nachfolgenden Funktionen. Die Funktion Object() { [native code] } wird zunächst in unserer Netzwerkklasse erstellt.
Ein Argument, Größen, wird von der Funktion Object() { [native code] } benötigt. Die Größenvariable ist eine Sammlung numerischer Werte, die die Anzahl der Eingabeknoten darstellt, die in jeder Schicht unseres neuronalen Netzwerks vorhanden sind.
Wir initialisieren vier Eigenschaften in unserer Methode __init__. Die Eingabevariablen, Größen, werden verwendet, um die Liste der Schichtgrößen bzw. die Anzahl der Schichten, Anzahl Schichten, festzulegen.
Der erste Schritt besteht darin, die anfänglichen Vorspannungen unseres Netzwerks zufällig jeder Schicht zuzuweisen, die der Eingabeschicht folgt.
Schließlich werden die Gewichtungen jeder Verbindung zwischen den Eingabe- und Ausgabeschichten zufällig generiert. Np.Random.Randn() gibt eine Zufallsstichprobe aus der Normalverteilung für den Kontext.
Feed-Forward-Funktion
In einem neuronalen Netzwerk werden Informationen durch die Feedforward-Funktion weitergeleitet. Diese Funktion benötigt ein Argument, a, das den aktuellen Aktivierungsvektor angibt.
Diese Funktion schätzt die Aktivierungen auf jeder Schicht, indem sie über alle Bias und Gewichtungen im Netzwerk iteriert. Die gegebene Antwort ist die Vorhersage, die die Aktivierungen der letzten Schicht sind.
Mini-Batch-Gradientenabstieg
Das Arbeitspferd unserer Netzwerkklasse ist Gradient Descent. In dieser Version verwenden wir einen (stochastischen) Mini-Batch-Gradientenabstieg, eine modifizierte Variante des Gradientenabstiegs.
Dies weist darauf hin, dass eine kleine Gruppe von Datenpunkten verwendet wird, um unser Modell zu aktualisieren. Dieser Methode werden vier erforderliche und ein optionales Argument übergeben. Die vier erforderlichen Variablen sind der Trainingsdatensatz, die Anzahl der Epochen, die Größe der Mini-Batches und die Lernrate (eta).
Testdaten sind auf Anfrage erhältlich. Wir werden Testdaten bereitstellen, wenn wir dieses Netzwerk schließlich evaluieren. Die Anzahl der Samples in dieser Funktion wird zunächst auf die Länge der Liste gesetzt, nachdem die Trainingsdaten in einen Listentyp umgewandelt wurden.
Dasselbe Verfahren wenden wir auch bei uns übergebenen Testdaten an. Denn diese kommen nicht als Listen, sondern als Listen-Zips an uns zurück. Wenn wir später die MNIST-Datenbeispiele laden, werden wir mehr darüber erfahren.
Wenn wir sicherstellen können, dass wir beide Arten von Daten als Listen bereitstellen, ist diese Typisierung nicht unbedingt erforderlich.
Sobald wir die Daten haben, gehen wir die Trainingsepochen in einer Schleife durch. Eine Trainingsperiode ist nur eine Runde des neuronalen Netzwerktrainings. Wir mischen zuerst die Daten in jeder Epoche, um die Zufälligkeit sicherzustellen, bevor wir eine Liste von Mini-Batches erstellen.
Die Update-Mini-Batch-Funktion, die unten diskutiert wird, wird für jeden Mini-Batch aufgerufen. Die Testgenauigkeit wird ebenfalls zurückgegeben, wenn die Testdaten verfügbar sind.
Kostenableitungs-Hilfsfunktion
Lassen Sie uns zuerst eine Hilfsfunktion namens Kostenableitung entwickeln, bevor wir den Backpropagation-Code wirklich erstellen. Wenn wir in unserer Ausgabeschicht einen Fehler machen, zeigt die Kostenableitungsfunktion dies an.
Es erfordert zwei Eingaben: das Array der Ausgabeaktivierungen und die y-Koordinaten der erwarteten Ausgabewerte.
Backpropagation-Funktion
Unser gegenwärtiger Aktivierungsvektor, Aktivierung, sowie alle anderen Aktivierungsvektoren, Aktivierungen und z-Vektoren, zs, müssen alle im Auge behalten werden. Zuerst wird eine Schicht namens Eingabeschicht aktiviert.
Wir werden jede Neigung und jedes Gewicht durchgehen, nachdem wir sie aufgestellt haben. Jede Schleife beinhaltet das Berechnen des z-Vektors als Skalarprodukt der Gewichtungen und der Aktivierung, das Hinzufügen zur Liste der zs, das Neuberechnen der Aktivierung und das Hinzufügen der aktualisierten Aktivierung zur Liste der Aktivierungen.
Zum Schluss die Mathematik. Das Delta, das gleich dem Fehler aus der vorherigen Schicht multipliziert mit der sigmoiden Primzahl des letzten Elements der zs-Vektoren ist, wird berechnet, bevor wir mit unserem Rückwärtsdurchlauf beginnen.
Die letzte Schicht von nabla b ist auf das Delta eingestellt, und die letzte Schicht von nabla w ist auf das Skalarprodukt des Deltas und der vorletzten Aktivierungsschicht eingestellt (transponiert, damit wir tatsächlich rechnen können). .
Wir gehen wie zuvor vor, beginnend mit der zweiten Schicht und schließen mit der letzten ab und wiederholen den Vorgang nach Abschluss dieser letzten Schichten. Die Nablas werden dann als Tupel zurückgegeben.
Aktualisierung des Mini-Batch-Gradientenabstiegs
Unsere SGD-Methode (Stochastic Gradient Descent) von früher beinhaltet eine Mini-Batch-Aktualisierung. Da es in SGD verwendet wird, aber auch Backprop benötigt, habe ich darüber diskutiert, wo ich diese Funktion platzieren soll.
Schließlich habe ich mich entschieden, es hier zu posten. Es beginnt mit der Generierung von 0 Vektoren der Nablas der Vorspannungen und Gewichtungen, genau wie es unsere Backprop-Funktion getan hat.
Es erfordert den Mini-Batch und die Eta-Lernrate als seine beiden Eingaben. Im Mini-Batch verwenden wir dann die Backprop-Funktion, um das Delta jedes Nabla-Arrays für jede Eingabe, x, und Ausgabe, y, zu erhalten. Die Nabla-Listen werden dann mit diesen Deltas aktualisiert.
Schließlich verwenden wir die Lernrate und die Nablas, um die Gewichtungen und Verzerrungen des Netzwerks zu aktualisieren. Jeder Wert wird auf den neuesten Wert abzüglich der Lernrate aktualisiert, mit der Minibatch-Größe multipliziert und dann zum Nabla-Wert addiert.
Funktion auswerten
Die Auswertungsfunktion ist die letzte, die wir schreiben müssen. Die Testdaten sind die einzige Eingabe für diese Funktion. In dieser Funktion vergleichen wir nur die Ausgänge des Netzwerks mit dem erwarteten Ergebnis y. Durch Weiterleiten der Eingabe x werden die Ausgaben des Netzwerks bestimmt.
Code vervollständigen
Wenn wir den gesamten Code kombinieren, sieht er so aus.
Testen des neuronalen Netzwerks
Laden von MNIST-Daten
Das MNIST-Daten ist im .pkl.gz-Format, das wir mit GZIP öffnen und mit pickle laden. Lassen Sie uns eine schnelle Methode schreiben, um diese Daten als Tupel der Größe drei zu laden, aufgeteilt in Trainings-, Validierungs- und Testdaten.
Um die Verwaltung unserer Daten zu vereinfachen, schreiben wir eine weitere Funktion, um das y in ein Array mit 10 Elementen zu codieren. Das Array besteht ausschließlich aus Nullen mit Ausnahme einer 0, die der richtigen Ziffer des Bildes entspricht.
Wir verwenden die grundlegenden Ladedaten und eine Hot-Encode-Methode, um unsere Daten in ein lesbares Format zu laden. Es wird eine weitere Funktion geschrieben, die unsere x-Werte in eine Liste der Größe 784 umwandelt, die zu den 784 Pixeln des Bildes passt, und unsere y-Werte in ihre einzelne heiß codierte Vektorform.
Dann kombinieren wir die x- und y-Werte so, dass ein Index mit dem anderen übereinstimmt. Dies gilt für die Trainings-, Validierungs- und Testdatensätze. Wir senden dann die geänderten Daten zurück.
Ausführen von Tests
Wir werden eine neue Datei namens „mnist loader“ erstellen, die sowohl das neurale Netzwerk, das wir zuvor erstellt haben (einfaches nn), als auch den MNIST-Dataset-Loader importiert, bevor wir mit dem Testen beginnen.
In dieser Datei müssen wir lediglich die Daten importieren, ein Netzwerk mit einer Eingabeschichtgröße von 784 und einer Ausgabeschichtgröße von 10 erstellen, die SGD-Funktion des Netzwerks auf den Trainingsdaten ausführen und es dann mit den Testdaten testen.
Denken Sie daran, dass es für unsere Liste der Eingabeebenen keinen Unterschied macht, welche Zahlen zwischen 784 und 10 liegen. Wir können die anderen Ebenen beliebig ändern. nur die Eingabe- und Ausgabegrößen sind festgelegt.
Drei Schichten sind nicht erforderlich; Wir könnten vier, fünf oder sogar nur zwei verwenden. Viel Spaß beim Experimentieren damit.
Zusammenfassung
Hier erstellen wir mit Python 3 ein neurales Netzwerk von Grund auf neu. Neben High-Level-Mathematik haben wir auch die Besonderheiten der Implementierung besprochen.
Wir begannen mit der Implementierung von Hilfsfunktionen. Damit die Neuronen funktionieren, sind die Sigmoid- und Sigmoid-Primzahlfunktionen entscheidend. Anschließend setzen wir die Feedforward-Funktion in die Praxis um, die der grundlegende Prozess zum Einspeisen von Daten in das neuronale Netzwerk ist.
Als nächstes haben wir die Gradientenabstiegsfunktion in Python erstellt, der Engine, die unser neuronales Netzwerk antreibt. Um „lokale Minima“ zu lokalisieren und deren Gewichte und Bias zu optimieren, nutzt unser neuronales Netzwerk den Gradientenabstieg. Wir haben die Backpropagation-Funktion mit erstellt Gradientenabstieg.
Durch die Bereitstellung von Aktualisierungen, wenn die Ausgaben nicht mit den richtigen Bezeichnungen übereinstimmen, ermöglicht diese Funktion dem neuronalen Netzwerk zu „lernen“.
Schließlich stellen wir unsere brandneue Python neuronale Netzwerk zum Test mit dem MNIST-Datensatz. Alles hat reibungslos funktioniert.
Viel Spaß beim Codieren!
Hinterlassen Sie uns einen Kommentar