ML Atlas

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

Gradient boosting : des arbres qui se corrigent

En bref

Chaque arbre corrige les erreurs des précédents. Après 200 arbres au pas 1, l’entraînement tombe à 2287 et le test monte à 5944, pire qu’une droite (4095).

Échauffement Deux questions de leçons précédentes. Une minute, sans jamais bloquer la leçon.
De la leçon 5.2 : Ensembles : pourquoi une forêt bat un seul arbre Vous faites passer une forêt aléatoire de 300 à 3 000 arbres. Quel est l’effet le plus probable ?

Voir la réponse

Bonne réponse : L’exactitude change à peine, mais l’entraînement devient beaucoup plus long

Une fois la part indépendante de l’erreur moyennée, plus d’arbres ajoutent du calcul, mais peu d’exactitude et aucun apprentissage par cœur supplémentaire.

De la leçon 5.1 : Arbres de décision : le jeu des vingt questions Comment un arbre de décision choisit-il la question à chaque étape ?

Voir la réponse

Bonne réponse : Il teste les questions possibles et garde celle qui rend les groupes les plus purs

La recherche gloutonne évalue les divisions candidates et garde celle qui fait le plus baisser l’impureté, par exemple l’indice de Gini.

Dans la leçon 5.2, une forêt aléatoire faisait la moyenne de nombreux arbres construits indépendamment les uns des autres, et ajouter des arbres ne faisait pas de mal. Le gradient boosting construit les arbres l’un après l’autre. Chaque nouvel arbre apprend les résidus, c’est-à-dire de combien l’ensemble des arbres précédents se trompe encore sur chaque exemple. Il ajoute sa correction multipliée par le taux d’apprentissage, un nombre entre 0 et 1. Les arbres sont petits, souvent avec une seule question (une souche) ou avec trois. Sur des tableaux de taille moyenne, les modèles à base d’arbres, boosting en tête, battent en général les réseaux de neurones (Grinsztajn et al., 2022). Le boosting a pourtant un trait que la forêt n’a pas : les corrections suivantes peuvent se mettre à corriger du bruit.

Prédisez, puis vérifiez On prédit la progression du diabète au bout d’un an à partir du seul IMC. Une régression linéaire a sur les patients de test une erreur quadratique moyenne (MSE) de 4095. Le gradient boosting ajoute des arbres d’au plus trois questions, chacun avec le pas complet 1. Après 200 arbres, la MSE d’entraînement passe de 3713 (un arbre) à 2287. Que donne le 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 : Moins bien que la droite, car les arbres suivants corrigent le bruit des patients

Moins bien : la MSE de test monte à 5944, alors que celle d’entraînement est tombée à 2287. Chaque arbre apprend les résidus des précédents, et après quelques tours il ne reste surtout dans les résidus que le bruit aléatoire de patients particuliers. Sur 20 autres découpages, 200 arbres de ce genre perdent toujours au test face à la droite.

À vous d’essayer

  • Commencez au départ : pas 1, profondeur 2, 200 arbres. Combien de marches a la fonction de l’ensemble, et à quelle distance sont les courbes d’entraînement et de validation ?
  • Baissez le nombre d’arbres. Avec combien d’arbres l’erreur de validation est-elle la plus basse ? Regardez le test seulement ensuite.
  • Réduisez le pas à 0,1 et prenez une souche. À quoi ressemble maintenant la courbe de validation quand on ajoute des arbres ?
  • Comparez la meilleure validation du boosting avec la ligne en pointillés de la droite. Laquelle est la plus basse ?

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

L’idée en termes simples

Le premier arbre pose quelques questions sur l’IMC et prédit la progression moyenne de la maladie dans chaque groupe. Il se trompe, donc on calcule les résidus : ce qui manque pour arriver à la vérité chez chaque patient. Le deuxième arbre ne prédit plus la maladie, seulement ces résidus. Son résultat multiplié par le taux d’apprentissage s’ajoute au premier. Le troisième arbre apprend ce qui reste après les deux, et ainsi de suite. L’ensemble grandit à coups de petites corrections.

Au début, les corrections captent le vrai motif : plus d’IMC, plus de progression. Une fois le motif capté, il reste surtout du bruit dans les résidus, les écarts aléatoires des patients sur lesquels le modèle apprend. Les arbres suivants apprennent justement cela. Au pas 1 avec des arbres à trois questions, l’entraînement passe de 3713 avec un arbre à 2287 avec 200, tandis que le test monte de 4319 à 5944. C’est du surapprentissage, comme avec un arbre trop profond, sauf qu’ici il grandit avec le nombre d’arbres. Dans une forêt aléatoire, chaque arbre voit les données de son côté, et la moyenne efface leurs erreurs. Dans le boosting, chaque arbre s’ajoute aux erreurs des précédents.

C’est pourquoi le nombre d’arbres, le pas et la profondeur se choisissent par validation, pas sur le test. Le lab calcule l’erreur de validation par une validation croisée en 5 parties à l’intérieur des 309 patients d’entraînement. Le plus bas, c’est une souche au pas 0,1 avec 50 arbres : validation 3960. La droite obtient 3823 sur la même validation, donc avec le seul IMC c’est la droite qui gagne. Le test ne le confirme qu’à la fin : 4154 pour le boosting contre 4095 pour la droite.

Jak to policzono
  • Données : Diabetes (Efron et al., 2004), dans scikit-learn sous licence BSD-3-Clause. 442 patients, 10 mesures, progression de la maladie après un an. On ne garde que l’IMC. Découpage : 309 patients pour apprendre, 133 pour le test.
  • Modèle : gradient boosting avec des arbres de régression de profondeur 1 ou 2 sur le seul IMC, perte quadratique, pas de 0,05 à 1, jusqu’à 200 arbres ; une régression linéaire sur l’IMC pour comparer. Les chiffres du lab correspondent à GradientBoostingRegressor de scikit-learn.
  • Validation : validation croisée en 5 parties à l’intérieur des 309 patients d’entraînement, les mêmes parties pour chaque réglage et pour la droite.

Pourquoi ça marche

Le résidu y − F(x) est la direction dans laquelle il faut déplacer la prédiction pour que l’erreur quadratique baisse le plus vite. Chaque arbre fait donc un petit pas de descente de gradient, mais dans l’espace des fonctions et non des poids. D’où le nom : gradient boosting. Un petit pas signifie qu’un arbre ne corrige qu’une partie de l’erreur. Il faut plus d’arbres, mais chacun ajoute moins de bruit. Sur 20 autres découpages, 200 arbres à trois questions au pas 0,1 ont au test une MSE de 3747 à 4802, à chaque fois moins que les mêmes arbres au pas 1 (de 4617 à 6983).

Cela ne veut pas dire que le boosting bat toujours une droite. Avec le seul IMC, le lien avec la maladie est presque linéaire, et les arbres ne peuvent imiter une droite qu’avec des marches. Sur 20 autres découpages, le boosting choisi par validation bat la droite au test dans 7. Le boosting brille là où il y a beaucoup de variables et où leurs effets sont à seuil et enchevêtrés. Les arbres suivants captent alors des dépendances qu’une droite ne sait pas exprimer.

Un parent plus ancien, AdaBoost, change les poids des exemples au lieu d’utiliser des résidus. Les exemples sur lesquels l’ensemble se trompe pèsent plus au tour suivant. Dans l’entrée de l’Atlas sur AdaBoost, la première souche sur des tumeurs du sein classe mal 10,3 % des tumeurs d’entraînement. Avant le deuxième tour, ces tumeurs mal classées portent exactement 50 % du poids total, donc la deuxième souche apprend surtout sur elles.

Une erreur fréquente

Vrai ou faux : « plus de tours de boosting aident toujours ». Faux. Chaque tour améliore l’entraînement, mais le test seulement jusqu’à un certain point. Au pas 1 avec des arbres à trois questions, 1 arbre est le meilleur en validation, et 200 arbres donnent 5944 au test au lieu de 4319. Dans le code ci-dessous, le test monte de 4079 après un arbre à 6437 après 200, tandis que l’entraînement passe de 3827 à 2044.

La voie sûre : un petit pas, beaucoup d’arbres et l’arrêt précoce de la leçon 3.6 : arrêtez d’ajouter des arbres quand l’erreur de validation ne baisse plus. Dans le code ci-dessous, l’arrêt garde 83 arbres sur 1000.

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. Qu’apprend le deuxième arbre dans le gradient boosting ?
Voir la réponse

Bonne réponse : Les résidus du premier arbre, c’est-à-dire de combien il se trompe encore

Chaque arbre suivant reçoit les résidus de l’ensemble précédent et ajoute une correction multipliée par le taux d’apprentissage. Les échantillons aléatoires et les arbres indépendants, c’est la forêt aléatoire.

2. Pas 1, arbres à trois questions : l’entraînement passe de 3713 à 2287, le test monte de 4319 à 5944. Que se passe-t-il ?
Voir la réponse

Bonne réponse : Du surapprentissage : les derniers arbres corrigent le bruit des patients

Une fois le vrai motif capté, il reste du bruit dans les résidus. Les arbres suivants l’apprennent, et chez de nouveaux patients ce bruit ne se répète pas.

3. Vrai ou faux : « plus de tours de boosting aident toujours ».
Voir la réponse

Bonne réponse : Faux, car au bout d’un moment les tours en plus ne corrigent que du bruit

L’entraînement baisse à chaque tour, le test non. Au pas 1, 1 arbre est le meilleur en validation, et 200 arbres donnent 5944 au test.

À retenir

  • Le gradient boosting construit les arbres à tour de rôle : chacun apprend les résidus de l’ensemble précédent et ajoute une correction multipliée par le taux d’apprentissage.
  • Contrairement à une forêt, le boosting peut surapprendre : au pas 1, le test monte de 4319 à 5944 pendant que l’entraînement baisse.
  • Choisissez le nombre d’arbres, le pas et la profondeur par validation ou arrêt précoce, jamais sur le test.
  • Le boosting ne bat pas toujours une droite : avec le seul IMC, la droite obtient 3823 en validation, le meilleur boosting 3960.

Pour aller plus loin : formule, code, pratique

Les maths

L’ensemble après m arbres : F_m(x) = F_{m−1}(x) + η · h_m(x), où F_0 est la moyenne de y sur l’entraînement, η le taux d’apprentissage, et l’arbre h_m ajuste les résidus r_i = y_i − F_{m−1}(x_i).

Pour la perte quadratique L = (y − F)² / 2, la dérivée par rapport à F vaut −(y − F), donc le résidu est l’opposé du gradient de la perte. Chaque arbre fait un pas de descente de gradient dans l’espace des fonctions. Dans AdaBoost, le poids d’un exemple mal classé est multiplié par e^α, où α = ln((1 − ε) / ε) et ε est l’erreur pondérée de la souche.

En code (Python)

La même expérience dans scikit-learn : 200 arbres au pas 1, étape par étape, puis trois réglages comparés par validation croisée à l’intérieur de l’entraînement, et l’arrêt précoce.

from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split, cross_val_score, KFold
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error as mse

X, y = load_diabetes(return_X_y=True, as_frame=True)
x_tr, x_te, y_tr, y_te = train_test_split(X[["bmi"]], y, test_size=0.3, random_state=0)
big = GradientBoostingRegressor(n_estimators=200, max_depth=2, learning_rate=1.0, random_state=0).fit(x_tr, y_tr)
for m, (p_tr, p_te) in enumerate(zip(big.staged_predict(x_tr), big.staged_predict(x_te)), start=1):
    if m in (1, 10, 50, 200):
        print(f"step 1, depth 2, {m:3d} trees: train MSE {mse(y_tr, p_tr):.0f}, test MSE {mse(y_te, p_te):.0f}")
cv = KFold(5, shuffle=True, random_state=0)
models = {"line": LinearRegression(), "step 1, 200 trees": big,
          "step 0.1, 50 stumps": GradientBoostingRegressor(n_estimators=50, max_depth=1, learning_rate=0.1, random_state=0)}
for name, model in models.items():
    val = -cross_val_score(model, x_tr, y_tr, cv=cv, scoring="neg_mean_squared_error").mean()  # validation uniquement à l’intérieur de l’entraînement
    print(f"{name}: validation MSE {val:.0f}")
stop = GradientBoostingRegressor(n_estimators=1000, max_depth=1, learning_rate=0.1, validation_fraction=0.2, n_iter_no_change=10, random_state=0).fit(x_tr, y_tr)
print(f"early stopping kept {stop.n_estimators_} of 1000 trees; test MSE {mse(y_te, stop.predict(x_te)):.0f}, line {mse(y_te, models['line'].fit(x_tr, y_tr).predict(x_te)):.0f}")

Sortie

step 1, depth 2,   1 trees: train MSE 3827, test MSE 4079
step 1, depth 2,  10 trees: train MSE 3013, test MSE 4798
step 1, depth 2,  50 trees: train MSE 2122, test MSE 6233
step 1, depth 2, 200 trees: train MSE 2044, test MSE 6437
line: validation MSE 3956
step 1, 200 trees: validation MSE 5728
step 0.1, 50 stumps: validation MSE 4030
early stopping kept 83 of 1000 trees; test MSE 4062, line 3921

Le découpage diffère de celui du lab, donc les chiffres diffèrent un peu aussi. Le tableau est le même : au pas 1, l’entraînement passe de 3827 à 2044 tandis que le test monte de 4079 à 6437. En validation, la droite (3956) bat le petit pas (4030), et 200 arbres au pas 1 font le pire (5728). L’arrêt précoce garde 83 arbres.

Pour les praticiens
  • Dans scikit-learn : HistGradientBoostingRegressor et HistGradientBoostingClassifier sont rapides sur de grands tableaux, gèrent eux-mêmes les données manquantes et ont un arrêt précoce (early_stopping). Hors de scikit-learn : XGBoost, LightGBM, CatBoost.
  • Un départ typique : un pas de 0,05–0,1, des arbres peu profonds, beaucoup d’arbres et l’arrêt précoce sur la validation. Réglez la profondeur et le pas par validation croisée (leçon 3.5), et gardez le test pour la toute fin.
  • Le boosting est plus sensible au bruit dans les étiquettes qu’une forêt : chaque exemple erroné reste dans les résidus et les arbres suivants essaient de le corriger. Avec des données sales, un pas plus petit, l’échantillonnage des lignes (subsample) et une régularisation plus forte des arbres aident.
  • Avant de sortir le boosting, mesurez un point de référence simple (leçon 1.3). Quand le lien est presque linéaire, une droite peut gagner.

Aller plus loin dans l’Atlas

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