Aller au contenu

Comprenez pourquoi un modèle doit généraliser

Un étudiant qui apprend par cœur les corrigés des annales obtient 20 sur 20 aux annales… et s’effondre le jour de l’examen, face à des questions nouvelles. Un modèle d’apprentissage peut tomber exactement dans le même piège. Dans ce chapitre, vous allez comprendre pourquoi réussir sur les exemples d’apprentissage ne prouve rien, et comment on cherche au contraire un modèle qui généralise, c’est-à-dire qui fonctionne sur des données qu’il n’a jamais vues.

Notre fil rouge : estimer le prix d’un appartement à Rennes à partir de sa surface.

Supposons que vous disposiez de 15 ventes récentes : pour chacune, la surface en m² et le prix de vente. Vous construisez un modèle hh (pour « hypothèse ») qui associe un prix à une surface. Comment savoir s’il est bon ?

Le premier réflexe est de mesurer ses erreurs sur ces 15 ventes. C’est l’erreur empirique (ou erreur apparente, ou risque empirique) :

R^(h)=1m∑i=1mℓ(h(xi),yi)\hat{R}(h) = \frac{1}{m} \sum_{i=1}^{m} \ell\big(h(x_i), y_i\big)
  • mm est le nombre d’exemples d’apprentissage (ici 15) ;
  • xix_i est la surface du ii-ème appartement et yiy_i son vrai prix ;
  • h(xi)h(x_i) est le prix prédit par le modèle ;
  • ℓ\ell est une fonction de perte (loss) qui mesure le coût d’une erreur : par exemple (h(xi)−yi)2(h(x_i) - y_i)^2 en régression, ou 1 si la classe prédite est fausse et 0 sinon en classification.

Mais ce qui vous intéresse vraiment, c’est le prix du prochain appartement mis en vente. C’est l’erreur réelle (ou risque réel) :

R(h)=E(x,y)[ℓ(h(x),y)]R(h) = \mathbb{E}_{(x, y)}\big[\ell\big(h(x), y\big)\big]

Le symbole E\mathbb{E} désigne l’espérance : la moyenne de la perte sur tous les appartements qui pourraient être mis en vente, tirés selon la même loi que vos données. En classification, avec la perte 0-1, R(h)R(h) est simplement la probabilité que le modèle se trompe sur un nouvel exemple.

Le problème, c’est que R(h)R(h) est inaccessible : vous ne connaissez pas tous les appartements futurs. Et R^(h)\hat{R}(h) est un estimateur optimiste de R(h)R(h), puisque le modèle a été choisi justement pour bien faire sur ces exemples-là.

En TP, la première évaluation proposée sur les fleurs d’iris tombait dans ce travers : un classifieur des k plus proches voisins, entraîné sur les 150 fleurs, était noté sur ces mêmes 150 fleurs. Le score obtenu ainsi mesure surtout la mémoire du modèle, pas sa capacité à reconnaître une fleur nouvelle. Le chapitre 3 vous montrera comment obtenir une estimation honnête.

Revenons aux appartements. Vous pouvez choisir des modèles plus ou moins souples : une droite (prix proportionnel à la surface, plus une constante), une courbe de degré 3, ou un polynôme de degré 9 qui ondule dans tous les sens.

  • La droite ne passe pas exactement par les points, mais elle capte la tendance générale.
  • Le polynôme de degré 9 peut passer presque exactement par chacune des 15 ventes. Son erreur empirique est quasi nulle. Mais entre deux points, il fait des bonds absurdes : il pourrait prédire qu’un 63 m² vaut moins qu’un studio.

Ce second cas, c’est le surapprentissage (overfitting) : le modèle a appris les particularités de l’échantillon (y compris son bruit : une vente précipitée, un appartement avec vue exceptionnelle) au lieu de la tendance. Son erreur d’apprentissage est très basse, son erreur réelle est élevée.

Le cas inverse existe aussi. Si vous prédisiez le même prix pour tous les appartements (la moyenne), votre modèle serait trop rigide pour capter quoi que ce soit : erreur d’apprentissage et erreur réelle seraient toutes deux élevées. C’est le sous-apprentissage (underfitting).

50100surface (m²)0100200300400500prix (k€)sous-apprentissageMSE app. 15 915MSE test 10 669vraietendancedegré 050100surface (m²)bonne tendanceMSE app. 274MSE test 670degré 150100surface (m²)bonne tendanceMSE app. 274MSE test 669degré 350100surface (m²)surapprentissageMSE app. 159MSE test 11 718degré 9
La simulation du texte : 15 ventes, prix = 3,5 × surface + 40 + bruit (pointillés : la vraie tendance). Le degré 9 a la plus petite erreur d'apprentissage (159) mais une erreur de test 17 fois plus grande que la droite (11 718 contre 670).

Le schéma ci-dessous résume la situation. Quand la complexité du modèle augmente, l’erreur d’apprentissage ne fait que baisser, tandis que l’erreur sur de nouvelles données baisse puis remonte.

complexité du modèleerreurbon compromissous-apprentissagesurapprentissageapprentissagetest

En pratique, on diagnostique la situation en comparant deux scores : celui obtenu sur les données d’apprentissage et celui obtenu sur des données mises de côté.

Score apprentissageScore sur données nouvellesDiagnostic
99 %70 %surapprentissage : le modèle récite
50 %49 %sous-apprentissage : le modèle est trop simple
90 %85 %situation saine, un léger écart est normal
80 %95 %suspect : cherchez une erreur de découpage ou une fuite de données

Prenez trois ventes : 30 m² à 150 000 €, 50 m² à 250 000 €, 70 m² à 320 000 €. Combien vaut un 60 m² ? Une infinité de courbes passent exactement par ces trois points, et elles donnent toutes des réponses différentes pour 60 m². Les données seules ne suffisent donc jamais à trancher.

20304050607080surface (m²)100150200250300350prix (k€)319 k€304 k€289 k€274 k€259 k€30 m² : 150 k€50 m² : 250 k€70 m² : 320 k€60 m² ?
Cinq courbes parfaitement compatibles avec les trois ventes, cinq prix différents pour un 60 m². Seule une hypothèse faite à l'avance (le biais inductif) permet de choisir.

Pour généraliser, un algorithme doit faire des hypothèses avant de voir les données : c’est son biais inductif. Supposer que le prix varie de façon linéaire avec la surface est un biais inductif. Supposer que des appartements proches se vendent à des prix proches (l’hypothèse des k plus proches voisins) en est un autre. Un arbre de décision suppose que l’on peut découper l’espace en rectangles par des questions successives. Sans biais inductif, aucune généralisation n’est possible : un modèle qui n’accepte aucune hypothèse ne peut que recopier ce qu’il a vu.

Parmi toutes les hypothèses compatibles avec les données, laquelle préférer ? Le rasoir d’Occam répond : la plus simple. Entre une droite et un polynôme de degré 9 qui expliquent aussi bien les données, choisissez la droite. Ce principe n’est pas une loi de la nature, mais il est payant en pratique : une hypothèse simple a moins de chances de s’être ajustée au hasard de l’échantillon.

Pourquoi l’erreur de test remonte-t-elle quand le modèle devient trop complexe ? La décomposition biais-variance donne une réponse précise dans le cas de la régression avec la perte quadratique. Pour un point xx donné :

E[(y−f^(x))2]=(E[f^(x)]−f(x))2⏟biais2+E[(f^(x)−E[f^(x)])2]⏟variance+σ2\mathbb{E}\Big[\big(y - \hat{f}(x)\big)^2\Big] = \underbrace{\Big(\mathbb{E}\big[\hat{f}(x)\big] - f(x)\Big)^2}_{\text{biais}^2} + \underbrace{\mathbb{E}\Big[\big(\hat{f}(x) - \mathbb{E}[\hat{f}(x)]\big)^2\Big]}_{\text{variance}} + \sigma^2

Détaillons chaque symbole :

  • y=f(x)+εy = f(x) + \varepsilon est le vrai prix, somme d’une tendance inconnue f(x)f(x) et d’un bruit ε\varepsilon de moyenne nulle et de variance σ2\sigma^2 (la part de hasard dans une vente) ;
  • f^\hat{f} est le modèle appris ; il dépend de l’échantillon d’apprentissage tiré, et l’espérance E\mathbb{E} porte justement sur ce tirage (et sur le bruit) ;
  • le biais mesure l’écart entre la prédiction moyenne (si l’on refaisait l’apprentissage sur de nombreux échantillons) et la vérité ;
  • la variance mesure à quel point la prédiction change d’un échantillon à l’autre ;
  • σ2\sigma^2 est le bruit irréductible : aucun modèle ne peut descendre en dessous.

Une image aide beaucoup : pensez à un joueur de fléchettes. Un joueur à fort biais groupe ses fléchettes, mais loin du centre (la droite, face à une relation courbe). Un joueur à forte variance vise en moyenne le centre, mais ses fléchettes sont dispersées (le polynôme de degré 9, qui change complètement de forme si l’on remplace une seule vente).

biais faible, variance faiblebiais faible, variance fortebiais fort, variance faible× prédiction moyenne + vérité f(x)biais fort, variance forte
Chaque point est le modèle appris sur un échantillon différent, le centre est la vérité. Le biais est l'écart entre la croix (prédiction moyenne) et le centre ; la variance, la dispersion des points autour de la croix.

Quand la complexité augmente, le biais diminue et la variance augmente. L’erreur totale est minimale entre les deux : c’est le compromis biais-variance. Chaque modèle de ce cours possède un « bouton » qui règle ce compromis :

complexité du modèle (degré, profondeur, 1/k…)erreur quadratiquebruit irréductible σ²meilleur compromis← sous-apprentissagesurapprentissage →biais²varianceerreur totale
L'erreur totale est la somme des trois termes de la décomposition. Le bruit σ² est un plancher fixe ; le meilleur réglage est au creux du U, là où la baisse du biais ne compense plus la hausse de la variance.
ModèleBouton de complexitéVers le surapprentissage quand…
k plus proches voisinsnombre de voisins kkkk diminue
Arbre de décisionprofondeur, élagagel’arbre est plus profond
Régression régulariséepénalité λ\lambdaλ\lambda diminue
SVMparamètre CCCC augmente
Réseau de neuronestaille, nombre d’époquesle réseau est plus grand ou entraîné plus longtemps

Mais comment trouver le bon réglage ? En mesurant l’erreur sur des données non vues, pour plusieurs valeurs du bouton, puis en gardant la meilleure. C’est tout l’objet du chapitre suivant.

Voici une petite expérience que vous pouvez lancer. On simule des ventes d’appartements dont le prix suit une tendance linéaire plus du bruit, puis on ajuste des polynômes de degrés croissants.

import numpy as np
from numpy.polynomial import Polynomial
rng = np.random.default_rng(0)
def simuler(n):
surface = rng.uniform(20, 120, n) # en m²
prix = 3.5 * surface + 40 + rng.normal(0, 25, n) # en milliers d'euros
return surface, prix
x_app, y_app = simuler(15) # 15 ventes pour apprendre
x_test, y_test = simuler(1000) # 1 000 ventes « futures »
for degre in [0, 1, 3, 9]:
modele = Polynomial.fit(x_app, y_app, degre) # moindres carrés
mse_app = np.mean((modele(x_app) - y_app) ** 2)
mse_test = np.mean((modele(x_test) - y_test) ** 2)
print(f"degré {degre} : MSE apprentissage {mse_app:8.1f}, MSE test {mse_test:10.1f}")
# degré 0 : MSE apprentissage 15914.5, MSE test 10669.3
# degré 1 : MSE apprentissage 274.0, MSE test 669.6
# degré 3 : MSE apprentissage 273.6, MSE test 669.0
# degré 9 : MSE apprentissage 159.1, MSE test 11718.2

Vous devriez constater que l’erreur d’apprentissage diminue à chaque degré supplémentaire, alors que l’erreur de test atteint son plancher dès le degré 1 (la vraie forme de la relation), le degré 3 ne gagnant presque rien, et devient bien plus grande pour le degré 9. Le degré 0 (un prix constant) illustre le sous-apprentissage. Les valeurs exactes dépendent du tirage aléatoire, mais la tendance est robuste.

Comment lutter contre le surapprentissage ? Vous rencontrerez tout au long du cours les mêmes leviers :

  • plus de données : la variance diminue quand l’échantillon grandit ;
  • un modèle plus simple ou contraint : élagage d’un arbre (chapitre 4), régularisation (chapitre 7), arrêt précoce d’un réseau (chapitre 9) ;
  • la moyenne de plusieurs modèles, qui réduit la variance (chapitre 8) ;
  • de meilleures caractéristiques, qui permettent à un modèle simple d’être juste.
  • L’erreur empirique se mesure sur les données d’apprentissage ; l’erreur réelle est l’erreur attendue sur de nouvelles données. La première est optimiste.
  • Surapprentissage : très bon en apprentissage, mauvais sur de nouvelles données (le modèle a appris le bruit). Sous-apprentissage : mauvais partout (le modèle est trop simple).
  • Tout algorithme repose sur un biais inductif, des hypothèses faites avant de voir les données ; sans elles, aucune généralisation n’est possible.
  • Le rasoir d’Occam recommande, à performance égale, l’hypothèse la plus simple.
  • L’erreur quadratique se décompose en biais² + variance + bruit irréductible ; augmenter la complexité réduit le biais et augmente la variance.
  • Chaque modèle a un bouton de complexité qu’on règle en mesurant l’erreur sur des données non vues.

Exercice · Poser un diagnostic

facile

Pour chacun de ces trois modèles de prédiction des absences, donnez un diagnostic (surapprentissage, sous-apprentissage, situation saine) et proposez une action.

ModèleExactitude en apprentissageExactitude sur données nouvelles
A : arbre de profondeur 30100 %71 %
B : k plus proches voisins avec k=2000k = 200062 %61 %
C : forêt aléatoire88 %84 %
Voir la solution
  • A est en surapprentissage : score parfait en apprentissage, écart de 29 points. Il faut contraindre l’arbre : limiter sa profondeur, imposer un nombre minimal d’exemples par feuille, ou l’élaguer.
  • B est en sous-apprentissage : les deux scores sont bas et proches. Avec 2 000 voisins, le vote est si lissé qu’il ne voit plus les différences locales. Il faut diminuer kk (et le choisir par validation).
  • C est dans une situation saine : l’écart de 4 points est normal. On peut chercher à progresser (meilleures caractéristiques, réglages), mais sans problème de fond.

Attention toutefois : ces pourcentages n’ont de sens qu’à côté d’une référence. Si 80 % des patients viennent, prédire « tout le monde vient » donne déjà 80 %, et même le modèle C n’apporte que peu. Nous verrons cela au chapitre 3.

En code

import pandas as pd
scores = pd.DataFrame(
{"apprentissage": [1.00, 0.62, 0.88], "nouvelles": [0.71, 0.61, 0.84]},
index=["A arbre prof. 30", "B k-NN k=2000", "C forêt"],
)
scores["écart"] = scores["apprentissage"] - scores["nouvelles"]
def diagnostic(ligne):
if ligne["écart"] > 0.10: # grand écart : le modèle a appris le bruit
return "surapprentissage"
if ligne["apprentissage"] < 0.70: # mauvais même sur ses propres données
return "sous-apprentissage"
return "situation saine"
scores["diagnostic"] = scores.apply(diagnostic, axis=1)
print(scores)
# A arbre prof. 30 : écart 0.29, surapprentissage
# B k-NN k=2000 : écart 0.01, sous-apprentissage
# C forêt : écart 0.04, situation saine

Exercice · Biais ou variance ?

moyen

Vous entraînez le même type de modèle sur cinq échantillons différents de 50 ventes d’appartements, et vous regardez la prédiction pour un 60 m² (le vrai prix moyen d’un 60 m² est de 250 000 €).

  • Modèle 1 : 205, 208, 203, 207, 206 (milliers d’euros).
  • Modèle 2 : 190, 310, 240, 285, 225 (milliers d’euros).

Lequel a un fort biais ? Lequel a une forte variance ? Lequel est probablement un polynôme de degré élevé ?

Voir la solution
  • Le modèle 1 donne des prédictions très stables (de 203 à 208) mais toutes éloignées de 250 : il a un fort biais et une faible variance. C’est typiquement un modèle trop simple, par exemple un prix constant ou une droite mal adaptée.
  • Le modèle 2 a une moyenne de (190+310+240+285+225)/5=250(190 + 310 + 240 + 285 + 225) / 5 = 250, donc un biais quasi nul, mais ses prédictions varient de 190 à 310 selon l’échantillon : forte variance. C’est le comportement d’un modèle trop souple, comme un polynôme de degré élevé, qui change de forme dès qu’on modifie quelques points.

Aucun des deux n’est satisfaisant : le bon modèle se trouve entre les deux, avec un biais et une variance tous deux modérés.

En code

import numpy as np
vrai_prix = 250 # vrai prix moyen d'un 60 m² (k€)
modele_1 = np.array([205, 208, 203, 207, 206])
modele_2 = np.array([190, 310, 240, 285, 225])
for nom, pred in [("modèle 1", modele_1), ("modèle 2", modele_2)]:
biais = pred.mean() - vrai_prix # écart moyen à la vérité
ecart_type = pred.std(ddof=1) # dispersion d'un échantillon à l'autre
print(f"{nom} : moyenne {pred.mean():.1f}, biais {biais:.1f}, écart-type {ecart_type:.1f}")
# modèle 1 : moyenne 205.8, biais -44.2, écart-type 1.9 (fort biais, faible variance)
# modèle 2 : moyenne 250.0, biais 0.0, écart-type 47.8 (biais nul, forte variance)

Exercice · Pourquoi pas zéro erreur ?

difficile

Un collègue affirme : « Avec assez de données et un modèle assez puissant, on peut toujours faire tendre l’erreur réelle vers zéro. » En vous appuyant sur la décomposition biais-variance, expliquez pourquoi c’est faux, avec un exemple tiré de l’immobilier.

Voir la solution

La décomposition fait apparaître trois termes : biais², variance et bruit irréductible σ2\sigma^2. Plus de données et un modèle bien choisi peuvent réduire les deux premiers, mais pas le troisième. Le bruit vient de tout ce que les caractéristiques ne décrivent pas : deux appartements de même surface, dans la même rue, peuvent se vendre à des prix différents parce que l’un a été vendu dans l’urgence, que l’autre a un balcon, ou simplement à cause de la négociation. Tant que le modèle ne connaît que la surface, cette part de hasard reste hors de sa portée. La seule façon de réduire σ2\sigma^2 est d’ajouter de l’information (de nouvelles caractéristiques, comme l’étage ou l’état du bien), ce qui change le problème lui-même. En classification, ce plancher porte un nom, l’erreur de Bayes, que vous rencontrerez au chapitre 5.

En code

import numpy as np
rng = np.random.default_rng(0)
def simuler(n):
surface = rng.uniform(20, 120, n)
prix = 3.5 * surface + 40 + rng.normal(0, 25, n) # bruit d'écart-type 25
return surface, prix
x_test, y_test = simuler(100_000)
for n in [15, 150, 1_500, 150_000]:
x, y = simuler(n)
coef = np.polyfit(x, y, 3) # modèle souple (degré 3)
mse = np.mean((np.polyval(coef, x_test) - y_test) ** 2)
print(f"n = {n:>7} : MSE test {mse:.1f}")
print("bruit irréductible sigma² =", 25 ** 2)
# n = 15 : MSE test 790.9
# n = 150 : MSE test 644.3
# n = 1500 : MSE test 628.9
# n = 150000 : MSE test 628.0 (plancher : sigma² = 625, jamais franchi)