← Comprendre les Réseaux de Neurones
🔗 Phase 2.5 · 2 jours

Le réseau à la main

🎯 Ce que tu retiens : Le flux des données

Pourquoi plusieurs neurones?

En Phase 2, un seul neurone pouvait seulement tracer une ligne droite pour séparer les classes.

Mais regardons le graphique de Phase 1 : Versicolor et Virginica ne sont pas séparables par une droite. Elles se chevauchent.

Un neurone seul ne peut pas résoudre ce problème.

C'est ici qu'intervient la couche cachée.

L'idée : des détecteurs en cascade

Première couche (cachée) : 3 neurones qui apprennent chacun à détecter quelque chose de différent.

Chacun donne une sortie entre 0 et 1.

Deuxième couche (sortie) : 1 neurone qui prend ces 3 signaux et fait un vote pondéré.

Architecture concrète

Entrées (x1, x2)
    ↓
    ├─→ [Neurone A] ─→ sortie a (0 à 1)
    ├─→ [Neurone B] ─→ sortie b (0 à 1)
    └─→ [Neurone C] ─→ sortie c (0 à 1)
          ↓
          Tous les trois vont vers...
          ↓
       [Neurone Final] ─→ sortie finale (0 à 1)

Ça ressemble à ça :

Explication détaillée

📖 Vocabulaire - français / anglais

  • couche cachée ↔ *hidden layer*
  • propagation avant ↔ *forward propagation* (calculer la sortie, de gauche à droite)
  • neurone caché ↔ *hidden unit / hidden neuron*

Exercice 2.5.1 - Calculer un réseau complet à la main

Cet exercice est important. Tu vas tracer, manuelle ment, le chemin d'une donnée à travers un réseau entier.

Une fois que tu l'as fait une fois, tu comprendras pourquoi NumPy est magique (il fait la même chose, mais pour 1000 fleurs à la fois).

Les données

Fleur : Virginica avec longueur pétale x1 = 5.1, largeur pétale x2 = 1.8.

Architecture du réseau :

Les poids (fixés d'avance)

Neurone A (détecteur de longueur):

Neurone B (détecteur de largeur):

Neurone C (détecteur mixte):

Neurone Final (vote final):

Ta tâche

✍️ À toi de jouer

Calcule complètement à la main, étape par étape :

Étape 1 : Couche cachée (les 3 détecteurs)

  1. Neurone A:
  • Somme_A = 5.1 * 0.5 + 1.8 * (-0.2) + 0.1 = ?
  • Sortie_A = sigmoide(Somme_A) = ? (utilise une calculatrice ou Python juste pour la sigmoïde)
  1. Neurone B:
  • Somme_B = 5.1 * 0.3 + 1.8 * 0.8 + (-0.3) = ?
  • Sortie_B = sigmoide(Somme_B) = ?
  1. Neurone C:
  • Somme_C = 5.1 * (-0.1) + 1.8 * 0.4 + 0.2 = ?
  • Sortie_C = sigmoide(Somme_C) = ?

Étape 2 : Couche de sortie (le vote final)

  1. Neurone Final:
  • Somme_Finale = Sortie_A * 0.4 + Sortie_B * 0.6 + Sortie_C * (-0.3) + 0.1 = ?
  • Prédiction finale = sigmoide(Somme_Finale) = ?

Écris tous tes calculs intermédiaires. Ensuite, vérifie avec Python.

Besoin d'un indice ?

Pour les calculs à la main :

  1. Commence par Neurone A :
  • 5.1 × 0.5 = 2.55
  • 1.8 × (-0.2) = -0.36
  • 2.55 + (-0.36) + 0.1 = 2.29
  • Maintenant, utilise Python pour sigmoide(2.29)
  1. Fais pareil pour B et C
  1. Quand tu as les trois sorties, utilise-les pour le neurone Final

Les valeurs de sigmoïde :

  • sigmoide(2.29) ≈ 0.908
  • sigmoide(2.37) ≈ 0.914
  • sigmoide(0.42) ≈ 0.603

(Ces valeurs sont approximatives; calcule avec Python pour la précision.)

Voir la réponse

Solution complète :

import math

def sigmoide(x):
    return 1 / (1 + math.exp(-x))

# Données d'entrée
x1, x2 = 5.1, 1.8

# ============ COUCHE CACHÉE ============
# Neurone A
somme_a = x1*0.5 + x2*(-0.2) + 0.1
sortie_a = sigmoide(somme_a)
print(f"Neurone A:")
print(f"  Somme: {x1}*0.5 + {x2}*(-0.2) + 0.1 = {somme_a:.3f}")
print(f"  Sortie: sigmoide({somme_a:.3f}) = {sortie_a:.3f}")

# Neurone B
somme_b = x1*0.3 + x2*0.8 + (-0.3)
sortie_b = sigmoide(somme_b)
print(f"Neurone B:")
print(f"  Somme: {x1}*0.3 + {x2}*0.8 + (-0.3) = {somme_b:.3f}")
print(f"  Sortie: sigmoide({somme_b:.3f}) = {sortie_b:.3f}")

# Neurone C
somme_c = x1*(-0.1) + x2*0.4 + 0.2
sortie_c = sigmoide(somme_c)
print(f"Neurone C:")
print(f"  Somme: {x1}*(-0.1) + {x2}*0.4 + 0.2 = {somme_c:.3f}")
print(f"  Sortie: sigmoide({somme_c:.3f}) = {sortie_c:.3f}")

# ============ COUCHE DE SORTIE ============
somme_finale = sortie_a*0.4 + sortie_b*0.6 + sortie_c*(-0.3) + 0.1
prediction = sigmoide(somme_finale)
print(f"\nNeurone Final:")
print(f"  Somme: {sortie_a:.3f}*0.4 + {sortie_b:.3f}*0.6 + {sortie_c:.3f}*(-0.3) + 0.1")
print(f"        = {somme_finale:.3f}")
print(f"  Prédiction finale: sigmoide({somme_finale:.3f}) = {prediction:.3f}")
print(f"\nRésultat : {prediction:.3f} (attendu ≈ 1 pour une Virginica)")

Résultat attendu :

  • Sortie_A ≈ 0.908
  • Sortie_B ≈ 0.914
  • Sortie_C ≈ 0.603
  • Prédiction finale ≈ 0.71

(Légèrement moins que 1, mais raisonnablement confiant : 71% = « c'est probablement une Virginica ».)

Ce que tu viens de faire : Tu as tracé, à la main, ce qu'on appelle la propagation avant (forward pass) à travers un réseau complet. C'est exactement ce que NumPy fera pour 150 fleurs en une seule ligne.

Exercice 2.5.2 - Interpréter les détecteurs

Maintenant que tu as les sorties (A ≈ 0.908, B ≈ 0.914, C ≈ 0.603), regarde ce qu'elles signifient.

Les poids révèlent le rôle de chaque neurone.

✍️ À toi de jouer

Regarde les poids et les sorties :

  1. Neurone A (w1=0.5, w2=−0.2) : Pourquoi sort-il 0.908?
  2. Neurone B (w1=0.3, w2=0.8) : Pourquoi sort-il 0.914?
  3. Neurone C (w1=−0.1, w2=0.4) : Pourquoi sort-il 0.603?
  4. Le vote final (A:0.4, B:0.6, C:−0.3) : Qui vote le plus?
Voir la réponse

Neurone A : w1=0.5 (amplifie la longueur), w2=-0.2 (réduit la largeur)

  • Rôle : Détecteur de « pétale long »
  • Pour x1=5.1 (long), il sort 0.908 (enthousiaste)

Neurone B : w1=0.3 (faible), w2=0.8 (amplifie fortement la largeur)

  • Rôle : Détecteur de « pétale large »
  • Pour x2=1.8 (large), il sort 0.914 (très enthousiaste)

Neurone C : w1=-0.1, w2=0.4 (poids faibles)

  • Rôle : Modulateur nuancé
  • Sort 0.603 (ni enthousias-te, ni sceptique)

Le vote final : B a le poids 0.6 (le plus élevé). Son signal domine. A apporte 0.4. C apporte -0.3 (modère un peu).

Ce que tu as appris :

  1. Chaque neurone caché détecte un motif différent. Ensemble, ils créent une limite courbe (pas une droite comme en Phase 0).
  1. Les poids cachés + le vote final = une équation complexe que un seul neurone ne pourrait pas exprimer.
  1. C'est ça, apprendre : ajuster ces poids pour que les détecteurs reconnaissent les bons motifs.

Conclusion : du manuel au NumPy

Tu viens de faire à la main :

Pour 150 fleurs : 3,750 opérations. Long.

NumPy le fait en 1 ligne :

hidden = sigmoid(np.dot(X, W1) + b1)      # Toutes les 150 fleurs, 3 neurones
output = sigmoid(np.dot(hidden, W2) + b2)  # Vote final

Ce n'est pas de la magie. Les mêmes 3,750 opérations, juste :

Tu comprends maintenant ce que NumPy, et plus tard PyTorch, automatisent.