ML Atlas

Le machine learning en partant de zéro · Leçon 3.6 · 19 sur 33 leçons prêtes · 12 min

Arrêt précoce

En bref

Un réseau entraîné trop longtemps mémorise les étiquettes fausses. Avec 20 % d’étiquettes au hasard, 100 époques font passer le test de 86,1 % à 76,3 %.

Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
De la leçon 3.5 : Régler les hyperparamètres sans tricher Comment évaluer honnêtement un modèle dont vous avez choisi les hyperparamètres par validation croisée ?

Voir la réponse

Bonne réponse : Le vérifier sur un test mis de côté ou par une validation croisée imbriquée autour du réglage

Le test mis de côté et la validation croisée imbriquée n’ont pas participé au choix. Dans le code, la validation croisée ordinaire donne 94,0 %, l’imbriquée 91,9 %.

De la leçon 3.4 : Régularisation : ridge et lasso En quoi la pénalité ridge diffère-t-elle de la pénalité lasso ?

Voir la réponse

Bonne réponse : Ridge tire tous les poids vers zéro, le lasso en met certains exactement à zéro

Ridge pénalise les carrés des poids et n’en annule aucun ; le lasso pénalise les valeurs absolues et annule les poids un par un. Dans le lab, ridge pour α = 398 a 10 poids non nuls, le lasso pour α = 15,8 seulement 3.

Un réseau de neurones apprend par époques : une époque est un passage sur tous les exemples d’entraînement. Après chaque époque, la perte d’entraînement baisse en général. La question de la leçon 3.1 revient sous une autre forme : combien d’époques, c’est trop ? L’arrêt précoce y répond avec l’ensemble de validation : l’entraînement s’arrête quand la perte de validation cesse de baisser, et le modèle revient à sa meilleure époque.

Prédisez, puis vérifiez Un petit réseau de neurones apprend à reconnaître des chiffres manuscrits sur 299 images. Pour 20 % d’entre elles, l’étiquette est un chiffre au hasard au lieu du vrai. La perte de validation la plus basse arrive à l’époque 28. Vous entraînez pourtant 100 époques au lieu de vous arrêter à la meilleure. Que devient l’exactitude au test ?
Quel est votre degré de certitude ?

Labo interactif

Ce labo interactif fonctionne dans un navigateur avec JavaScript activé. Le texte qui l’entoure décrit ce qu’il montre.

Voir la réponse

Bonne réponse : Elle passe de 86,1 % à 76,3 %, parce que le réseau mémorise aussi les étiquettes fausses

Les poids de l’époque 28 obtiennent 86,1 % sur les 997 images de test, après 100 époques 76,3 % : 9,7 points de moins. Pendant ce temps, la perte de validation monte de 0,48 à 0,84, et des 51 étiquettes fausses, le réseau finit par toutes les répéter.

À vous de jouer

  • Le labo s’ouvre sur les étiquettes propres. Passez aux étiquettes au hasard et gardez une patience de 5. À quelle époque l’entraînement s’arrête-t-il, quels poids sont gardés, et est-ce la meilleure époque de tout le parcours ?
  • Montez la patience à 10. Qu’est-ce qui change dans l’époque gardée et dans l’exactitude au test ?
  • Revenez aux étiquettes propres. Combien coûte maintenant l’entraînement jusqu’au bout ?

Une fois vérifié dans le lab, mettons un nom sur ce que vous voyez.

L’idée en quelques mots

Au début de l’entraînement, le réseau apprend ce que beaucoup d’images ont en commun : la forme d’un zéro, d’un huit, d’un sept. Les pertes d’entraînement et de validation baissent ensemble. Puis le réseau se met à ajuster des exemples isolés, y compris ceux dont l’étiquette est fausse. La perte d’entraînement continue de baisser, la perte de validation commence à monter. C’est le surapprentissage de la leçon 3.1, mais le long des époques au lieu du nombre de paramètres.

L’arrêt précoce surveille la perte de validation. Il retient l’époque à la perte la plus basse et compte les époques sans amélioration. Quand il y en a autant que la patience, l’entraînement s’arrête et le réseau revient aux poids de la meilleure époque. Dans le lab, avec une patience de 10, l’entraînement s’arrête à l’époque 38 et l’on garde les poids de l’époque 28 : 86,1 % au test au lieu de 76,3 % après 100 époques.

Trop peu de patience nuit aussi. La courbe de validation tremble d’une époque à l’autre. Avec une patience de 5, l’entraînement s’arrête dès l’époque 23 et garde les poids de l’époque 18 (85,0 % au test), alors que la meilleure était l’époque 28.

Jak to policzono
  • Chiffres : Optical Recognition of Handwritten Digits, UCI, licence CC BY 4.0. 1797 images de 8×8 pixels.
  • Découpage stratifié : 299 images pour apprendre, 501 pour la validation, 997 pour le test. Dans la version bruitée, chaque étiquette d’entraînement est remplacée, avec une probabilité de 20 %, par un chiffre au hasard : 51 étiquettes ont changé (un chiffre au hasard tombe parfois sur le vrai).
  • Réseau 64 → 32 → 10, ReLU, entropie croisée, SGD avec un momentum de 0,9, pas de 0,05, lots de 32 images, 100 époques. Perte de validation calculée après chaque époque.
  • La validation et le test ont les vraies étiquettes. Le bruit est seulement dans les données d’entraînement.

Pourquoi ça marche

Un exemple à l’étiquette fausse est difficile pour le réseau : l’image ressemble à un trois, mais l’étiquette dit « sept ». Pour réduire la perte sur un tel exemple, le réseau doit apprendre une règle qui ne convient qu’à lui. Il le fait en général tard, une fois les motifs faciles et communs acquis. Dans le lab, le réseau répète 10 des 51 étiquettes fausses à l’époque 28, et les 51 après 100 époques. Sur ses propres données d’entraînement, il a alors 99,7 % d’exactitude : il est d’accord même avec les étiquettes fausses.

Les règles ajustées à des étiquettes fausses gâchent les réponses sur de nouvelles images. L’ensemble de validation a les vraies étiquettes, donc sa perte monte précisément quand le réseau commence à apprendre le bruit. C’est pour cela que c’est elle, et non la perte d’entraînement, qui dit quand s’arrêter.

Ce n’est pas un hasard d’un seul passage. Dans le code plus bas, la même expérience tourne dans scikit-learn sur 10 autres découpages et tirages du bruit : la meilleure époque tombe entre 13 et 23, et entraîner jusqu’à 100 époques fait baisser l’exactitude de test dans chacun des 10 passages, en moyenne de 87,2 % à 76,4 %. La meilleure époque du lab (28) sort de cet intervalle, car elle dépend aussi des poids de départ et de l’ordre des lots : le même réseau que dans le lab, avec 9 autres graines aléatoires, est au mieux entre les époques 12 et 25, et entraîner jusqu’à 100 époques fait baisser l’exactitude de test à chaque fois.

Erreur fréquente

Vrai ou faux : « entraîner plus longtemps donne toujours un meilleur modèle ». Faux. Entraîner plus longtemps colle toujours mieux aux données d’entraînement, mais pas aux nouvelles. Avec des étiquettes au hasard, 100 époques donnent 99,7 % d’exactitude à l’entraînement et 76,3 % au test, alors que s’arrêter à l’époque 28 donne 86,1 % au test.

Une remarque dans l’autre sens : avec des étiquettes propres, entraîner jusqu’au bout ne gâche presque rien. La perte de validation la plus basse arrive à l’époque 30 (93,9 % au test), et après 100 époques l’exactitude est de 94,5 %. L’arrêt précoce ne sauve pas toujours l’exactitude, mais il fait toujours gagner du temps et protège contre des données moins bonnes que vous ne le pensez.

Quiz

Trois questions pour vérifier vos acquis. Choisissez une réponse ou dépliez la solution sous chaque question. Au clavier : les flèches choisissent, Entrée ou Espace valide.

1. Sur quoi l’arrêt précoce se base-t-il pour décider quand arrêter l’entraînement ?
Voir la réponse

Bonne réponse : Sur la perte de validation : il s’arrête quand elle ne baisse plus

La perte d’entraînement baisse presque jusqu’au bout, même quand le réseau apprend du bruit. La perte de validation, calculée sur des données hors entraînement, monte quand le modèle commence à surapprendre.

2. Avec 20 % d’étiquettes au hasard, le réseau a 99,7 % à l’entraînement et 76,3 % au test après 100 époques. Qu’est-ce que cela veut dire ?
Voir la réponse

Bonne réponse : Le réseau a aussi mémorisé les étiquettes fausses, et cela gâche ses réponses sur de nouvelles données

Une exactitude d’entraînement élevée avec du bruit dans les étiquettes veut dire que le réseau a ajusté le bruit aussi. Les poids de l’époque 28 obtiennent 86,1 % au test.

3. Une patience de 5 arrête l’entraînement à l’époque 23 et garde l’époque 18, alors que la perte la plus basse est à l’époque 28. Pourquoi ?
Voir la réponse

Bonne réponse : Parce que la courbe tremble et qu’une patience trop courte prend un tremblement pour le minimum

La perte de validation ne baisse pas régulièrement : quelques époques moins bonnes d’affilée peuvent être du hasard. Avec une patience de 10, l’entraînement atteint l’époque 28.

À retenir

  • Une époque est un passage sur les données d’entraînement ; la perte d’entraînement baisse presque toujours, la perte de validation non.
  • L’arrêt précoce interrompt l’entraînement quand la perte de validation ne s’améliore pas pendant quelques époques (la patience) et revient aux meilleurs poids.
  • Entraîner trop longtemps sur des étiquettes fausses apprend le bruit au réseau : le test passe de 86,1 % à 76,3 %.
  • Trop peu de patience arrête l’entraînement sur un tremblement fortuit de la courbe.

Pour aller plus loin : formule, code, pratique

Les maths

Perte de validation après l’époque e : L_val(e) = −(1/m) · Σᵢ log p_e(yᵢ | xᵢ) sur m images de validation (entropie croisée).

La règle avec une patience P : e = argmin_{e ≤ t} L_val(e) ; l’entraînement s’arrête à la première époque t telle que t − e ≥ P et renvoie les poids w(e). Si une telle époque n’arrive pas, il renvoie w(e) sur tout le parcours.

L’arrêt précoce agit un peu comme la pénalité de la leçon 3.4. Avec une descente de gradient à petit pas, les poids partent près de zéro et s’en éloignent à chaque époque. Moins d’époques, ce sont des poids plus petits : pour un modèle linéaire à perte quadratique, s’arrêter après t pas a à peu près le même effet que ridge avec un α de l’ordre de 1 / (pas · t).

En code (Python)

La même expérience dans scikit-learn : 10 découpages et tirages du bruit différents, un réseau 64 → 32 → 10 entraîné époque par époque, en gardant les poids de l’époque à la perte de validation la plus basse.

import copy
import numpy as np
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
from sklearn.metrics import log_loss

X, y = load_digits(return_X_y=True)
X = X / 16
def run(seed):  # 300 chiffres pour apprendre, 500 pour la validation, les 997 autres pour le test
    used, te = train_test_split(np.arange(len(y)), train_size=800, stratify=y, random_state=seed)
    tr, va = train_test_split(used, test_size=500, stratify=y[used], random_state=seed)
    rng = np.random.default_rng(seed)
    noisy = y[tr].copy()
    flip = rng.random(len(tr)) < 0.2  # 20 % des étiquettes d’entraînement remplacées par un chiffre au hasard
    noisy[flip] = rng.integers(0, 10, flip.sum())
    net = MLPClassifier(hidden_layer_sizes=(32,), solver="sgd", learning_rate_init=0.05, momentum=0.9, batch_size=32, alpha=0, random_state=seed)
    best, best_loss = None, np.inf
    for epoch in range(1, 101):
        net.partial_fit(X[tr], noisy, classes=np.arange(10))
        loss = log_loss(y[va], net.predict_proba(X[va]), labels=np.arange(10))
        if loss < best_loss:
            best, best_loss, best_epoch = copy.deepcopy(net), loss, epoch  # l’arrêt précoce garde les poids de la meilleure époque
    return best_epoch, best.score(X[te], y[te]), net.score(X[te], y[te])
r = np.array([run(s) for s in range(10)])
print(f"10 splits and noise draws: lowest validation loss at epoch {r[:, 0].min():.0f} to {r[:, 0].max():.0f}; test at that epoch {r[:, 1].mean():.1%}, after 100 epochs {r[:, 2].mean():.1%}; lower after 100 in {(r[:, 2] < r[:, 1]).sum()} of 10")

Sortie

10 splits and noise draws: lowest validation loss at epoch 13 to 23; test at that epoch 87.2%, after 100 epochs 76.4%; lower after 100 in 10 of 10

Les découpages, les poids de départ et le bruit diffèrent de ceux du lab, donc les nombres aussi. L’image est la même : la meilleure époque arrive tôt (entre 13 et 23), et entraîner jusqu’à 100 époques fait baisser l’exactitude de test dans les 10 passages, en moyenne de 87,2 % à 76,4 %.

Pour les praticiens
  • Dans Keras : EarlyStopping(monitor="val_loss", patience=10, restore_best_weights=True). Sans restore_best_weights=True, on garde les poids de la dernière époque, pas ceux de la meilleure.
  • Dans PyTorch, vous écrivez la boucle vous-même : après chaque époque, calculez la perte de validation et gardez une copie des poids quand elle est la plus basse.
  • Dans scikit-learn : MLPClassifier(early_stopping=True, n_iter_no_change=...) met de côté une partie des données d’entraînement pour la validation ; il surveille l’exactitude de validation, pas la perte. En gradient boosting, la même idée s’appelle n_iter_no_change ou early_stopping_rounds.
  • Le nombre d’époques choisi en validation est lui aussi un hyperparamètre : le score de validation à la meilleure époque est un peu gonflé (leçon 3.5), donc faites l’évaluation finale sur un test mis de côté.

Aller plus loin dans l’Atlas

Articles de l’encyclopédie sur les notions de cette leçon :