Das XOR-Problem und Bias-Neuronen: Eine detaillierte Analyse

Neuronale Netze haben sich als leistungsstarke Werkzeuge für Klassifikationsprobleme etabliert. Dieser Artikel beleuchtet die grundlegenden Konzepte neuronaler Netze, insbesondere im Kontext des XOR-Problems (exklusives Oder) und der Rolle von Bias-Neuronen. Wir werden uns mit der Funktionsweise von Perzeptronen, Lernalgorithmen und den Grenzen einzelner Neuronen befassen und aufzeigen, wie mehrschichtige Netzwerke diese Einschränkungen überwinden können.

Einführung in Neuronale Netze und Klassifikation

Nachdem wir gesehen haben, wie wir mit Regression einen Wert vorhersagen können, kommen wir jetzt zur Frage, wie man eine Klasse, Kategorie oder Label vorhersagt. Genauer gesagt: Wir suchen zu einem Feature-Vektor die dazugehörige Klasse oder Kategorie. Formal haben einen Datensatz von (N) gelabelten Beispielen ((x^{k}, y^{k})) mit (k = 1, \ldots, N). Das (x^k \in \mathbb{R}^n) ist ein (n)-dimensionaler Feature-Vektor. Im Fall der binären Klassifikation ist der Ausgabewert (y \in {0, 1}) ein binärer Wert, z.B. Klassfikation von Bildern: der Feature-Vektor (x) enthält alle Pixelwerte eines Bildes in Form eines Arrays und Kategorie (y) gibt z.B. Man nehme etwa 2000 ausgewählte, alphabetisch sortierte Wörter, die also einen eindeutigen Wortindex haben. Kategorie (y) gibt z.B.

Künstliche Neuronale Netze sind inspiriert von biologischen Gehirnen, z.B. das des Menschen oder das der Katze. Die wichtigsten Bestandteile eines biologischen Gehirns sind die Gehirnzellen, auch Neuronen genannt, und die Verbindungen zwischen den Neuronen. Das menschliche Gehirn besteht aus etwa 86 Milliarden Neuronen und ca. (10^{14}) (100 Trillionen) Verbindungen, also Synapsen. Die Neuronen sind die atomaren Einheiten des Gehirns. Neuronen empfangen elektrische Signale über Dendriten und laden sich gewissermaßen auf, man spricht vom Aktionspotential oder Erregung. Erst wenn ein bestimmter Schwellwert erreicht ist, “feuert” das Neuron über das Axon ein Signal nach außen. Die Erregung eines Neurons wird über sein Axon weitergegeben und über Synapsen auf die Dendriten anderer Neuronen weitergegeben (Abb. 3.1). Eine Synapse bezeichnet eine Stelle mit einer physikalischen Lücke, die durch Neurotransmitter - das sind chemische Botenstoffe - überbrückt werden. Neurotransmitter können das Signal verstärken (exzitatorisch) oder hemmen (inhibitorisch). Das ist natürlich eine stark vereinfachte Darstellung der Funktionsweise biologischer Neuronen. Zu den am besten erforschten Regionen im Gehirn gehört der visuelle Cortex, auf den wir im Kapitel über Konvolutionsnetze noch sprechen werden. Ein besonders interessantes ungeklärtes Phänomen im Gehirn ist die Frage, wie verschiedene Hirnareale sich untereinander koordinieren. Eine Hypothese ist, dass die Frequenz des implusartigen Feuerns der Neuronen damit zusammenhängt. Hier sei der kurze Wikipedia-Artikel zur Functional integration empfohlen.

Das McCulloch-Pitts-Neuron und das Perzeptron

Bereits 1943 schlugen Warren McCulloch und Walter Pitts ein informationstechnisches Modell des biologischen Neurons vor: das McCulloch-Pitts-Neuron (McCulloch and Pitts 1943). Das Modell verarbeitete eingehende Signale durch Aufsummieren und kontrollierte die Weiterleitung durch einen Schwellwert. Es wurde gezeigt, dass die grundlegenden booleschen Operatoren (AND, OR, NOT) realisiert werden können.

Das Perzeptron (engl. perceptron) hatte bereits ein verfeinertes Modell und vor allem einen Lernalgorithmus (allerdings nur für ein Perzeptron mit einer Schicht). Es wurde 1958 von Frank Rosenblatt in einer Publikation der Öffentlichkeit vorgestellt (Rosenblatt 1958). Er hatte es bereits 1957 in einem technischen Bericht beschrieben (Rosenblatt 1957). 1969 gewann das Perzeptron größere Bekanntheit durch eine Buchpublikation der KI-Pioniere Marvin Minsky und Seymour Papert (1969; 2017). Durch das Buch wurden auch die Grenzen des Perzeptrons (sogenanntes XOR-Problem) bekannt. Das Adaline (ADAptive Linear NEuron) wurde 1960 von Bernard Widrow eingeführt (Widrow 1960).

Lesen Sie auch: Wie Confirmation Bias unser Denken beeinflusst

Auch wenn künstliche NN von biologischen Neuronen inspiriert sind, ist es doch wichtig festzuhalten, dass die Funktionsweise eines künstlichen NN wenig Rückschlüsse auf das menschliche Denken oder auf die Funktionsweise des menschlichen Hirns zulässt. In einem natürlichen Neuron spielen viele Faktoren (biologische, chemische, physikalische) eine Rolle, die in einem künstlichen Neuronalen Netz nicht modelliert sind. Das Lernverfahren “Backpropagation”, mit dem künstliche NN trainiert werden, hat wenig mit biologischen Vorgängen zu tun. Mit der Frage, inwiefern menschliches Denken mit Hilfe von informationstechnischen Modellen erforscht werden kann, beschäftigt sich die Kognitionswissenschaft.

Das Perzeptron ist nach dem McCulloch-Pitts-Neuron der erste Versuch, einen lernendes Netzwerk nach dem Vorbild biologischer Neuronen zu erstellen. Es wurde von Frank Rosenblatt entwickelt und 1958 der Öffentlichkeit vorgestellt. Stark verwandt mit dem Perzeptron ist das ADALINE-Netz von Widrow (1960). Die Inhalte dieses Kapitels sind eine Kombination beider Verfahren.

Architektur und Funktionsweise des Perzeptrons

Das Perzeptron ist ein Netzwerk aus Neuronen und gerichteten Verbindungen. Die Neuronen sind in Schichten (engl. layers) organisiert, der Eingabeschicht und der Ausgabeschicht. Die Verbindungen laufen von Eingabeschicht zu Ausgabeschicht. Ein solches Netz ist somit ein gerichteter azyklischer Graph (engl. directed acyclic graph, DAG). Die Ausgabeschicht besteht aus einem einzigen Neuron. Das Netz kann zur binären Klassifikation verwendet werden, d.h. für einen Input (x) (wir nennen dies auch Featurevektor, z.B. die Pixel eines Bildes) kann das Netz entscheiden, ob dieser Input zu einer bestimmten Kategorie gehört (Katzenbild) oder nicht (kein Katzenbild). Wir haben gerade von “Schichten” gesprochen. Es zeigt sich, dass es sinnvoll ist, eine Schicht so zu definieren, dass eine Schicht mehrere Parameter/Gewichte enthält. In diesem Sinne hat das Perzeptron nur eine Schicht.

Der Input durch die Eingabeneuronen wird repräsentiert durch einen Vektor (x = (x1, \ldots, xn)) der Länge (n), wobei jedes einzelne Feature (xi \in \mathbb{R}). Auch wenn wir im Text Vektoren oft als Zeilenvektor schreiben, ist in Berechnungen immer ein Spaltenvektor gemeint, d.h. Die Parameter des Perzeptrons nennen wir Gewichte (engl. weights). Sie sind ein Vektor (w), wobei (wi \in \mathbb{R}).

Wenn wir an den Eingabeneuronen Werte in Form des Vektors (x) anlegen, wie wird der Output (y) berechnet? In einem ersten Schritt berechnen wir für einen gegebenen Featurevektor (x) die Roheingabe (z) (engl. net input) des Ausgabeneurons (siehe Abb. oben).

Lesen Sie auch: Ursachen, Symptome und Behandlungen von Motoneuron-Erkrankungen

Vektor (w^T) ist dabei der transponierte Vektor von (w) und daher ein Zeilenvektor. Im zweiten Schritt berechnen wir die Aktivierung (y) des Ausgabeneurons. wobei (\theta) (griech. Buchstabe Theta) auch der Schwellwert (engl. threshold) genannt wird.

Lernen im Perzeptron: Gradientenabstieg

Lernen bedeutet, dass die Gewichte (w) mit Hilfe von Trainingsdaten schrittweise angepasst werden, so dass unser Netzwerk sich der gewünschten idealen Funktion (h^*) annähert. Trainingsdaten sind z.B. eine Reihe von Bildern mit Labeln (z.B. Katze und Nicht-Katze). Wir gehen von (N) Traningsdaten aus und verwenden (k \in {1,\ldots , N}) als Index für ein Trainingsbeispiel. Bei (y^k) handelt es sich um den korrekten Output des Trainingsbeispiels. Lernen bedeutet, dass wir für jedes Trainingsbeispiel (k) den Output (\hat{y}^k) berechnen und die Gewichte so anpassen, dass der Fehler, also die Differenz zwischen berechnetem und korrekten Output, kleiner wird. Dazu addieren wir auf jedes Gewicht ein “Delta”.

Unsere Herleitung folgt der Idee des Gradientenabstieg und dieses Verfahren bedeutet etwas ganz Einfaches: Wenn wir einen Parameter (w) haben und diesen leicht vergrößern, wird dann der Fehler kleiner oder größer? Sie erinnern sich: Das originale Perzeptron hat hier die Heaviside-Funktion. Der entscheidende Unterschied ist, dass die Identitäts-Funktion differenzierbar ist, d.h. man kann eine Ableitung bilden. Man beachte, dass die berechnete Ausgabe (\hat{y} = g(z) = z) jetzt eine Dezimalzahl (\in \mathbb{R}) ist, da wir den Rohinput einfach “durchschleifen”.

Dazu müssen wir die Abweichung zwischen den berechneten Ouputs und den korrekten Outputs berechnen. Dies tut man über eine Zielfunktion (J). Wir folgen hier der Literatur, wo die Fehlerfunktion sehr oft mit dem Buchstaben (J) repräsentiert wird. Das hängt vermutlich mit dem Konzept der Jacobi-Matrix zusammen. Die Jacobi-Matrix einer Funktion (f) enthält alle partiellen Ableitungen von (f). Für unser (J) wählen wir den Mittelwert der Fehlerquadrate (engl. mean of squared errors oder MSE). Vergegenwärtigen Sie sich, dass dieser Fehler in der Hauptsache davon abhängt, in welcher “Konfiguration” sich das Netz befindet, also wie die Gewichte (w) eingestellt ist. Wir sind daran interessiert, die Gewichte so einzustellen, dass der Gesamtfehler (J) möglichst klein wird. Diese Abhängigkeit von (w) zu (J) spannt eine Fehlerlandschaft auf. Bei dem Beispiel in Abbildung 3.2 kann man sich zwei beliebige Gewichte (z.B. (w0) und (w1)) als 2-dimensionale Ebene vorstellen, wohingegen der Fehlerwert (J) nach oben zeigt.

Jetzt kommt der Gradientenabstieg zum Zug. Wir wollen die Gewichte so anpassen, dass der Fehler sich verringert. Dazu gehen wir in Richtung des negativen Gradienten, denn der Gradient gibt uns den größten Anstieg. Aufgrund der obigen Ausführungen können wir das Delta definieren als den negativen Gradienten des Fehlers (J) definieren. Denken Sie immer daran, dass sich die Gewichte (w) im Verlauf des Trainings ändern. Das (w) in dem Ausdruck (-\alpha \nabla J(w)) soll deutlich machen, dass wir in die Ableitungen immer konkrete Werte im Form des Gewichtsvektors (w) einsetzen. Die Gewichte sind sozusagen die “aktuelle Konfiguration” des Netzwerks (in der Abbildung oben ist das ein Punkt in der Ebene, die von (w0) und (w1) aufgespannt wird).

Lesen Sie auch: Fliegen und Drohnen im Fokus

Die Lernrate (\alpha) wird zwischen 0 und 1 gewählt und bestimmt, wie schnell das Lernen stattfindet. Eine zu hohe Lernrate kann dazu führen, dass das Optimum immer wieder “übersprungen” wird, so dass das Lernen doch wieder langsamer wird oder sogar nie das Optimum erreicht. Eine zu niedrige Lernrate kann zu sehr langsamen Lernprozessen führen. Als Daumenregel sollte man mit niedrigen Lernraten beginnen und diese dann schrittweise erhöhen.

Wie man an dem Summenzeichen sieht, wird ein Update erst nach Abarbeiten aller Trainingsdaten durchgeführt. Wir können uns unabhängig von der Herleitung überlegen, ob die obige Rechnung plausibel ist. Nehmen wir einmal an, es gäbe nur ein Traningsbeispiel, d.h. Wenn die berechnete Ausgabe (\hat{y}) größer ist als die korrekte Ausgabe (y), dann wird die Änderung negativ, also wird das Gewicht abgeschwächt. Wie stark sich das Gewicht verkleinert, hängt von der Differenz von korrekter und berechneter Ausgabe ab und, genauso wichtig, vom Wert (x). Das (x) zeigt nämlich an, wie relevant diese Verbindung für die Ausgabe war (im Extremfall war (x) gleich Null, dann lohnt sich eine Änderung nicht). Wenn die berechnete Ausgabe (\hat{y}) kleiner ist als die korrekte Ausgabe (y), dann wird die Änderung positiv, d.h. das Gewicht wird gestärkt. Dies wird wie im obigen Fall moduliert durch Differenz und Stärke von (x). Angesichts unserer Herleitung formulieren wir einen Lernalgorithmus. Man beachte, dass wir das (\Delta w_i) innerhalb einer Epoche als Speicher benutzen, um alle Deltas für alle Trainingsdaten “einzusammeln” (zu aggregieren).

Algorithmus für das Perzeptron-Lernen

Setze alle Gewichte (w = (w0, \ldots, wn)), z.B. Wie viele Epochen zum Training genutzt werden, ist dem Anwender überlassen. In der Regel wählt man eine Epochenzahl, z.B. Der hier berechnete Fehler gilt zu Beginn der jeweiligen Epoche (als vor dem Gewichtsupdate), da man diesen bei der Berechnung der Deltas quasi “geschenkt” bekommt, denn bei beiden Rechnungen benötigt man ((y^k - \hat{y}^k)).

Das XOR-Problem: Eine Herausforderung für das Perzeptron

Das Perzeptron kann grundlegende logische Operationen nachbilden. Ähnlich wie mit dem AND verhält es sich mit dem OR. Im Vergleich zum AND-Perzeptron kann man z.B. Wenn Sie probieren, das XOR mit diesem Netz zu lösen, werden Sie feststellen, dass es nicht geht. Man benötigt für das XOR eine weitere Schicht. Probieren Sie doch mal, ein solches Netz zu entwerfen.

Das Perzeptron kann als logisches Gatter gedacht werden, mit dem logische Verknüpfungen wie UND und ODER realisiert werden können. Beim Training des Perzeptrons werden die Testeingabedaten an die Eingabeneuronen angelegt. Entspricht die Ausgabe dem erwarteten Ergebnis, so bleiben die Gewichte und der Bias unverändert. Bei einem abweichenden Ergebnis werden die Gewichte nach oben bzw. nach unten korrigiert, d.h. Hierbei sind die Testdaten und eine Lernrate. Tatsächlich ist es mit NumPy wieder sehr einfach, das Perzeptron zu implementieren. Wir formulieren einfach den Lernschritt auf den Gewichten. Gewichte= [0.01 0. Wie man sieht, gibt es bei der XODER-Verknüpfung kein zufriedenstellendes Ergebnis. Eine Analyse zeigt, dass das Perzeptron dieses Aufgabe grundsätzlich nicht lösen kann. Sind etwa bei der UND- und ODER-Verknüpfung die Eingabedaten in der Ebene durch eine Gerade trennbar, so ist dies bei der XODER-Verknüpfung nicht der Fall.

Tatsächlich taucht mit dem Verschwinden des einen Problems - der eingeschränkten Leistungsfähigkeit einfacher Algo­rithmen - ein anderes Problem am Horizont auf: das Problem der Überanpassung (Overfitting).Dabei geht es um die Frage, wie man zu einem Modell kommt, das seine Leistungsfähigkeit nicht nur dazu nutzt, eine durch die Trainingsdaten gestellte Aufgabe zu lösen, sondern dazu, eine Aufgabe so zu lösen, dass sich damit auch andere, bisher ungesehene Daten an­gemessen bearbeiten lassen. Das ist das Problem der Generalisierung, und es ist im Deep Learning ein gravierendes Problem, weil komplexe Algorithmen eben alle Möglichkeiten haben, sich mit komplizierten Funktionen an die Eigenarten der Trainingsdaten anzupassen.

Die Rolle von Bias-Neuronen

Der Schwellwert (\theta) ist etwas umständlich für weitere Berechnungen. Wir erweitern jetzt einfach die Vektoren (x) und (w) um jeweils eine Stelle mit Index (0).

In diesem Beispiel dienen drei Eingabeneuronen dazu, die Merkmale oder Attribute der Eingabedaten aufzunehmen; z. B. eine einfache logische Verknüpfung wie ein XOR. Der Bias ist ein zusätzliches Neuron, das stets den Wert 1 hat. Er ermöglicht es dem Netzwerk, die Aktivierungsfunktion nach oben oder unten zu verschieben, was die Flexibilität beim Lernen erhöht.

Überwindung des XOR-Problems mit Mehrschichtigen Perzeptronen

Die Delta-Lernregel lässt sich zwar auch auf mehrlagige Perzeptronen verallgemeinern, allerdings liefert sie auch dann lediglich im Falle separierbarer Eingangsdaten brauchbare Ergebnisse. Beim Perzeptron können sich die Ausgangsdaten wegen der nicht-stetigen Treppenfunktion sprunghaft mit den Eingangsdaten ändern. Deshalb können kleine Änderungen in den Eingangdaten große und sprunghafte Änderungen in den Ausgangsdaten zur Folge haben.

Mehrschichtige neuronale Netzwerke besitzen nicht nur mehr Flexibilität als ein einzelnes Perzeptron - sie verfügen auch über eine bemerkenswerte mathematische Eigenschaft. Das bedeutet, dass Neuronale Netzwerke dieser Bauart prinzipiell in der Lage sind, jede stetige Abbildung nachzuformen. Ohne Aktivierungsfunktionen könnten mehrere Schichten nur eine verschachtelte lineare Abbildung darstellen. Das Universal Approximation Theorem sagt nichts über die Effizienz des Trainings oder die nötige Netzgröße aus.

Indem man mehrere künstliche Neuronen miteinander verbindet, entsteht ein Neuronales Netzwerk. Die Ausgaben einiger Neuronen dienen dabei als Eingaben für andere. Mehrschichtige neuronale Netzwerke besitzen nicht nur mehr Flexibilität als ein einzelnes Perzeptron - sie verfügen auch über eine bemerkenswerte mathematische Eigenschaft. Das bedeutet, dass Neuronale Netzwerke dieser Bauart prinzipiell in der Lage sind, jede stetige Abbildung nachzuformen. Ohne Aktivierungsfunktionen könnten mehrere Schichten nur eine verschachtelte lineare Abbildung darstellen. Das Universal Approximation Theorem sagt nichts über die Effizienz des Trainings oder die nötige Netzgröße aus. Damit ein neuronales Netzwerk nützliche Entscheidungen trifft, müssen die Gewichte und der Bias jedes Neurons geeignet gewählt werden. Dieser Prozess wird viele Male wiederholt, bis das Netzwerk die Aufgabe gut beherrscht.

In den 1950er-Jahren entwickelte Frank Rosenblatt das Perzeptron und weckte damit große Hoffnungen. Zeitungen berichteten begeistert, seine lernfähige Maschine könne eines Tages „denken wie ein Gehirn“. Diese Erkenntnis traf die junge KI-Forschung hart. Viele sahen darin eine grundsätzliche Grenze künstlicher Neuronen, und die Finanzierung brach ein - man spricht heute vom ersten „AI Winter“. Ironischerweise stellte sich später heraus, dass Minsky und Papert nur die Grenzen einer einzigen Schicht beschrieben hatten. Mehrschichtige Netzwerke können XOR sehr wohl lösen.

Implementierung in Python am Beispiel des Iris-Datensatzes

Wir implementieren das Perzeptron in Python, um die Funktionsweise besser zu verstehen. Im Iris-Datensatz geht es darum, eine Blume aufgrund der Abmessungen ihrer Blüte zu klassifizieren. Es gibt drei Blumen-Klassen, die es vorherzusagen gilt: iris setosa, iris virginica und iris versicolor. Es gibt vier Blüten-Abmessungen als Eingabe-Features für den Input: sepal length, sepal width, petal length und petal width (“sepal” ist das Kelchblatt und “petal” das Kronblatt, siehe Wikipedia). Der für den Einstieg sehr beliebte, sehr kleine Iris-Datensatz stammt aus dem Jahr 1936. Bei diesem Datensatz geht es um Blumen, genauer gesagt um die Gattung der “Schwertlilien”, deren lateinischer Name Iris lautet. Der Datensatz besteht nur aus 150 Trainingsbeispielen. In der Sammlung sind 150 Dateneinträge, jeweils 50 pro Klasse. [4.9, 3. Diese Zahlen bilden den Index für den Array von Klassennamen. array([5.1, 4.9, 4.7, 4.6, 5. , 5.4, 4.6, 5. 4.3, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 4.6, 5.1, 4.8, 5. 5. , 5.2, 5.2, 4.7, 4.8, 5.4, 5.2, 5.5, 4.9, 5. 5.1, 5. , 4.5, 4.4, 5. , 5.1, 4.8, 5.1, 4.6, 5.3, 5. array([[5.1, 4.9, 4.7, 4.6, 5. , 5.4, 4.6, 5. 4.3, 5.8, 5.7, 5.4, 5.1, 5.7, 5.1, 5.4, 5.1, 4.6, 5.1, 4.8, 5. 5. , 5…

tags: #bias #neuron #xor