Deep learning
Le deep learning n'est pas un meilleur machine learning : c'est une famille de modèles qui apprennent leurs propres représentations, ce qui les rend imbattables là où les données brutes sont structurées et abondantes — images, son, texte, signaux — et souvent décevants ailleurs. Ce module couvre les architectures, les recettes d'entraînement qui font réellement la différence, et les PINN, qui relient réseaux de neurones et équations aux dérivées partielles.
📋 Au programme
1. Quand le deep learning est pertinent
Le deep learning gagne quand... Le ML classique gagne quand... ────────────────────────────────────────────────────────────────────────────── données brutes structurées données tabulaires hétérogènes (pixels, audio, texte, séquences) (le boosting reste devant, module 14) beaucoup de données (10⁴ – 10⁹) peu de données (10² – 10⁴) la REPRÉSENTATION est le problème les variables métier existent déjà une architecture pré-entraînée existe l'interprétabilité est exigée un GPU est disponible le coût d'inférence doit rester minimal
La question utile n'est donc pas « quel modèle est le meilleur » mais « existe-t-il un biais inductif adapté à mes données ? » (module 15). Une convolution encode l'invariance par translation ; une attention encode des dépendances à longue portée ; un arbre encode des effets de seuil. Choisir un modèle, c'est choisir l'hypothèse structurelle qui correspond au problème.
2. Du neurone au MLP
Un neurone calcule une somme pondérée de ses entrées, ajoute un biais, et passe le tout dans une fonction non linéaire : \(a = \sigma(w^\top x + b)\). Une couche est un ensemble de neurones qui voient les mêmes entrées, ce qui s'écrit matriciellement \(h = \sigma(Wx + b)\). Un perceptron multicouche (MLP) empile ces couches.
entrée x couche 1 couche 2 sortie
(10 var.) (64 neurones) (32 neurones) (1 valeur)
x₁ ──┐ ┌─ σ(·) ─┐ ┌─ σ(·) ─┐
x₂ ──┼─ W₁ ──►│ ... │─ W₂ ──►│ ... │─ W₃ ──► ŷ
... │ │ │ │ │
x₁₀ ─┘ └─ σ(·) ─┘ └─ σ(·) ─┘
(10×64 + 64 (64×32 + 32 (32×1 + 1
= 704 param.) = 2 080 param.) = 33 param.)Sans la non-linéarité \(\sigma\), la composition de couches affines resterait affine : trois couches vaudraient une seule, et toute la profondeur serait inutile. C'est \(\sigma\) qui donne sa puissance à l'empilement. Le théorème d'approximation universelle garantit d'ailleurs qu'un réseau à une seule couche cachée suffisamment large approche n'importe quelle fonction continue sur un compact — résultat rassurant mais peu opérationnel, car il ne dit rien du nombre de neurones nécessaires ni de la possibilité d'apprendre ces poids. La profondeur, elle, permet d'exprimer certaines fonctions avec exponentiellement moins de paramètres que la largeur.
ReLU max(0, x) le défaut. Gradient constant à droite, nul à gauche —
d'où les neurones "morts" si le gradient les pousse
durablement dans la zone négative.
LeakyReLU max(αx, x) corrige les neurones morts avec une pente résiduelle.
GELU x·Φ(x) lisse ; le standard dans les transformers.
SiLU/Swish x·sigmoid(x) proche de GELU, très utilisé en vision moderne.
tanh (-1, 1) centrée ; encore utile dans les RNN et les PINN,
car ses dérivées d'ordre 2 sont lisses.
sigmoid (0, 1) réservée à la SORTIE binaire. En couche cachée, elle
sature et tue le gradient (dérivée ≤ 0,25).
softmax sortie multiclasse : produit une distribution.L'initialisation n'est pas un détail. Trop petite, le signal s'éteint en traversant les couches ; trop grande, il explose. Les schémas de Xavier/Glorot (pour tanh) et He/Kaiming (pour ReLU) choisissent la variance des poids de façon à conserver l'échelle du signal d'une couche à l'autre — \(\operatorname{Var}(w) = 2/n_{\text{entrées}}\) pour He. C'est ce qui a rendu possible l'entraînement des réseaux profonds bien avant les architectures modernes.
3. Rétropropagation
La rétropropagation n'est rien d'autre que la règle de dérivation des fonctions composées, appliquée efficacement. Pour une couche \(z^{(l)} = W^{(l)}a^{(l-1)}+b^{(l)}\), on définit l'erreur locale \(\delta^{(l)} = \partial L/\partial z^{(l)}\) et on la propage vers l'arrière :
L'astuce algorithmique tient en une phrase : en réutilisant les \(\delta\) déjà calculés au lieu de recalculer chaque dérivée depuis le début, le coût du gradient complet est du même ordre que celui d'une passe avant — et non proportionnel au nombre de paramètres, comme le serait une différentiation numérique paramètre par paramètre. C'est ce qui rend l'entraînement de réseaux à des milliards de paramètres possible.
Le produit de matrices sur toute la profondeur explique aussi les pathologies classiques. Si les termes \(W^\top \sigma'\) sont systématiquement inférieurs à 1 en module, leur produit tend vers zéro : le gradient s'évanouit et les premières couches n'apprennent plus rien. S'ils dépassent 1, il explose, et les poids partent à l'infini en une itération. Les trois remèdes structurels sont les connexions résiduelles (section 5), la normalisation (section 4) et l'écrêtage du gradient (module 8).
4. Les recettes d'entraînement
En deep learning, l'écart entre un modèle qui converge et un modèle qui stagne tient rarement à l'architecture. Les leviers, par ordre d'impact :
- Taux d'apprentissage — de loin le plus important (module 8). Le trouver par une montée exponentielle sur quelques centaines de pas (LR range test), puis prendre un ordre de grandeur en dessous du point de divergence.
- Normalisation — la batch norm normalise chaque variable sur le lot (efficace en vision, mais dépendante de la taille du lot et délicate en inférence, où l'on utilise des statistiques mémorisées) ; la layer norm normalise sur les variables d'un exemple (indépendante du lot, standard dans les transformers). L'effet principal est un meilleur conditionnement, donc une convergence plus rapide et plus stable.
- Régularisation — le dropout désactive aléatoirement une fraction des neurones à chaque passage, ce qui force le réseau à ne pas dépendre d'un chemin unique ; le weight decay via AdamW ; et surtout l'early stopping, la plus simple et la plus efficace : on garde les poids du meilleur point de validation.
- Augmentation de données — en vision, c'est souvent le gain le plus important : recadrages, symétries, variations colorimétriques, mixup, cutmix. On encode ainsi des invariances connues sans annoter davantage (module 13).
- Taille de lot — grand lot = gradient moins bruité et meilleure utilisation du GPU, mais généralisation parfois moins bonne. Règle empirique : en multipliant le lot par \(k\), multiplier le taux d'apprentissage par \(k\) (ou \(\sqrt{k}\) avec Adam). Si la mémoire manque, l'accumulation de gradient simule un grand lot (module 25).
- Précision mixte — calculs en 16 bits avec accumulation en 32 bits : mémoire divisée par deux et accélération d'un facteur 2 à 3 sur GPU récent, sans perte mesurable de qualité.
import torch, torch.nn as nn
from torch.amp import autocast, GradScaler
modele = modele.to("cuda")
opt = torch.optim.AdamW(modele.parameters(), lr=3e-4, weight_decay=0.01)
sched = torch.optim.lr_scheduler.OneCycleLR(opt, max_lr=3e-4,
total_steps=n_epoques * len(train_loader))
scaler = GradScaler()
meilleure_val, patience, attente = float("inf"), 10, 0
for epoque in range(n_epoques):
modele.train() # active dropout et batch norm
for xb, yb in train_loader:
xb, yb = xb.to("cuda", non_blocking=True), yb.to("cuda", non_blocking=True)
opt.zero_grad(set_to_none=True)
with autocast("cuda", dtype=torch.bfloat16): # précision mixte
perte = critere(modele(xb), yb)
scaler.scale(perte).backward()
scaler.unscale_(opt) # avant l'écrêtage
nn.utils.clip_grad_norm_(modele.parameters(), 1.0)
scaler.step(opt); scaler.update(); sched.step()
modele.eval() # désactive dropout
with torch.no_grad(): # pas de graphe = plus rapide
val = sum(critere(modele(x.to("cuda")), y.to("cuda")).item()
for x, y in val_loader) / len(val_loader)
if val < meilleure_val: # EARLY STOPPING
meilleure_val, attente = val, 0
torch.save(modele.state_dict(), "meilleur.pt")
else:
attente += 1
if attente >= patience:
break
modele.load_state_dict(torch.load("meilleur.pt")) # on garde le MEILLEUR, pas le dernierLa première chose à faire avant tout entraînement long
Surapprendre volontairement un tout petit échantillon — seize exemples, sans augmentation ni régularisation. Si le modèle n'atteint pas une perte quasi nulle dessus, il y a un bug : étiquettes mal alignées, normalisation erronée, gradients non propagés, perte mal branchée, ou couche gelée par erreur. Aucun réglage d'hyperparamètre ne sauvera cela. Ce test de trente secondes évite des heures de calcul inutile, et c'est le premier réflexe à acquérir.
5. CNN et vision
Une convolution applique un même petit noyau à toutes les positions de l'image. Concrètement, sur une fenêtre 3×3 :
image (extrait) noyau 3×3 on multiplie terme à terme ┌───┬───┬───┐ ┌───┬───┬───┐ et on somme : │ 10│ 10│ 10│ │ -1│ 0│ 1│ ├───┼───┼───┤ ├───┼───┼───┤ (10×-1)+(10×0)+(10×1) + │ 10│ 10│ 80│ × │ -1│ 0│ 1│ = (10×-1)+(10×0)+(80×1) + ├───┼───┼───┤ ├───┼───┼───┤ (10×-1)+(10×0)+(80×1) │ 10│ 10│ 80│ │ -1│ 0│ 1│ = 140 → un CONTOUR VERTICAL détecté └───┴───┴───┘ └───┴───┴───┘ Ce noyau est un détecteur de contours verticaux. Un CNN n'utilise pas des noyaux écrits à la main : il les APPREND, et les premières couches convergent spontanément vers des détecteurs de contours et de textures.
Deux propriétés en découlent. Le partage de poids : un noyau 3×3 a neuf paramètres, quelle que soit la taille de l'image — là où une couche dense sur une image 224×224 en aurait des dizaines de millions. Et l'équivariance par translation : un motif déplacé produit une réponse déplacée. C'est le biais inductif exact des images, et la raison pour laquelle un CNN bat massivement un MLP à nombre de paramètres égal.
En empilant des couches, le champ réceptif — la zone de l'image influençant un neurone — s'élargit : deux couches 3×3 voient une zone 5×5, trois couches en voient 7×7. Les premières couches détectent des contours, les suivantes des textures, puis des parties d'objets. Le pooling (ou une convolution à pas 2) réduit la résolution spatiale tout en augmentant le nombre de canaux, ce qui concentre l'information sémantique.
Le tournant architectural est la connexion résiduelle de ResNet : \(y = \mathcal{F}(x) + x\). Le bloc n'apprend qu'une correction à l'identité, ce qui est plus facile que d'apprendre la transformation entière, et le terme \(+x\) ouvre au gradient un chemin direct vers les couches profondes — le gradient passe par l'addition sans être multiplié. C'est ce qui a rendu possible l'entraînement de réseaux de plus de cent couches, et l'idée est si générale qu'on la retrouve dans tous les transformers.
import torch, torchvision as tv
modele = tv.models.resnet50(weights="IMAGENET1K_V2")
for p in modele.parameters(): # 1. on gèle le tronc pré-entraîné
p.requires_grad = False
modele.fc = torch.nn.Linear(2048, n_classes) # nouvelle tête, entraînable
# 2. entraîner la tête seule quelques époques, avec un taux élevé (1e-3)
# 3. puis dégeler les derniers blocs et affiner avec un taux 10 à 100× plus faible
for p in modele.layer4.parameters():
p.requires_grad = True
opt = torch.optim.AdamW([
{"params": modele.layer4.parameters(), "lr": 1e-5}, # tronc : taux minuscule
{"params": modele.fc.parameters(), "lr": 1e-3}, # tête : taux normal
])6. RNN, LSTM, et leurs limites
Un réseau récurrent maintient un état caché \(h_t = \sigma(W_h h_{t-1} + W_x x_t + b)\), mis à jour pas à pas : à chaque instant, il combine ce qu'il vient de voir et ce qu'il a retenu. Élégant pour les séquences, mais handicapé par deux défauts. Le gradient, propagé à travers le temps, s'évanouit sur les longues dépendances — le même produit de matrices que plus haut, mais sur la longueur de la séquence. Et le calcul est intrinsèquement séquentiel, donc impossible à paralléliser sur la longueur : on ne peut pas calculer \(h_{100}\) sans avoir calculé les 99 précédents.
LSTM et GRU corrigent partiellement le premier point avec des portes — des vannes apprises qui régulent ce qui entre dans la mémoire, ce qui en sort et ce qui est oublié — mais pas le second. Les transformers ont remplacé les RNN presque partout en traitement du langage, précisément parce qu'ils traitent toute la séquence en parallèle. Les RNN gardent un intérêt en inférence à très faible latence sur séquences courtes, et sur les très petits jeux de données temporelles — où, cela dit, un gradient boosting sur variables de décalage reste souvent supérieur aux deux (module 17).
7. Transformers et attention
Le mécanisme d'attention répond à une question simple : pour produire la représentation du mot \(i\), quels autres mots faut-il regarder, et avec quel poids ? Dans la phrase « le chat que le chien poursuivait était noir », comprendre « était » demande de remonter à « chat », six mots plus tôt — et un RNN doit faire transiter cette information par tous les mots intermédiaires.
Chaque position projette son vecteur en trois rôles, par trois matrices apprises : une requête \(Q\) (« ce que je cherche »), une clé \(K\) (« ce que je propose ») et une valeur \(V\) (« ce que je transmets »). L'analogie est celle d'un annuaire : on compare sa requête à toutes les clés, et l'on récupère un mélange des valeurs correspondantes, pondéré par la ressemblance.
1. QKᵀ produit scalaire entre chaque requête et chaque clé
→ matrice n×n de scores de compatibilité
2. / √d_k mise à l'échelle. INDISPENSABLE : en dimension d_k, les produits
scalaires ont une variance ∝ d_k ; sans division, le softmax
sature (un poids à 1, tous les autres à 0) et le gradient disparaît.
3. softmax chaque ligne devient une distribution de poids sommant à 1
4. × V moyenne pondérée des valeurs : voilà la nouvelle représentationL'attention multi-têtes réalise plusieurs fois cette opération en parallèle dans des sous-espaces différents, chaque tête pouvant se spécialiser (accord syntaxique, coréférence, position relative), puis concatène les résultats. Comme l'opération est invariante à l'ordre — permuter les mots permute simplement les lignes —, il faut injecter la position explicitement : encodages sinusoïdaux à l'origine, positions relatives ou rotatives (RoPE) aujourd'hui.
x = x + MultiHeadAttention(LayerNorm(x)) # connexion résiduelle + pré-normalisation x = x + FeedForward(LayerNorm(x)) # MLP 2 couches, expansion ×4, GELU Encodeur seul BERT — compréhension, classification, embeddings (module 22) Décodeur seul GPT — génération, attention CAUSALE (on ne regarde que le passé) Encodeur-décodeur T5, traduction — l'architecture d'origine
Le coût : l'attention est quadratique en longueur de séquence, \(O(n^2 d)\), puisqu'on compare chaque position à toutes les autres. C'est ce qui borne la taille du contexte, et ce qui a engendré une industrie entière de variantes — attention creuse, FlashAttention (exacte, mais optimisée pour la hiérarchie mémoire du GPU, module 25), et modèles à espace d'états comme Mamba, linéaires en \(n\). Le bénéfice : chaque position accède directement à toutes les autres, sans le chemin de longueur \(n\) d'un RNN, et l'ensemble se parallélise — c'est ce qui a rendu possible l'entraînement à l'échelle actuelle.
Le Vision Transformer applique la même recette aux images en les découpant en imagettes traitées comme des jetons. Il dépasse les CNN au-delà d'un certain volume de données, mais reste en retrait sur les petits jeux : n'ayant pas le biais inductif de la convolution, il doit apprendre la localité à partir des exemples (module 15).
8. Autoencodeurs et représentations
Un autoencodeur compresse l'entrée dans un espace latent de faible dimension, puis la reconstruit. Avec des couches linéaires et une perte quadratique, il retrouve exactement le sous-espace de la PCA (module 8) ; avec des non-linéarités, il capture des variétés courbes. Usages : réduction de dimension non linéaire, débruitage (on entraîne à reconstruire une entrée propre depuis une entrée bruitée), et détection d'anomalies par erreur de reconstruction — ce qui est mal reconstruit est ce que le modèle n'a jamais vu.
Plus important encore : l'apprentissage auto-supervisé, qui fabrique une tâche à partir des données non annotées — prédire un mot masqué, rapprocher deux vues augmentées d'une même image (module 13). C'est le principe qui a permis de pré-entraîner sur des corpus gigantesques sans annotation humaine, et qui produit les embeddings utilisés en recherche sémantique (module 22).
9. PINN : apprendre sous contrainte physique
Les Physics-Informed Neural Networks répondent à une situation fréquente en ingénierie : on connaît les équations qui régissent le système, mais on a peu de données — ou l'inverse, on a des mesures et un paramètre physique inconnu à identifier. L'idée est d'ajouter le résidu de l'équation dans la fonction de perte : le réseau doit à la fois coller aux données et satisfaire la physique.
Pour une EDP \(\mathcal{N}[u](x,t) = 0\), on approche la solution par un réseau \(u_\theta(x,t)\) et on minimise :
Le point élégant : les dérivées de l'EDP sont obtenues par différentiation automatique du réseau lui-même (module 3), exactement et en tout point — pas de maillage, pas de schéma aux différences finies, pas d'erreur de discrétisation. Les points de collocation où l'on évalue le résidu peuvent être tirés au hasard dans le domaine, et ils ne coûtent aucune donnée expérimentale.
import torch, torch.nn as nn
m, c, k = 1.0, 0.4, 20.0 # paramètres physiques connus
reseau = nn.Sequential( # tanh : dérivées d'ordre 2 lisses et non nulles
nn.Linear(1, 64), nn.Tanh(), # (avec ReLU, la dérivée seconde serait nulle
nn.Linear(64, 64), nn.Tanh(), # partout — inutilisable pour une EDP d'ordre 2)
nn.Linear(64, 64), nn.Tanh(),
nn.Linear(64, 1),
)
opt = torch.optim.Adam(reseau.parameters(), lr=1e-3)
def residu(t):
t = t.requires_grad_(True)
u = reseau(t)
# create_graph=True : on dérivera ENCORE cette dérivée (pour u'' et pour backward)
u_t = torch.autograd.grad(u, t, torch.ones_like(u), create_graph=True)[0]
u_tt = torch.autograd.grad(u_t, t, torch.ones_like(u_t), create_graph=True)[0]
return m * u_tt + c * u_t + k * u # doit valoir 0 partout
t0 = torch.zeros(1, 1, requires_grad=True) # conditions initiales : u(0)=1, u'(0)=0
for etape in range(20_000):
tf = torch.rand(256, 1) * 2.0 # collocation ALÉATOIRE sur [0, 2]
u0 = reseau(t0)
u0_t = torch.autograd.grad(u0, t0, torch.ones_like(u0), create_graph=True)[0]
perte = (residu(tf) ** 2).mean() + (u0 - 1.0) ** 2 + u0_t ** 2
opt.zero_grad(); perte.backward(); opt.step()Ce que les PINN apportent : une solution continue et différentiable, donc évaluable et dérivable partout ; l'absence de maillage, avantage décisif en géométrie complexe ou en grande dimension ; l'assimilation naturelle de données expérimentales bruitées ; et surtout la résolution de problèmes inverses — en déclarant un paramètre physique comme entraînable (c = nn.Parameter(torch.tensor(0.1))), le réseau l'identifie à partir de quelques mesures. C'est le cas d'usage où ils sont réellement compétitifs (module 21).
10. Limites
- Appétit en données et en calcul — sans pré-entraînement, un réseau profond sur 2 000 exemples surapprend systématiquement.
- Opacité — l'attribution par gradients ou par SHAP donne des indications, pas une explication vérifiable.
- Incertitude mal calibrée — un réseau est typiquement trop confiant, y compris sur des entrées hors distribution. Remèdes : température de calibration, ensembles profonds, dropout à l'inférence, ou modèles probabilistes (module 10).
- Fragilité — les exemples adverses montrent qu'une perturbation imperceptible peut renverser une prédiction (module 27).
- Reproductibilité — non-déterminisme des noyaux GPU, sensibilité aux graines : deux entraînements identiques ne donnent pas exactement le même modèle (module 26).
- Empreinte — coût énergétique et financier de l'entraînement comme de l'inférence, qui doit entrer dans l'arbitrage (module 25).
Ce qu'il faut retenir du module
- Choisir une architecture, c'est choisir un biais inductif : convolution pour la localité, attention pour les dépendances longues.
- Sans non-linéarité, la profondeur ne sert à rien ; l'initialisation conditionne la propagation du signal.
- La rétropropagation coûte le prix d'une passe avant, ce qui rend l'échelle actuelle possible.
- Le taux d'apprentissage domine tous les autres hyperparamètres ; commencer par surapprendre 16 exemples pour valider la chaîne.
- Connexions résiduelles, normalisation et écrêtage résolvent les pathologies du gradient.
- Transfer learning par défaut : entraîner de zéro est rarement le bon choix.
- L'attention est quadratique en longueur de séquence — c'est la contrainte structurante des LLM.
- Les PINN brillent sur les problèmes inverses et l'assimilation de données, pas en remplacement d'un solveur.