Zurück zu den Herausforderungen
Schwierig 0 gelöst 0% Erfolgsquote

Ein neuronales Netz trainieren, das XOR löst

Alles zusammen: Trainiere ein 2-2-1-Sigmoid-Netz mit Backpropagation, bis es XOR lernt.

Das lernst du

  • Ein kleines Netz von Anfang bis Ende trainieren
  • Sehen, warum XOR eine verborgene Schicht braucht
  • Vorwärts- und Rückwärtsdurchlauf zusammenführen

Problem

XOR (exklusives Oder) ist das klassische Problem, das ein einzelnes Neuron nicht lösen kann, ein Netz mit einer verborgenen Schicht aber schon. Trainiere ein Netz mit 2 Eingaben, 2 verborgenen Neuronen und 1 Ausgabe, alle mit Sigmoid (σ(z) = 1 / (1 + e^(-z))), mit dem Verlust L = (y - target)².

Die Trainingsdaten, in jeder Epoche immer in dieser Reihenfolge verwendet:

Eingabetarget
[0, 0]0
[0, 1]1
[1, 0]1
[1, 1]0

Für jedes Beispiel:

  1. Vorwärts: a_j = σ(x₁ × hidden_weights[j][0] + x₂ × hidden_weights[j][1] + hidden_biases[j]), y = σ(a₁ × output_weights[0] + a₂ × output_weights[1] + output_bias)
  2. delta_out = 2 × (y - target) × y × (1 - y) und delta_j = delta_out × output_weights[j] × a_j × (1 - a_j), mit den Gewichten vor der Aktualisierung für dieses Beispiel
  3. Aktualisiere jeden Parameter mit der Lernrate lr: output_weights[j] -= lr × delta_out × a_j, output_bias -= lr × delta_out, hidden_weights[j][i] -= lr × delta_j × x_i, hidden_biases[j] -= lr × delta_j

Implementiere train_xor(hidden_weights, hidden_biases, output_weights, output_bias, learning_rate, epochs).

Ausgabe

Gib nach dem Training die Vorhersagen y des Netzes für die Eingaben [0, 0], [0, 1], [1, 0] und [1, 1] in dieser Reihenfolge zurück.

Einschränkungen

0 ≤ epochs ≤ 5.000

0 < learning_rate ≤ 5

-2 ≤ jedes Startgewicht und jeder Start-Bias ≤ 2

Beispiele

Beispiel 1
Eingabe:
epochs = 0
output_bias = 0.0
hidden_biases = [0.0, 0.3]
learning_rate = 1.5
hidden_weights = [
    [0.2, 0.8],
    [0.9, -0.7]
]
output_weights = [-0.6, 0.4]

Erwartete Ausgabe:
expected = [0.482451, 0.436972, 0.494378, 0.452729]
Eingabe:
long long epochs = 0;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0, 0.3};
double learning_rate = 1.5;
std::vector<std::vector<double>> hidden_weights = {
    {0.2, 0.8},
    {0.9, -0.7}
};
std::vector<double> output_weights = {-0.6, 0.4};

Erwartete Ausgabe:
std::vector<double> expected = {0.482451, 0.436972, 0.494378, 0.452729};
Eingabe:
long epochs = 0;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0, 0.3};
double learning_rate = 1.5;
double[][] hidden_weights = new double[][] {
    new double[] {0.2, 0.8},
    new double[] {0.9, -0.7}
};
double[] output_weights = new double[] {-0.6, 0.4};

Erwartete Ausgabe:
double[] expected = new double[] {0.482451, 0.436972, 0.494378, 0.452729};

Erläuterung

Bei 0 Epochen wird nichts trainiert, also ist das Ergebnis einfach der Vorwärtsdurchlauf mit den Startgewichten: etwa [0.482, 0.437, 0.494, 0.453]. Das untrainierte Netz gibt jeder Eingabe fast dieselbe Antwort.

Beispiel 2
Eingabe:
epochs = 2000
output_bias = 0.0
hidden_biases = [0.0, 0.3]
learning_rate = 1.5
hidden_weights = [
    [0.2, 0.8],
    [0.9, -0.7]
]
output_weights = [-0.6, 0.4]

Erwartete Ausgabe:
expected = [0.015727, 0.982119, 0.985515, 0.013682]
Eingabe:
long long epochs = 2000;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0, 0.3};
double learning_rate = 1.5;
std::vector<std::vector<double>> hidden_weights = {
    {0.2, 0.8},
    {0.9, -0.7}
};
std::vector<double> output_weights = {-0.6, 0.4};

Erwartete Ausgabe:
std::vector<double> expected = {0.015727, 0.982119, 0.985515, 0.013682};
Eingabe:
long epochs = 2000;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0, 0.3};
double learning_rate = 1.5;
double[][] hidden_weights = new double[][] {
    new double[] {0.2, 0.8},
    new double[] {0.9, -0.7}
};
double[] output_weights = new double[] {-0.6, 0.4};

Erwartete Ausgabe:
double[] expected = new double[] {0.015727, 0.982119, 0.985515, 0.013682};

Erläuterung

Nach 2.000 Epochen liegen die Vorhersagen bei etwa [0.016, 0.982, 0.986, 0.014]: niedrig für [0, 0] und [1, 1], hoch für [0, 1] und [1, 0]. Das Netz hat XOR gelernt.

So gehst du vor

Versuch es zuerst allein und öffne dann einen Hinweis nach dem anderen.

Hinweis 1

Verarbeite die vier XOR-Samples in jeder Epoche in derselben festen Reihenfolge und aktualisiere die Parameter sofort nach jedem einzelnen.

Hinweis 2

Nutze Vorwärtsdurchlauf und leite dann den Output-Fehler mit den aktuellen Gewichten auf beide Hidden-Neuronen zurück, bevor du updatest.

Hinweis 3

Achte auf die Sigmoid-Ableitung und darauf, dass die Hidden-Layer-Updates von den Inputwerten abhängen, sodass bei nullen Inputs manche Gewichte unverändert bleiben.

Erwartete Komplexität

Zeit O(epochs), zusätzlicher Speicher O(1)

Referenzen

Diese Aufgabe wurde für CodeUtility angepasst. Beachte die oben genannten Vorgaben und Einschränkungen.

Von anderen lernen

Community-Lösungen

Noch keine veröffentlichten Lösungen. Löse die Aufgabe und teile als Erster eine Lösung.