← Comprendre les Réseaux de Neurones
🎛️ Phase 2 · 2-3 jours

Le neurone - réglage manuel

🎯 Ce que tu retiens : Comprendre l'erreur

Qu'est-ce qu'un neurone, vraiment?

Si tu as suivi la Phase 0, tu as déjà deviné une règle : « Si la longueur du pétale dépasse un certain seuil, c'est une Virginica ». C'était une règle dure — oui ou non, noir ou blanc.

Un neurone artificiel fait quelque chose de similaire, mais beaucoup plus nuancé.

Au lieu d'une règle dure, un neurone calcule une probabilité progressive : « Vu ces deux mesures, quelle est la confiance que c'est une Virginica? »

La recette d'un neurone :

  1. Prendre les entrées (longueur et largeur du pétale)
  2. Peser chacune - décider laquelle est plus importante (poids1, poids2)
  3. Additionner le tout - un biais (décalage initial)
  4. Appliquer une courbe - la sigmoïde, qui transforme n'importe quel nombre en probabilité entre 0 et 1

Aucune intelligence là-dedans. Juste des multiplications, une addition, et une courbe.

📖 Vocabulaire - français / anglais

  • neurone ↔ *neuron* (une calculatrice avec des poids)
  • poids ↔ *weight* (l'importance de chaque entrée)
  • biais ↔ *bias* (un décalage initial)
  • sigmoïde ↔ *sigmoid* (la courbe en S, 0 → 0.5 → 1)
  • pré-activation ↔ *pre-activation* (avant la sigmoïde)

Exemple concret : la température

Avant le code, comprends la recette avec un exemple simple.

Imagine un neurone qui prédit si c'est un jour chaud, basé sur :

Le neurone a déjà des poids (ajustés par entraînement antérieur) :

Étape 1 : pré-activation (somme pondérée)

somme = x1*poids1 + x2*poids2 + biais
somme = 0.6*2.0 + 0.8*1.5 + (-1.0)
somme = 1.2 + 1.2 - 1.0
somme = 1.4

À ce stade, somme = 1.4. C'est un nombre brut, sans limites. Il pourrait être 100 ou -50.

Étape 2 : sigmoid (normalisation en probabilité)

La sigmoïde est une courbe lisse en S qui écrase n'importe quel nombre entre 0 et 1.

prediction = sigmoide(1.4)
           = 1 / (1 + e^(-1.4))
           ≈ 0.80

Donc, le neurone dit : 80% de chance que c'est un jour chaud.

Pourquoi la sigmoïde?

En Phase 0, tu as utilisé une règle dure : « Si longueur > 3, c'est Virginica ». C'était un saut sec.

La sigmoïde, c'est le contraire. Au lieu d'un saut, tu obtiens une courbe douce :

C'est ce qui permet au neurone de dire « 60% sûr, 80% sûr », au lieu de juste « oui ou non ».

Code Python

Maintenant, le code qui fait ces calculs :

import math

def sigmoide(x):
    # La formule : 1 / (1 + e^(-x))
    # Elle transforme n'importe quel nombre entre 0 et 1
    return 1 / (1 + math.exp(-x))

def neurone(x1, x2, poids1, poids2, biais):
    # Étape 1 : somme pondérée (pré-activation)
    somme = x1 * poids1 + x2 * poids2 + biais
    
    # Étape 2 : appliquer la sigmoïde (activation)
    sortie = sigmoide(somme)
    
    return sortie

# Test avec l'exemple ci-dessus
prediction = neurone(0.6, 0.8, 2.0, 1.5, -1.0)
print(f"Probabilité d'un jour chaud : {prediction:.2f}")  # -> 0.80

# Teste avec des fleurs Iris
# (x1 = longueur pétale, x2 = largeur pétale)
prediction_virginica = neurone(5.1, 1.8, 0.1, 0.1, 0.0)
print(f"C'est une Virginica? {prediction_virginica:.2f} (50% = incertain, proche de 1 = sûr)")

Note sur Python :

Exercice 2.1 - Ajuster les poids à la main

Tu vas faire maintenant ce que l'apprentissage automatique fait à l'échelle des millions : ajuster les poids pour réduire l'erreur.

La tâche :

Une fleur Virginica a : longueur pétale = 5.1, largeur pétale = 1.8.

Idéalement, le neurone devrait répondre 1.0 (« j'en suis certain, c'est une Virginica »).

Actuellement, avec poids1=0.1, poids2=0.1, biais=0.0, il répond seulement ≈ 0.62.

Ce que tu vas faire :

  1. Copie le code du neurone.
  2. Teste avec les poids actuels : neurone(5.1, 1.8, 0.1, 0.1, 0.0) → Résultat: 0.62
  3. Change UN SEUL poids à la fois, teste, observe.
  4. Continue jusqu'à obtenir une réponse > 0.90.

✍️ À toi de jouer

Expérimente :

  1. Augmente poids1 tout seul de 0.1 à 0.5, teste après chaque changement. Que remarques-tu?
  2. Ajoute un biais négatif, disons -1.0. Que se passe-t-il?
  3. Teste poids2 négatif. Que devient la prédiction?

Enregistre ce que tu observes pour chaque changement.

Besoin d'un indice ?

Pense logiquement :

  • x1 (5.1) est un grand nombre. Quand tu le multiplies par un poids, l'effet dépend de ce poids.
  • Si poids1 = 0.1, le contribution est 5.1 * 0.1 = 0.51 à la somme.
  • Si poids1 = 1.0, la contribution est 5.1 * 1.0 = 5.1 — beaucoup plus.
  • Le biais ajoute ou enlève un offset constant, indépendamment des entrées.

Essaie cet ordre :

  1. Augmente poids1 à 1.0, teste : neurone(5.1, 1.8, 1.0, 0.1, 0.0)
  2. Ajoute un biais, essaie -1.0 : neurone(5.1, 1.8, 1.0, 0.1, -1.0)
  3. Ajuste fino si besoin.
Voir la réponse
# Voici une solution possible (il y en a d'autres!)
p1, p2, b = 1.2, 0.3, -3.0
resultat = neurone(5.1, 1.8, p1, p2, b)
print(f"Prédiction: {resultat:.3f}")  # -> environ 0.95

# Vérification détaillée (pour comprendre chaque étape)
somme = 5.1*p1 + 1.8*p2 + b
print(f"Somme pré-activation: {somme:.3f}")  # -> environ 5.07
print(f"Après sigmoïde: {resultat:.3f}")  # -> 0.95

Ce que tu as appris :

  1. Poids1 a le plus grand effet, car x1 (5.1) est le plus grand nombre. Un poids plus fort le rend plus influent.
  1. Le biais est un décalage qui s'applique toujours, indépendamment des entrées. Un biais négatif rend le neurone « sceptique par défaut ». Il faut des entrées fortes pour le convaincre. C'est comme un seuil : « prouves-moi que c'est une Virginica ».
  1. Poids2 reste faible car x2 (1.8) est petit. Un poids négatif réduirait l'influence de la largeur du pétale.

L'analogie : Tu viens de faire, à la main, ce que l'algorithme de rétropropagation (backpropagation) fait automatiquement lors de l'entraînement : observer l'erreur et ajuster les poids pour la réduire. C'est EXACTEMENT ça, l'apprentissage.

Exercice 2.2 - Le défi : classer 4 fleurs à la main

Voilà le vrai défi : trouve UN jeu de poids qui classe correctement toutes les 4 fleurs.

Les données :

FleurLongueur (x1)Largeur (x2)EspèceSortie attendue
A1.40.2Setosa0 (non-Virginica)
B1.30.2Setosa0 (non-Virginica)
C5.11.8Virginica1 (oui, Virginica)
D5.92.1Virginica1 (oui, Virginica)

Comment le faire :

  1. Prépare une boucle qui teste tes poids sur les 4 fleurs à la fois
  2. Pour chaque fleur, affiche la prédiction vs l'attendu
  3. Ajuste UN poids à la fois
  4. Re-teste les 4 fleurs
  5. Répète jusqu'à ce que toutes les 4 soient bonnes

Stratégie :

Observe les différences :

La longueur est très différente. La largeur (x2) aussi change, mais moins. Tu peux probablement te débrouiller avec juste poids1 sans poids2.

✍️ À toi de jouer

Fais cet exercice :

# Commence ici
p1, p2, b = 0.5, 0.0, -1.0  # Valeurs de départ

# Crée une boucle de test
for nom, x1, x2, attendu in [("A", 1.4, 0.2, 0), 
                               ("B", 1.3, 0.2, 0),
                               ("C", 5.1, 1.8, 1), 
                               ("D", 5.9, 2.1, 1)]:
    pred = neurone(x1, x2, p1, p2, b)
    erreur = "✓" if (pred > 0.5 and attendu == 1) or (pred < 0.5 and attendu == 0) else "✗"
    print(f"{nom}: x1={x1}, x2={x2} | prédiction={pred:.3f} | attendu={attendu} {erreur}")

# Après chaque ajustement, réexécute la boucle

Ajuste tes poids graduellement :

  1. D'abord, augmente p1 pour que C et D remontent
  2. Puis, augmente |b| (le biais en valeur absolue) pour que A et B redescendent
  3. Si besoin, ajuste p2 pour la largeur

Quel ensemble de poids finit par fonctionner? Trace ton chemin.

Besoin d'un indice ?

Pense en termes de « confiance » :

  • Quand x1 est petit (1.3), le neurone doit répondre proche de 0 = « c'est pas Virginica »
  • Quand x1 est grand (5.1+), le neurone doit répondre proche de 1 = « c'est Virginica »

Un biais très négatif (disons -5.0) force le neurone à exiger des entrées fortes. Un poids1 très positif (disons 2.0) amplifie la longueur du pétale.

Essaie cet ordre de progression :

  1. p1=1.0, p2=0.0, b=-1.0 → teste
  2. p1=2.0, p2=0.0, b=-3.0 → teste
  3. Affine si besoin
Voir la réponse
# Une solution qui marche
p1, p2, b = 2.0, 0.0, -3.0

print("TEST FINAL :")
for nom, x1, x2, attendu in [("A", 1.4, 0.2, 0), 
                               ("B", 1.3, 0.2, 0),
                               ("C", 5.1, 1.8, 1), 
                               ("D", 5.9, 2.1, 1)]:
    pred = neurone(x1, x2, p1, p2, b)
    erreur = "✓" if (pred > 0.5 and attendu == 1) or (pred < 0.5 and attendu == 0) else "✗"
    print(f"{nom}: prediction={pred:.3f}, attendu={attendu} {erreur}")

# Calculs détaillés pour fleur C (la plus proche du seuil)
print("\nDétail pour C:")
somme_c = 5.1*p1 + 1.8*p2 + b
print(f"  Somme: 5.1*{p1} + 1.8*{p2} + {b} = {somme_c:.2f}")
pred_c = neurone(5.1, 1.8, p1, p2, b)
print(f"  Sigmoïde({somme_c:.2f}) = {pred_c:.3f}")

Résultats attendus : A ≈ 0.02, B ≈ 0.01, C ≈ 0.95, D ≈ 0.98

Observations clés :

  1. La longueur suffit presque toujours. Remarque que p2=0 marche bien. La largeur n'aide pas beaucoup ici — la longueur seule sépare bien les deux espèces.
  1. Le biais rend le seuil « mobile ». Un biais très négatif (-3.0) force le neurone à être méfiant. Même une longueur = 1.4 donne une réponse proche de 0.
  1. C'est ça, ajuster un réseau : Tu viens de faire exactement ce que l'entraînement automatique fait, mais à la main. Une fois cette expérience terminée, tu comprends pourquoi les données d'entraînement sont cruciales : elles disent au réseau « voilà des cas réels; fais en sorte de bien les classer ». Le réseau ajuste alors les poids, un peu comme tu viens de le faire.

Le grand saut : Avec 2 entrées et 1 neurone, tu dois ajuster 3 nombres (2 poids + 1 biais). En Phase 3, tu en auras 10. En Phase 4, des milliers. NumPy fera ces ajustements pour toi. Mais la mécanique reste identique.