Dies ist eine alte Version des Dokuments!
Nikolai, Adam
Neuronale Netzwerke
Einleitung
Viele kennen neuronale Netzwerke als Diagramme mit Punkten, die in Spalten angeordnet sind und durch Linien miteinander verbunden werden. Auf den ersten Blick wirkt das ziemlich technisch, aber die Grundidee dahinter ist eigentlich leicht zu verstehen. Ein neuronales Netzwerk versucht, Muster in Daten zu erkennen, so wie wir Menschen Dinge wiedererkennen, wenn wir sie oft genug gesehen haben.
In unserem Beispiel besteht das Netzwerk aus drei Schichten. Die erste Schicht hat 784 Eingabewerte. Das sind die einzelnen Pixel eines 28×28 Pixel grossen Bildes, auf dem ein Buchstabe zu sehen ist. Diese Informationen gelangen dann in die mittlere Schicht mit 128 Neuronen. Dort versucht das Netzwerk, wichtige Merkmale zu finden wie Linien, Rundungen oder Ecken. Danach geht alles weiter zur Ausgabeschicht mit 52 Neuronen. Jedes dieser Neuronen steht für einen Buchstaben des Alphabets, jeweils in Gross- und Kleinbuchstaben. Am Ende entscheidet das Netzwerk, welcher Buchstabe am besten zum eingegebenen Bild passt.
So zeigt das Diagramm sehr anschaulich, wie ein neuronales Netzwerk Informationen verarbeitet und Schritt für Schritt immer näher an die richtige Antwort kommt.
Vom Pixel zum Input
Wenn du dir die Grafik anschaust, siehst du auf der linken Seite die lila Kreise. Jeder dieser Kreise ist ein einzelnes Neuron, und zusammen bilden sie die Input Layer. Was steckt da drin? Ganz einfach: jeder Pixelwert des Buchstabenbildes, umgerechnet auf einen Wert zwischen 0 und 1.
inputVector = 1.0 - arr.flatten() / 255.0
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_1, x_2, \ldots, x_{784}</m>.
Gewichte und gewichtete Summe
Schau jetzt auf die Linien zwischen den lila und den grünen Kreisen. Jede einzelne Linie ist ein Gewicht. Sie verbindet jeden Input-Neuron mit jedem Hidden-Neuron, und jede Verbindung hat einen eigenen Wert, der bestimmt, wie stark dieser Input Einfluss hat. Im Code stecken alle diese Gewichte zusammen in einer Matrix:
self.W1 = np.random.randn(inputSize, hiddenSize) * 0.01
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:
<m>z = (x_1 \cdot w_1) + (x_2 \cdot w_2) + \ldots + (x_{784} \cdot w_{784}) + b</m>
Oder kompakter geschrieben als Summe:
<m>z = \sum_{i=1}^{784} x_i \cdot w_i + b</m>
Und im Code passiert das für alle 128 Neuronen auf einmal, dank der Matrix-Multiplikation:
self.z1 = X @ self.W1 + self.b1
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.
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:
self.a1 = self.relu(self.z1)
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>:
self.z2 = self.a1 @ self.W2 + self.b2
Nur der letzte Schritt ist anders. Statt ReLU kommt jetzt Softmax, die die Rohwerte in Wahrscheinlichkeiten umwandelt. Am Ende gibt jeder der 52 orangen Neuronen eine Wahrscheinlichkeit aus, und der Buchstabe mit dem höchsten Wert ist die Vorhersage des Netzes.
ReLU und Softmax im Detail
Wenn du dir nochmal die Grafik anschaust, steht unter den grünen Kreisen „ReLU Aktivierung“ und unter den orangen „Softmax“. Das sind die zwei Aktivierungsfunktionen im Netz, und sie machen eigentlich sehr unterschiedliche Dinge.
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:
def relu(z): return np.maximum(0, z)
Mathematisch sieht das so aus:
<m>f(z) = \max(0, z) = \left\{ \begin{matrix} z & \mbox{wenn } z > 0
0 & \mbox{sonst} \end{matrix} \right.</m>
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.
Softmax
Bei der Output Layer ist ReLU aber nicht mehr geeignet. Dort brauchen wir keine stummen Neuronen, wir brauchen Wahrscheinlichkeiten. Genau das macht Softmax. Sie nimmt alle 52 Rohwerte der Output-Neuronen auf einmal und rechnet sie so um, dass sie zusammen 1.0 ergeben:
def softmax(z): e = np.exp(z - np.max(z, axis=1, keepdims=True)) return e / e.sum(axis=1, keepdims=True)
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>
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:
labels[np.argmax(probs)]
ReLU und Softmax haben also ganz verschiedene Rollen. ReLU filtert innerhalb des Netzes und schafft die Nichtlinearität. Softmax macht am Schluss aus rohen Zahlen eine lesbare Aussage, nämlich wie sicher das Netz ist, welchen Buchstaben es gerade sieht.
Perzeptron und Feedforward-Netz
Ein Perzeptron ist eigentlich der Vorläufer von allem, was wir bisher besprochen haben. Es ist das einfachste denkbare künstliche Neuron, erfunden in den 1950er Jahren von Frank Rosenblatt. Die Idee dahinter ist genau dieselbe wie bei unserem Neuron: Inputs kommen rein, werden mit Gewichten multipliziert, Bias wird addiert, und dann fällt eine Entscheidung. Der Unterschied ist, dass ein klassisches Perzeptron am Ende nur 0 oder 1 ausgeben kann, also entweder ja oder nein. Erkenne ich den Buchstaben oder nicht.
Mathematisch sieht ein Perzeptron so aus:
<m>y = \left\{ \begin{matrix} 1 & \mbox{wenn } \sum_{i} w_i x_i + b > 0
0 & \mbox{sonst} \end{matrix} \right.</m>
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.
Genau deshalb wurde das Feedforward-Netz entwickelt. Die Idee ist simpel: man nimmt nicht ein Perzeptron, sondern viele, stapelt sie in Schichten übereinander und verbindet sie. Das ist genau das, was du in der Grafik siehst. Die Informationen fliessen dabei immer nur in eine Richtung, von links nach rechts, von der Input Layer durch die Hidden Layer bis zur Output Layer. Kein Rückweg, kein Kreis, nur vorwärts. Daher der Name Feedforward.
Im Code ist dieser Vorwärtsdurchlauf die forward-Methode:
def forward(self, X): self.z1 = X @ self.W1 + self.b1 self.a1 = self.relu(self.z1) self.z2 = self.a1 @ self.W2 + self.b2 self.a2 = self.softmax(self.z2) return self.a2
Man sieht es schön: zuerst Input Layer zu Hidden Layer, dann Hidden Layer zu Output Layer. Schritt für Schritt nach vorne. Jede Schicht nimmt das Ergebnis der vorherigen, verarbeitet es weiter und gibt es an die nächste weiter.
Der entscheidende Unterschied zum einzelnen Perzeptron ist die Hidden Layer in der Mitte. Dort lernt das Netz nicht mehr nur eine einzige Entscheidung, sondern viele kleine Teilmuster gleichzeitig. Ein Neuron lernt vielleicht auf geschwungene Linien zu reagieren, ein anderes auf senkrechte Striche, wieder ein anderes auf geschlossene Formen. Zusammen können diese 128 Neuronen dann auch komplexe Buchstaben wie G oder R auseinanderhalten, was ein einzelnes Perzeptron niemals könnte.
Ein einfaches Beispiel: das AND-Gatter
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) |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
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>
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>
- <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>
- <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>
- <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>
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.
Gewichtete Summe, Schwellenwert und Entscheidungsgrenze
Die gewichtete Summe ist der erste Schritt, den jedes Neuron macht. Es nimmt alle seine Inputs, multipliziert jeden mit seinem zugehörigen Gewicht und addiert alles zusammen. Das Gewicht entscheidet dabei, wie wichtig ein Input ist. Ein Pixel, der für die Erkennung eines bestimmten Buchstabens sehr relevant ist, bekommt ein hohes Gewicht, ein unwichtiger Pixel ein niedriges. Im Code landet das alles in dieser einen Zeile:
self.z1 = X @ self.W1 + self.b1
Das Ergebnis <m>z</m> 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:
self.a1 = self.relu(self.z1)
Der Schwellenwert ist also nicht irgendeine komplizierte Einstellung, sondern schlicht die Grenze zwischen feuern und nicht feuern.
Und genau da kommen wir zur Entscheidungsgrenze. Das ist das, was das ganze Netz letztendlich lernt. Durch das Training mit vielen Buchstabenbildern passen sich die Gewichte so an, dass das Netz den Raum aller möglichen Inputs aufteilt. Auf der einen Seite der Grenze liegt zum Beispiel ein „a“, auf der anderen ein „o“. Diese Grenze ist nicht gerade wie eine Linie auf einem Blatt Papier, sie ist hochdimensional und sehr komplex. Genau deshalb braucht man ReLU, denn ohne Aktivierungsfunktion könnte das Netz nur gerade Linien als Entscheidungsgrenze lernen, was für Buchstaben bei weitem nicht ausreicht. Mit ReLU kann es gebogene, verschachtelte und viel feinere Grenzen ziehen und dadurch auch ähnliche Buchstaben wie „c“ und „e“ oder „i“ und „l“ sauber voneinander trennen.
Backpropagation
Fangen wir ganz klein an, mit einem einzigen Neuron. Stell dir vor, das Netz sagt „b“, aber die richtige Antwort wäre „a“. Das Netz hat also einen Fehler gemacht. Backpropagation ist nichts anderes als die Frage: welches Gewicht war schuld daran, und wie stark?
Schritt 1: Fehler messen
Der erste Schritt ist, den Fehler zu messen. Das macht die Loss Function, in unserem Fall Cross Entropy Loss:
def crossEntropyLoss(probs, yOnehot): return -np.mean(np.sum(yOnehot * np.log(np.clip(probs, 1e-12, 1.0)), axis=1))
Mathematisch gesehen berechnet sie, wie weit die vorhergesagte Wahrscheinlichkeit vom richtigen Wert entfernt ist:
<m>L = -\sum_{i} y_i \cdot \log(\hat{y}_i)</m>
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.
Schritt 2: Gradient und 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:
<m>\delta = \hat{y} - y</m>
Das Gewicht <m>w</m> hat diesen Fehler verursacht, proportional dazu, wie gross der Input <m>x</m> war. Also ist der Gradient:
<m>\frac{\partial L}{\partial w} = \delta \cdot x</m>
Und das Gewicht wird dann in die entgegengesetzte Richtung angepasst:
<m>w_{neu} = w_{alt} - \eta \cdot \frac{\partial L}{\partial w}</m>
Dabei ist <m>\eta</m> die Lernrate, also wie gross jeder Schritt bergab ist. Im Code ist das:
self.lr = learningRate
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
Soweit so gut für einen einzelnen Neuron. Aber jetzt kommt die eigentliche Herausforderung.
In unserem Netz hat kein Gewicht in der Hidden Layer einen direkten Kontakt zum Fehler am Ausgang. Die Hidden Layer sieht den Fehler nicht direkt, sie hat ihn nur indirekt mitverursacht. Backpropagation löst genau dieses Problem, indem es den Fehler rückwärts durch das Netz schickt, Schicht für Schicht.
Zuerst wird der Fehler an der Output Layer berechnet. Das ist noch einfach: Vorhersage minus richtige Antwort:
d2 = self.a2 - yOnehot
Mathematisch:
<m>\delta_2 = \hat{y} - y</m>
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:
<m>\delta_1 = (\delta_2 \cdot W_2^T) \odot \mbox{ReLU}'(z_1)</m>
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:
d1 = (d2 @ self.W2.T) * self.reluDerivative(self.z1)
Jetzt kennt jede Schicht ihren Fehleranteil. Damit können alle Gewichte und Biases aktualisiert werden:
self.W2 -= self.lr * (self.a1.T @ d2) / N self.b2 -= self.lr * d2.mean(axis=0) self.W1 -= self.lr * (X.T @ d1) / N self.b1 -= self.lr * d1.mean(axis=0)
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>
<m>W_1 = W_1 - \eta \cdot \frac{X^T \cdot \delta_1}{N}</m>
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.
Dieser ganze Prozess – Forward Pass, Loss berechnen, Fehler zurückpropagieren, Gewichte anpassen – wiederholt sich dann für jeden Batch und jede Epoche:
for epoch in range(epochs): for start in range(0, N, batchSize): probs = self.forward(Xs[start:end]) epochLoss += self.crossEntropyLoss(probs, Ys[start:end]) self.backward(Xs[start:end], Ys[start:end])
Nach hunderten von Epochen haben sich die Gewichte so weit angepasst, dass das Netz die meisten Buchstaben richtig erkennt. Backpropagation ist also im Grunde nur eine sehr clevere Art, die Schuld für einen Fehler auf alle Beteiligten aufzuteilen und jeden ein kleines Stück besser zu machen.
Die drei Schichten im Überblick
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>.
Hidden Layer
Die Hidden Layer ist dort, wo das eigentliche Lernen passiert. Sie liegt in der Mitte, zwischen Input und Output, und ist von aussen nicht direkt sichtbar. Daher der Name. Ihre 128 Neuronen nehmen alle 784 Eingabewerte, berechnen daraus ihre gewichteten Summen und entscheiden via ReLU, ob sie feuern oder nicht. Mit der Zeit lernt jedes dieser Neuronen, auf bestimmte Muster zu reagieren: geschwungene Linien, senkrechte Striche, geschlossene Formen. In der Grafik sind das die grünen Kreise in der Mitte. Im Code wird die Grösse dieser Schicht so festgelegt:
self.W1 = np.random.randn(inputSize, hiddenSize) * 0.01
Output Layer
Die Output Layer ist die letzte Schicht und gibt die finale Antwort des Netzes. Sie hat genau 52 Neuronen, eines pro Buchstabe von a bis Z. Jedes dieser Neuronen gibt eine Wahrscheinlichkeit aus, wie sicher das Netz ist, dass der gesehene Buchstabe dieser Klasse entspricht. Der Buchstabe mit der höchsten Wahrscheinlichkeit ist dann die Vorhersage. In der Grafik sind das die orangen Kreise ganz rechts. Im Code:
self.W2 = np.random.randn(hiddenSize, outputSize) * 0.01
Flache und tiefe Netze
Ein tiefes neuronales Netz, auf Englisch Deep Neural Network, ist im Grunde nichts anderes als ein Netz mit mehreren Hidden Layers hintereinander. Statt einer einzigen mittleren Schicht wie in unserem Code hat ein tiefes Netz vielleicht fünf, zehn oder sogar hunderte davon. Jede Schicht lernt dabei etwas ein bisschen Abstrakteres als die vorherige. Die erste Hidden Layer erkennt vielleicht einfache Kanten und Striche, die zweite kombiniert diese zu Kurven und Ecken, die dritte erkennt daraus ganze Buchstabenteile und so weiter. Je tiefer das Netz, desto komplexere Konzepte kann es verstehen.
Genau da liegt der Unterschied zu einem flachen Netz. Ein flaches Netz hat nur eine oder sehr wenige Hidden Layers, so wie unseres mit genau einer. Es kann durchaus funktionieren, und für unsere Aufgabe der Buchstabenerkennung reicht es gut aus. Aber es hat eine natürliche Grenze. Mit nur einer Hidden Layer muss das Netz alle Muster auf einmal lernen, ohne sie in kleinere Teilprobleme aufzuteilen. Das wird schnell schwierig, wenn die Aufgabe komplexer wird.
Ein tiefes Netz löst das, indem es die Arbeit auf viele Schichten verteilt. Jede Schicht baut auf der vorherigen auf und abstrahiert weiter. Das ist auch der Grund, warum moderne KI-Modelle für Bilderkennung, Sprachverarbeitung oder Übersetzungen so gut funktionieren: sie sind extrem tief. GPT, das Modell hinter vielen Chatbots, hat zum Beispiel nicht 128 Neuronen in einer Schicht, sondern Milliarden von Parametern verteilt über viele Schichten.
Der Nachteil dabei ist, dass tiefe Netze viel mehr Daten, viel mehr Rechenleistung und viel mehr Zeit zum Trainieren brauchen. Unser flaches Netz mit 784 Inputs, 128 Hidden-Neuronen und 52 Outputs hat knapp 102'000 Parameter. Ein modernes Deep-Learning-Modell hat davon Milliarden. Für eine einfache Aufgabe wie unsere wäre das völlig übertrieben, weshalb ein flaches Netz hier die richtige Wahl ist.
Zusammenfassung der wichtigsten Begriffe
- künstliches Neuron – Grundbaustein, berechnet gewichtete Summe und wendet Aktivierungsfunktion an
- Input – rohe Eingabewerte, bei uns 784 Pixelwerte zwischen 0 und 1
- Gewicht – bestimmt, wie stark ein Input Einfluss hat
- Bias – verschiebt die Aktivierungsschwelle unabhängig vom Input
- Aktivierungsfunktion – entscheidet, ob und wie stark ein Neuron feuert (ReLU, Softmax)
- Perzeptron – einfachstes künstliches Neuron, gibt nur 0 oder 1 aus
- 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
- Schwellenwert – Grenze zwischen feuern und nicht feuern (bei ReLU: 0)
- Entscheidungsgrenze – hochdimensionale Trennfläche, die das Netz zwischen Klassen lernt
- Backpropagation – Verfahren, das den Fehler rückwärts durchs Netz schickt und Gewichte anpasst
- Input Layer – erste Schicht, nimmt die rohen Inputs entgegen
- Hidden Layer – mittlere Schicht, lernt Teilmuster
- Output Layer – letzte Schicht, gibt die Vorhersage als Wahrscheinlichkeiten aus
- Tiefe neuronale Netze (Deep Neural Networks) – Netze mit vielen Hidden Layers
- flache vs. tiefe Netze – eine vs. viele Hidden Layers, Komplexität und Rechenaufwand steigen
- künstliches Neuron
- Input
- Gewicht
- Bias
- Aktivierungsfunktion
- Perzeptron
- Feedforward-Netz
- gewichtete Summe
- Schwellenwert
- Entscheidungsgrenze
- Backpropagation
- Input Layer
- Hidden Layer
- Output Layer
- Tiefe neuronale Netze (Deep Neural Networks)
- flache vs. tiefe Netze
Evtl. ein ganz simples Beispiel zeigen und durchgehen (AND).