Aller au contenu principal

Module 6 — Rappels : point de contrôle, arrêt anticipé, planification du taux

Un rappel est un objet que fit invoque à des instants précis : début et fin d'époque, de lot, d'entraînement. C'est le moyen d'agir sur un entraînement en cours sans en réécrire la boucle. Trois rappels suffisent à couvrir presque tous les besoins, et leurs réglages par défaut sont rarement les bons.

Sauvegarder le meilleur état, pas le dernier

Un entraînement de plusieurs heures qui s'interrompt sans point de contrôle est perdu. Mais l'enjeu principal est ailleurs : le modèle de la dernière époque n'est presque jamais le meilleur.

from tensorflow import keras

point_de_controle = keras.callbacks.ModelCheckpoint(
filepath="modeles/meilleur.keras",
monitor="val_loss",
mode="min",
save_best_only=True,
save_weights_only=False,
verbose=1,
)

save_best_only=True est le réglage qui compte. Sans lui, chaque époque écrase le fichier, et la dernière écriture correspond à l'état final — souvent surajusté. Avec lui, le fichier contient l'époque où la métrique surveillée était la meilleure.

monitor et mode vont par paire et se contredisent facilement. Surveiller val_loss en mode="max" conserve le pire modèle, sans qu'aucun message ne le signale. La règle : une perte se minimise, une exactitude se maximise. En cas de doute, mode="auto" déduit la direction du nom de la métrique.

Arrêter quand la validation cesse de progresser

EarlyStopping interrompt l'entraînement quand la métrique surveillée stagne, ce qui évite de brûler du temps de calcul et limite le surajustement.

arret = keras.callbacks.EarlyStopping(
monitor="val_loss",
patience=10,
min_delta=1e-4,
restore_best_weights=True,
verbose=1,
)

restore_best_weights=True est indispensable et vaut False par défaut. Sans lui, l'entraînement s'arrête après patience époques de stagnation, et le modèle en mémoire est celui de la dernière époque, c'est-à-dire dix époques après le meilleur point. Vous avez détecté le bon moment d'arrêt et conservé le mauvais modèle.

La patience se règle en fonction du bruit des courbes. Trop courte, elle coupe sur une fluctuation ordinaire alors que la perte allait redescendre. Trop longue, elle ne sert plus à rien. Un ordre de grandeur raisonnable est cinq à quinze époques, à ajuster après avoir observé la variabilité de la validation.

min_delta définit ce qui compte comme une amélioration. Sans lui, un gain de 10810^{-8} réinitialise le compteur de patience et l'arrêt ne se déclenche jamais.

Deux rappels qui se contredisent

ModelCheckpoint et EarlyStopping doivent surveiller la même métrique. Surveiller val_loss pour l'un et val_accuracy pour l'autre produit un arrêt gouverné par une grandeur et une sauvegarde gouvernée par une autre : le fichier conservé n'a alors aucun rapport avec le moment où l'entraînement s'est arrêté.

Réduire le taux d'apprentissage au bon moment

Un taux fixe finit par empêcher la convergence fine : les pas restent trop grands pour se poser dans le minimum. Deux stratégies existent.

La réactive observe la validation et réduit le taux quand elle stagne :

reduction = keras.callbacks.ReduceLROnPlateau(
monitor="val_loss",
factor=0.5,
patience=5,
min_lr=1e-6,
verbose=1,
)

La programmée suit une courbe décidée d'avance, indépendante des résultats :

planification = keras.optimizers.schedules.CosineDecay(
initial_learning_rate=1e-3,
decay_steps=nb_epoques * pas_par_epoque,
alpha=0.01,
)
modele.compile(optimizer=keras.optimizers.Adam(planification), loss="mse")
ApprocheAvantageLimite
réactives'adapte au déroulement réelréagit après le plateau, avec retard
programméereproductible, sans hyperparamètre de patienceexige de connaître le nombre d'époques

La décroissance cosinus est devenue la convention dans l'entraînement des grands modèles, souvent précédée d'une montée en régime de quelques centaines de pas. Cette montée évite qu'un taux plein appliqué à des poids fraîchement initialisés ne détruise l'information dès les premiers lots.

La patience de ReduceLROnPlateau doit être inférieure à celle de EarlyStopping

Si l'arrêt anticipé est plus impatient que la réduction du taux, l'entraînement se termine avant la première baisse et le rappel n'a jamais servi. Un rapport de deux à trois entre les deux fonctionne bien : patience de 5 pour la réduction, de 12 pour l'arrêt.

Combiner, et connaître l'ordre

modele.fit(
jeu_entrainement,
validation_data=jeu_validation,
epochs=200,
callbacks=[point_de_controle, arret, reduction,
keras.callbacks.CSVLogger("journal.csv")],
)

Avec ce jeu de rappels, epochs=200 n'est plus une prédiction mais une borne haute : c'est EarlyStopping qui décide de la fin. C'est la bonne façon de raisonner, et elle supprime un hyperparamètre à régler.

Les rappels s'exécutent dans l'ordre de la liste, à chaque fin d'époque. ModelCheckpoint en premier garantit que la sauvegarde a lieu avant qu'un autre rappel n'interrompe l'entraînement.

Écrire son propre rappel

L'interface est ouverte, et un rappel maison tient en quelques lignes.

class ArretSurSeuil(keras.callbacks.Callback):
def __init__(self, seuil=0.98):
super().__init__()
self.seuil = seuil

def on_epoch_end(self, epoque, logs=None):
logs = logs or {}
if logs.get("val_accuracy", 0) >= self.seuil:
print(f"\nSeuil atteint a l'epoque {epoque + 1}, arret.")
self.model.stop_training = True

Le dictionnaire logs contient les métriques de l'époque, avec les mêmes noms que dans l'historique. self.model donne accès au modèle complet, et self.model.stop_training = True est le mécanisme qu'utilise EarlyStopping lui-même.

Les points d'entrée disponibles vont de on_train_begin à on_predict_batch_end. Attention toutefois aux rappels par lot : un traitement coûteux dans on_train_batch_end s'exécute des milliers de fois par époque et peut dominer le temps d'entraînement.

En résumé

  • ModelCheckpoint n'a d'intérêt qu'avec save_best_only=True ; sinon le fichier final contient la dernière époque, presque jamais la meilleure.
  • EarlyStopping exige restore_best_weights=True, faux par défaut : sans lui on détecte le bon moment d'arrêt et on conserve le mauvais modèle.
  • La réduction du taux peut être réactive avec ReduceLROnPlateau ou programmée avec une décroissance cosinus ; dans le premier cas sa patience doit rester inférieure à celle de l'arrêt anticipé.
  • Avec ces rappels, epochs devient une borne haute et non une prédiction, ce qui supprime un hyperparamètre.

Module suivant : TensorBoard, pour voir ce que les journaux ne disent pas.