Neuronale Netze und tiefes Lernen, Kapitel 2: Funktionsweise des Backpropagation-Algorithmus


Im letzten Kapitel haben wir gesehen, wie neuronale Netze mithilfe des Gradientenabstiegsalgorithmus unabhängig voneinander Gewichte und Offsets lernen können. Es gab jedoch eine Lücke in unserer Erklärung: Wir haben die Berechnung des Gradienten der Kostenfunktion nicht diskutiert. Und das ist eine anständige Lücke! In diesem Kapitel werde ich einen schnellen Algorithmus zur Berechnung solcher Gradienten vorstellen, der als Rückausbreitung bezeichnet wird.

Der Backpropagation-Algorithmus wurde erstmals in den 1970er Jahren erfunden, aber seine Bedeutung wurde erst im berühmten Werk von 1986 von David Rumelhart, Joffrey Hinton und Ronald Williams vollständig verstanden. Das Papier beschreibt mehrere neuronale Netze, in denen die Backpropagation viel schneller funktioniert als in früheren Lernansätzen, weshalb es seitdem möglich war, ein neuronales Netz zur Lösung bisher unlösbarer Probleme zu verwenden. Heute ist der Backpropagation-Algorithmus das Arbeitstier zum Erlernen eines neuronalen Netzwerks.

Dieses Kapitel enthält mehr Mathematik als alle anderen im Buch. Wenn Sie Mathematik nicht besonders mögen, könnten Sie versucht sein, dieses Kapitel zu überspringen und die Rückverteilung einfach als Black Box zu behandeln, deren Details Sie gerne ignorieren. Warum Zeit damit verschwenden, sie zu studieren?

Der Grund ist natürlich das Verständnis. Die Rückausbreitung basiert auf dem Ausdruck der partiellen Ableitung ∂C / ∂w der Kostenfunktion C in Bezug auf das Gewicht w (oder die Vorspannung b) des Netzwerks. Der Ausdruck zeigt, wie schnell sich der Wert ändert, wenn sich Gewichte und Offsets ändern. Und obwohl dieser Ausdruck ziemlich komplex ist, hat er seine eigene Schönheit, weil jedes seiner Elemente eine natürliche und intuitive Interpretation hat. Backpropagation ist daher nicht nur ein Algorithmus für schnelles Lernen. Es gibt uns ein detailliertes Verständnis darüber, wie das Ändern von Gewichten und Offsets das gesamte Netzwerkverhalten verändert. Und es lohnt sich, die Details zu studieren.

Vor diesem Hintergrund ist es in Ordnung, wenn Sie nur dieses Kapitel durchblättern oder zum nächsten springen möchten. Ich habe den Rest des Buches so geschrieben, dass es verständlich ist, auch wenn wir die umgekehrte Verteilung als Black Box betrachten. Natürlich wird es später in diesem Buch Momente geben, in denen ich auf die Ergebnisse dieses Kapitels verweise. Aber in diesem Moment sollten Sie die grundlegenden Schlussfolgerungen verstehen, auch wenn Sie nicht allen Argumenten gefolgt sind.

Zum Aufwärmen: Ein schneller Matrixansatz zur Berechnung der Leistung eines neuronalen Netzwerks


Bevor wir uns mit der Backpropagation befassen, wollen wir einen schnellen Matrixalgorithmus zur Berechnung der Ausgabe eines neuronalen Netzwerks erstellen. Wir haben diesen Algorithmus bereits am Ende des vorherigen Kapitels kennengelernt, aber ich habe ihn schnell beschrieben, daher lohnt es sich, ihn noch einmal genauer zu betrachten. Insbesondere ist dies eine gute Möglichkeit, sich an den in der Rückverteilung verwendeten Datensatz anzupassen, jedoch in einem vertrauten Kontext.

Beginnen wir mit einer Aufzeichnung, mit der wir die Gewichte im Netz klar angeben können. Wir werden w l jk verwenden , um das Verbindungsgewicht des Neurons Nr. K in Schicht Nr. (L-1) mit dem Neuron Nr. J in Schicht Nr. 1 zu bezeichnen. So zeigt beispielsweise das folgende Diagramm das Verbindungsgewicht des vierten Neurons der zweiten Schicht mit dem zweiten Neuron der dritten Schicht:



Eine solche Aufnahme scheint zunächst umständlich und gewöhnungsbedürftig. Bald wird es Ihnen jedoch einfach und natürlich erscheinen. Eines seiner Merkmale ist die Reihenfolge der Indizes j und k. Sie könnten entscheiden, dass es sinnvoller wäre, j zur Bezeichnung des Eingangsneurons und k - für das Ausgangsneuron zu verwenden, und nicht umgekehrt, wie wir es getan haben. Ich werde den Grund für diese Funktion unten erläutern.

Wir werden ähnliche Notationen für Offsets und Netzwerkaktivierungen verwenden. Insbesondere bezeichnet b l j die Verschiebung des Neurons Nr. J in der Schicht Nr. 1. a l j bezeichnet die Aktivierung des Neurons Nr. j in der Schicht Nr. 1. Das folgende Diagramm zeigt Beispiele für die Verwendung dieses Eintrags:



Mit einer solchen Aufzeichnung ist die Aktivierung eines lj des Neurons Nr. J in Schicht Nr. 1 mit der Aktivierung in Schicht Nr. (L-1) durch die folgende Gleichung verbunden (vergleiche mit Gleichung (4) und ihrer Diskussion im vorherigen Kapitel):

a l j = s i g m a ( s u m k w l j k a l - 1 k + b l j ) t a g 23   



wobei die Summe über alle Neuronen k in der Schicht (l-1) geht. Um diesen Ausdruck in Matrixform umzuschreiben, definieren wir für jede Schicht l eine Gewichtsmatrix w l. Die Elemente der Gewichtsmatrix sind einfach die Gewichte, die mit der Schicht Nr. 1 verbunden sind, dh das Element in Zeile Nr. J und Spalte Nr. K ist w l jk . In ähnlicher Weise definieren wir für jede Schicht l den Verschiebungsvektor b l . Sie haben wahrscheinlich erraten, wie dies funktioniert - die Komponenten des Verschiebungsvektors sind einfach die Werte b l j , eine Komponente für jedes Neuron in Schicht Nr. 1. Und schließlich definieren wir den Aktivierungsvektor a l , dessen Komponenten die Aktivierung a l j sind .

Der letzte Bestandteil, der zum Umschreiben benötigt wird (23), ist die Matrixform der Vektorisierung der Funktion σ. Wir sind im letzten Kapitel gelegentlich auf Vektorisierung gestoßen - die Idee ist, dass wir die Funktion σ auf jedes Element des Vektors v anwenden wollen. Wir verwenden die offensichtliche Notation σ (v), um die elementweise Anwendung der Funktion zu bezeichnen. Das heißt, die Komponenten σ (v) sind einfach σ (v) j = σ (v j ). Wenn wir zum Beispiel eine Funktion f (x) = x 2 haben , dann gibt uns die vektorisierte Form f

f ( b e g i n b m a t r i x 2 3 endbmatrix)= beginbmatrixf(2)f(3) endbmatrix= beginbmatrix49 endbmatrix tag24



Das heißt, ein vektorisiertes f quadriert einfach jedes Element des Vektors.

In Anbetracht all dieser Schreibformen kann Gleichung (23) in einer schönen und kompakten vektorisierten Form umgeschrieben werden:

al= sigma(wlal1+bl) tag25



Ein solcher Ausdruck ermöglicht es uns, die Beziehung zwischen den Aktivierungen einer Schicht und den Aktivierungen der vorherigen Schicht globaler zu betrachten: Wir wenden einfach die Gewichtsmatrix auf die Aktivierungen an, fügen den Verschiebungsvektor hinzu und wenden dann das Sigmoid an. Übrigens ist es dieser Datensatz, der die Verwendung des Datensatzes w l jk erfordert. Wenn wir den Index j zur Bezeichnung des Eingangsneurons und k für das Ausgangsneuron verwenden würden, müssten wir die Gewichtsmatrix in Gleichung (25) durch die transponierte ersetzen. Dies ist eine kleine, aber ärgerliche Änderung, und wir würden die Einfachheit der Aussage (und Reflexion) über das „Anwenden der Gewichtsmatrix auf Aktivierungen“ verlieren. Ein solcher globaler Ansatz ist einfacher und prägnanter (und verwendet weniger Indizes!) Als der Poneuron-Ansatz. Dies ist nur ein Weg, um die Indexhölle zu vermeiden, ohne die Genauigkeit des Geschehens zu verlieren. Dieser Ausdruck ist auch in der Praxis nützlich, da die meisten Matrixbibliotheken schnelle Möglichkeiten zum Multiplizieren von Matrizen, Hinzufügen von Vektoren und Vektorisieren bieten. Der Code im letzten Kapitel verwendete diesen Ausdruck direkt zur Berechnung des Netzwerkverhaltens.

Unter Verwendung von Gleichung (25) zur Berechnung von a l berechnen wir den Zwischenwert z l ≡ w l a l - 1 + b l . Dieser Wert ist sehr nützlich für die Benennung: Wir nennen z l die gewichtete Eingabe von Neuronen der Schicht Nr. 1. Später werden wir diese gewichtete Eingabe aktiv nutzen. Gleichung (25) wird manchmal durch eine gewichtete Eingabe geschrieben, als l = σ (z l ). Es ist auch erwähnenswert, dass z l Komponenten hat zlj= sumkwljkal1k+blj das heißt, z l j ist nur eine gewichtete Eingabe der Aktivierungsfunktion des Neurons j in Schicht l.

Zwei wesentliche Annahmen zur Kostenfunktion


Das Ziel der Rückausbreitung besteht darin, die partiellen Ableitungen ∂C / ∂w und ∂C / ∂b der Kostenfunktion C für jedes Gewicht w und die Vorspannung b des Netzwerks zu berechnen. Damit die Backpropagation funktioniert, müssen wir zwei Hauptannahmen über die Form der Kostenfunktion treffen. Zuvor wäre es jedoch sinnvoll, sich ein Beispiel für eine Kostenfunktion vorzustellen. Wir verwenden die quadratische Funktion aus dem vorherigen Kapitel (Gleichung (6)). Im Eintrag aus dem vorherigen Abschnitt wird es so aussehen

C= frac12n sumx||y(x)aL(x)||2 tag26



wobei: n die Gesamtzahl der Trainingsbeispiele ist; die Summe gilt für alle Beispiele x; y = y (x) ist die erforderliche Ausgabe; L bezeichnet die Anzahl der Schichten im Netzwerk; a L = a L (x) ist der Ausgangsvektor der Netzwerkaktivierungen, wenn x am Eingang ist.

Okay, welche Annahmen brauchen wir über die Kostenfunktion C, um die Backpropagation anzuwenden? Zunächst kann die Kostenfunktion als Mittelwert C = 1 / n ∑ x C x der Kostenfunktion C x für einzelne Trainingsbeispiele x geschrieben werden. Dies geschieht im Fall einer quadratischen Kostenfunktion, bei der die Kosten eines Trainingsbeispiels C x = 1/2 || y - a L || sind 2 . Diese Annahme gilt für alle anderen Kostenfunktionen, die wir im Buch erfüllen werden.

Wir brauchen diese Annahme, weil die Rückausbreitung es uns tatsächlich ermöglicht, die partiellen Ableitungen ∂C / ∂w und ∂C / ∂b zu berechnen, die über die Trainingsbeispiele gemittelt werden. Wenn wir diese Annahme akzeptieren, nehmen wir an, dass das Trainingsbeispiel x fest ist, und hören auf, den Index x anzugeben, indem wir den Wert von C x als C aufschreiben. Dann geben wir x zurück, aber im Moment ist es besser, es einfach so zu meinen.

Die zweite Annahme bezüglich der Kostenfunktion - sie kann als Funktion der Ausgabe eines neuronalen Netzwerks geschrieben werden:



Beispielsweise erfüllt die quadratische Kostenfunktion diese Anforderung, da die quadratischen Kosten eines Trainingsbeispiels x als geschrieben werden können

C=1/2||yaL||2=1/2 sumj(yjaLj)2 tag27



Dies ist die Funktion der Ausgangsaktivierungen. Natürlich hängt diese Kostenfunktion auch von der gewünschten Ausgabe y ab, und Sie fragen sich vielleicht, warum wir C nicht auch als Funktion von y betrachten. Denken Sie jedoch daran, dass das Eingabe-Trainingsbeispiel x fest ist, sodass auch die Ausgabe y fest ist. Insbesondere können wir es nicht ändern, indem wir Gewichte und Verschiebungen ändern, das heißt, das lernt das neuronale Netzwerk nicht. Daher ist es sinnvoll, C als Funktion nur der Ausgangsaktivierungen a L und y als nur einen Parameter zu betrachten, der zur Bestimmung beiträgt.

Die Arbeit von Hadamard s⊙t


Der Backpropagation-Algorithmus basiert auf den üblichen Operationen der linearen Algebra - Addition von Vektoren, Multiplikation eines Vektors mit einer Matrix usw. Eine der Operationen wird jedoch weniger häufig verwendet. Angenommen, s und t sind zwei Vektoren derselben Dimension. Dann bezeichnen wir mit s⊙t die elementweise Multiplikation zweier Vektoren. Dann sind die Komponenten s⊙t einfach (s⊙t) j = s j t j . Zum Beispiel:

 beginbmatrix12 endbmatrix odot beginbmatrix34 endbmatrix= beginbmatrix1324 endbmatrix= beginbmatrix38 endbmatrix tag28



Eine solche stückweise Arbeit wird manchmal die Arbeit von Hadamard oder die Arbeit von Schur genannt. Wir werden es die Arbeit von Hadamard nennen. Gute Bibliotheken für die Arbeit mit Matrizen haben normalerweise eine schnelle Implementierung des Hadamard-Produkts, und dies kann bei der Implementierung der Backpropagation hilfreich sein.

Vier Grundgleichungen für die Rückausbreitung


Backpropagation beinhaltet das Verständnis, wie das Ändern von Gewichten und Offsets des Netzwerks die Kostenfunktion verändert. Im Wesentlichen bedeutet dies die Berechnung der partiellen Ableitungen ∂C / ∂w l jk und ∂C / ∂b l j . Für ihre Berechnung berechnen wir jedoch zunächst den Zwischenwert δ l j , den wir als Fehler im Neuron Nr. J in Schicht Nr. 1 bezeichnen. Die Rückausbreitung gibt uns eine Prozedur zum Berechnen des Fehlers δlj und assoziiert dann δlj mit ∂C / ∂wljk und ∂C / ∂blj.

Um zu verstehen, wie ein Fehler festgestellt wird, stellen Sie sich vor, dass ein Dämon in unserem neuronalen Netzwerk gestartet ist:



Er sitzt auf dem Neuron Nr. J in Schicht Nr. 1. Beim Empfang der Eingabedaten stört der Dämon den Betrieb des Neurons. Es fügt der gewichteten Eingabe des Neurons eine kleine Änderung von Δz l j hinzu, und anstatt σ (z l j ) zu ergeben, erzeugt das Neuron σ (z l j + Δz l j ). Diese Änderung wird sich auch auf die folgenden Schichten des Netzwerks ausbreiten, wodurch sich die Gesamtkosten letztendlich um (∂C / ∂z l j ) * Δz l j ändern.

Aber unser Dämon ist gut und er versucht Ihnen zu helfen, die Kosten zu verbessern, dh Δz l j zu finden , das die Kosten senkt. Angenommen, der Wert ∂C / ∂z l j ist groß (positiv oder negativ). Dann kann der Dämon die Kosten ernsthaft reduzieren, indem er Δz l j mit dem Vorzeichen gegenüber ∂C / ∂z l j wählt. Wenn jedoch ∂C / ∂z l j nahe Null ist, kann der Dämon die Kosten nicht wesentlich verbessern, indem er die gewichtete Eingabe z l j ändert. Aus Sicht des Dämons ist das Neuron also bereits nahezu optimal (dies gilt natürlich nur für kleine Δz l j . Angenommen, dies sind die Einschränkungen der Handlungen des Dämons). Daher ist ∂C / ∂z l j im heuristischen Sinne ein Maß für den Neuronenfehler.

Unter der Motivation aus dieser Geschichte definieren wir den Fehler δ l j des Neurons j in der Schicht l als

 deltalj equiv frac partiellesC partielleszlj tag29



Nach unserer üblichen Konvention verwenden wir δ l , um den Fehlervektor zu bezeichnen, der der Schicht l zugeordnet ist. Die Rückausbreitung gibt uns die Möglichkeit, δ l für jede Schicht zu berechnen und diese Fehler dann mit den Größen zu korrelieren, die uns wirklich interessieren, ∂C / ∂w l jk und ∂C / ∂b l j .

Sie fragen sich vielleicht, warum der Dämon die gewichtete Eingabe z l j ändert. Schließlich wäre es natürlicher, sich vorzustellen, dass der Dämon die Ausgangsaktivierung a l j so ändert, dass wir ∂C / ∂a l j als Maß für den Fehler verwenden. Wenn Sie dies tun, wird alles sehr ähnlich zu dem, was wir weiter diskutieren werden. In diesem Fall ist die Darstellung der Rückausbreitung jedoch algebraisch etwas komplizierter. Daher beschäftigen wir uns mit der Variante δ l j = ∂C / ∂z l j als Maß für den Fehler.

Bei Klassifizierungsproblemen bedeutet der Begriff „Fehler“ manchmal die Anzahl falscher Klassifizierungen. Wenn beispielsweise ein neuronales Netzwerk 96,0% der Ziffern korrekt klassifiziert, beträgt der Fehler 4,0%. Offensichtlich ist dies überhaupt nicht das, was wir mit den Vektoren δ meinen. In der Praxis kann man jedoch normalerweise leicht verstehen, was Bedeutung bedeutet.

Angriffsplan : Die Backpropagation basiert auf vier Grundgleichungen. Zusammen geben sie uns eine Möglichkeit, sowohl den Fehler δ l als auch den Gradienten der Kostenfunktion zu berechnen. Ich gebe sie unten. Sie müssen nicht mit ihrer sofortigen Entwicklung rechnen. Sie werden enttäuscht sein. Die Backpropagation-Gleichungen sind so tief, dass ein gutes Verständnis greifbare Zeit und Geduld sowie eine schrittweise Vertiefung der Frage erfordert. Die gute Nachricht ist, dass sich diese Geduld gut auszahlt. Daher beginnen unsere Überlegungen in diesem Abschnitt erst am Anfang und helfen Ihnen, dem Weg eines tiefen Verständnisses von Gleichungen zu folgen.

Hier ist ein Diagramm, wie wir uns später mit diesen Gleichungen befassen werden: Ich werde einen kurzen Beweis dafür geben, um zu erklären, warum sie wahr sind; Wir werden sie in einer algorithmischen Form in Form eines Pseudocodes umschreiben und sehen, wie man sie in echten Python-Code implementiert. Im letzten Teil des Kapitels werden wir eine intuitive Vorstellung von der Bedeutung der Backpropagation-Gleichungen entwickeln und wie sie von Grund auf neu gefunden werden können. Wir werden in regelmäßigen Abständen zu den vier Grundgleichungen zurückkehren. Je tiefer Sie sie verstehen, desto komfortabler und vielleicht schöner und natürlicher werden sie Ihnen erscheinen.

Die Gleichung des Fehlers der Ausgangsschicht δ L : Die Komponenten von δ L werden als betrachtet

 deltaLj= frac partiellesC partiellesaLj sigma(zLj) tagBP1



Sehr natürlicher Ausdruck. Der erste Term rechts, ∂C / ∂a L j , misst, wie schnell sich die Kosten in Abhängigkeit von der Ausgangsaktivierung Nr. J ändern. Wenn zum Beispiel C nicht besonders von dem bestimmten Ausgangsneuron j abhängig ist, ist δLj erwartungsgemäß klein. Der zweite Term rechts, σ ​​'(z L j ), misst, wie schnell sich die Aktivierungsfunktion σ in z L j ändert.

Beachten Sie, dass alles in (BP1) leicht zu zählen ist. Insbesondere berechnen wir z L j, wenn wir das Verhalten des Netzwerks berechnen, und es wird etwas mehr Ressourcen benötigen, um σ '(z L j ) zu berechnen. Natürlich hängt die genaue Form ∂C / ∂a L j von der Form der Kostenfunktion ab. Wenn jedoch die Kostenfunktion bekannt ist, sollte es keine Probleme bei der Berechnung von ∂C / ∂a L j geben . Wenn wir zum Beispiel die quadratische Kostenfunktion verwenden, dann ist C = 1/2 ∑ j (y j - a L j ) 2 , also ∂C / ∂a L j = (a L j - y j ), was leicht zu berechnen ist.

Gleichung (BP1) ist eine explodierte Expression von δL . Es ist völlig normal, aber nicht in der Matrixform aufgezeichnet, die wir für die Rückverteilung benötigen. Es ist jedoch leicht, in Matrixform umzuschreiben, als

 deltaL= nablaaC odot sigma(zL) tagBP1a



Hier ist C a C als ein Vektor definiert, dessen Komponenten die partiellen Ableitungen ∂C / ∂a L j sind . Es kann als Ausdruck der Änderungsrate von C in Bezug auf Ausgangsaktivierungen dargestellt werden. Es ist leicht zu erkennen, dass die Gleichungen (BP1a) und (BP1) äquivalent sind, daher werden wir (BP1) verwenden, um auf eine der folgenden Gleichungen zu verweisen. Zum Beispiel haben wir im Fall eines quadratischen Wertes ∇ a C = (a L - y), also ist die vollständige Matrixform (BP1)

 deltaL=(aLy) odot sigma(zL) tag30



Alles in diesem Ausdruck hat eine bequeme Vektorform und es ist einfach, mit einer Bibliothek wie Numpy zu berechnen.

Der Ausdruck des Fehlers δ l durch den Fehler in der nächsten Schicht, δ l + 1 : insbesondere

 deltal=((wl+1)T deltal+1) cdot sigma(zl) tagBP2



wobei (w l + 1 ) T die Transposition der Gewichtsmatrix w l + 1 für die Schicht Nr. (l + 1) ist. Die Gleichung scheint kompliziert zu sein, aber jedes Element ist leicht zu interpretieren. Angenommen, wir kennen den Fehler δ l + 1 für die Schicht (l + 1). Man kann sich vorstellen, dass die Transposition der Gewichtsmatrix (w l + 1 ) T den Fehler rückwärts durch das Netzwerk bewegt, was uns ein gewisses Maß an Fehler am Ausgang der Schicht Nr. 1 gibt. Dann betrachten wir das Hadamard-Produkt ⊙σ '(z l ). Dies drückt den Fehler durch die Aktivierungsfunktion in Schicht 1 zurück und gibt uns den Fehlerwert δl in der gewichteten Eingabe für Schicht l.

Durch Kombinieren von (BP2) mit (BP1) können wir den Fehler δl für jede Netzwerkschicht berechnen.Wir beginnen mit (BP1), um δ L zu berechnen , verwenden dann Gleichung (BP2), um δ L-1 zu berechnen, dann erneut, um δ L-2 zu berechnen , und so weiter bis zum hinteren Teil des Netzwerks.

Die Gleichung der Änderungsrate der Kosten in Bezug auf einen Offset im Netzwerk : insbesondere:

C.b l j =δ l j



Das heißt, der Fehler Delta L j ist , genau zu der Änderungsrate gleich ∂C / ∂B l j . Dies ist hervorragend, da (BP1) und (BP2) uns bereits erklärt haben, wie man δ l j berechnet . Wir können (BP3) kürzer umschreiben als

C.b =δ



wobei δ für dasselbe Neuron wie die Vorspannung b geschätzt wird.

Die Gleichung für die Änderungsrate des Werts in Bezug auf ein beliebiges Gewicht im Netzwerk : insbesondere:

C.w l j k =a l - 1 k δ l j



Von hier aus lernen wir, wie man die partielle Ableitung ∂C / ∂w l jk durch die Werte von δ l und a l-1 berechnet, deren Berechnungsmethode wir bereits kennen. Diese Gleichung kann in einer weniger geladenen Form umgeschrieben werden:

C.w =ainδout



wobei a in die Aktivierung des neuronalen Eingangs für das Gewicht w ist und δ out der Fehler des neuronalen Ausgangs aus dem Gewicht w ist. Wenn wir das Gewicht w und zwei damit verbundene Neuronen genauer betrachten, können wir es folgendermaßen zeichnen:



Eine schöne Konsequenz von Gleichung (32) ist, dass, wenn die Aktivierung a in klein ist, a in ≈ 0, der Term Term ∂C / ∂w ebenfalls dazu neigt auf Null. In diesem Fall sagen wir, dass das Gewicht langsam trainiert wird, das heißt, es ändert sich während des Gefälles nicht viel. Mit anderen Worten, eine der Konsequenzen (BP4) ist, dass die gewichtete Ausgabe von Neuronen mit geringer Aktivierung langsam lernt.

Andere Ideen können aus (BP1) - (BP4) gezogen werden. Beginnen wir mit der Ausgabeebene. Betrachten Sie den Term σ '(z L j) in (BP1). Aus dem Diagramm des Sigmoid aus dem vorherigen Kapitel geht hervor, dass es flach wird, wenn sich σ (z L j ) 0 oder 1 nähert. In diesen Fällen wird σ '(z L j ) ≈ 0. Daher wird das Gewicht in der letzten Schicht bei Aktivierung langsam trainiert Das Ausgangsneuron ist klein (≈ 0) oder groß (≈ 1). In diesem Fall wird normalerweise gesagt, dass das Ausgangsneuron gesättigt ist und infolgedessen das Gewicht nicht mehr trainiert wird (oder langsam trainiert wird). Die gleichen Bemerkungen gelten für Verschiebungen des Ausgangsneurons.

Ähnliche Ideen können für frühere Schichten erhalten werden. Betrachten Sie insbesondere den Term σ '(z l ) in (BP2). Dies bedeutet, dass δ l jhöchstwahrscheinlich wird es klein sein, wenn sich das Neuron der Sättigung nähert. Dies bedeutet wiederum, dass alle Gewichte am Eingang eines gesättigten Neurons langsam trainiert werden (obwohl dies nicht funktioniert, wenn w l + 1 T δ l + 1 ausreichend große Elemente aufweist, die den kleinen Wert von σ '(z L) kompensieren j )).

Zusammenfassend: Wir haben gelernt, dass das Gewicht langsam trainiert wird, wenn entweder die Aktivierung des Eingangsneurons klein oder das Ausgangsneuron gesättigt ist, dh seine Aktivierung klein oder groß ist.

Dies ist nicht besonders überraschend. Und doch helfen diese Beobachtungen dabei, besser zu verstehen, was passiert, wenn wir das Netzwerk trainieren. Darüber hinaus können wir uns diesen Argumenten von der anderen Seite nähern. Die vier Grundgleichungen gelten für jede Aktivierungsfunktion und nicht nur für das Standard-Sigmoid (da, wie wir später sehen werden, die Eigenschaften das Sigmoid nicht verwenden). Daher können diese Gleichungen verwendet werden, um Aktivierungsfunktionen mit bestimmten notwendigen Lerneigenschaften zu entwickeln. Nehmen wir zum Beispiel an, wir wählen eine Aktivierungsfunktion σ, die sich von einem Sigmoid unterscheidet, so dass σ 'immer positiv ist und sich nicht Null nähert. Dies verhindert die Lernverlangsamung, die auftritt, wenn normale Sigmoidneuronen gesättigt sind. Später in diesem Buch werden wir Beispiele sehen, bei denen sich die Aktivierungsfunktion auf ähnliche Weise ändert.Anhand der Gleichungen (BP1) - (BP4) können wir erklären, warum solche Änderungen erforderlich sind und wie sie sich auf die Situation auswirken können.


:


  • . . , . , , . , (BP1) ,


δL=Σ(zL)aC



Dabei ist Σ '(z L ) eine quadratische Matrix mit Werten von σ' (z L j ) entlang der Diagonale und anderen Elementen gleich 0. Beachten Sie, dass diese Matrix durch die übliche Matrixmultiplikation mit ∇ a C interagiert .

Zeigen Sie, dass (BP2) umgeschrieben werden kann als

δ l = Σ ' ( z l ) ( w l + 1 ) T δ l + 1



Zeigen Sie beim Kombinieren der vorherigen Aufgaben Folgendes:

δ l = Σ ' ( z l ) ( w l + 1 ) T ... Σ ' ( z L - 1 ) ( w L ) T Σ ' ( z L ) a C.



Für Leser, die an Matrixmultiplikation gewöhnt sind, ist diese Gleichung leichter zu verstehen als (BP1) und (BP2). Ich konzentriere mich auf (BP1) und (BP2), weil dieser Ansatz numerisch schneller zu implementieren ist. [hier ist Σ nicht die Summe (∑), sondern das Kapital σ (Sigma) / ca. perev. ]]

Beweis der vier Grundgleichungen (optionaler Abschnitt)


Nun beweisen wir die vier Grundgleichungen (BP1) - (BP4). Alle von ihnen sind Konsequenzen der Kettenregel (der Regel der Differenzierung einer komplexen Funktion) aus der Analyse von Funktionen vieler Variablen. Wenn Sie mit der Kettenregel vertraut sind, empfehle ich dringend, die Ableitungen selbst zu zählen, bevor Sie mit dem Lesen fortfahren.

Beginnen wir mit der Gleichung (BP1) beginnen, die uns für den Ausgangsfehler Delta einen Ausdruck gibt von L . Um dies zu beweisen, erinnern wir uns per Definition daran:

δ L j = C.z L j



Unter Anwendung der Kettenregel schreiben wir die partiellen Ableitungen durch die partiellen Ableitungen von Ausgabeaktivierungen neu:

δ L j = k C.a L ka L kz L j



wobei die Summation über alle Neuronen k in der Ausgangsschicht geht. Natürlich hängt die Ausgangsaktivierung a L k des Neurons Nr. K nur von dem gewichteten Eingang z L j für das Neuron Nr. J ab, wenn k = j ist. Daher verschwindet ∂a L k / ∂z L j , wenn k ≠ j ist. Infolgedessen vereinfachen wir die vorherige Gleichung auf

δ L j = C.a L ja L jz L j



Wenn wir uns daran erinnern, dass a L j = σ (z L j ) ist, können wir den zweiten Term rechts als σ '(z L j ) umschreiben , und die Gleichung wird zu

δ L j = C.a L j σ(z L j )



das heißt, in (BP1) in einer Explosionsansicht.

Dann beweisen (BP2), um eine Gleichung für den Fehler gibt δ l durch Fehler δ in der nächsten Schicht i + 1 . Um dies zu tun, müssen wir das Delta neu zu schreiben l j = ∂C / dz l j durch das Delta l + 1, die k = ∂C / dz l + 1, die k . Dies kann mithilfe der Kettenregel erfolgen:

δ l j = C.z l j

= k C.z l + 1 kz l + 1 kz l j

= k z l + 1 kz l j δ l + 1 k



In der letzten Zeile haben wir die beiden Terme rechts vertauscht und die Definition von δ l + 1 k ersetzt . Beachten Sie Folgendes, um den ersten Term in der letzten Zeile zu berechnen

z l + 1 k = j w l + 1 k j a l j + b l + 1 k = j w l + 1 k j σ ( z l j ) + b l + 1 k



Differenzierung bekommen wir

z l + 1 kz l j =w l + 1 k j σ'(z l j ).



Wenn wir dies in (42) einsetzen, erhalten wir

δ l j = k w l + 1 k j δ l + 1 k σ ' ( z l j ) .



Das heißt, (BP2) in einem explodierten Eintrag.

Es bleibt zu beweisen (BP3) und (BP4). Sie folgen ebenfalls aus der Kettenregel, ungefähr auf die gleiche Weise wie die beiden vorherigen. Ich werde sie dir als Übung überlassen.

Übung


  • Beweisen Sie (BP3) und (BP4).


Das ist der Beweis für die vier grundlegenden Backpropagation-Gleichungen. Es mag kompliziert erscheinen. In Wirklichkeit ist dies jedoch einfach das Ergebnis einer sorgfältigen Anwendung der Kettenregel. Weniger prägnant kann man sich die Rückausbreitung als eine Möglichkeit vorstellen, den Gradienten der Kostenfunktion durch systematische Anwendung der Kettenregel aus der Analyse der Funktionen vieler Variablen zu berechnen. Und das ist wirklich alles, was die Rückverteilung ausmacht - der Rest sind nur Details.

Backpropagation-Algorithmus


Die Backpropagation-Gleichungen geben uns eine Methode zur Berechnung des Gradienten der Kostenfunktion. Schreiben wir dies explizit als Algorithmus:
  1. Eingabe x: Weisen Sie der Eingabeebene die entsprechende Aktivierung a 1 zu.
  2. : l = 2,3,…,L z l = w l a l−1 +b l a l = σ(z l ).
  3. δ L : δ L = ∇ a C ⊙ σ'(z L ).
  4. : l = L−1,L−2,…,2 δ l = ((w l+1 ) T δ l+1 ) ⊙ σ'(z l ).
  5. : Cwljk=al1kδlj und Cblj=δlj .


Wenn Sie sich den Algorithmus ansehen, werden Sie verstehen, warum er als Backpropagation bezeichnet wird. Wir berechnen die Fehlervektoren δ l rückwärts, beginnend mit der letzten Schicht. Es mag seltsam erscheinen, dass wir rückwärts durch das Netzwerk gehen. Wenn Sie jedoch über den Beweis der Rückausbreitung nachdenken, ist die umgekehrte Bewegung eine Folge der Tatsache, dass die Kosten eine Funktion der Netzwerkleistung sind. Um zu verstehen, wie sich die Kosten mit frühen Gewichten und Offsets ändern, müssen wir die Kettenregel immer wieder anwenden und die Ebenen durchgehen, um nützliche Ausdrücke zu erhalten.

Übungen


  • . , , f(∑ j w j x j +b), f – , . ?
  • . , σ(z) = z . .


Wie ich zuvor erklärt habe, berechnet der Backpropagation-Algorithmus den Gradienten der Kostenfunktion für ein Trainingsbeispiel, C = C x . In der Praxis wird die Rückausbreitung häufig mit einem Lernalgorithmus kombiniert, beispielsweise mit stochastischem Gradientenabstieg, wenn wir den Gradienten für viele Trainingsbeispiele berechnen. Insbesondere für ein gegebenes Minipaket mit m Trainingsbeispielen wendet der folgende Algorithmus einen Gradientenabstieg basierend auf diesem Minipaket an:

  1. Eintritt: Eine Reihe von Trainingsbeispielen.
  2. Weisen Sie für jedes Trainingsbeispiel x die entsprechende Eingabeaktivierung a x, 1 zu und führen Sie die folgenden Schritte aus:
    • l=2,3,…,L z x,l = w l a x,l−1 +b l a x,l = σ(z x,l ).
    • δ x,L : δ x,L = ∇ a C x ⋅ σ'(z x,L ).
    • : l=L−1,L−2,…,2 δ x,l = ((w l+1 ) T δ x,l+1 ) ⋅ σ'(z x,l ).
  3. : l=L,L−1,…,2 wl rightarrowwl frac etam sumx deltax,l(ax,l1)T und Offsets gemäß der Regel bl rightarrowbl frac etam sumx deltax,l .


Um einen stochastischen Gradientenabstieg in der Praxis zu implementieren, benötigen Sie natürlich auch einen externen Zyklus, der Mini-Pakete mit Trainingsbeispielen generiert, und einen externen Zyklus, der mehrere Trainingsepochen durchläuft. Der Einfachheit halber habe ich sie weggelassen.

Code für die Rückverteilung


Nachdem wir die abstrakte Seite der Backpropagation verstanden haben, können wir nun den im vorherigen Kapitel verwendeten Code verstehen, der die Backpropagation implementiert. Erinnern Sie sich aus diesem Kapitel daran, dass der Code in den Methoden update_mini_batch und backprop der Network-Klasse enthalten war. Der Code für diese Methoden ist eine direkte Übersetzung des oben beschriebenen Algorithmus. Insbesondere aktualisiert die update_mini_batch-Methode die Netzwerkgewichte und -versätze, indem sie den Gradienten für die aktuellen mini_batch-Trainingsbeispiele berechnet:

class Network(object): ... def update_mini_batch(self, mini_batch, eta): """    ,          -. mini_batch –    (x, y),  eta –  .""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] for x, y in mini_batch: delta_nabla_b, delta_nabla_w = self.backprop(x, y) nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)] nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)] self.weights = [w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)] self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)] 


Der größte Teil der Arbeit wird durch die Zeilen delta_nabla_b, delta_nabla_w = self.backprop (x, y) erledigt, wobei die partiellen Ableitungen ∂C x / ∂b l j und ∂C x / ∂w l jk unter Verwendung der Backprop-Methode berechnet werden. Die Backprop-Methode wiederholt fast den Algorithmus des vorherigen Abschnitts. Es gibt einen kleinen Unterschied: Wir verwenden einen etwas anderen Ansatz für die Ebenenindizierung. Dies geschieht, um die Python-Funktion zu nutzen, negative Array-Indizes, mit denen Sie Elemente vom Ende an rückwärts zählen können. l [-3] ist das dritte Element vom Ende des Arrays l. Der Backprop-Code wird unten zusammen mit Hilfsfunktionen angegeben, die zur Berechnung des Sigmoid, seiner Ableitung und Ableitung der Kostenfunktion verwendet werden. Mit ihnen ist der Code vollständig und verständlich. Wenn etwas unklar ist, lesen Sie die erste vollständige Beschreibung des Listencodes.

 class Network(object): ... def backprop(self, x, y): """  ``(nabla_b, nabla_w)``,      C_x. ``nabla_b``  ``nabla_w`` -    numpy,   ``self.biases`` and ``self.weights``.""" nabla_b = [np.zeros(b.shape) for b in self.biases] nabla_w = [np.zeros(w.shape) for w in self.weights] #   activation = x activations = [x] #      zs = [] #     z- for b, w in zip(self.biases, self.weights): z = np.dot(w, activation)+b zs.append(z) activation = sigmoid(z) activations.append(activation) #   delta = self.cost_derivative(activations[-1], y) * \ sigmoid_prime(zs[-1]) nabla_b[-1] = delta nabla_w[-1] = np.dot(delta, activations[-2].transpose()) """ l      ,      . l = 1    , l = 2 – ,   .    ,   python      .""" for l in xrange(2, self.num_layers): z = zs[-l] sp = sigmoid_prime(z) delta = np.dot(self.weights[-l+1].transpose(), delta) * sp nabla_b[-l] = delta nabla_w[-l] = np.dot(delta, activations[-l-1].transpose()) return (nabla_b, nabla_w) ... def cost_derivative(self, output_activations, y): """    ( C_x /  a)   .""" return (output_activations-y) def sigmoid(z): """.""" return 1.0/(1.0+np.exp(-z)) def sigmoid_prime(z): """ .""" return sigmoid(z)*(1-sigmoid(z)) 


Herausforderung


  • Ein vollständig matrixbasierter Backpropagation-Ansatz für das Minipack. Unsere Implementierung des stochastischen Gradientenabstiegs verwendet eine Reihe von Trainingsbeispielen aus dem Minipaket. Der Backpropagation-Algorithmus kann so geändert werden, dass er gleichzeitig die Gradienten für alle Trainingsbeispiele des Mini-Pakets berechnet. Anstatt mit einem einzelnen Vektor x zu beginnen, können wir mit der Matrix X = [x 1 x 2 ... x m ] beginnen, deren Spalten die Vektoren des Minipacks sind. Die direkte Verteilung erfolgt durch das Produkt von Gewichtsmatrizen, die Zugabe einer geeigneten Matrix für Verschiebungen und die weit verbreitete Verwendung von Sigmoid. Die Rückausbreitung folgt dem gleichen Muster. Schreiben Sie Pseudocode für diesen Ansatz für den Backpropagation-Algorithmus. Ändern Sie network.py so, dass dieser Matrixansatz verwendet wird. Der Vorteil dieses Ansatzes besteht darin, dass alle Vorteile moderner Bibliotheken für die lineare Algebra genutzt werden. Infolgedessen kann es schneller als der Minipaket-Zyklus ausgeführt werden (auf meinem Computer beschleunigt das Programm beispielsweise die Klassifizierungsaufgaben von MNIST etwa zweimal). In der Praxis verwenden alle seriösen Bibliotheken für die Rückverteilung einen solchen Vollmatrix-Ansatz oder eine Version davon.


Inwiefern ist die Rückausbreitung ein schneller Algorithmus?


Inwiefern ist die Rückausbreitung ein schneller Algorithmus? Betrachten Sie zur Beantwortung dieser Frage einen anderen Ansatz zur Berechnung des Gradienten. Stellen Sie sich die Anfänge der neuronalen Netzwerkforschung vor. Vielleicht sind dies die 1950er oder 1960er Jahre, und Sie sind die erste Person auf der Welt, die auf die Idee gekommen ist, den Gradientenabstieg für das Training zu verwenden! Damit dies funktioniert, müssen Sie den Gradienten der Kostenfunktion berechnen. Sie erinnern sich an die Algebra und entscheiden, ob Sie die Kettenregel zur Berechnung des Gradienten verwenden können. Wenn Sie ein wenig gespielt haben, sehen Sie, dass Algebra schwierig erscheint, und Sie sind enttäuscht. Sie versuchen einen anderen Ansatz zu finden. Sie beschließen, die Kosten nur als Funktion der Gewichte C = C (w) zu betrachten (wir werden etwas später auf die Verschiebungen zurückkommen). Sie nummerieren die Gewichte w 1 , w 2 , ... und möchten ∂C / ∂w j für das Gewicht w j berechnen. Der naheliegende Weg ist die Verwendung der Näherung

 frac partiellesC partielleswj ungefähr fracC(w+ epsilonej)C(w) epsilon tag46



Wobei ε> 0 eine kleine positive Zahl ist und e j der Einheitsrichtungsvektor j ist. Mit anderen Worten, wir können ∂C / ∂w j ungefähr schätzen, indem wir die Kosten C für zwei leicht unterschiedliche Werte von w j berechnen und dann Gleichung (46) anwenden. Die gleiche Idee erlaubt es uns, die partiellen Ableitungen von ∂C / ∂b in Bezug auf Verschiebungen zu berechnen.

Der Ansatz sieht vielversprechend aus. Konzeptionell einfach, leicht zu implementieren, verwendet nur wenige Codezeilen. Es sieht vielversprechender aus als die Idee, eine Kettenregel zur Berechnung des Gradienten zu verwenden!

Obwohl dieser Ansatz vielversprechend aussieht, stellt sich bei der Implementierung in Code leider heraus, dass er extrem langsam funktioniert. Um zu verstehen, warum, stellen Sie sich vor, wir haben eine Million Gewichte im Netzwerk. Dann müssen wir für jedes Gewicht w j C (w + εe j ) berechnen, um ∂C / ∂w j zu berechnen. Dies bedeutet, dass wir zur Berechnung des Gradienten die Kostenfunktion millionenfach berechnen müssen, was eine Million direkte Durchgänge durch das Netzwerk erfordert (für jedes Trainingsbeispiel). Und wir müssen auch C (w) berechnen, damit wir eine Million und einen Durchgang durch das Netzwerk erhalten.

Der Trick der Backpropagation besteht darin, dass wir alle partiellen Ableitungen ∂C / ∂w j gleichzeitig mit nur einem direkten Durchgang durch das Netzwerk berechnen können, gefolgt von einem umgekehrten Durchgang. Grob gesagt sind die Berechnungskosten des Rückpasses ungefähr die gleichen wie die des direkten.

Daher sind die Gesamtkosten der Rückausbreitung ungefähr gleich denen von zwei direkten Durchläufen durch das Netzwerk. Vergleichen Sie dies mit der Million und einem direkten Durchgang, die zur Implementierung der Methode (46) erforderlich sind! Obwohl die Backpropagation komplizierter aussieht, ist sie in Wirklichkeit viel schneller.

Zum ersten Mal wurde diese Beschleunigung 1986 voll gewürdigt, und dies erweiterte das Spektrum der Aufgaben, die mit Hilfe neuronaler Netze gelöst wurden, dramatisch. Dies hat wiederum zu einer Zunahme der Anzahl von Menschen geführt, die neuronale Netze nutzen. Backpropagation ist natürlich kein Allheilmittel. Sogar in den späten 1980er Jahren stießen die Menschen auf ihre Grenzen, insbesondere beim Versuch, mithilfe der Rückausbreitung tiefe neuronale Netze zu trainieren, dh Netze mit vielen verborgenen Schichten. Später werden wir sehen, wie moderne Computer und neue knifflige Ideen es ermöglichen, Backpropagation zu verwenden, um solch tiefe neuronale Netze zu trainieren.

Umgekehrte Verteilung: im Allgemeinen


Wie ich bereits erklärt habe, enthüllt uns die Rückausbreitung zwei Geheimnisse. Das erste, was der Algorithmus tatsächlich tut? Wir haben ein Rückausbreitungsschema für den Fehler aus der Ausgabe entwickelt. Ist es möglich, tiefer zu gehen und eine intuitivere Vorstellung davon zu bekommen, was bei all diesen Multiplikationen von Vektoren und Matrizen passiert? Das zweite Rätsel ist, wie jemand die Rückausbreitung überhaupt entdeckt hat. Es ist eine Sache, den Schritten des Algorithmus oder dem Beweis seiner Funktionsweise zu folgen. Dies bedeutet jedoch nicht, dass Sie das Problem so gut verstanden haben, dass Sie diesen Algorithmus erfinden konnten. Gibt es eine vernünftige Argumentation, die uns zur Entdeckung des Backpropagation-Algorithmus führen kann? In diesem Abschnitt werde ich beide Rätsel behandeln.

Um das Verständnis der Funktionsweise des Algorithmus zu verbessern, stellen Sie sich vor, wir hätten eine kleine Änderung Δw l jk eines bestimmten Gewichts w l jk vorgenommen :



Diese Gewichtsänderung führt zu einer Änderung der Ausgangsaktivierung des entsprechenden Neurons:



Dies führt zu einer Änderung aller Aktivierungen der nächsten Ebene:



Diese Änderungen führen zu Änderungen in der nächsten Ebene usw. bis zur letzten Ebene und dann zu Änderungen in der Kostenfunktion:



Die Änderung von ΔC hängt mit der Änderung von Δw l jk durch die Gleichung zusammen

 DeltaC approx frac partiellesC partielleswljk Deltawljk tag47



Daraus folgt, dass ein wahrscheinlicher Ansatz zur Berechnung von ∂C / ∂w l jk darin besteht, die Ausbreitung einer kleinen Änderung w l jk sorgfältig zu überwachen, was zu einer kleinen Änderung von C führt. Wenn wir dies tun können, drücken Sie auf dem Weg sorgfältig alles in Mengen aus, die leicht zu berechnen sind dann können wir ∂C / ∂w l jk berechnen.

Lass es uns versuchen. Eine Änderung von & Dgr; w l jk bewirkt eine leichte Änderung von & Dgr; a l j bei der Aktivierung des Neurons j in der Schicht l. Diese Änderung ist festgelegt.

 Deltaalj approx frac partiellalj partiellwljk Deltawljk tag48



Die Änderung der Aktivierung Δa lj führt zu Änderungen aller Aktivierungen der nächsten Schicht (l + 1). Wir werden uns nur auf eine dieser veränderten Aktivierungen konzentrieren, zum Beispiel a l + 1 q ,



Dies führt zu folgenden Änderungen:

 Deltaal+1q approx frac partiellal+1q partiellalj Deltaalj tag49



Wenn wir Gleichung (48) einsetzen, erhalten wir:

 Deltaal+1q approx frac partiellal+1q partiellalj frac partiellalj partiellwljk Deltawljk tag50



Natürlich ändert eine Änderung von Δa l + 1 q auch die Aktivierung in der nächsten Schicht. Wir können uns sogar einen Pfad entlang des gesamten Netzwerks von w l jk nach C vorstellen, bei dem jede Änderung der Aktivierung zu einer Änderung der nächsten Aktivierung und schließlich zu einer Änderung der Kosten am Ausgang führt. Wenn der Pfad die Aktivierungen a l j , a l + 1 q , ..., a L - 1 n , a L m durchläuft, ist der endgültige Ausdruck

 DeltaC approx frac partiellesC partiellesaLm frac partiellesaLm partiellesaL1n frac partiellesaL.1n partiellaL2p ldots frac partiellal+1q partiellalj frac partiellalj partiellewljk Deltawljk tag51



Das heißt, wir wählen für jedes nächste Neuron, das wir passieren, sowie für den Term ∂C / ∂a L m am Ende ein Mitglied der Form ∂a / ∂a aus. Dies ist eine Darstellung von Änderungen in C aufgrund von Änderungen in Aktivierungen auf diesem bestimmten Pfad durch das Netzwerk. Natürlich gibt es viele Möglichkeiten, wie eine Änderung von w l jk die Kosten beeinflussen kann, und wir haben nur eine davon in Betracht gezogen. Um die Gesamtänderung in C zu berechnen, ist anzunehmen, dass wir alle möglichen Pfade vom Gewicht bis zu den Endkosten zusammenfassen sollten:

 DeltaC approx summnp ldotsq frac partiellesC partiellesaLm frac partiellesaLm partiellesaL1n frac partiellaL1n partiellaL2p ldots frac partiellal+1q partiellalj frac partiellalj partiellwljk Deltawljk tag52



Hier haben wir alle möglichen Optionen für intermediäre Neuronen auf dem Weg zusammengefasst. Wenn wir dies mit (47) vergleichen, sehen wir Folgendes:

 frac partiellesC partielleswljk= summnp ldotsq frac partiellesC partiellesaLm frac partiellesaLm partiellaL1n frac partiellaL1n partiellaL2p ldots frac partiellal+1q partiellalj frac partiellalj partiellwljk. tag53



Gleichung (53) sieht kompliziert aus. Es hat jedoch eine schöne intuitive Interpretation. Wir zählen die Änderung von C in Bezug auf die Netzwerkgewichte. Es sagt uns, dass jede Kante zwischen zwei Neuronen des Netzwerks einem Verhältnisfaktor zugeordnet ist, der nur eine teilweise Ableitung der Aktivierung eines Neurons in Bezug auf die Aktivierung eines anderen Neurons ist. Für eine Rippe vom ersten Gewicht zum ersten Neuron beträgt der Verhältnisfaktor ∂a lj / ∂wljk. Der Verhältniskoeffizient für den Pfad ist einfach das Produkt der Koeffizienten entlang des Pfades. Und der Gesamtänderungskoeffizient ∂C / ∂w l jk ist die Summe der Koeffizienten in jeder Hinsicht vom Anfangsgewicht bis zu den Endkosten. Diese Prozedur wird unten für einen Pfad gezeigt:



Bisher haben wir ein heuristisches Argument gegeben, um darzustellen, was passiert, wenn sich die Netzwerkgewichte ändern. Lassen Sie mich eine weitere Denkweise zu diesem Thema für die Entwicklung dieses Arguments skizzieren. Zunächst können wir den genauen Ausdruck für alle einzelnen partiellen Ableitungen in Gleichung (53) ableiten. Dies ist mit einfacher Algebra einfach zu bewerkstelligen. Danach können Sie versuchen zu verstehen, wie Sie alle Summen nach Indizes in Form von Matrixprodukten aufschreiben. Dies stellt sich als mühsame Aufgabe heraus, die Geduld erfordert, aber nichts Außergewöhnliches. Nach all dem und maximaler Vereinfachung werden Sie sehen, dass genau der gleiche Backpropagation-Algorithmus erhalten wird! Daher kann der Backpropagation-Algorithmus als ein Weg zur Berechnung der Summe der Koeffizienten für alle Pfade vorgestellt werden. Um es neu zu formulieren, ist der Backpropagation-Algorithmus eine schwierige Methode, um kleine Änderungen der Gewichte (und Offsets) zu verfolgen, wenn sie sich über das Netzwerk ausbreiten, die Ausgabe erreichen und die Kosten beeinflussen.

Hier werde ich das alles nicht tun. Dieses Geschäft ist unattraktiv und erfordert eine sorgfältige Untersuchung der Details. Wenn Sie dazu bereit sind, möchten Sie dies möglicherweise tun. Wenn nicht, hoffe ich, dass solche Gedanken Ihnen einige Ideen bezüglich der Ziele der Rückausbreitung geben.

Was ist mit einem anderen Rätsel - wie könnte die Rückausbreitung überhaupt entdeckt werden? Wenn Sie dem von mir beschriebenen Weg folgen, erhalten Sie tatsächlich Hinweise auf eine Rückausbreitung. Leider wird der Beweis länger und komplizierter sein als das, was ich zuvor beschrieben habe. Wie wurden diese kurzen (aber noch mysteriöseren) Beweise entdeckt? Wenn Sie alle Details eines langen Beweises aufschreiben, werden Sie sofort einige offensichtliche Vereinfachungen bemerken. Sie wenden Vereinfachungen an, erhalten einfachere Beweise und schreiben sie auf. Und dann stoßen Sie wieder auf einige offensichtliche Vereinfachungen. Und Sie wiederholen den Vorgang. Nach mehreren Wiederholungen wird der Beweis, den wir zuvor gesehen haben, kurz, aber etwas unverständlich sein, da alle Meilensteine ​​entfernt wurden! Natürlich schlage ich vor, dass Sie mein Wort dafür nehmen, aber tatsächlich gibt es kein Geheimnis über die Herkunft der Beweise. Nur viel harte Arbeit, um den Beweis zu vereinfachen, den ich in diesem Abschnitt beschrieben habe.

Es gibt jedoch einen cleveren Trick in diesem Prozess. In Gleichung (53) sind die Zwischenvariablen Aktivierungen vom Typ a l + 1 q . Der Trick besteht darin, gewichtete Eingaben wie z l + 1 q als Zwischenvariablen zu verwenden. Wenn Sie dies nicht verwenden und weiterhin Aktivierungen verwenden, sind die erhaltenen Beweise etwas komplizierter als die zuvor in diesem Kapitel angegebenen.

Source: https://habr.com/ru/post/de457980/


All Articles