ef:ki:nn

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
ef:ki:nn [2026/04/21 11:00] andristnef:ki:nn [2026/04/23 14:17] (aktuell) andristn
Zeile 21: Zeile 21:
 </code> </code>
  
-Weiss wird zu 0.0, schwarz zu 1.0. Und weil das Bild 28×28 Pixel gross ist, entstehen genau 784 Werte. Deshalb steht in der Grafik auch <m>x_1x_2\ldotsx_{784}</m>.+Weiss wird zu 0.0, schwarz zu 1.0. Und weil das Bild 28×28 Pixel gross ist, entstehen genau 784 Werte. Deshalb stehen in der Grafik auch die Inputs x₁x₂x₇₈₄.
  
 ===== Gewichte und gewichtete Summe ===== ===== Gewichte und gewichtete Summe =====
Zeile 33: Zeile 33:
 784 Inputs mal 128 Hidden-Neuronen ergibt über 100'000 Gewichte, nur für diesen einen Übergang. Die werden am Anfang zufällig gesetzt und dann durch das Training langsam verbessert. 784 Inputs mal 128 Hidden-Neuronen ergibt über 100'000 Gewichte, nur für diesen einen Übergang. Die werden am Anfang zufällig gesetzt und dann durch das Training langsam verbessert.
  
-Die grünen Kreise in der Mitte, <m>h_1</m> bis <m>h_{128}</m>, sind die **Hidden Layer**. Jedes dieser Neuronen nimmt alle 784 Eingabewerte, multipliziert sie mit seinen Gewichten und addiert noch einen **Bias** dazu. Der Bias ist ein freier Wert, der dem Neuron erlaubt, seine Schwelle unabhängig vom Input zu verschieben. Mathematisch sieht das so aus:+Die grünen Kreise in der Mitte, h₁ bis h₁₂₈, sind die **Hidden Layer**. Jedes dieser Neuronen nimmt alle 784 Eingabewerte, multipliziert sie mit seinen Gewichten und addiert noch einen **Bias** dazu. Der Bias ist ein freier Wert, der dem Neuron erlaubt, seine Schwelle unabhängig vom Input zu verschieben. Mathematisch sieht das so aus:
  
-<m>z = (x_1 \cdot w_1) + (x_2 \cdot w_2) + \ldots + (x_{784} \cdot w_{784}) + b</m>+<code> 
 +z = (x₁ · w₁) + (x₂ · w₂) + … + (x₇₈₄ · w₇₈₄) + b 
 +</code>
  
-Oder kompakter geschrieben als Summe:+Oder kompakter als Summe:
  
-<m>z = \sum_{i=1}^{784} x_i \cdot w_i + b</m>+<code> 
 +       784 
 +   Σ  xᵢ · wᵢ  +  b 
 +      i=1 
 +</code>
  
 Und im Code passiert das für alle 128 Neuronen auf einmal, dank der Matrix-Multiplikation: Und im Code passiert das für alle 128 Neuronen auf einmal, dank der Matrix-Multiplikation:
Zeile 47: Zeile 53:
 </code> </code>
  
-Dieses <m>z</m> ist noch nicht das finale Ergebnis des Neurons. Es ist die rohe gewichtete Summe, auch //pre-activation// genannt. Ob der Neuron jetzt wirklich etwas weitergibt, entscheidet die Aktivierungsfunktion.+Dieses z ist noch nicht das finale Ergebnis des Neurons. Es ist die rohe gewichtete Summe, auch //pre-activation// genannt. Ob der Neuron jetzt wirklich etwas weitergibt, entscheidet die Aktivierungsfunktion.
  
 ===== Aktivierungsfunktion: ReLU ===== ===== Aktivierungsfunktion: ReLU =====
  
-Ist <m>z</m> grösser als 0, kommt der Wert durch. Ist er kleiner oder gleich 0, wird er auf 0 gesetzt:+Ist z grösser als 0, kommt der Wert durch. Ist er kleiner oder gleich 0, wird er auf 0 gesetzt:
  
 <code python> <code python>
Zeile 57: Zeile 63:
 </code> </code>
  
-Was danach rauskommt, fliesst zu den orangen Kreisen rechts in der Grafik, der **Output Layer**. Dort passiert genau dasselbe nochmal, mit Gewichten <m>W_2</m> und Bias <m>b_2</m>:+Was danach rauskommt, fliesst zu den orangen Kreisen rechts in der Grafik, der **Output Layer**. Dort passiert genau dasselbe nochmal, mit Gewichten W₂ und Bias b₂:
  
 <code python> <code python>
Zeile 71: Zeile 77:
 ==== ReLU ==== ==== ReLU ====
  
-ReLU steht für //Rectified Linear Unit//, auf Deutsch in etwa "gleichgerichtete lineare Einheit". Nachdem ein Neuron seine gewichtete Summe <m>z</m> berechnet hat, wird diese einfach durch ReLU geschickt. Die Regel ist denkbar simpel: ist <m>z</m> grösser als 0, kommt der Wert unverändert durch. Ist <m>z</m> kleiner oder gleich 0, wird er auf 0 gesetzt. Das war's:+ReLU steht für //Rectified Linear Unit//, auf Deutsch in etwa gleichgerichtete lineare Einheit". Nachdem ein Neuron seine gewichtete Summe z berechnet hat, wird diese einfach durch ReLU geschickt. Die Regel ist denkbar simpel: ist z grösser als 0, kommt der Wert unverändert durch. Ist z kleiner oder gleich 0, wird er auf 0 gesetzt. Das war's:
  
 <code python> <code python>
Zeile 80: Zeile 86:
 Mathematisch sieht das so aus: Mathematisch sieht das so aus:
  
-<m>f(z) = \max(0, z) = \left\{ \begin{matrix} z & \mbox{wenn } z > 0 \\ & \mbox{sonst} \end{matrix} \right.</m>+<code> 
 +                    ⎧ z    wenn z > 0 
 +f(z) = max(0, z) =  ⎨ 
 +                    ⎩    sonst 
 +</code>
  
 Warum macht man das überhaupt? Ohne eine Aktivierungsfunktion wäre das ganze Netz nur eine einzige grosse lineare Gleichung, egal wie viele Schichten man draufpackt. ReLU bringt die **Nichtlinearität** rein, die das Netz braucht, um wirklich komplexe Muster zu lernen. Ein Neuron, das 0 ausgibt, ist quasi stumm. Es gibt nichts weiter. Ein Neuron, das einen positiven Wert ausgibt, feuert und beeinflusst die nächste Schicht. Warum macht man das überhaupt? Ohne eine Aktivierungsfunktion wäre das ganze Netz nur eine einzige grosse lineare Gleichung, egal wie viele Schichten man draufpackt. ReLU bringt die **Nichtlinearität** rein, die das Netz braucht, um wirklich komplexe Muster zu lernen. Ein Neuron, das 0 ausgibt, ist quasi stumm. Es gibt nichts weiter. Ein Neuron, das einen positiven Wert ausgibt, feuert und beeinflusst die nächste Schicht.
Zeile 96: Zeile 106:
 Mathematisch passiert Folgendes: jeder Rohwert wird mit der Exponentialfunktion hochgerechnet und dann durch die Summe aller hochgerechneten Werte geteilt: Mathematisch passiert Folgendes: jeder Rohwert wird mit der Exponentialfunktion hochgerechnet und dann durch die Summe aller hochgerechneten Werte geteilt:
  
-<m>\sigma(z_i) = \frac{e^{z_i}}{\sum_{j=1}^{52} e^{z_j}}</m>+<code> 
 +                  e^(zᵢ) 
 +σ(zᵢ)    ───────────────── 
 +                52 
 +                Σ  e^(zⱼ) 
 +               j=1 
 +</code>
  
 Das sorgt dafür, dass ein hoher Rohwert eine hohe Wahrscheinlichkeit bekommt und ein tiefer eine kleine. Am Ende schaut das Netz einfach, welcher der 52 Neuronen die höchste Wahrscheinlichkeit hat, und das ist dann der vorhergesagte Buchstabe: Das sorgt dafür, dass ein hoher Rohwert eine hohe Wahrscheinlichkeit bekommt und ein tiefer eine kleine. Am Ende schaut das Netz einfach, welcher der 52 Neuronen die höchste Wahrscheinlichkeit hat, und das ist dann der vorhergesagte Buchstabe:
Zeile 112: Zeile 128:
 Mathematisch sieht ein Perzeptron so aus: Mathematisch sieht ein Perzeptron so aus:
  
-<m>y = \left\{ \begin{matrix} & \mbox{wenn } \sum_{i} w_i x_i + b > 0 \\ & \mbox{sonst} \end{matrix} \right.</m>+<code> 
 +       ⎧    wenn Σ wᵢ·xᵢ + b > 0 
 +y  =   ⎨ 
 +       ⎩    sonst 
 +</code>
  
 Das Problem dabei ist schnell klar. Mit nur 0 und 1 kann man keine Wahrscheinlichkeiten ausdrücken, und man kann auch keine komplexen Muster lernen. Ein einzelnes Perzeptron kann zum Beispiel nicht unterscheiden, ob ein Pixel oben links oder unten rechts liegt. Es sieht alles als eine einzige Entscheidung. Das Problem dabei ist schnell klar. Mit nur 0 und 1 kann man keine Wahrscheinlichkeiten ausdrücken, und man kann auch keine komplexen Muster lernen. Ein einzelnes Perzeptron kann zum Beispiel nicht unterscheiden, ob ein Pixel oben links oder unten rechts liegt. Es sieht alles als eine einzige Entscheidung.
Zeile 137: Zeile 157:
 Um das Ganze mal ganz konkret zu machen, schauen wir uns ein Perzeptron an, das die logische //AND//-Funktion lernt. Bei AND ist die Ausgabe nur dann 1, wenn beide Inputs 1 sind. Sonst ist sie 0. Um das Ganze mal ganz konkret zu machen, schauen wir uns ein Perzeptron an, das die logische //AND//-Funktion lernt. Bei AND ist die Ausgabe nur dann 1, wenn beide Inputs 1 sind. Sonst ist sie 0.
  
-<m>x_1</m> <m>x_2</m> <m>y</m> (AND) ^+x₁ x₂ ^ y (AND) ^
 | 0 | 0 | 0 | | 0 | 0 | 0 |
 | 0 | 1 | 0 | | 0 | 1 | 0 |
Zeile 145: Zeile 165:
 Ein einzelnes Perzeptron mit zwei Inputs reicht, um das zu lernen. Wir brauchen nur passende Gewichte und einen Bias. Zum Beispiel: Ein einzelnes Perzeptron mit zwei Inputs reicht, um das zu lernen. Wir brauchen nur passende Gewichte und einen Bias. Zum Beispiel:
  
-<m>w_1 = 1, \quad w_2 = 1, \quad b = -1.5</m>+<code> 
 +w₁ = 1,   w₂ = 1,   b = -1.5 
 +</code>
  
 Rechnen wir das für alle vier Fälle durch: Rechnen wir das für alle vier Fälle durch:
  
-  * <m>x_1 = 0, x_2 = 0</m><m>z = 0 \cdot 1 0 \cdot 1 - 1.5 = -1.5</m> → ReLU/Schwelle: <m>y = 0</m> +  * x₁ = 0, x₂ = 0:   z = 0·1 0·1 − 1.5 = 1.5   →   y = 0 
-  * <m>x_1 = 0, x_2 = 1</m><m>z = 0 \cdot 1 1 \cdot 1 - 1.5 = -0.5</m> → <m>y = 0</m> +  * x₁ = 0, x₂ = 1:   z = 0·1 1·1 − 1.5 = 0.5   →   y = 0 
-  * <m>x_1 = 1, x_2 = 0</m><m>z = 1 \cdot 1 0 \cdot 1 - 1.5 = -0.5</m> → <m>y = 0</m> +  * x₁ = 1, x₂ = 0:   z = 1·1 0·1 − 1.5 = 0.5   →   y = 0 
-  * <m>x_1 = 1, x_2 = 1</m><m>z = 1 \cdot 1 1 \cdot 1 - 1.5 = 0.5</m> → <m>y = 1</m>+  * x₁ = 1, x₂ = 1:   z = 1·1 1·1 − 1.5 =  0.5   →   y = 1
  
-Das Perzeptron gibt also genau dann 1 aus, wenn beide Inputs 1 sind. Die **Entscheidungsgrenze** ist hier die Gerade <m>x_1 x_2 = 1.5</m>. Alles darüber wird als 1 klassifiziert, alles darunter als 0. Genau dasselbe Prinzip passiert in unserem Buchstabennetz, nur eben 784-dimensional statt 2-dimensional, und mit 128 Neuronen parallel statt nur einem.+Das Perzeptron gibt also genau dann 1 aus, wenn beide Inputs 1 sind. Die **Entscheidungsgrenze** ist hier die Gerade x₁ x₂ = 1.5. Alles darüber wird als 1 klassifiziert, alles darunter als 0. Genau dasselbe Prinzip passiert in unserem Buchstabennetz, nur eben 784-dimensional statt 2-dimensional, und mit 128 Neuronen parallel statt nur einem.
  
 ===== Gewichtete Summe, Schwellenwert und Entscheidungsgrenze ===== ===== Gewichtete Summe, Schwellenwert und Entscheidungsgrenze =====
Zeile 164: Zeile 186:
 </code> </code>
  
-Das Ergebnis <m>z</m> ist einfach eine Zahl, die zusammenfasst, was der Neuron aus allen seinen Inputs herausgelesen hat.+Das Ergebnis z ist einfach eine Zahl, die zusammenfasst, was der Neuron aus allen seinen Inputs herausgelesen hat.
  
-Jetzt kommt der **Schwellenwert** ins Spiel. Man kann sich das vorstellen wie eine Eingangstür. Nur wenn die gewichtete Summe gross genug ist, also den Schwellenwert überschreitet, gibt der Neuron etwas weiter. Bei ReLU ist dieser Schwellenwert genau 0. Ist <m>z</m> grösser als 0, kommt der Wert durch. Ist <m>z</m> kleiner oder gleich 0, wird alles auf 0 gesetzt und der Neuron bleibt stumm:+Jetzt kommt der **Schwellenwert** ins Spiel. Man kann sich das vorstellen wie eine Eingangstür. Nur wenn die gewichtete Summe gross genug ist, also den Schwellenwert überschreitet, gibt der Neuron etwas weiter. Bei ReLU ist dieser Schwellenwert genau 0. Ist z grösser als 0, kommt der Wert durch. Ist z kleiner oder gleich 0, wird alles auf 0 gesetzt und der Neuron bleibt stumm:
  
 <code python> <code python>
Zeile 182: Zeile 204:
 ==== Schritt 1: Fehler messen ==== ==== Schritt 1: Fehler messen ====
  
-Der erste Schritt ist, den Fehler zu messen. Das macht die **Loss Function**, in unserem Fall //Cross Entropy Loss//:+Der erste Schritt ist, den Fehler zu messen. Das macht die **Loss Function**. Davon gibt es natürlich mehrere Variantendie zwei wichtigsten sind //Mean Squared Error// und //Cross Entropy Loss//
 + 
 +Der **Mean Squared Error** (MSE) ist der Klassiker und wird zum Beispiel auch von 3Blue1Brown in seiner bekannten YouTube-Serie über neuronale Netzwerke verwendet. Er misst den Fehler, indem er für jedes Output-Neuron die Differenz zwischen Vorhersage und richtigem Wert quadriert und dann den Durchschnitt bildet: 
 + 
 +<code> 
 +          1      
 +MSE  =  ───  Σ (ŷᵢ − yᵢ)² 
 +           i 
 +</code> 
 + 
 +Wir haben uns aber für **Cross Entropy Loss** entschieden, weil er für Klassifikationsaufgaben wie unsere Buchstabenerkennung besser geeignet ist. Im Code sieht das so aus:
  
 <code python> <code python>
Zeile 189: Zeile 221:
 </code> </code>
  
-Mathematisch gesehen berechnet sie, wie weit die vorhergesagte Wahrscheinlichkeit vom richtigen Wert entfernt ist:+Mathematisch gesehen berechnet er, wie weit die vorhergesagte Wahrscheinlichkeit vom richtigen Wert entfernt ist:
  
-<m>L = -\sum_{i} y_i \cdot \log(\hat{y}_i)</m>+<code> 
 +  − Σ  yᵢ · log(ŷᵢ) 
 +         i 
 +</code> 
 + 
 +Der grosse Vorteil von Cross Entropy gegenüber MSE ist, dass er starke Fehler viel härter bestraft. Sagt das Netz mit 99% Sicherheit "b", obwohl die richtige Antwort "a" wäre, geht der Loss dank des Logarithmus praktisch gegen unendlich. Bei MSE wäre der Fehler in so einem Fall höchstens 1. Dadurch bekommt das Netz bei Fehlklassifikationen einen viel stärkeren Gradienten und **konvergiert deutlich schneller**. Ausserdem passt Cross Entropy perfekt zu Softmax, weil beide mit Wahrscheinlichkeiten arbeiten.
  
 War die Vorhersage für "a" zum Beispiel nur 0.02, obwohl sie 1.0 sein sollte, ist der Loss gross. War sie 0.95, ist der Loss klein. Jetzt wissen wir, wie gross der Fehler ist, aber noch nicht, woher er kommt. War die Vorhersage für "a" zum Beispiel nur 0.02, obwohl sie 1.0 sein sollte, ist der Loss gross. War sie 0.95, ist der Loss klein. Jetzt wissen wir, wie gross der Fehler ist, aber noch nicht, woher er kommt.
Zeile 199: Zeile 236:
 Hier kommt der **Gradient** ins Spiel. Ein Gradient sagt uns für jedes einzelne Gewicht, in welche Richtung und wie stark es den Loss beeinflusst. Man kann sich das wie einen Hügel vorstellen. Der Loss ist die Höhe, und wir wollen den tiefsten Punkt finden. Der Gradient zeigt uns die steilste Richtung bergauf, also gehen wir genau die entgegengesetzte Richtung bergab. Das nennt sich **Gradientenabstieg**. Hier kommt der **Gradient** ins Spiel. Ein Gradient sagt uns für jedes einzelne Gewicht, in welche Richtung und wie stark es den Loss beeinflusst. Man kann sich das wie einen Hügel vorstellen. Der Loss ist die Höhe, und wir wollen den tiefsten Punkt finden. Der Gradient zeigt uns die steilste Richtung bergauf, also gehen wir genau die entgegengesetzte Richtung bergab. Das nennt sich **Gradientenabstieg**.
  
-Bei einem einzelnen Neuron ist das noch überschaubar. Angenommen, wir haben einen Output-Neuron mit nur einem Gewicht <m>w</m>Der Fehler am Ausgang ist einfach die Differenz zwischen Vorhersage und richtigem Wert:+Um den Gradienten zu berechnenmüssen wir verstehen, wie ein Gewicht überhaupt den Loss beeinflusstDas Gewicht w ist ja nicht direkt im Loss drin, sondern es gibt eine ganze Kette von Zwischenschritten:
  
-<m>\delta = \hat{y} - y</m>+<code> 
 +w  ──►  z  ──►  ŷ  ──► 
 +     (gewichtete    (Softmax)   (Cross Entropy 
 +       Summe)                    Loss) 
 +</code>
  
-Das Gewicht <m>w</m> hat diesen Fehler verursachtproportional dazu, wie gross der Input <m>x</m> warAlso ist der Gradient:+Das Gewicht beeinflusst zuerst die gewichtete Summe zdiese wird dann durch Softmax zur Vorhersage ŷ, und ŷ fliesst in den Loss L. Um zu wissen, wie stark w den Loss verändert, müssen wir diese Kette komplett durchrechnenGenau dafür gibt es die **Kettenregel** aus der Differentialrechnung:
  
-<m>\frac{\partial L}{\partial w} \delta \cdot x</m>+<code> 
 + ∂       ∂L      ∂ŷ      ∂z 
 +────    ──── ·  ──── ·  ──── 
 + ∂w        ∂ŷ      ∂z      ∂w 
 +</code>
  
-Und das Gewicht wird dann in die entgegengesetzte Richtung angepasst:+Wir leiten also drei Mal einzeln ab und multiplizieren das Ergebnis. Schauen wir uns jeden Teil einzeln an.
  
-<m>w_{neu} = w_{alt} - \eta \cdot \frac{\partial L}{\partial w}</m>+**1. Ableitung des Loss nach der Vorhersage**
  
-Dabei ist <m>\eta</m> die **Lernrate**, also wie gross jeder Schritt bergab ist. Im Code ist das:+Cross Entropy Loss ist L = −Σ yᵢ · log(ŷᵢ). Leiten wir ihn nach ŷ ab: 
 + 
 +<code> 
 + ∂L         y 
 +────  =  − ─── 
 + ∂ŷ         ŷ 
 +</code> 
 + 
 +**2. Ableitung der Softmax nach der gewichteten Summe** 
 + 
 +Hier wird es etwas komplizierter. Softmax ist nämlich eine Funktion, bei der jeder Output ŷᵢ von //allen// z-Werten gleichzeitig abhängt (wegen der Summe im Nenner). Die vollständige Ableitung ist deshalb eine sogenannte Jacobi-Matrix und würde den Rahmen hier sprengen. Wir sparen uns den detaillierten Zwischenschritt und halten einfach fest: es gibt eine wohldefinierte Ableitung. 
 + 
 +**3. Ableitung der gewichteten Summe nach dem Gewicht** 
 + 
 +Die gewichtete Summe ist z = w·x + b. Leiten wir nach w ab, bleibt einfach x übrig: 
 + 
 +<code> 
 + ∂z 
 +────  =  x 
 + ∂w 
 +</code> 
 + 
 +**Alles einsetzen** 
 + 
 +Wenn man nun alle drei Teile in die Kettenregel einsetzt und sauber ausrechnet (das ist der Punkt, an dem sich die komplizierte Softmax-Ableitung mit der −y/ŷ aus dem Cross Entropy Loss gegenseitig auffrisst), bleibt am Ende dieser wunderschön einfache Ausdruck übrig: 
 + 
 +<code> 
 + ∂L 
 +────  =  (ŷ − y) · x     δ · x 
 + ∂w 
 +</code> 
 + 
 +Das ist genau das, was wir vorhin als "Fehler mal Input" beschrieben haben. Der Term δ = ŷ − y ist der Fehler am Output. Genau deshalb ist die Kombination aus Softmax und Cross Entropy so elegant: nach der ganzen Ableiterei bleibt einfach die Differenz zwischen Vorhersage und Zielwert übrig. 
 + 
 +**Gradient für den Bias** 
 + 
 +Für den Bias b läuft dieselbe Kettenregel, nur der letzte Teil ist anders. Die gewichtete Summe ist z = w·x + b. Leiten wir nach b ab: 
 + 
 +<code> 
 + ∂z 
 +────  =  1 
 + ∂b 
 +</code> 
 + 
 +Also ist der Gradient für den Bias einfach der Fehler selbst, ohne Multiplikation mit dem Input: 
 + 
 +<code> 
 + ∂L 
 +────  =  (ŷ − y) · 1     δ 
 + ∂b 
 +</code> 
 + 
 +**Update-Regel** 
 + 
 +Jetzt wo wir beide Gradienten kennen, können wir Gewicht und Bias in die entgegengesetzte Richtung anpassen: 
 + 
 +<code> 
 +w_neu  =  w_alt  −  η · (∂L / ∂w)  =  w_alt  −  η · δ · x 
 + 
 +b_neu  =  b_alt  −  η · (∂L / ∂b)  =  b_alt  −  η · δ 
 +</code> 
 + 
 +Dabei ist η (eta) die **Lernrate**, also wie gross jeder Schritt bergab ist. Im Code ist das:
  
 <code python> <code python>
Zeile 219: Zeile 326:
 Ist die Lernrate zu gross, springt das Netz über das Minimum hinweg. Ist sie zu klein, braucht das Training ewig. 0.01 ist ein guter Startwert für unser Netz. Ist die Lernrate zu gross, springt das Netz über das Minimum hinweg. Ist sie zu klein, braucht das Training ewig. 0.01 ist ein guter Startwert für unser Netz.
  
-==== Schritt 3: Fehler zurück durch das Netz =====+**Das Ganze als Matrix** 
 + 
 +Bisher haben wir so getan, als hätten wir nur ein einziges Gewicht w und einen einzigen Input x. In Wirklichkeit ist w natürlich die ganze **Gewichtsmatrix W** und x der ganze **Input-Vektor**. Schauen wir uns ein Mini-Beispiel mit 3 Inputs und 2 Hidden-Neuronen an: 
 + 
 +<code> 
 +X = [ x₁  x₂  x₃ ] 
 + 
 + 
 +     ⎡ w₁₁  w₁₂ ⎤ 
 +W =  ⎢ w₂₁  w₂₂ ⎥ 
 +     ⎣ w₃₁  w₃₂ ⎦ 
 + 
 + 
 +b = [ b₁  b₂ ] 
 +</code> 
 + 
 +Die gewichtete Summe ist dann eine Matrix-Multiplikation: 
 + 
 +<code> 
 +z  =  X · W  +  b 
 + 
 +     = [x₁·w₁₁ + x₂·w₂₁ + x₃·w₃₁ + b₁ ,  x₁·w₁₂ + x₂·w₂₂ + x₃·w₃₂ + b₂] 
 +</code> 
 + 
 +Für die Ableitung gilt genau dasselbe Prinzip wie vorher, nur eben für alle Gewichte auf einmal. Statt δ · x schreiben wir die Matrix-Version: 
 + 
 +<code> 
 + ∂L 
 +────  =  Xᵀ · δ 
 + ∂W 
 +</code> 
 + 
 +Das Xᵀ (X transponiert) sorgt dabei einfach dafür, dass die Dimensionen zusammenpassen. Im Code ist genau das diese Zeile, die du schon von oben kennst: 
 + 
 +<code python> 
 +self.W1 -= self.lr * (X.T @ d1) / N 
 +</code> 
 + 
 +Der Vorteil der Matrix-Schreibweise ist enorm: statt 100'000 mal einzeln Ableitungen auszurechnen, macht NumPy das in einer einzigen Zeile parallel für alle Gewichte gleichzeitig. 
 + 
 +==== Schritt 3: Fehler zurück durch das Netz ====
  
 Soweit so gut für einen einzelnen Neuron. Aber jetzt kommt die eigentliche Herausforderung. Soweit so gut für einen einzelnen Neuron. Aber jetzt kommt die eigentliche Herausforderung.
Zeile 233: Zeile 380:
 Mathematisch: Mathematisch:
  
-<m>\delta_2 \hat{y} - y</m>+<code> 
 +δ₂   ŷ − y 
 +</code>
  
-Jetzt muss dieser Fehler zurück durch die Gewichte <m>W_2</m> in die Hidden Layer propagiert werden. Dazu wird <m>\delta_2</m> mit der transponierten Gewichtsmatrix multipliziert und mit der Ableitung von ReLU komponentenweise verrechnet:+Jetzt muss dieser Fehler zurück durch die Gewichte W₂ in die Hidden Layer propagiert werden. Das klingt kompliziert, ist aber wieder nur eine Kettenregel. Schauen wir uns an, wie ein Hidden-Wert z₁ den Loss beeinflusst:
  
-<m>\delta_1 = (\delta_2 \cdot W_2^T) \odot \mbox{ReLU}'(z_1)</m>+<code> 
 +z₁  ──►  a₁  ──►  z₂  ──►  ŷ  ──► 
 +     (ReLU)    (W₂, b₂)  (Softmax)  (Cross Entropy) 
 +</code>
  
-Das <m>\mbox{ReLU}'</m> ist die Ableitung von ReLU, also ''reluDerivative''. Sie sorgt dafür, dass nur die Neuronen einen Fehleranteil zugewiesen bekommen, die vorhin auch wirklich gefeuert haben. Neuronen, die 0 ausgegeben haben, bekommen auch 0 Fehler zurück, denn sie haben nichts beigetragen:+z₁ wirkt also über mehrere Zwischenschritte auf den Loss. Die Kettenregel sagt uns: 
 + 
 +<code> 
 + ∂L        ∂L      ∂z₂      ∂a₁ 
 +────  =  ──── ·  ──── ·  ──── 
 + ∂z₁       ∂z₂     ∂a₁      ∂z₁ 
 +</code> 
 + 
 +Schauen wir uns jeden Teil an: 
 + 
 +  * **∂L / ∂z₂**  –  das kennen wir schon, das ist der Output-Fehler δ₂ = ŷ − y 
 +  * **∂z₂ / ∂a₁**  –  die gewichtete Summe ist z₂ = a₁ · W₂ + b₂, abgeleitet nach a₁ bleibt W₂ übrig (in der Matrix-Version brauchen wir W₂ transponiert, damit die Dimensionen passen) 
 +  * **∂a₁ / ∂z₁**  –  das ist die Ableitung von ReLU, also ReLU'(z₁). Sie ist 1, wenn z₁ > 0, sonst 0 
 + 
 +Setzen wir alles zusammen: 
 + 
 +<code> 
 +δ₁  =  (δ₂ · W₂ᵀ)  ⊙  ReLU'(z₁) 
 +</code> 
 + 
 +Das ⊙ steht dabei für "elementweise multiplizieren" (nicht Matrix-Multiplikation). Also: zuerst wird der Fehler δ₂ über die transponierten Gewichte W₂ᵀ zurück in die Hidden Layer gerechnet, und dann wird jedes Element mit der Ableitung von ReLU verrechnet. 
 + 
 +Das ReLU'(z₁) sorgt dafür, dass nur die Neuronen einen Fehleranteil zugewiesen bekommen, die vorhin auch wirklich gefeuert haben. Neuronen, die 0 ausgegeben haben, bekommen auch 0 Fehler zurück, denn sie haben nichts beigetragen:
  
 <code python> <code python>
Zeile 256: Zeile 430:
 Mathematisch passiert hier für jede Schicht dasselbe wie beim einzelnen Neuron, nur jetzt für alle Gewichte gleichzeitig: Mathematisch passiert hier für jede Schicht dasselbe wie beim einzelnen Neuron, nur jetzt für alle Gewichte gleichzeitig:
  
-<m>W_2 W_2 - \eta \cdot \frac{a_1^T \cdot \delta_2}{N}</m>+<code> 
 +                 a₁ᵀ · δ₂ 
 +W₂   W₂  −  η · ───────── 
 +                     N
  
-<m>W_1 W_1 - \eta \cdot \frac{X^T \cdot \delta_1}{N}</m>+                 Xᵀ · δ₁ 
 +W₁   W₁  −  η · ───────── 
 +                     N 
 +</code>
  
-Die Division durch <m>N</m> ist dabei wichtig: sie mittelt den Fehler über alle Trainingsbeispiele im Batch, damit kein einzelnes Bild zu viel Einfluss hat.+Die Division durch N ist dabei wichtig: sie mittelt den Fehler über alle Trainingsbeispiele im Batch, damit kein einzelnes Bild zu viel Einfluss hat.
  
-Dieser ganze Prozess  – Forward Pass, Loss berechnen, Fehler zurückpropagieren, Gewichte anpassen – wiederholt sich dann für jeden Batch und jede Epoche:+Dieser ganze Prozess – Forward Pass, Loss berechnen, Fehler zurückpropagieren, Gewichte anpassen – wiederholt sich dann für jeden Batch und jede Epoche:
  
 <code python> <code python>
Zeile 278: Zeile 458:
 ==== Input Layer ==== ==== Input Layer ====
  
-Die **Input Layer** ist der Eingang des Netzes. Hier kommt das Bild rein, nichts weiter. Jeder Pixel wird zu einem Neuron, und weil unsere Bilder 28×28 Pixel gross sind, hat diese Schicht genau 784 Neuronen. Sie rechnet nichts, sie bewertet nichts, sie gibt einfach die rohen Pixelwerte weiter. In der Grafik sind das die lila Kreise ganz links, beschriftet mit <m>x_1</m> bis <m>x_{784}</m>.+Die **Input Layer** ist der Eingang des Netzes. Hier kommt das Bild rein, nichts weiter. Jeder Pixel wird zu einem Neuron, und weil unsere Bilder 28×28 Pixel gross sind, hat diese Schicht genau 784 Neuronen. Sie rechnet nichts, sie bewertet nichts, sie gibt einfach die rohen Pixelwerte weiter. In der Grafik sind das die lila Kreise ganz links, beschriftet mit x₁ bis x₇₈₄.
  
 ==== Hidden Layer ==== ==== Hidden Layer ====
Zeile 315: Zeile 495:
   * **Perzeptron** – einfachstes künstliches Neuron, gibt nur 0 oder 1 aus   * **Perzeptron** – einfachstes künstliches Neuron, gibt nur 0 oder 1 aus
   * **Feedforward-Netz** – Informationen fliessen nur in eine Richtung, von Input zu Output   * **Feedforward-Netz** – Informationen fliessen nur in eine Richtung, von Input zu Output
-  * **gewichtete Summe** – <m>z = \sum w_i x_i + b</m>, das Zwischenergebnis eines Neurons+  * **gewichtete Summe** – z = Σ wᵢ·xᵢ + b, das Zwischenergebnis eines Neurons
   * **Schwellenwert** – Grenze zwischen feuern und nicht feuern (bei ReLU: 0)   * **Schwellenwert** – Grenze zwischen feuern und nicht feuern (bei ReLU: 0)
   * **Entscheidungsgrenze** – hochdimensionale Trennfläche, die das Netz zwischen Klassen lernt   * **Entscheidungsgrenze** – hochdimensionale Trennfläche, die das Netz zwischen Klassen lernt
Zeile 325: Zeile 505:
   * **flache vs. tiefe Netze** – eine vs. viele Hidden Layers, Komplexität und Rechenaufwand steigen   * **flache vs. tiefe Netze** – eine vs. viele Hidden Layers, Komplexität und Rechenaufwand steigen
  
 +===== Quellen =====
  
 +==== Videos ====
  
 +Die Videoserie von //3Blue1Brown// (Grant Sanderson) gilt als die beste visuelle Einführung in neuronale Netze und erklärt die Mathematik dahinter sehr anschaulich:
  
 +  * [[https://www.youtube.com/watch?v=aircAruvnKk|But what is a Neural Network? – Deep learning, chapter 1]]
 +  * [[https://www.youtube.com/watch?v=IHZwWFHWa-w|Gradient descent, how neural networks learn – Deep learning, chapter 2]]
 +  * [[https://www.youtube.com/watch?v=Ilg3gGewQ5U|What is backpropagation really doing? – Deep learning, chapter 3]]
 +  * [[https://www.youtube.com/watch?v=tIeHLnjs5U8|Backpropagation calculus – Deep learning, chapter 4]]
 +  * [[https://www.youtube.com/playlist?list=PLZZWrBYkx7Otcjr3eCLZDCgfpqnxMY29s|Komplette Playlist: 3Blue1Brown Neural Networks]]
  
 +==== Wikipedia ====
  
 +  * [[https://de.wikipedia.org/wiki/K%C3%BCnstliches_neuronales_Netz|Künstliches neuronales Netz]]
 +  * [[https://de.wikipedia.org/wiki/Perzeptron|Perzeptron]]
 +  * [[https://de.wikipedia.org/wiki/Backpropagation|Backpropagation]]
 +  * [[https://de.wikipedia.org/wiki/Aktivierungsfunktion|Aktivierungsfunktion]]
 +  * [[https://en.wikipedia.org/wiki/Softmax_function|Softmax function (englisch)]]
 +  * [[https://en.wikipedia.org/wiki/Cross-entropy|Cross-Entropy (englisch)]]
 +  * [[https://en.wikipedia.org/wiki/Rectifier_(neural_networks)|ReLU / Rectifier (englisch)]]
 +  * [[https://de.wikipedia.org/wiki/Gradientenverfahren|Gradientenverfahren]]
  
 +==== Weiterführende Literatur ====
  
 +  * Michael Nielsen: //Neural Networks and Deep Learning// – kostenloses Online-Buch unter [[http://neuralnetworksanddeeplearning.com/]]
 +  * Ian Goodfellow, Yoshua Bengio, Aaron Courville: //Deep Learning// – frei verfügbar unter [[https://www.deeplearningbook.org/]]
  
 +==== Bibliotheken und Tools ====
  
- +  * [[https://numpy.org/|NumPy]] – die Bibliothek, die wir für alle Matrix-Operationen verwenden 
- +  * [[https://pillow.readthedocs.io/|Pillow (PIL)]] – für die Bildverarbeitung der Buchstabenbilder
- +
  • ef/ki/nn.1776762054.txt.gz
  • Zuletzt geändert: 2026/04/21 11:00
  • von andristn