Aller au contenu
Apprendre.
  • M1 · toutes les matières15 matières : Préparation de données, API & sécurité, CI/CD, Docker, Merise, Dataviz, KNIME, ML appliqué : projet LoL, SQL & UML, SQL avancé, Machine Learning, Git, IA frugale & responsable, Qualité des données, MathématiquesAnnée
  • M2 · toutes les matières4 matières : Deep Learning, AI Act, Comex & Fundraising, Gouvernance & DataMeshAnnée
  • Deep LearningM2 · 4 modules · Réseaux de neurones, CNN, texte, modèles génératifs.Matière
  • Préparation de donnéesM1 · 3 modules · Nettoyer, transformer et fusionner des données avec Python.Matière
  • API & sécuritéM1 · 2 modules · Consommer, concevoir et sécuriser des API.Matière
  • CI/CDM1 · 1 module · Intégration et livraison continues.Matière
  • DockerM1 · 3 modules · Conteneurs, images, volumes, réseaux, Compose.Matière
  • MeriseM1 · 2 modules · Modéliser une base : MCD, MLD, MPD.Matière
  • DatavizM1 · 2 modules · Visualiser pour comprendre et décider.Matière
  • KNIMEM1 · 1 module · Explorer et nettoyer des données en workflow.Matière
  • ML appliqué : projet LoLM1 · 2 modules · Du besoin métier au POC de vision par ordinateur.Matière
  • SQL & UMLM1 · 3 modules · Modèles UML et requêtes SQL.Matière
  • SQL avancéM1 · 3 modules · Jointures, fenêtres, CTE, optimisation.Matière
  • Machine LearningM1 · 3 modules · Régression, classification, segmentation, projet.Matière

↑↓ naviguer↵ ouvre le résultat en surbrillanceesc fermer

Partie 3 · Voir

Éviter le par-cœur

Un vrai problème de dépistage : PneumoniaMNIST, des radiographies du thorax d'enfants de 1 à 5 ans (hôpital de Canton). Le jeu d'entraînement compte 4 708 radiographies, plus de 7 fois moins que les coupes d'organes ; environ 3 sur 4 montrent une pneumonie (3 494 sur 4 708). Répondre toujours « pneumonie » donne déjà 390 bonnes réponses sur 624 au test, soit 62,5 % : la référence à battre. Une seule question : pneumonie, oui ou non.

Le même CNN sert, avec une seule sortie : nn.Linear(32 * 7 * 7, 1) et la perte nn.BCEWithLogitsLoss (sigmoïde, puis −log(p)). Pour un enfant malade, p = a ; pour un enfant sain, p = 1 − a, où a est la sortie de la sigmoïde. Le CNN a maintenant 6 369 paramètres. Vérifie-le, et recode la perte.

À toi de coder

Une seule sortie : paramètres et perte binaire

Pour répondre oui ou non, la dernière couche n'a plus 11 sorties mais une. Calcule d'abord total, le nombre de paramètres du CNN à une sortie : les deux convolutions comptent comme avant (160 et 4 640) et la couche dense lit toujours 1 568 nombres, mais n'a qu'une sortie (donc un seul biais).

Puis écris perte(score, y) : la sigmoïde donne a = 1 / (1 + exp(−score)), la probabilité de pneumonie ; p est la probabilité donnée à la bonne réponse (a si y == 1, 1 − a si y == 0) ; la perte vaut −log(p), comme en J1.

Ctrl/⌘+Entrée

Entraîné sur peu d'images, ce CNN apprend par cœur : la perte d'entraînement baisse sans cesse, mais celle de test baisse, atteint un minimum, puis remonte. Le remède d'hier (garder les poids de la meilleure époque) a un défaut : pour choisir l'époque, on a regardé le test, qui n'est plus « jamais vu ». C'est comme laisser un élève passer le même examen 30 fois et ne retenir que sa meilleure note.

D'où un troisième groupe : l'entraînement (4 708 images) apprend les poids ; la validation (524) sert à choisir (époque, réglages, seuil) ; le test (624) note, une seule fois. La validation, c'est l'examen blanc ; le test, c'est l'examen. L'early stopping : à chaque époque on mesure la perte de validation ; si c'est la meilleure, on garde une copie des poids ; si elle ne baisse plus depuis plusieurs époques (la patience, par exemple 5), on arrête et on recharge la meilleure copie (copy.deepcopy(model.state_dict()) : sans deepcopy, on garde un lien vers les poids vivants).

Courbes d'allure typique, simulées pour illustrer : ce ne sont pas des mesures du cours (les vraies courbes viennent du notebook). Réduis le nombre d'images pour provoquer le par-cœur, puis active les remèdes et l'early stopping.

À toi de coder

Early stopping avec patience

(Valeurs inventées pour l'exercice, pas des mesures du cours.) L'early stopping est une petite machine à états : on retient la meilleure perte de validation vue jusqu'ici, et on compte les époques sans progrès. Écris early_stopping(pertes_val, patience) qui renvoie le couple (meilleure_epoque, epoque_arret), en numérotant les époques à partir de 1. Une perte n'est une amélioration que si elle est strictement plus basse ; une amélioration remet le compteur à 0 ; quand le compteur atteint la patience, on s'arrête. Si on ne s'arrête jamais, epoque_arret est le nombre total d'époques.

Ctrl/⌘+Entrée

L'augmentation : plus d'images, sans en prendre de nouvelles. À chaque époque, chaque radiographie est légèrement transformée au hasard : T.RandomAffine(degrees=10, translate=(0.1, 0.1)) (jusqu'à 10° et 10 % de décalage ; valeurs courantes, à régler sur la validation). Le réseau ne revoit jamais exactement la même image, et il apprend qu'un petit décalage ne change pas la réponse. Seulement sur l'entraînement : la validation et le test restent intacts.

Et retourner l'image comme un miroir ? Pour un chat, oui ; pour une radiographie, non : le cœur changerait de côté, le réseau apprendrait sur des thorax qui n'existent presque pas. Une augmentation doit produire des images plausibles : le choix est médical autant qu'informatique.

Le dropout (nn.Dropout(0.5), avant la dernière couche) : pendant l'apprentissage, à chaque pas, chaque neurone est éteint au hasard, souvent avec une chance sur deux. Le réseau ne peut plus compter sur une petite équipe de neurones qui auraient retenu les détails d'une image ; à l'évaluation, tous travaillent.

Pourquoi doubler les valeurs gardées ? Un neurone reçoit 10 valeurs égales à 1. À l'évaluation : somme 10. À l'apprentissage, avec une valeur éteinte sur deux : 4 dans le tirage du cours (5 en moyenne). Sans correction, il apprendrait avec des entrées deux fois plus petites que celles de l'évaluation. On multiplie donc les valeurs gardées par 1 / (1 − p) = 1 / (1 − 0,5) = 2 : somme 8 pour ce tirage, 10 en moyenne. Avec p = 0,2, le facteur serait 1,25.

Le dropout ne sait pas dans quelle phase on est : on le lui dit. model.train() avant chaque époque d'apprentissage (le dropout tire au sort et double) ; model.eval() avant de mesurer validation ou test (il ne fait rien). Oublier model.eval() est l'erreur classique : la note change d'une mesure à l'autre.

Les 10 valeurs égales à 1 de la diapositive. À p = 0,5 tu retrouves le tirage du cours : 6 éteintes, 4 gardées doublées, somme 8. Bascule en model.eval() : somme 10. Change p pour voir le facteur 1 / (1 − p).

À toi de coder

Appliquer le dropout à la main

Le tirage au hasard est fourni (liste garde : 1 = neurone gardé, 0 = éteint), pour que le résultat soit déterministe. Écris facteur(p) (la correction du cours) et dropout(valeurs, garde, p, train) : en mode apprentissage, chaque valeur gardée est multipliée par le facteur et chaque valeur éteinte devient 0 ; en mode évaluation, les valeurs passent telles quelles, sans tirage ni correction.

Ctrl/⌘+Entrée

Le weight decay ramène à chaque pas chaque poids un peu vers 0 : w ← w × (1 − η λ), puis le pas habituel de la descente. Avec η = 0,001 et λ = 0,01 : × 0,99999 à chaque pas, presque rien, mais un poids dont la perte n'a pas besoin finit près de 0. En PyTorch : AdamW(model.parameters(), lr=0.001, weight_decay=0.01).

Pourquoi tous les poids ne baissent pas pareil ? Le rappel est le même pour tous, mais le pas de descente qui suit dépend de la pente de chaque poids. Exemple jouet du cours (facteur exagéré 0,99, η = 0,1, deux poids valant 2) : le poids utile (perte (w − 2)²) fait 2 × 0,99 = 1,98, pente 2 × (1,98 − 2) = −0,04, puis 1,98 − 0,1 × (−0,04) = 1,984 et se stabilise à 1,923 ; le poids inutile (perte indépendante de lui) tombe à 1,81 après 10 pas et 0,01 après 500.

À toi de coder

Le weight decay sur deux poids

Tu rejoues l'exemple jouet du cours. À chaque pas : d'abord le rappel vers 0 (le poids est multiplié par f = 0.99), puis le pas de descente avec η = 0,1. Le poids utile a la perte (w − 2)², donc la pente 2 * (w - 2), calculée après le rappel, comme dans le cours ; le poids inutile n'a pas de pente. Complète les deux fonctions, puis fais 500 pas depuis w = 2 pour chaque poids.

Ctrl/⌘+Entrée