Partie 6 · Apprendre
Le sur-apprentissage
Avec seulement 1 000 images d'entraînement, le réseau des organes finit par les apprendre par cœur : il connaît ses images, mais plus les nouvelles. Dans l'exercice 6, tu vas le voir sur les courbes, appliquer le remède du cours (garder les poids de la meilleure époque de validation), puis mesurer la note de test, une seule fois.
Le petit jeu : Subset(train_set, range(1000)) garde les 1 000 premières images d'un jeu ; un DataLoader par paquets de 64, mélangés, donne 16 paquets par époque (1 000 / 64 = 15,6 arrondi vers le haut). On entraîne 60 époques et on note, à chaque époque, la perte d'entraînement et la perte de validation (sur le jeu de validation, via val_loader).
À toi de coder
Lire les courbes
(Lecture usuelle, reprise du tableau de la partie 9 du polycopié, non fourni.)
| Ce que tu vois | Ce que ça veut dire |
|---|---|
| Entraînement et validation baissent ensemble | le réseau apprend : continue |
| Entraînement baisse, validation remonte | le réseau apprend par cœur : sur-apprentissage |
| Les deux restent hautes | le réseau n'apprend pas assez (boucle, pas, capacité) |
Le contrôle du notebook (verifier_sur_apprentissage) utilise la règle suivante : la perte d'entraînement finale tombe sous 0,1, la perte de validation finale dépasse 1,1 fois son minimum, et ce minimum n'est pas à la dernière époque. Tu l'as déjà observée en petit à l'exercice 5 : l'entraînement passe de 0,627 à 0,056 (sous 0,1), alors que la validation passe de 0,388 à 0,547, plus de 1,1 fois son minimum 0,388 (atteint à l'époque 1).
À toi de coder
Garder les poids de la meilleure époque
modele.state_dict() renvoie tous les poids du modèle, mais ce sont les poids vivants : ils continuent de changer à chaque pas. Pour en garder une photo figée, on les copie avec copy.deepcopy(...). Plus tard, modele.load_state_dict(poids) remet ces poids dans le modèle.
La boucle : à chaque époque, si la perte de validation est la plus basse vue jusqu'ici, on note le numéro de l'époque (epoque + 1) et on garde une copie figée des poids. On part de meilleure_perte = float("inf") (l'infini : la première perte fera forcément mieux). À la fin, on remet les meilleurs poids dans le modèle.
À toi de coder
La note finale, une seule fois
Les images de test n'ont servi à rien jusqu'ici : ni à apprendre, ni à choisir l'époque. On mesure l'accuracy de test, avec les meilleurs poids, une seule fois, à la toute fin (un DataLoader sur test_set, par paquets de 256, et evaluer(modele, test_loader)). Le jeu de test d'OrganAMNIST compte 17 778 images.
Pourquoi une seule fois ? Réponse b du notebook : parce qu'on a choisi la meilleure époque grâce à la validation, sa note est donc un peu trop optimiste ; le test, jamais utilisé avant, donne une note honnête. Ce n'est pas une question de temps de calcul (réponse a), ni d'organes différents (réponse c : les trois groupes contiennent les mêmes 11 organes, mais des scanners différents).
Pour aller plus loin (notebook) : entraîne le même réseau sur les 34 561 images pendant 5 époques. Quelle accuracy de test obtiens-tu ? Qu'en conclus-tu sur le meilleur remède au sur-apprentissage ? Le notebook laisse la conclusion ouverte (piste, non vérifiée ici : plus d'images d'entraînement).