Retour aux défis
Difficile 0 résolus 0 % de réussite

Entraîner un réseau de neurones pour résoudre XOR

Tout réunir : entraînez un réseau sigmoïde 2-2-1 par rétropropagation jusqu'à ce qu'il apprenne XOR.

Ce que vous allez apprendre

  • Entraîner un petit réseau de bout en bout
  • Comprendre pourquoi XOR a besoin d'une couche cachée
  • Assembler propagations avant et arrière

Problème

XOR (ou exclusif) est le problème classique qu'un seul neurone ne peut pas résoudre, mais qu'un réseau avec une couche cachée peut résoudre. Entraînez un réseau à 2 entrées, 2 neurones cachés et 1 sortie, tous sigmoïdes (σ(z) = 1 / (1 + e^(-z))), avec la perte L = (y - target)².

Les données d'entraînement, toujours utilisées dans cet ordre à chaque époque :

entréetarget
[0, 0]0
[0, 1]1
[1, 0]1
[1, 1]0

Pour chaque exemple :

  1. Propagation avant : 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), et delta_j = delta_out × output_weights[j] × a_j × (1 - a_j), avec les poids avant la mise à jour de cet exemple
  3. Mettez à jour chaque paramètre avec le taux d'apprentissage 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

Implémentez train_xor(hidden_weights, hidden_biases, output_weights, output_bias, learning_rate, epochs).

Sortie

Après l'entraînement, renvoyez les prédictions y du réseau pour les entrées [0, 0], [0, 1], [1, 0] et [1, 1], dans cet ordre.

Contraintes

0 ≤ epochs ≤ 5 000

0 < learning_rate ≤ 5

-2 ≤ chaque poids et biais de départ ≤ 2

Exemples

Exemple 1
Entrée :
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]

Sortie attendue :
expected = [0.482451, 0.436972, 0.494378, 0.452729]
Entrée :
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};

Sortie attendue :
std::vector<double> expected = {0.482451, 0.436972, 0.494378, 0.452729};
Entrée :
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};

Sortie attendue :
double[] expected = new double[] {0.482451, 0.436972, 0.494378, 0.452729};

Explication

Avec 0 époque, rien n'est entraîné : le résultat est simplement la propagation avant avec les poids de départ, environ [0.482, 0.437, 0.494, 0.453]. Le réseau non entraîné donne presque la même réponse à chaque entrée.

Exemple 2
Entrée :
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]

Sortie attendue :
expected = [0.015727, 0.982119, 0.985515, 0.013682]
Entrée :
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};

Sortie attendue :
std::vector<double> expected = {0.015727, 0.982119, 0.985515, 0.013682};
Entrée :
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};

Sortie attendue :
double[] expected = new double[] {0.015727, 0.982119, 0.985515, 0.013682};

Explication

Après 2 000 époques, les prédictions sont d'environ [0.016, 0.982, 0.986, 0.014] : faibles pour [0, 0] et [1, 1], élevées pour [0, 1] et [1, 0]. Le réseau a appris XOR.

Comment l'aborder

Essayez d'abord seul, puis ouvrez les indices un par un.

Indice 1

Traitez les quatre exemples XOR dans le même ordre fixe à chaque epoch, et mettez à jour les paramètres immédiatement après chacun.

Indice 2

Utilisez la propagation avant, puis rétropropagez l’erreur de sortie vers les deux neurones cachés avec les poids courants avant d’appliquer les mises à jour.

Indice 3

Faites attention à la dérivée de la sigmoid et au fait que les mises à jour de la couche cachée dépendent des valeurs d’entrée, donc des entrées nulles laissent certains poids inchangés.

Complexité attendue

temps O(epochs), espace supplémentaire O(1)

Références

Ce défi a été adapté pour CodeUtility. Suivez l'énoncé et les contraintes ci-dessus.

Apprenez des autres

Solutions de la communauté

Aucune solution publiée pour l'instant. Résolvez ce défi pour partager la première.