Le machine learning en partant de zéro · Leçon 3.5 · 18 sur 33 leçons prêtes · 14 min
Régler les hyperparamètres sans tricher
En bref
Le meilleur des 9 réglages de l’arbre obtient 93,7 % en validation croisée et 88,3 % sur de nouvelles biopsies. Choisir le gagnant gonfle son score.
Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
Dans la leçon 3.2, la validation croisée évaluait un seul réglage du modèle. En pratique, on en essaie beaucoup et on garde le meilleur. C’est le réglage des hyperparamètres. Les réglages que vous choisissez avant l’entraînement (la profondeur d’un arbre, la force de la pénalité α de la leçon 3.4) sont des hyperparamètres : le modèle ne les apprend pas à partir des données, c’est vous qui les choisissez. Aujourd’hui, vous allez voir que le score du gagnant du réglage est trop optimiste, et pourquoi.
Choisissez une réponse et votre degré de certitude.
Répondez pour débloquer le labo.
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 : Moins, par exemple 88,3 %, parce que nous avons aussi choisi du bruit favorable
Sur les 171 biopsies de test, le gagnant obtient 88,3 %, 5,4 points de moins qu’en validation croisée. Une partie vient de la sélection, une partie de la petite taille du test : une biopsie vaut 0,6 point. Choisir la meilleure de 20 graines de découpage gonfle le score de 2,7 points. Ce découpage est du côté pessimiste : sur 50 autres découpages (code plus bas), le gagnant perd en moyenne 1,4 point.
À vous de jouer
- Avec la grille, passez le budget de 4 à 9. Quel score a le gagnant en validation croisée, et lequel au test ?
- Passez à la recherche aléatoire et cliquez plusieurs fois sur « nouveau tirage ». Le gagnant est-il parfois meilleur au test qu’en validation ?
- Dans la deuxième partie, déplacez le curseur des graines de 1 à 20. Comment le meilleur score augmente-t-il, et à quelle distance s’éloigne-t-il de la moyenne de 200 découpages ?
Une fois vérifié dans le lab, mettons un nom sur ce que vous voyez.
L’idée en quelques mots
Régler, c’est comparer de nombreux réglages sur des données de validation et choisir le meilleur. La recherche en grille essaie toutes les combinaisons de quelques valeurs. La recherche aléatoire tire des combinaisons dans toute la plage. À budget égal, une grille 3×3 n’essaie que 3 profondeurs : 1, 6 et 12. Neuf essais au hasard voient en général plus de valeurs différentes de chaque hyperparamètre.
Chaque score de validation est la vraie qualité du réglage plus un peu de chance : quelles biopsies sont tombées dans quelle partie. Quand vous choisissez le meilleur score, vous choisissez aussi le réglage que la chance a le plus aidé. Sur de nouvelles données, cette chance a disparu. C’est la malédiction du gagnant. Elle grandit avec le nombre de réglages comparés et diminue avec la taille des données.
La même chose arrive quand vous cherchez le meilleur découpage des données. La même régression logistique sur 200 découpages aléatoires obtient en moyenne 93,8 % au test. Si vous essayez les graines 1–20 et publiez la meilleure, vous obtenez 96,5 %, 2,7 points de plus. Le code est le même ; vous avez seulement choisi la chance.
Jak to policzono
- Biopsies : Breast Cancer Wisconsin (Diagnostic), UCI, licence CC BY 4.0. 569 biopsies, 10 mesures « mean » chacune.
- Réglage : découpage stratifié, 398 biopsies pour régler et 171 pour le test. Un arbre CART (Gini), 10 profondeurs fois 11 nombres minimaux de biopsies par feuille, soit 110 réglages, chacun en validation croisée à 5 blocs sur les 398 biopsies.
- Gagnant : la meilleure moyenne sur les 5 parties ; en cas d’égalité, l’arbre le plus simple. Au test, on évalue l’arbre entraîné sur les 398 biopsies.
- Graines : régression logistique (C = 1) sur des mesures standardisées, 200 découpages aléatoires 70/30, avec 171 biopsies de test dans chacun.
Pourquoi ça marche
Prenez 9 réglages de vraie qualité presque égale. Leurs scores de validation diffèrent surtout par le bruit. Le plus haut des 9 scores est presque toujours un score où le bruit était positif. Dans le lab, la meilleure CV trouve juste 373 biopsies sur 398, et plusieurs réglages n’ont qu’une ou deux biopsies de retard. Des écarts aussi petits relèvent en bonne partie du hasard.
La sélection se voit en mode aléatoire : sur 200 tirages de 9 réglages, le gagnant obtient plus en validation qu’au test dans chacun d’eux, 3,6 points en moyenne. Le test n’a pas participé au choix, il ne porte donc aucune sélection, seulement le bruit ordinaire d’un ensemble fini. Mais les 200 tirages sont des réglages différents sur un seul et même découpage des données, et celui-ci est tombé du côté pessimiste : même sans aucun choix, les 110 réglages obtiennent en moyenne 0,6 point de plus en validation qu’au test. Dans le code plus bas, sur 50 découpages différents, le gagnant perd en moyenne 1,4 point, et dans 17 découpages sur 50 la validation ne dépasse pas le test.
C’est pourquoi le test ne doit pas servir à choisir. Si l’on choisissait un réglage d’après son score de test, la meilleure case obtiendrait 92,4 % au test. Ce nombre serait gonflé lui aussi, seulement plus difficile à repérer, parce qu’il ne resterait plus de données pour le vérifier.
Erreur fréquente
Vrai ou faux : « le score du gagnant du réglage est une prévision pour de nouvelles données ». Faux. Le score de validation du gagnant est gonflé, car c’est le maximum de nombreux nombres bruités. Dans le lab, le gagnant des 9 réglages a 93,7 % en validation et 88,3 % au test. Dans le code plus bas, sur 50 découpages et 110 réglages, le gagnant obtient en moyenne 93,3 % en validation et 91,9 % sur le test mis de côté.
Une prévision honnête passe par l’une de deux voies. La première : un test mis de côté, qui ne sert à aucun choix et que l’on regarde une fois, à la fin. La seconde : la validation croisée imbriquée, c’est-à-dire tout le réglage répété dans chaque partie d’une validation croisée extérieure. Sur les 569 biopsies, le gagnant obtient 94,0 % en validation croisée ordinaire, alors que la validation imbriquée donne 91,9 %. Le second nombre est plus proche de ce que fera le modèle demain.
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.
À retenir
- Les hyperparamètres, c’est vous qui les choisissez, avant l’entraînement ; on les règle en validation, jamais sur le test.
- Le score du gagnant du réglage est gonflé : en choisissant le meilleur score, on choisit aussi la chance (la malédiction du gagnant).
- Choisir la meilleure graine de découpage, c’est aussi régler sur le jeu de test.
- Une prévision honnête vient d’un test mis de côté regardé une seule fois, ou de la validation croisée imbriquée.
Pour aller plus loin : formule, code, pratique
Les maths
Soit μₖ la vraie qualité du réglage k et Ŝₖ = μₖ + εₖ son score de validation, où le bruit εₖ a une moyenne de 0. Pour un réglage, E[Ŝₖ] = μₖ. Pour le gagnant k = argmaxₖ Ŝₖ, en moyenne E[Ŝ_k] ≥ μ_k* : le maximum de plusieurs nombres bruités est en moyenne plus haut que la vraie qualité de celui qu’on choisit. Avec m réglages de même qualité, E[max εₖ] croît avec m à peu près comme σ · √(2 · ln m).
Une biopsie de test pour n = 171 vaut 1/171, soit 0,6 point. L’erreur type d’une exactitude p sur n exemples : √(p(1 − p)/n).
Validation croisée imbriquée : une boucle extérieure découpe les données en K parties ; pour chaque partie, tout le réglage (une validation croisée intérieure) se fait sur les autres seulement, et le modèle choisi est évalué sur la partie mise de côté.
En code (Python)
La même expérience dans scikit-learn : la malédiction du gagnant sur 50 découpages avec les 110 réglages de l’arbre, la validation croisée ordinaire et imbriquée sur toutes les biopsies, et la meilleure de 20 graines de découpage.
import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split, GridSearchCV, StratifiedKFold, cross_val_score
from sklearn.tree import DecisionTreeClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
X, y = load_breast_cancer(return_X_y=True)
X = X[:, :10] # les 10 mesures « mean », comme dans le lab
grid = {"max_depth": [1, 2, 3, 4, 5, 6, 7, 8, 10, 12], "min_samples_leaf": [1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48]} # les 110 réglages du lab
tree = DecisionTreeClassifier(random_state=0)
r = []
for s in range(50):
tr, te = train_test_split(np.arange(len(y)), test_size=0.3, stratify=y, random_state=s)
search = GridSearchCV(tree, grid, cv=StratifiedKFold(5, shuffle=True, random_state=s)).fit(X[tr], y[tr])
r.append((search.best_score_, search.score(X[te], y[te]))) # la CV du gagnant, puis le gagnant sur le test mis de côté
r = np.array(r)
print(f"winner of 110 settings, 50 splits: CV {r[:, 0].mean():.1%}, held-out test {r[:, 1].mean():.1%}; CV higher in {(r[:, 0] > r[:, 1]).sum()} of 50")
outer = StratifiedKFold(5, shuffle=True, random_state=0)
flat = GridSearchCV(tree, grid, cv=outer).fit(X, y).best_score_ # le score du gagnant sur les mêmes parties qui l’ont choisi
nested = cross_val_score(GridSearchCV(tree, grid, cv=StratifiedKFold(5, shuffle=True, random_state=1)), X, y, cv=outer).mean() # la recherche se fait dans chaque partie extérieure
print(f"all 569 biopsies: winner's CV {flat:.1%}, nested CV {nested:.1%}")
model = make_pipeline(StandardScaler(), LogisticRegression())
acc = []
for s in range(200): # 200 découpages aléatoires, 30 % de test, comme dans le lab
tr, te = train_test_split(np.arange(len(y)), test_size=0.3, random_state=s)
acc.append(model.fit(X[tr], y[tr]).score(X[te], y[te]))
acc = np.array(acc)
best = acc.reshape(10, 20).max(axis=1) # dix personnes, chacune essaie 20 graines et publie la meilleure
print(f"logistic regression, 200 seeds: mean {acc.mean():.1%}; best of 20 seeds {best.mean():.1%} on average (+{(best.mean() - acc.mean()) * 100:.1f} points), higher in {(best > acc.mean()).sum()} of 10")
Sortie
winner of 110 settings, 50 splits: CV 93.3%, held-out test 91.9%; CV higher in 33 of 50
all 569 biopsies: winner's CV 94.0%, nested CV 91.9%
logistic regression, 200 seeds: mean 93.7%; best of 20 seeds 96.4% on average (+2.6 points), higher in 10 of 10
Les découpages diffèrent de ceux du lab, donc les nombres aussi. L’image est la même : le gagnant du réglage obtient en moyenne 93,3 % en validation et 91,9 % sur le test mis de côté ; la validation est plus haute dans 33 découpages sur 50. La validation croisée imbriquée donne 91,9 % au lieu de 94,0 %, et la meilleure de 20 graines gonfle le score de 2,6 points, pour chacune des 10 personnes.
Télécharger le notebook (.ipynb). Ouvrez-le dans Jupyter ou importez-le dans Google Colab ; il télécharge lui-même les données manquantes.
Pour les praticiens
- Dans scikit-learn :
GridSearchCVetRandomizedSearchCV. Lebest_score_est gonflé pour la même raison que dans le lab ; évaluez le gagnant avecscoresur un test mis de côté. - Validation croisée imbriquée :
cross_val_score(GridSearchCV(...), X, y, cv=...). Le réglage se fait alors dans chaque partie extérieure. - Avec de nombreux hyperparamètres dont peu comptent, la recherche aléatoire trouve en général un bon réglage plus vite qu’une grille (Bergstra et Bengio, 2012).
- Fixez la graine aléatoire une fois, avant l’expérience, et notez-la. Donnez la moyenne et la dispersion sur plusieurs découpages ou en validation croisée, pas le score de la meilleure graine.
Cela vous a-t-il aidé ?
Merci ! Cela nous aide à nous améliorer.
Aller plus loin dans l’Atlas
Articles de l’encyclopédie sur les notions de cette leçon :