Tuesday, 17 October 2017

Moving Average Neural Netzwerk


John Bullinarias Schritt für Schritt Anleitung zur Umsetzung eines neuronalen Netzes in C Von John A. Bullinaria von der School of Informatik der Universität von Birmingham, Großbritannien. Dieses Dokument enthält eine Schritt-für-Schritt-Anleitung zur Implementierung eines einfachen neuronalen Netzes in C. Es richtet sich vor allem an Studenten, die eine neuronale Netzwerk-Lernkomponente in ein größeres System aufbauen wollen, das sie bauen. Offensichtlich gibt es viele Arten von neuronalen Netzwerk, die man sich überlegen könnte - hier konzentriere ich mich auf einen besonders häufigen und nützlichen Typ, nämlich ein einfaches, dreischichtiges Vorwärts-Weiterverbreitungsnetzwerk (mehrschichtiges Perceptron). Diese Art von Netzwerk wird nützlich sein, wenn wir einen Satz von Eingangsvektoren und einen entsprechenden Satz von Ausgangsvektoren haben, und unser System muss eine geeignete Ausgabe für jede Eingabe, die es gegeben wird, produzieren. Natürlich, wenn wir bereits einen kompletten rauschfreien Satz von Eingabe - und Ausgabevektoren haben, dann wäre eine einfache Nachschlagetabelle ausreichend. Allerdings, wenn wir das System verallgemeinern wollen. D. h. geeignete Ausgänge für Eingaben, die es noch nie zuvor gesehen hat, dann ein neuronales Netzwerk, das gelernt hat, wie man zwischen den bekannten Eingängen und Ausgängen kartiert (d. h. unser Trainingsset), wird oft auch einen guten Job für neue Eingaben machen. Ich nehme an, dass der Leser bereits mit C vertraut ist und für weitere Details über neuronale Netze im Allgemeinen einfach den Leser an die Newsgroup comp. ai. neural-Netze und die dazugehörigen Neuronalen Netzwerke FAQ verweisen. Also, fangen wir an. Ein einzelnes Neuron (d. h. Verarbeitungseinheit) nimmt die Gesamteingabe In und erzeugt eine Ausgangsaktivierung aus. Ich nehme das zur Sigmoidfunktion, obwohl andere Aktivierungsfunktionen häufig verwendet werden (z. B. lineare oder hyperbolische Tangente). Dies hat die Wirkung, den unendlichen Bereich von In in den Bereich von 0 bis 1 zu zerquetschen. Es hat auch die praktische Eigenschaft, dass seine Ableitung die besonders einfache Form annimmt. SigmoidDerivative Sigmoid (1,0 - Sigmoid) Typischerweise wird der Eingang In in ein gegebenes Neuron sein Die gewichtete Summe der Output-Aktivierungen, die von einer Anzahl anderer Neuronen einströmen. Es ist bequem, an die Aktivierungen zu denken, die durch Schichten von Neuronen fließen. Also, wenn es NumUnits1 Neuronen in Schicht 1 gibt, ist die gesamte Aktivierung, die in unsere Schicht 2 Neuron fließt, nur die Summe über Layer1OutiWeighti. Wo Weighti ist das Festigkeit der Verbindung zwischen Einheit i in Schicht 1 und unsere Einheit in Schicht 2. Jedes Neuron wird auch eine Bias oder Ruhezustand, die hinzugefügt wird, um die Summe der Eingänge, und es ist bequem, dieses Gewicht0 zu nennen . Wir können dann schreibenLayer2In Weight0 Start mit der Bias für (i 1 i lt NumUnits1 i) Layer2In Layer1Outi Weighti addieren gewichtete Beiträge aus Schicht 1 Layer2Out 1.0 (1.0 exp (-Layer2In)) berechnen Sigmoid, um Aktivierung zu geben Normalerweise Schicht 2 wird viele Einheiten haben Ebenso ist es angebracht, die Gewichte zwischen Einheit i in Schicht 1 und Einheit j in Schicht 2 als Array Gewicht zu schreiben. Um also die Ausgabe von Einheit j in Schicht 2 zu erhalten, haben wir Layer2Inj Weight0j für (i 1 i lt NumUnits1 i) Layer2Inj Layer1Outi Weightij Layer2Outj 1.0 (1.0 exp (-Layer2Inj)) Denken Sie daran, dass in C die Array-Indizes von Null anfangen, nicht eins , Also würden wir unsere Variablen deklarieren Layer1OutNumUnits11 double Layer2InNumUnits21 double Layer2OutNumUnits21 double WeightNumUnits11NumUnits21 (oder, eher, deklarieren Sie Zeiger und verwenden Sie calloc oder malloc, um den Speicher zuzuordnen). Natürlich brauchen wir eine weitere Schleife, um alle Layer 2 Ausgänge zu erhalten (j 1 j lt NumUnits2 j) Layer2Inj Gewicht0j für (i 1 i lt NumUnits1 i) Layer2Inj Layer1Outi Weightij Layer2Outj 1.0 (1.0 exp (-Layer2Inj)) Es sind drei Layer-Netzwerke notwendig Und genügend für die meisten Zwecke, so dass unsere Schicht 2 Ausgänge in eine dritte Schicht in der gleichen Weise wie oben füllen Der Code kann anfangen, an diesem Punkt verwirrend zu werden - ich finde, dass ein separater Index i, j, k für jede Schicht hilft, Ebenso wie eine intuitive Notation zur Unterscheidung zwischen den verschiedenen Gewichtsabschnitten Weight12 und Weight23. Aus offensichtlichen Gründen ist es für dreischichtige Netzwerke üblich, Schicht 1 die Eingangsschicht, Schicht 2 die verborgene Schicht und Schicht 3 die Ausgabeschicht aufzurufen. Unser Netzwerk übernimmt also die vertraute Form, die wir für den Rest dieses Dokuments verwenden werden. Außerdem solltest du LayerNIn als SumN schreiben, um das ganze In s und Out zu verwirren. Unser Code kann also geschrieben werden. Im Allgemeinen haben wir einen ganzen Satz von NumPattern Trainingsmustern, d. h. Paare von Eingabe - und Zielausgabevektoren, die durch den Index p markiert sind. Das Netzwerk lernt durch Minimierung eines Maßes des Fehlers der Netzwerk-Ist-Ausgänge im Vergleich zu den Ziel-Ausgängen. Zum Beispiel wird der Summenquadratfehler über alle Ausgabeeinheiten k und alle Trainingsmuster p gegeben durch Fehler 0.0 für (p 1 p lt NumPattern p) für (k 1 k lt NumOutput k) Fehler 0.5 (Targetpk - Outputpk) (Targetpk - Outputpk) (Der Faktor von 0,5 ist üblicherweise enthalten, um die Algebra bei der Ableitung des Lernalgorithmus zu vereinfachen.) Wenn wir den obigen Code für die Berechnung der Netzwerkausgänge in die p-Schleife einfügen, so landen wir am Ende mit dem Verlassen des Lesers Mit allen Indizes, die sie nicht für die Zwecke ihres eigenen Systems benötigen (zB die Indizes auf SumH und SumO). Die nächste Stufe ist, iterativ die Gewichte anzupassen, um den Netzwerkfehler zu minimieren. Ein Standard-Weg, dies zu tun, ist durch Gradientenabstieg auf die Fehlerfunktion. Wir können berechnen, wieviel der Fehler durch eine kleine Änderung in jedem Gewicht verändert wird (d. h. die Teilableitungen d Error d Gewicht) und die Gewichte um einen kleinen Betrag in der Richtung, die den Fehler reduziert, Die Literatur ist voll von Variationen über diesen allgemeinen Ansatz - ich beginne mit der Standard-Online-Back-Propagation mit Impulsalgorithmus. Dies ist nicht der Ort, um durch die ganze Mathematik zu gehen, aber für den obigen Summenquadratfehler können wir eine Iteration (oder Epoche) der erforderlichen Gewichtsänderungen berechnen und anwenden DeltaWeightIH und DeltaWeightHO mit Fehler 0.0 für (p 1 p lt NumPattern p) Für (j 1 j lt NumHidden j) SumHpj WeightIH0j für (i 1 i lt NumInput i) SumHpj Inputpi WeightIHij Hiddenpj 1.0 (1.0 exp (-SumHpj)) für (k 1 k lt NumOutput k) SumOpk GewichtHO0k für (j 1 j lt (Targetpk - Outputpk) (Targetpk - Outputpk) DeltaOk (Targetpk - Outputpk) OutputPk (1.0 - Outputpk) für (j 1 j lt NumHidden j) SumDOWj (Targetpk - Outputpk) DeltaOk (Targetpk - Outputpk) 0,03 für (k 1 k lt NumOutput k) SumDOWj GewichtHOjk DeltaOk DeltaHj SumDOWj Hiddenpj (1.0 - Hiddenpj) für (j 1 j lt NumHidden j) DeltaWeightIH0j eta DeltaHj alpha DeltaWeightIH0j WeightIH0j DeltaWeightIH0j für (i 1 i lt NumInput i) DeltaWeightIHij eta Inputpi DeltaHj Alpha DeltaWeightIHij WeightIHij DeltaWeightIHij für (k 1 k lt NumOutput k) DeltaWeightHO0k eta DeltaOk alpha DeltaWeightHO0k GewichtHO0k DeltaWeightHO0k für (j 1 j lt NumHidden j) DeltaWeightHOjk eta Hiddenpj DeltaOk alpha DeltaWeightHOjk GewichtHOjk DeltaWeightHOjk (Es gibt eindeutig viel Spielraum für die Neuordnung, die Kombination Und vereinfacht die Schleifen hier - ich werde das für den Leser zu tun, wenn sie verstanden haben, was die einzelnen Codeabschnitte zu tun haben.) Die Gewichtsänderungen DeltaWeightIH und DeltaWeightHO bestehen jeweils aus zwei Komponenten. Erstens, die eta-Komponente, die der Gradient Abstieg Beitrag ist. Zweitens ist die Alpha-Komponente, die ein Impuls-Term ist, der effektiv einen gleitenden Durchschnitt des Gradientenabsenk-Gewichts-Änderungsbeitrags beibehält und somit die Gesamtgewichtsänderungen glättet. Die Festlegung guter Werte der Lernparameter eta und alpha ist in der Regel eine Frage von Versuch und Irrtum. Sicherlich muss Alpha im Bereich von 0 bis 1 liegen, und ein Wert ungleich Null beschleunigt in der Regel das Lernen. Die Suche nach einem guten Wert für eta hängt vom Problem ab, und auch von dem für alpha gewählten Wert. Wenn es zu niedrig eingestellt ist, wird das Training unnötig langsam. Wenn es zu groß ist, wird das Gewicht sich ändern, um wild zu oszillieren, und kann verlangsamen oder sogar verhindern, dass das Lernen insgesamt. (Ich fange in der Regel mit dem Versuch eta 0.1 und erforsche die Auswirkungen der wiederholten Verdopplung oder Halbierung.) Der komplette Trainingsprozess besteht aus der Wiederholung der oben genannten Gewichts-Updates für eine Reihe von Epochen (mit anderen für Loop), bis einige Fehler Crierion erfüllt ist, Zum Beispiel fällt der Fehler unter eine gewählte kleine Zahl. (Beachten Sie, dass bei Sigmoiden auf den Ausgängen der Fehler nur genau Null erreichen kann, wenn die Gewichte unendlich anfallen. Beachten Sie auch, dass manchmal das Training in einem lokalen Minimum der Fehlerfunktion steckenbleibt und niemals das tatsächliche Minimum erreicht.) Also, Wir müssen den letzten Block des Codes in etwas wie verpacken (Epoche 1 Epoche lt LARGENUMBER Epoche) OBEN CODE FÜR EINE ITERATION Wenn (Fehler lt SMALLNUMBER) brechen Wenn die Trainingsmuster in der gleichen systematischen Reihenfolge während jeder Epoche präsentiert werden, ist es Möglich für gewichtsschwingungen auftreten. Es ist daher generell eine gute Idee, eine neue zufällige Reihenfolge für die Trainingsmuster für jede Epoche zu verwenden. Wenn wir die NumPattern Trainingsmusterindizes p in zufälliger Reihenfolge in ein Array ranpat setzen. Dann ist es einfach eine Frage der Ersetzung unserer Trainingsmusterschleife Generieren der zufälligen Array Ranpat ist nicht ganz so einfach, aber der folgende Code wird den Job machen Natürlich muss man einige anfängliche Netzwerkgewichte setzen, um den Lernprozess zu starten. Das Starten aller Gewichte bei Null ist in der Regel keine gute Idee, da das oft ein lokales Minimum der Fehlerfunktion ist. Es ist normal, alle Gewichte mit kleinen zufälligen Werten zu initialisieren. Wenn rando () Ihre Lieblings-Zufallszahlgenerator-Funktion ist, die eine flache Verteilung von Zufallszahlen im Bereich von 0 bis 1 zurückgibt und kleinste die maximale absolute Größe Ihrer Anfangsgewichte ist, dann wäre ein geeigneter Abschnitt des Gewichtsinitialisierungscodes zu beachten, Dass es eine gute Idee ist, alle anfänglichen DeltaWeights gleichzeitig auf Null zu stellen. Wir haben jetzt genügend Code, um ein funktionierendes neuronales Netzwerkprogramm zusammenzustellen. Ich habe den oben genannten Code in die Datei nn. c geschnitten und geklebt (was dein Browser dir erlauben soll, in deinem eigenen Speicherplatz zu speichern). Ich habe den Standard hinzugefügt, deklariert alle Variablen, hart codiert die Standard XOR Trainingsdaten und Werte für eta. Alpha und smallwt. Definiert ein über einfaches rando (). Fügte einige Druckaussagen hinzu, um zu zeigen, was das Netz tut, und wickelte das ganze Los in ein main () ein. Die Datei sollte auf normale Weise kompilieren und laufen (z. B. mit den UNIX-Befehlen cc nn. c - O-lm - o nn und nn). Ive verließ viel für den Leser zu tun, um dies in ein nützliches Programm zu konvertieren, zum Beispiel: Lesen Sie die Trainingsdaten aus Datei Lassen Sie die Parameter (eta. Alpha. Smallwt. NumHidden etc.) während der Laufzeit variiert werden Haben passende Array Größen bestimmt Und verteilen sie Speicher während der Laufzeit Speichern von Gewichten zu Datei und lesen sie wieder in wieder Plotten von Fehlern, Ausgabe-Aktivierungen, etc. während des Trainings Es gibt auch zahlreiche Netzwerk-Variationen, die implementiert werden könnten, zum Beispiel: Batch-Lernen, anstatt On - Line-Learning Alternative Aktivierungsfunktionen (linear, tanh usw.) Real (anstelle von binären) bewerteten Ausgängen erfordern lineare Ausgabefunktionen Outputpk SumOpk DeltaOk Targetpk - Outputpk Cross-Entropy-Kostenfunktion statt Summequadrat Fehlerfehler - (Targetpk log (Outputpk) ( 1.0 - Targetpk) log (1.0 - Outputpk)) DeltaOk Targetpk - Outputpk Separate Trainings-, Validierungs - und Test-Sets Gewicht-Zerfall Regularisierung Aber von hier aus, du bist auf eigene Faust. Ich hoffe du hast diese Seite nützlich gefunden. Diese Seite wird von John Bullinaria gepflegt. Letzte Aktualisierung am 18. November 2002. Wissenschaftler und Ingenieure Leitfaden zur digitalen Signalverarbeitung Von Steven W. Smith, Ph. D. Kapitel 26: Neuronale Netze (und mehr) Neuronale Netzwerkarchitektur Menschen und andere Tiere verarbeiten Informationen mit neuronalen Netzwerken. Diese werden aus Billionen von Neuronen (Nervenzellen) gebildet, die kurze elektrische Impulse, die als Aktionspotentiale bezeichnet werden, austauschen. Computeralgorithmen, die diese biologischen Strukturen nachahmen, werden formal künstliche neuronale Netzwerke genannt, um sie von den squishy Sachen innerhalb der Tiere zu unterscheiden. Allerdings sind die meisten Wissenschaftler und Ingenieure nicht so formell und verwenden den Begriff neuronales Netzwerk, um sowohl biologische als auch nichtbiologische Systeme einzubeziehen. Die neuronale Netzwerkforschung wird durch zwei Wünsche motiviert: ein besseres Verständnis des menschlichen Gehirns zu erhalten und Computer zu entwickeln, die mit abstrakten und schlecht definierten Problemen umgehen können. Zum Beispiel haben herkömmliche Computer Schwierigkeiten, die Sprache zu verstehen und die Gesichter der Völker zu erkennen. Im Vergleich dazu sind die Menschen bei diesen Aufgaben sehr gut. Viele verschiedene neuronale Netzwerkstrukturen wurden ausprobiert, manche basieren darauf, was ein Biologe unter dem Mikroskop sieht, manche basieren auf einer mathematischeren Analyse des Problems. Die am häufigsten verwendete Struktur ist in Fig. 1 gezeigt. 26-5. Dieses neuronale Netzwerk wird in drei Schichten gebildet, die als Eingabeschicht, versteckte Schicht und Ausgabeschicht bezeichnet werden. Jede Schicht besteht aus einem oder mehreren Knoten. Dargestellt in diesem Diagramm durch die kleinen Kreise. Die Zeilen zwischen den Knoten geben den Informationsfluss von einem Knoten zum nächsten an. Bei dieser besonderen Art von neuronalen Netzwerk fließt die Information nur von der Eingabe zum Ausgang (dh von links nach rechts). Andere Arten von neuronalen Netzwerken haben kompliziertere Verbindungen, wie z. B. Rückkopplungspfade. Die Knoten der Eingangsschicht sind passiv. Dh sie ändern die Daten nicht. Sie erhalten einen einzelnen Wert an ihrem Eingang und duplizieren den Wert zu ihren mehreren Ausgängen. Im Vergleich dazu sind die Knoten der Hidden - und Output-Layer aktiv. Dies bedeutet, dass sie die Daten wie in Abb. 26-6 Die Variablen: X1 1, X1 2 8230 X1 15 halten die zu bewertenden Daten (siehe Abb. 26-5). Zum Beispiel können sie Pixel-Werte aus einem Bild, Proben aus einem Audiosignal, Börsenpreise an aufeinanderfolgenden Tagen, etc. Sie können auch die Ausgabe von einem anderen Algorithmus, wie die Klassifikatoren in unserer Krebserkennung Beispiel: Durchmesser, Helligkeit, Kantenschärfe usw. Jeder Wert aus der Eingangsschicht wird dupliziert und an alle verborgenen Knoten gesendet. Dies wird als voll miteinander verbundene Struktur bezeichnet. Wie in Fig. 26-6 werden die Werte, die in einen ausgeblendeten Knoten eingegeben werden, mit Gewichten multipliziert. Eine Menge von vorgegebenen Zahlen, die im Programm gespeichert sind. Die gewichteten Eingaben werden dann hinzugefügt, um eine einzelne Zahl zu erzeugen. Dies ist im Diagramm durch das Symbol Summe dargestellt. Vor dem Verlassen des Knotens wird diese Zahl durch eine nichtlineare mathematische Funktion geführt, die als Sigmoid bezeichnet wird. Dies ist eine s-förmige Kurve, die die Knotenausgabe begrenzt. Das heißt, der Eingang zum Sigmoid ist ein Wert zwischen - infin und infin, während seine Ausgabe nur zwischen 0 und 1 liegen kann. Die Ausgänge aus der verborgenen Schicht werden im Flußdiagramm (Abb. 26-5) durch die Variablen dargestellt: X2 1, X2 2, X2 3 und X 2 4. Genau wie zuvor wird jeder dieser Werte dupliziert und auf die nächste Schicht angewendet. Die aktiven Knoten der Ausgabeschicht kombinieren und modifizieren die Daten, um die beiden Ausgangswerte dieses Netzes X3 1 und X3 2 zu erzeugen. Neuronale Netze können beliebig viele Ebenen und beliebig viele Knoten pro Ebene haben. Die meisten Anwendungen verwenden die dreischichtige Struktur mit maximal wenigen hundert Eingangsknoten. Die verborgene Schicht ist in der Regel etwa 10 der Größe der Eingangsschicht. Im Falle der Zielerfassung benötigt die Ausgabeschicht nur einen einzigen Knoten. Die Ausgabe dieses Knotens wird eingeschränkt, um eine positive oder negative Anzeige der Zielvorgaben oder Abwesenheit in den Eingangsdaten bereitzustellen. Tabelle 26-1 ist ein Programm zur Durchführung des Flußdiagramms von Fig. 26-5. Der entscheidende Punkt ist, dass diese Architektur sehr einfach und sehr verallgemeinert ist. Dieses gleiche Flussdiagramm kann für viele Probleme verwendet werden, unabhängig von ihren jeweiligen Macken. Die Fähigkeit des neuronalen Netzes, eine nützliche Datenmanipulation zu liefern, liegt in der richtigen Auswahl der Gewichte. Dies ist eine dramatische Abkehr von der konventionellen Informationsverarbeitung, wo Lösungen in Schritt-für-Schritt-Verfahren beschrieben werden. Als Beispiel stellen Sie sich ein neuronales Netzwerk vor, um Objekte in einem Sonarsignal zu erkennen. Angenommen, dass 1000 Samples aus dem Signal in einem Computer gespeichert sind. Wie stellt der Computer fest, ob diese Daten einen U-Boot-, Wal-, Unterwasser-Berg darstellen oder gar nichts Konventionelles DSP würde dieses Problem mit Mathematik und Algorithmen, wie Korrelation und Frequenzspektrumanalyse, ansprechen. Mit einem neuronalen Netzwerk werden die 1000 Samples einfach in die Eingangsschicht eingegeben, was dazu führt, dass Werte aus der Ausgabeschicht kommen. Durch die Auswahl der richtigen Gewichte kann die Ausgabe so konfiguriert werden, dass sie eine breite Palette von Informationen meldet. Zum Beispiel gibt es Ausgänge für: U-Boot (jano), Wal (jano), Unterwasserberg (jano) usw. Mit anderen Gewichten können die Ausgänge die Objekte als: Metall oder Nichtmetall, biologisch oder nichtbiologisch, feindlich klassifizieren Oder Ally, etc. Keine Algorithmen, keine Regeln, keine Prozeduren nur eine Beziehung zwischen der Eingabe und Ausgabe diktiert durch die Werte der gewählten Gewichte. Abbildung 26-7a zeigt einen genaueren Blick auf die Sigmoidfunktion, mathematisch beschrieben durch die Gleichung: Die genaue Form des Sigmoids ist nicht wichtig, nur dass es eine glatte Schwelle ist. Zum Vergleich ergibt ein einfacher Schwellenwert einen Wert von eins bei x gt 0 und einen Wert von null bei x lt 0. Der Sigmoid führt diese gleiche grundsätzliche Schwellwertfunktion aus, ist aber auch differenzierbar. Wie in Fig. 26-7b. Während die Ableitung im Flußdiagramm nicht verwendet wird (Abb. 25-5), ist es ein kritischer Teil, die richtigen Gewichte zu finden. Mehr dazu in Kürze Ein Vorteil des Sigmoids besteht darin, daß es eine Verknüpfung zur Berechnung des Wertes seiner Ableitung gibt: Wenn z. B. x 0, dann gilt s (x) 0,5 (nach Gleichung 26-1) und die erste Ableitung berechnet: s ( X) 0,5 (1 - 0,5) 0,25. Dies ist kein kritisches Konzept, nur ein Trick, um die Algebra kürzer zu machen. Wäre das neuronale Netzwerk nicht flexibler, wenn das Sigmoid links oder rechts eingestellt werden könnte, so dass es auf einen anderen Wert als x 0 zentriert ist. Die Antwort ist ja, und die meisten neuronalen Netze erlauben dies. Es ist sehr einfach, einen zusätzlichen Knoten zu implementieren, der der Eingangsschicht hinzugefügt wird, wobei seine Eingabe immer einen Wert von eins hat. Wenn dies mit den Gewichten der verborgenen Schicht multipliziert wird, stellt es für jedes Sigmoid eine Vorspannung (DC-Offset) bereit. Dieser Zusatz wird als Bias-Knoten bezeichnet. Es wird wie die anderen Knoten behandelt, mit Ausnahme der konstanten Eingabe. Können neuronale Netze ohne Sigmoid oder ähnliche Nichtlinearität gemacht werden. Um dies zu beantworten, schau auf das dreischichtige Netzwerk von Abb. 26-5. Wenn die Sigmoiden nicht vorhanden wären, würden die drei Schichten nur in zwei Schichten zusammenfallen. Mit anderen Worten, die Summationen und Gewichte der versteckten und ausgegebenen Schichten könnten zu einer einzigen Schicht kombiniert werden, was zu nur einem zweischichtigen Netzwerk führt. Die Wissenschaftler und Ingenieure Leitfaden zur digitalen Signalverarbeitung Von Steven W. Smith, Ph. D. Kapitel 26: Neuronale Netze (und mehr) Schulung des Neuronalen Netzes Neuronales Netzwerkdesign lässt sich am besten mit einem Beispiel erklären. Abbildung 26-8 zeigt das Problem, das wir angreifen werden, indem wir einzelne Buchstaben in einem Bild des Textes identifizieren. Diese Mustererkennung hat viel Aufmerksamkeit erhalten. Es ist einfach genug, dass viele Ansätze teilweise Erfolg erzielen, aber schwierig genug, dass es keine perfekten Lösungen gibt. Viele erfolgreiche kommerzielle Produkte basieren auf diesem Problem, wie zum Beispiel: Lesen der Adressen auf Briefe für Post-Routing, Dokumenteneintrag in Textverarbeitungsprogramme usw. Der erste Schritt bei der Entwicklung eines neuronalen Netzwerks besteht darin, eine Datenbank mit Beispielen zu erstellen. Für das Texterkennungsproblem wird dies durch das Drucken der 26 Großbuchstaben: A, B, C, D 8230 Y, Z, 50 Mal auf einem Blatt Papier erreicht. Als nächstes werden diese 1300 Buchstaben in ein digitales Bild umgewandelt, indem sie eines der vielen Scan-Geräte für Personal Computer verwenden. Dieses große digitale Bild wird dann in kleine Bilder von 10 × 10 Pixeln aufgeteilt, die jeweils einen einzelnen Buchstaben enthalten. Diese Information wird als 1,3-Megabyte-Datenbank gespeichert: 1300 Bilder 100 Pixel pro Bild 8 Bits pro Pixel. Wir werden die ersten 260 Bilder in dieser Datenbank verwenden, um das neuronale Netzwerk zu trainieren (d. h. die Gewichte zu bestimmen) und der Rest, um seine Leistung zu testen. Die Datenbank muss auch eine Möglichkeit enthalten, den in jedem Bild enthaltenen Buchstaben zu identifizieren. Zum Beispiel könnte ein zusätzliches Byte zu jedem 10times10 Bild hinzugefügt werden, das den Buchstaben ASCII-Code enthält. In einem anderen Schema könnte die Position jedes 10times10 Bildes in der Datenbank anzeigen, was der Buchstabe ist. Zum Beispiel können Bilder von 0 bis 49 alle ein A sein, Bilder 50-99 könnten alle ein B sein. Für diese Demonstration wird das neuronale Netzwerk für eine beliebige Aufgabe entworfen: bestimmen, welches der 10times10 Bilder einen Vokal enthält. D. h. A, E, I, O oder U. Dies mag keine praktische Anwendung haben, aber es veranschaulicht die Fähigkeit des neuronalen Netzes, sehr abstrakte Mustererkennungsprobleme zu lernen. Durch die Aufnahme von zehn Beispielen für jeden Buchstaben in das Trainingsset, wird das Netzwerk (hoffentlich) die wichtigsten Merkmale erlernen, die das Ziel von den nicht gezielten Bildern unterscheiden. Das in diesem Beispiel verwendete neuronale Netzwerk ist die traditionelle dreischichtige, vollständig miteinander verbundene Architektur, wie in den Fig. 26-5 und 26-6. Es gibt 101 Knoten in der Eingabeschicht (100 Pixelwerte plus einen Vormagnetisierungsknoten), 10 Knoten in der verborgenen Schicht und 1 Knoten in der Ausgabeschicht. Wenn ein 100-Pixel-Bild an den Eingang des Netzwerks angelegt wird, wollen wir, dass der Ausgangswert nahe bei Eins liegt, wenn ein Vokal vorhanden ist, und nahe Null, wenn kein Vokal vorhanden ist. Sei nicht besorgt, dass das Eingangssignal als zweidimensionales Array (10x10) erfasst wurde, während die Eingabe in das neuronale Netzwerk ein eindimensionales Array ist. Dies ist Ihr Verständnis davon, wie die Pixelwerte miteinander verknüpft sind. Das neuronale Netzwerk findet eigene Beziehungen. Tabelle 26-2 zeigt das Hauptprogramm zur Berechnung der neuronalen Netzgewichte, wobei Tabelle 26-3 drei Unterprogramme enthält, die aus dem Hauptprogramm aufgerufen werden. Die Array-Elemente: X11 bis X1100, halten die Eingabeschichtwerte. Zusätzlich hält X1101 immer einen Wert von 1, der die Eingabe für den Bias-Knoten bereitstellt. Die Ausgabewerte aus den ausgeblendeten Knoten sind in den Arrayelementen enthalten: X21 bis X210. Die Variable X3 enthält den Netzwerkausgangswert. Die Gewichte der verborgenen Schicht sind im Array enthalten. WH. , Wobei der erste Index den verborgenen Knoten (1 bis 10) identifiziert und der zweite Index der Eingangsschichtknoten (1 bis 101) ist. Die Gewichte der Ausgangsschicht werden in WO1 bis WO10 gehalten. Dies macht insgesamt 1020 Gewichtswerte, die definieren, wie das Netzwerk funktionieren wird. Die erste Aktion des Programms besteht darin, jedes Gewicht auf einen beliebigen Anfangswert zu setzen, indem ein Zufallszahlengenerator verwendet wird. Wie in den Zeilen 190 bis 240 gezeigt, werden den verborgenen Schichtgewichten Anfangswerte zwischen -0.0005 und 0.0005 zugewiesen, während die Ausgabeschichtgewichte zwischen -0,5 und 0,5 liegen. Diese Bereiche sind so gewählt, dass sie die gleiche Größenordnung haben, dass die Endgewichte sein müssen. Dies beruht auf: (1) dem Wertebereich im Eingangssignal, (2) der Anzahl der Eingänge, die an jedem Knoten summiert werden, und (3) der Wertebereich, über den das Sigmoid aktiv ist, eine Eingabe von etwa -5 Lt x lt 5 und ein Ausgang von 0 bis 1. Wenn beispielsweise 101 Eingänge mit einem typischen Wert von 100 mit dem typischen Gewichtswert von 0,0002 multipliziert werden, beträgt die Summe der Produkte etwa 2, was im aktiven Bereich liegt Der Sigmoiden Eingang. Wenn wir die Leistung des neuronalen Netzes mit diesen zufälligen Gewichten auswerten, würden wir erwarten, dass es das gleiche wie zufällige Vermutung ist. Der Lernalgorithmus verbessert die Leistungsfähigkeit des Netzwerks durch allmähliches Ändern jedes Gewichts in die richtige Richtung. Dies wird als iterative Prozedur bezeichnet und wird im Programm durch die FOR-NEXT-Schleife in den Zeilen 270-400 gesteuert. Jede Iteration macht die Gewichte bei der Trennung des Ziels von den Nargearget-Beispielen etwas effizienter. Die Iterationsschleife wird in der Regel durchgeführt, bis keine weitere Verbesserung erfolgt. In typischen neuronalen Netzwerken kann dies überall von zehn bis zehntausend Iterationen sein, aber ein paar hundert ist üblich. Dieses Beispiel führt 800 Iterationen durch. Um diese iterative Strategie zu bearbeiten, muss es einen einzigen Parameter geben, der beschreibt, wie gut das System gerade arbeitet. Die Variable ESUM (für Fehlersumme) dient dieser Funktion im Programm. Die erste Aktion innerhalb der Iterationsschleife besteht darin, ESUM auf Null (Zeile 290) zu setzen, so dass sie als Akkumulator verwendet werden kann. Am Ende jeder Iteration wird der Wert von ESUM auf den Videobildschirm (Zeile 380) gedruckt, so dass der Bediener sicherstellen kann, dass Fortschritte gemacht werden. Der Wert von ESUM wird hoch anfangen und allmählich abnehmen, wenn das neuronale Netzwerk trainiert wird, um die Ziele zu erkennen. Abbildung 26-9 zeigt Beispiele, wie ESUM bei laufenden Iterationen abnimmt. Alle 260 Bilder im Trainingssatz werden bei jeder Iteration ausgewertet, die von der FOR-NEXT-Schleife in den Zeilen 310-360 gesteuert wird. Subroutine 1000 wird verwendet, um Bilder aus der Datenbank von Beispielen abzurufen. Da dies hier nicht besonders interessant ist, werden wir nur die an diese Unterroutine übergebenen Parameter beschreiben. Subroutine 1000 wird mit dem Parameter LETTER zwischen 1 und 260 eingegeben. Bei der Rückgabe enthalten die Eingangsknotenwerte X11 bis X1100 die Pixelwerte für das Bild in der Datenbank, die LETTER entspricht. Der Bias-Knotenwert X1101 wird immer mit einem konstanten Wert von eins zurückgegeben. Subroutine 1000 gibt auch einen anderen Parameter zurück, CORRECT. Dies enthält den gewünschten Ausgangswert des Netzes für diesen Buchstaben. Das heißt, wenn der Buchstabe im Bild ein Vokal ist, wird CORRECT mit einem Wert von einem zurückgegeben. Wenn der Buchstabe im Bild kein Vokal ist, wird CORRECT mit einem Wert von Null zurückgegeben. Nachdem das bearbeitete Bild in X11 bis X1100 geladen ist, übergibt die Subroutine 2000 die Daten durch das aktuelle neuronale Netzwerk, um den Ausgangsknotenwert X3 zu erzeugen. Mit anderen Worten, die Subroutine 2000 ist die gleiche wie das Programm in Tabelle 26-1, mit Ausnahme einer unterschiedlichen Anzahl von Knoten in jeder Schicht. Diese Unterroutine berechnet auch, wie gut das aktuelle Netzwerk den Buchstaben als Ziel oder ein Nicht-Ziel identifiziert. In Zeile 2210 wird die Variable ELET (für Fehlerbrief) als Differenz zwischen dem tatsächlich erzeugten Ausgangswert, X3 und dem gewünschten Wert CORRECT berechnet. Damit ist ELET ein Wert zwischen -1 und 1. Alle 260 Werte für ELET sind kombiniert (Zeile 340), um ESUM zu bilden, den gesamten quadratischen Fehler des Netzwerks für den gesamten Trainingssatz. Zeile 2220 zeigt eine Option, die oft bei der Berechnung des Fehlers enthalten ist: Zuordnen einer anderen Bedeutung für die Fehler für Ziele und Nicht-Ziele. Zum Beispiel erinnern wir an das Krebsbeispiel, das früher in diesem Kapitel vorgestellt wurde, und die Konsequenzen eines falsch-positiven Fehlers gegenüber einem falsch-negativen Fehler. Im vorliegenden Beispiel werden wir willkürlich deklarieren, dass der Fehler beim Erkennen eines Ziels fünfmal so schlimm ist wie der Fehler beim Erkennen eines Nichtziels. In der Tat, dies sagt dem Netzwerk, um einen besseren Job mit den Zielen zu tun, auch wenn es die Leistung der Nicht-Ziele weh tut. Subroutine 3000 ist das Herzstück der neuronalen Netzwerkstrategie, der Algorithmus zum Ändern der Gewichte bei jeder Iteration. Wir werden eine Analogie verwenden, um die zugrundeliegende Mathematik zu erklären. Betrachten Sie die Zwangslage eines militärischen Fallschirmjägers fallen hinter feindlichen Linien. Er fährt auf den Boden in fremdem Territorium, nur um zu finden, dass es so dunkel ist, kann er nicht mehr als ein paar Meter entfernt sehen. Seine Befehle sollen auf den Boden des nächsten Tales gehen, um den Rest seiner Mission zu beginnen. Das Problem ist, ohne in der Lage zu sein, mehr als ein paar Meter zu sehen, wie macht er seinen Weg zum Talboden. Anderenfalls braucht er einen Algorithmus, um seine x - und y-Position auf der Erdoberfläche anzupassen, um seine Erhebung zu minimieren . Dies ist analog zum Problem der Anpassung der neuronalen Netzwerkgewichte, so dass der Netzwerkfehler, ESUM, minimiert wird. Wir werden zwei Algorithmen betrachten, um dieses Problem zu lösen: Evolution und steilste Abstammung. In der Evolution nimmt der Fallschirmjäger einen fliegenden Sprung in irgendeiner zufälligen Richtung. Wenn die neue Erhebung höher ist als die vorherige, verflucht er und kehrt zu seinem Ausgangspunkt zurück, wo er wieder versucht. Wenn die neue Erhebung niedriger ist. Er fühlt sich ein Maß an Erfolg und wiederholt den Prozess vom neuen Standort. Irgendwann wird er den Boden des Tales erreichen, wenn auch in einem sehr ineffizienten und zufälligen Weg. Diese Methode heißt Evolution, weil es die gleiche Art von Algorithmus ist, der von der Natur in der biologischen Evolution eingesetzt wird. Jede neue Generation einer Art hat zufällige Variationen von der vorherigen. Wenn diese Unterschiede für die Arten von Nutzen sind, werden sie eher beibehalten und an die nächste Generation weitergegeben. Dies ist ein Ergebnis der Verbesserung, die es dem Tier ermöglicht, mehr Nahrung zu erhalten, seinen Feinden zu entkommen, mehr Nachkommen zu produzieren usw. Wenn das neue Merkmal nachteilig ist, wird das benachteiligte Tier für einige Raubtiere zum Mittagessen, und die Variation wird verworfen. In diesem Sinne ist jede neue Generation eine Iteration des evolutionären Optimierungsverfahrens. Wenn die Evolution als Trainingsalgorithmus verwendet wird, wird jedes Gewicht im neuronalen Netzwerk durch Ändern des Wertes von einem Zufallszahlengenerator etwas verändert. Wenn die modifizierten Gewichte ein besseres Netzwerk (d. h. einen niedrigeren Wert für ESUM) machen, bleiben die Änderungen erhalten, andernfalls werden sie verworfen. Während dies funktioniert, ist es sehr langsam in konvergierenden. Dies ist der Jargon, der verwendet wird, um zu beschreiben, dass eine kontinuierliche Verbesserung auf eine optimale Lösung (der Boden des Tales) gemacht wird. In einfacheren Begriffen wird das Programm Tage brauchen, um eine Lösung zu erreichen, anstatt Minuten oder Stunden. Glücklicherweise ist der steilste Abfallalgorithmus viel schneller. So wird der Fallschirmjäger natürlich antworten: Auswertung, welcher Weg bergab ist. Und ziehe in diese Richtung. Denken Sie über die Situation auf diese Weise. Der Fallschirmjäger kann einen Schritt nach Norden bewegen und die Höhenänderung aufzeichnen. Nach der Rückkehr in seine ursprüngliche Position, kann er einen Schritt nach Osten nehmen und diese Höhenänderung aufzeichnen. Mit diesen beiden Werten kann er bestimmen, welche Richtung bergab ist. Angenommen, der Fallschirmfänger fällt 10 cm, wenn er einen Schritt in die nördliche Richtung bewegt, und fällt 20 cm, wenn er einen Schritt in die östliche Richtung bewegt. Um direkt bergab zu fahren, muss er sich entlang jeder Achse bewegen, eine Menge, die proportional zur Steigung entlang dieser Achse ist. In diesem Fall könnte er sich nach Norden um 10 Stufen und nach Osten um 20 Stufen bewegen. Dies bewegt ihn den steilsten Teil des Hanges hinunter einen Abstand von radic 10 2 20 2 Schritte. Alternativ könnte er sich in einer geraden Linie zum neuen Standort bewegen, 22,4 Schritte entlang der Diagonale. Der entscheidende Punkt ist: Der steilste Abstieg wird erreicht, indem man entlang jeder Achse eine Distanz bewegt, die proportional zur Steigung entlang dieser Achse ist. Subroutine 3000 implementiert denselben steilsten anständigen Algorithmus für die Netzwerkgewichte. Vor dem Eintritt in die Subroutine 3000 wurde eines der Beispielbilder auf die Eingabeschicht angewendet und die Information an den Ausgang weitergegeben. This means that the values for: X1 , X2 and X3 are all specified, as well as the current weight values: WH. and WO . In addition, we know the error the network produces for this particular image, ELET. The hidden layer weights are updated in lines 3050 to 3120, while the output layer weights are modified in lines 3150 to 3190. This is done by calculating the slope for each weight, and then changing each weight by an amount proportional to that slope . In the paratrooper case, the slope along an axis is found by moving a small distance along the axis (say, Delta x ), measuring the change in elevation (say, Delta E ), and then dividing the two (Delta E Delta x ). The slope of a neural network weight can be found in this same way: add a small increment to the weight value (Delta w ), find the resulting change in the output signal (Delta X3 ), and divide the two (Delta X3 Delta w ). Later in this chapter we will look at an example that calculates the slope this way. However, in the present example we will use a more efficient method. Earlier we said that the nonlinearity (the sigmoid) needs to be differentiable . Here is where we will use this property. If we know the slope at each point on the nonlinearity, we can directly write an equation for the slope of each weight (Delta X3 Delta w) without actually having to perturb it. Consider a specific weight, for example, WO1, corresponding to the first input of the output node. Look at the structure in Figs. 26-5 and 26-6, and ask: how will the output ( X3 ) be affected if this particular weight ( w ) is changed slightly, but everything else is kept the same The answer is: where SLOPE O is the first derivative of the output layer sigmoid, evaluated where we are operating on its curve. In other words, SLOPE O describes how much the output of the sigmoid changes in response to a change in the input to the sigmoid. From Eq. 26-2, SLOPE O can be calculated from the current output value of the sigmoid, X3. This calculation is shown in line 3160. In line 3170, the slope for this weight is calculated via Eq. 26-3, and stored in the variable DX3DW (i. e. Delta X3 Delta w). Using a similar analysis, the slope for a weight on the hidden layer, such as WH1,1, can be found by: SLOPE H1 is the first derivative of the hidden layer sigmoid, evaluated where we are operating on its curve. The other values, X11 and WO1, are simply constants that the weight change sees as it makes its way to the output. In lines 3070 and 3080, the slopes of the sigmoids are calculated using Eq. 26-2. The slope of the hidden layer weight, DX3DW is calculated in line 3090 via Eq. 26-4. Now that we know the slope of each of the weights, we can look at how each weight is changed for the next iteration. The new value for each weight is found by taking the current weight, and adding an amount that is proportional to the slope: This calculation is carried out in line 3100 for the hidden layer, and line 3180 for the output layer. The proportionality constant consists of two factors, ELET, the error of the network for this particular input, and MU, a constant set at the beginning of the program. To understand the need for ELET in this calculation, imagine that an image placed on the input produces a small error in the output signal. Next, imagine that another image applied to the input produces a large output error. When adjusting the weights, we want to nudge the network more for the second image than the first. If something is working poorly, we want to change it if it is working well, we want to leave it alone. This is accomplished by changing each weight in proportion to the current error, ELET. To understand how MU affects the system, recall the example of the paratrooper. Once he determines the downhill direction, he must decide how far to proceed before reevaluating the slope of the terrain. By making this distance short, one meter for example, he will be able to precisely follow the contours of the terrain and always be moving in an optimal direction. The problem is that he spends most of his time evaluating the slope, rather than actually moving down the hill. In comparison, he could choose the distance to be large, say 1000 meters. While this would allow the paratrooper to move rapidly along the terrain, he might overshoot the downhill path. Too large of a distance makes him jump all over the country-side without making the desired progress. In the neural network, MU controls how much the weights are changed on each iteration. The value to use depends on the particular problem, being as low as 10 -6. or as high as 0.1. From the analogy of the paratrooper, it can be expected that too small of a value will cause the network to converge too slowly. In comparison, too large of a value will cause the convergence to be erratic, and will exhibit chaotic oscillation around the final solution. Unfortunately, the way neural networks react to various values of MU can be difficult to understand or predict. This makes it critical that the network error (i. e. ESUM) be monitored during the training, such as printing it to the video screen at the end of each iteration. If the system isnt converging properly, stop the program and try another value for MU.

No comments:

Post a Comment