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

Backpropagation in einem zweischichtigen Netz

Berechne alle Gradienten der Gewichte und Biases eines Netzes mit einer verborgenen Sigmoid-Schicht und einer Sigmoid-Ausgabe.

Das lernst du

  • Jeden Gradienten eines zweischichtigen Netzes berechnen
  • Fehlerterme rückwärts durch die Schichten geben
  • Mathematik und Code Schritt für Schritt verbinden

Problem

Backpropagation wendet die Kettenregel Schicht für Schicht an, von der Ausgabe zurück zu den Eingaben. Das Netz hat n Eingaben, h verborgene Neuronen und eine Ausgabe, alle mit Sigmoid-Aktivierung (σ(z) = 1 / (1 + e^(-z))):

  • verborgen: a_j = σ(inputs · hidden_weights[j] + hidden_biases[j])
  • Ausgabe: y = σ(a · output_weights + output_bias)
  • Verlust: L = (y - target)²

Gradienten:

  1. delta_out = 2 × (y - target) × y × (1 - y)
  2. Ausgabeschicht: dL/doutput_weights[j] = delta_out × a_j und dL/doutput_bias = delta_out
  3. delta_j = delta_out × output_weights[j] × a_j × (1 - a_j)
  4. Verborgene Schicht: dL/dhidden_weights[j][i] = delta_j × inputs[i] und dL/dhidden_biases[j] = delta_j

Implementiere backprop_gradients(inputs, hidden_weights, hidden_biases, output_weights, output_bias, target).

Ausgabe

Gib eine Matrix mit h + 1 Zeilen zurück:

  • Zeile j (für jedes verborgene Neuron j, in Reihenfolge): die n Gradienten von hidden_weights[j], dann der Gradient von hidden_biases[j].
  • Letzte Zeile: die h Gradienten von output_weights, dann der Gradient von output_bias.

Einschränkungen

1 ≤ n, h ≤ 20

-5 ≤ jede Eingabe, jedes Gewicht und jeder Bias ≤ 5

0 ≤ target ≤ 1

Beispiele

Beispiel 1
Eingabe:
inputs = [1.0]
target = 1.0
output_bias = 0.0
hidden_biases = [0.0]
hidden_weights = [
    [0.0]
]
output_weights = [0.0]

Erwartete Ausgabe:
expected = [
    [0.0, 0.0],
    [-0.125, -0.25]
]
Eingabe:
std::vector<double> inputs = {1.0};
double target = 1.0;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0};
std::vector<std::vector<double>> hidden_weights = {
    {0.0}
};
std::vector<double> output_weights = {0.0};

Erwartete Ausgabe:
std::vector<std::vector<double>> expected = {
    {0.0, 0.0},
    {-0.125, -0.25}
};
Eingabe:
double[] inputs = new double[] {1.0};
double target = 1.0;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0};
double[][] hidden_weights = new double[][] {
    new double[] {0.0}
};
double[] output_weights = new double[] {0.0};

Erwartete Ausgabe:
double[][] expected = new double[][] {
    new double[] {0.0, 0.0},
    new double[] {-0.125, -0.25}
};

Erläuterung

a = σ(0) = 0.5 und y = σ(0) = 0.5. delta_out = 2 × (0.5 - 1) × 0.25 = -0.25. Ausgabezeile: [-0.25 × 0.5, -0.25] = [-0.125, -0.25]. delta_1 = -0.25 × 0 × 0.25 = 0, also ist die verborgene Zeile [0, 0]: Ein Ausgabegewicht von null blockiert den Gradienten.

Beispiel 2
Eingabe:
inputs = [1.0, 0.0]
target = 0.0
output_bias = -1.0
hidden_biases = [0.0, 0.0]
hidden_weights = [
    [0.0, 1.0],
    [0.0, -1.0]
]
output_weights = [1.0, 1.0]

Erwartete Ausgabe:
expected = [
    [0.0625, 0.0, 0.0625],
    [0.0625, 0.0, 0.0625],
    [0.125, 0.125, 0.25]
]
Eingabe:
std::vector<double> inputs = {1.0, 0.0};
double target = 0.0;
double output_bias = -1.0;
std::vector<double> hidden_biases = {0.0, 0.0};
std::vector<std::vector<double>> hidden_weights = {
    {0.0, 1.0},
    {0.0, -1.0}
};
std::vector<double> output_weights = {1.0, 1.0};

Erwartete Ausgabe:
std::vector<std::vector<double>> expected = {
    {0.0625, 0.0, 0.0625},
    {0.0625, 0.0, 0.0625},
    {0.125, 0.125, 0.25}
};
Eingabe:
double[] inputs = new double[] {1.0, 0.0};
double target = 0.0;
double output_bias = -1.0;
double[] hidden_biases = new double[] {0.0, 0.0};
double[][] hidden_weights = new double[][] {
    new double[] {0.0, 1.0},
    new double[] {0.0, -1.0}
};
double[] output_weights = new double[] {1.0, 1.0};

Erwartete Ausgabe:
double[][] expected = new double[][] {
    new double[] {0.0625, 0.0, 0.0625},
    new double[] {0.0625, 0.0, 0.0625},
    new double[] {0.125, 0.125, 0.25}
};

Erläuterung

Beide verborgenen Werte sind σ(0) = 0.5, also y = σ(0.5 + 0.5 - 1) = 0.5 und delta_out = 2 × 0.5 × 0.25 = 0.25. Ausgabezeile: [0.125, 0.125, 0.25]. Jedes delta_j = 0.25 × 1 × 0.25 = 0.0625, was die verborgenen Zeilen [0.0625, 0, 0.0625] ergibt (die zweite Eingabe ist 0).

So gehst du vor

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

Hinweis 1

Gehe zuerst vom Output-Neuron rückwärts und verwende dieses Signal dann wieder, um den Beitrag jedes Hidden-Neurons zu berechnen.

Hinweis 2

Du brauchst ein Delta für die Output-Schicht und je ein Delta pro Hidden-Neuron, beide basierend auf den Sigmoid-Ableitungen.

Hinweis 3

Achte darauf, für das Zurückpropagieren des Fehlers zu jedem Hidden-Neuron dessen eigenes Ausgabengewicht zu verwenden.

Erwartete Komplexität

Zeit O(hn), zusätzlicher Speicher O(hn)

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.