Réseaux de neurones
Du perceptron aux réseaux profonds
Les réseaux de neurones artificiels s'inspirent du fonctionnement du cerveau pour apprendre à partir de données. Ils sont la brique fondamentale du Deep Learning.
Le neurone biologique
Le cerveau contient ~86 milliards de neurones interconnectés.
Dendrites Axone
(entrées) (sortie)
\ | / |
\ | / |
\|/ ↓
┌──────────────┐ ┌──────────┐
│ Corps │──────────│ Synapses │──→ Autres neurones
│ cellulaire │ └──────────┘
└──────────────┘
│
Si signal > seuil
→ neurone "fire"Le perceptron (1957)
Premier modèle de neurone artificiel, inventé par Frank Rosenblatt.
Structure
x₁ ──w₁──┐
│
x₂ ──w₂──┼──→ Σ ──→ Seuil ──→ Sortie (0 ou 1)
│ │
x₃ ──w₃──┘ │
│ │
biais ─┘ y = 1 si Σ > 0
y = 0 sinonMathématiquement
z = Σ(wᵢxᵢ) + b = w₁x₁ + w₂x₂ + ... + wₙxₙ + b
y = step(z) = { 1 si z > 0
{ 0 sinonLimites du perceptron simple
Le perceptron ne peut résoudre que des problèmes linéairement séparables.
✓ Peut apprendre ✗ Ne peut PAS apprendre
AND XOR
○ ● (1,1)=1 ● ○ (0,1)=1
○ ○ (0,0)=0 ○ ● (1,0)=1
● ○ (0,0)=0
Séparable par ○ ● (1,1)=0
une ligne
Non séparable !En 1969, Minsky et Papert ont prouvé cette limitation, causant le premier "hiver de l'IA".
Perceptron multicouche (MLP)
La solution : empiler plusieurs couches de neurones.
Architecture
Entrée Couche cachée 1 Couche cachée 2 Sortie
○─────────────○─────────────────○───────────────────○
│ │ │
○─────────────○─────────────────○───────────────────○
│ │ │
○─────────────○─────────────────○
│ │ │
○─────────────○─────────────────○
4 neurones 5 neurones 4 neurones 2 neuronesPourquoi ça marche ?
Chaque couche apprend des représentations de plus en plus abstraites :
Image → Couche 1: bords, textures
→ Couche 2: formes simples
→ Couche 3: parties d'objets
→ Couche 4: objets entiers
→ Sortie: chat/chienFonctions d'activation
Sans fonction d'activation non-linéaire, un réseau profond équivaut à une seule couche linéaire.
ReLU (Rectified Linear Unit)
La plus utilisée aujourd'hui.
f(x) = max(0, x)
│ /
│ /
│ /
──────┼───────
│nn.ReLU()Avantages :
- Simple et rapide
- Pas de vanishing gradient (pour x > 0)
- Convergence rapide
Variantes :
- Leaky ReLU : f(x) = max(0.01x, x)
- PReLU : paramètre appris
- ELU : exponentielle pour x < 0
Sigmoid
f(x) = 1 / (1 + e⁻ˣ)
Sortie entre 0 et 1
1 ──────────────────
│ ●●●●●
│ ●●●
│ ●●
0 ●●──────────────────nn.Sigmoid()Usage : Dernière couche pour classification binaire (probabilité).
Problème : Vanishing gradient pour |x| grand.
Tanh
f(x) = (eˣ - e⁻ˣ) / (eˣ + e⁻ˣ)
Sortie entre -1 et 1nn.Tanh()Softmax
Convertit un vecteur en distribution de probabilités.
softmax(xᵢ) = eˣⁱ / Σⱼ eˣʲ
Exemple :
[2.0, 1.0, 0.1] → [0.659, 0.242, 0.099]
Somme = 1.0nn.Softmax(dim=1)Usage : Dernière couche pour classification multiclasse.
GELU
Utilisée dans les Transformers (BERT, GPT).
f(x) = x · Φ(x) où Φ = CDF gaussiennenn.GELU()Backpropagation
L'algorithme qui permet d'entraîner les réseaux profonds.
Principe
- Forward pass : calculer la sortie
- Calculer la loss : mesurer l'erreur
- Backward pass : calculer les gradients (règle de la chaîne)
- Mise à jour : ajuster les poids
Règle de la chaîne
x → f → g → h → Loss
∂Loss/∂x = ∂Loss/∂h × ∂h/∂g × ∂g/∂f × ∂f/∂xVanishing Gradient
Problème historique : les gradients deviennent très petits dans les premières couches.
Gradient × 0.1 × 0.1 × 0.1 × 0.1 = très petit !
↓
Les premières couches n'apprennent pasSolutions :
- ReLU au lieu de sigmoid
- Initialisation appropriée (He, Xavier)
- Batch Normalization
- Connexions résiduelles (ResNet)
Optimiseurs
SGD (Stochastic Gradient Descent)
w = w - lr × gradientoptim.SGD(model.parameters(), lr=0.01, momentum=0.9)Adam
Combine momentum et adaptation du learning rate.
optim.Adam(model.parameters(), lr=0.001)Le plus utilisé pour sa simplicité et ses bonnes performances.
Learning Rate Schedulers
Réduire le learning rate au cours de l'entraînement.
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=100)Initialisation des poids
Une bonne initialisation est cruciale.
Xavier/Glorot
Pour sigmoid/tanh.
nn.init.xavier_uniform_(layer.weight)He/Kaiming
Pour ReLU.
nn.init.kaiming_uniform_(layer.weight, nonlinearity='relu')Implémentation complète
import torch
import torch.nn as nn
import torch.optim as optim
# 1. Définir le modèle
class MLP(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super().__init__()
self.layers = nn.Sequential(
nn.Linear(input_dim, hidden_dim),
nn.ReLU(),
nn.BatchNorm1d(hidden_dim),
nn.Dropout(0.3),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.BatchNorm1d(hidden_dim),
nn.Dropout(0.3),
nn.Linear(hidden_dim, output_dim)
)
def forward(self, x):
return self.layers(x)
# 2. Créer le modèle
model = MLP(input_dim=784, hidden_dim=256, output_dim=10)
# 3. Définir loss et optimiseur
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 4. Boucle d'entraînement
for epoch in range(num_epochs):
model.train() # Mode entraînement
for batch_x, batch_y in train_loader:
# Forward
outputs = model(batch_x)
loss = criterion(outputs, batch_y)
# Backward
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Validation
with torch.no_grad():
correct = 0
for batch_x, batch_y in val_loader:
outputs = model(batch_x)
correct += (outputs.argmax(1) == batch_y).sum().item()
accuracy = correct / len(val_dataset)
print(f"Epoch {epoch}: Acc={accuracy:.4f}")Debugging et bonnes pratiques
Checklist
- Vérifier les shapes :
print(x.shape)à chaque étape - Commencer petit : peu de données, petit modèle
- Overfitter d'abord : si ça n'overfit pas, problème !
- Visualiser : loss, gradients, activations
Problèmes courants
| Symptôme | Cause probable | Solution |
|---|---|---|
| Loss = NaN | LR trop grand | Réduire LR, gradient clipping |
| Loss ne descend pas | LR trop petit, bug | Augmenter LR, vérifier code |
| Val loss augmente | Overfitting | Régularisation, plus de données |
| Train loss stagne | Modèle trop petit | Plus de couches/neurones |