D’où vient une fonction de perte : de la vraisemblance, pas d’une convention
Trois droites sur les mêmes vingt mesures, trois règles de score, trois gagnantes. L’erreur quadratique est un choix.
Dans cet article
La lame qui découpe les pièces s’use. Au cours d’un poste de dix heures, elle perd assez de tranchant pour que les pièces sortent du tapis quelques fractions de millimètre plus larges qu’au départ ; dès qu’elles dépassent 23,5 millimètres, l’inspection les rejette. Personne dans l’usine ne sait quand cela arrive. Ce qu’ils ont, c’est un pied à coulisse, un carnet, et vingt relevés du mardi précédent : les heures écoulées depuis le changement de lame, et la largeur de la pièce mesurée à cet instant.
Quelqu’un trace une droite à travers les points. Quelqu’un d’autre en trace une légèrement différente. Une troisième personne en trace une troisième. Les trois semblent raisonnables sur le papier, et elles ne sont pas d’accord sur le moment où changer la lame, avec plusieurs heures d’écart — dans cette usine, la différence entre une semaine tranquille et un lot mis au rebut.
Quelle droite est meilleure ?
Formulée ainsi, cette question n’a pas de réponse. Pas une réponse difficile — aucune réponse du tout. « Meilleure » n’est pas une propriété d’une droite comme l’est sa pente ; c’est une propriété d’une droite avec une règle pour noter les droites, et tant que quelqu’un n’a pas écrit la règle, il n’y a rien à calculer. Ce chapitre prend cette phrase au sérieux, et se termine par la découverte que la règle la plus courante en machine learning n’est pas une convention, mais la conséquence d’une affirmation sur le monde — une affirmation que vous pouvez tester, et qui est parfois fausse.
Un aveu avant la première ligne de code. Ces vingt relevés ne viennent pas d’une vraie usine : je les ai générés à partir d’une droite que j’ai choisie, , plus un bruit aléatoire avec une dispersion d’environ un dixième de millimètre. C’est important, parce que tout ce qui suit cherche à savoir si une méthode retrouve une vérité, et la seule façon de le vérifier est de connaître cette vérité à l’avance. Donc : 0,30 millimètre par heure est la réponse au fond du manuel. Vous n’avez pas le droit de l’utiliser, seulement de comparer avec elle.
Trois règles, trois gagnantes
Lien vers la section : Trois règles, trois gagnantesVoici les relevés et les trois droites, notés de trois façons : erreur quadratique, celle vers laquelle tout le monde se tourne ; erreur absolue, qu’un statisticien pourrait choisir ; et pire erreur, que le machiniste choisirait, parce que l’inspecteur ne se soucie pas de votre moyenne — il rejette la seule pièce hors tolérance.
NumPy arrive ici, un chapitre après le perceptron en pur Python, pour une raison : à la fin de ce chapitre, nous évaluons quatre cent mille droites candidates contre vingt relevés chacune, et une boucle Python n’est pas le bon outil pour cela. C’est aussi la notation dans laquelle toutes les sources citées plus bas sont écrites.
import numpy as np
# Hours since the blade was changed, and the width of the part measured then.
SHIFT = np.array([
(0.5, 20.17), (1.0, 20.28), (1.5, 20.53), (2.0, 20.61), (2.5, 20.69),
(3.0, 20.94), (3.5, 21.21), (4.0, 21.31), (4.5, 21.27), (5.0, 21.35),
(5.5, 21.58), (6.0, 21.80), (6.5, 21.67), (7.0, 22.07), (7.5, 22.10),
(8.0, 22.31), (8.5, 22.48), (9.0, 22.66), (9.5, 22.90), (10.0, 23.13),
])
h, y = SHIFT[:, 0], SHIFT[:, 1]
LINES = {"A": (20.10, 0.26), "B": (20.20, 0.28), "C": (20.30, 0.26)}
for name, (a, b) in LINES.items():
r = y - (a + b * h)
print(f"{name} mean square {np.mean(r**2):.5f}"
f" mean absolute {np.mean(np.abs(r)):.5f}"
f" worst {np.max(np.abs(r)):.3f}") La quantité dans les lignes surlignées est le résidu : ce que la droite annonçait moins ce que le pied à coulisse annonçait, un nombre par relevé. Chaque règle de score de ce chapitre, et chaque loss function des vingt-huit chapitres qui suivent, est une façon de comprimer une liste de résidus en un seul nombre. Elles ne diffèrent que par la façon dont elles compriment.
A mean square 0.02699 mean absolute 0.12600 worst 0.430
B mean square 0.02524 mean absolute 0.13700 worst 0.350
C mean square 0.03179 mean absolute 0.15000 worst 0.320Lisez les colonnes, pas les lignes. L’erreur quadratique dit B, l’erreur absolue dit A, la pire erreur dit C : trois règles, trois gagnantes, sur les mêmes vingt points.
J’ai choisi ces trois droites pour qu’elles ne soient pas d’accord, et je dois le dire clairement. Ce qui compte, c’est la facilité avec laquelle cela s’est produit — quelques minutes de recherche parmi des ordonnées à l’origine et des pentes plausibles font apparaître des centaines de tels triplets. Le classement est une propriété de la règle que vous avez choisie, pas un fait sur les droites ; la règle n’est donc pas un détail d’implémentation : elle est la définition du problème. Ce qui soulève la question à laquelle ce chapitre existe pour répondre : sur quelles bases la choisir ?
Un paramètre, et une vallée
Lien vers la section : Un paramètre, et une valléeD’abord une question plus petite, parce qu’il n’y a pas trois droites mais une infinité. Prenez l’erreur quadratique pour l’instant, puisque c’est ce que tout le monde prend, et réduisez le problème à un seul nombre avec l’astuce qui a épargné onze mille époques au perceptron dans le Chapitre 1 : soustraire la moyenne des deux colonnes. Une fois le nuage de points centré sur l’origine, la meilleure droite selon l’erreur quadratique passe exactement par l’origine — l’ordonnée à l’origine est donc réglée, et seule la pente reste à choisir.
u, v = h - h.mean(), y - y.mean() # 5.25 hours, 21.553 mm
def mse(theta):
return np.mean((v - theta * u) ** 2)
grid = np.arange(0.0, 0.6001, 0.001)
curve = np.array([mse(t) for t in grid])
print(grid.size, "candidates ->", f"theta={grid[curve.argmin()]:.3f}", f"mse={curve.min():.6f}")601 candidates -> theta=0.293 mse=0.010115Six cent une pentes candidates, une gagnante : 0,293 millimètre par heure, contre une vérité de 0,300. Vingt relevés bruités et une boucle for arrivent à moins d’un centième de millimètre par heure — deux virgule trois pour cent.
La partie intéressante n’est pas la gagnante, mais la forme de la recherche. Affichez toute la courbe, tournée pour que la perte aille de gauche à droite :
ts = np.arange(0.0, 0.6001, 0.04)
ls = np.array([mse(t) for t in ts])
for t, l in zip(ts, ls):
col = round(l / ls.max() * 50)
print(f"theta={t:.2f} |{' ' * col}*{' ' * (50 - col)}| mse={l:7.4f}")theta=0.00 | * | mse= 0.7244
theta=0.04 | * | mse= 0.5428
theta=0.08 | * | mse= 0.3878
theta=0.12 | * | mse= 0.2593
theta=0.16 | * | mse= 0.1575
theta=0.20 | * | mse= 0.0822
theta=0.24 | * | mse= 0.0336
theta=0.28 | * | mse= 0.0116
theta=0.32 | * | mse= 0.0161
theta=0.36 | * | mse= 0.0473
theta=0.40 | * | mse= 0.1050
theta=0.44 | * | mse= 0.1894
theta=0.48 | * | mse= 0.3004
theta=0.52 | * | mse= 0.4379
theta=0.56 | * | mse= 0.6021
theta=0.60 | *| mse= 0.7928C’est une vallée, vue de côté. Elle a un seul fond, les parois montent doucement des deux côtés, et — c’est ce que l’escalier du Chapitre 1 ne pouvait pas offrir — en chaque point, il existe une direction bien définie vers « le bas ». Retenez cette forme. Le Chapitre 3 porte entièrement sur la façon de la descendre sans visiter les six cent un points, et sur ce qui change quand une vallée a plus d’un fond.
Alors pourquoi le carré ?
Lien vers la section : Alors pourquoi le carré ?Nous avons une vallée parce que nous avons élevé au carré. L’erreur absolue aurait donné un coude au fond ; la pire erreur aurait donné des zones plates où déplacer la droite ne change rien du tout. Élever au carré est indéniablement pratique — et la praticité est à peu près la raison donnée par la plupart des cours, habillée de quatre façons : cela rend les erreurs positives (la valeur absolue aussi) ; cela pénalise davantage les grosses erreurs (pourquoi le faudrait-il ?) ; c’est différentiable (la puissance quatrième aussi) ; c’est ce que tout le monde utilise (c’est vrai, et ce n’est pas un argument).
Voici la position honnête. L’erreur quadratique a sélectionné la droite B et l’erreur absolue a sélectionné la droite A. L’une des deux est correcte pour cette usine et l’autre est fausse, et rien de ce qui a été dit jusqu’ici ne permet de savoir laquelle. Pour choisir la règle, vous devez savoir quelque chose sur la manière dont les relevés se sont écartés de la droite, et c’est une question sur le monde, pas sur les mathématiques. Y répondre demande un petit outil.
La vraisemblance d’une droite
Lien vers la section : La vraisemblance d’une droiteVoici l’hypothèse qui transforme « quelle droite est meilleure » en une question avec une réponse.
Supposez que la largeur d’une pièce soit la droite plus une erreur aléatoire, et supposez que cette erreur soit tirée d’une gaussienne — la courbe en cloche — de moyenne zéro et d’écart-type :
La densité de la gaussienne est
Faites maintenant quelque chose que le perceptron ne pouvait pas faire. Pour une pente candidate donnée , chaque relevé a un résidu, et la formule ci-dessus transforme ce résidu en un nombre : à quel point une erreur d’exactement cette taille est-elle plausible, si cette pente est la vérité ? Un relevé sur la droite obtient un grand nombre, un relevé à un demi-millimètre de distance en obtient un petit.
Les relevés sont indépendants — le pied à coulisse ne se souvient pas de la dernière pièce — donc la règle du produit dit que la plausibilité de tout le carnet est le produit des densités individuelles. Ce produit est la vraisemblance de .1 Notez le sens, parce que c’est le sens dont parle la règle de Bayes : les données sont fixes et connues, et c’est le paramètre qui varie. Ce n’est pas « la probabilité de la pente ». C’est la probabilité que le modèle attribue aux données que vous avez réellement obtenues, lue comme une fonction de la pente.
SIGMA = 0.12
def gaussian(r, sigma):
return np.exp(-r ** 2 / (2 * sigma ** 2)) / (sigma * np.sqrt(2 * np.pi))
def likelihood(theta):
return np.prod(gaussian(v - theta * u, SIGMA))
for t in (0.25, 0.293, 0.35):
print(f"theta={t} likelihood = {likelihood(t):.6g}")theta=0.25 likelihood = 521.952
theta=0.293 likelihood = 2.42028e+07
theta=0.35 likelihood = 0.190312Une pente de 0,293 rend ce carnet quarante-six mille fois plus plausible que 0,25, et cent vingt-sept millions de fois plus plausible que 0,35. La vraisemblance maximale est le principe selon lequel vous choisissez le paramètre qui rend ce que vous avez réellement observé aussi peu surprenant que possible. Ce n’est pas un théorème mais une proposition sur ce que « meilleur » devrait signifier — une proposition qui a du contenu, parce qu’elle vous oblige à énoncer votre hypothèse sur le bruit avant d’avoir le droit de noter quoi que ce soit.
Le produit casse
Lien vers la section : Le produit casseExécutez les mêmes trois lignes de code sur un mois de postes au lieu d’un seul, et la méthode s’effondre.
rng = np.random.default_rng(7)
u_big = rng.uniform(-5.25, 5.25, 2000) # 2000 readings, not 20
v_big = 0.30 * u_big + 0.12 * rng.standard_normal(2000)
print("2000 readings, sigma = 0.12 mm :", np.prod(gaussian(v_big - 0.30 * u_big, 0.12)))
noisy = 0.30 * u_big + 2.0 * rng.standard_normal(2000)
print("2000 readings, sigma = 2.00 mm :", np.prod(gaussian(noisy - 0.30 * u_big, 2.0)))
print("largest float64 :", np.finfo(np.float64).max)RuntimeWarning: overflow encountered in reduce
2000 readings, sigma = 0.12 mm : inf
2000 readings, sigma = 2.00 mm : 0.0
largest float64 : 1.7976931348623157e+308Deux mille multiplications et la réponse est inf. Changez une constante — un pied à coulisse moins précis, de sorte que les densités sortent plus petites que 1 au lieu de plus grandes — et le même code renvoie 0.0. Les deux réponses sont fausses, dans des directions opposées, aucune ne déclenche une exception que vous pouvez intercepter, et la seconde n’affiche même pas d’avertissement.
Rien ne cloche dans les mathématiques. La vraisemblance à ces réglages est un nombre fini parfaitement défini : son logarithme naturel est 1400,91, donc le nombre lui-même vaut environ . Le problème est que votre ordinateur ne possède pas ce nombre, et il vaut la peine de comprendre exactement quels nombres il possède, parce que ce n’est pas la dernière fois qu’il décidera du résultat.
D’où vient le carré
Lien vers la section : D’où vient le carréLe correctif pour le produit qui explose est le correctif habituel : prendre les logarithmes. Le logarithme transforme les produits en sommes, il est strictement croissant donc il ne peut pas déplacer l’emplacement du maximum, et une somme de deux mille nombres modérés est quelque chose que float64 gère sans se plaindre. Par convention, nous prenons la vraisemblance logarithmique négative, afin que meilleur signifie plus petit. Remplacez maintenant par la densité gaussienne et regardez ce qui se passe.
-
Partez du produit. La vraisemblance est , avec la densité gaussienne ci-dessus.
-
Prenez moins le logarithme. Le produit devient une somme, et l’exponentielle dans la densité s’annule directement avec le logarithme :
- Jetez tout ce qui ne contient pas . Le premier terme est une constante. Le devant la somme est une constante positive, et multiplier une fonction par une constante positive ne peut pas déplacer l’emplacement de son minimum. Il reste
qui est la somme des résidus au carré — la chose avec laquelle nous avons commencé le chapitre, parce que c’était la première chose à laquelle tout le monde pense.
C’est le résultat pour lequel ce chapitre existe, et il mérite d’être énoncé sans nuance : l’erreur quadratique n’est pas une convention. C’est la vraisemblance logarithmique négative d’une gaussienne, constantes retirées. Minimiser l’erreur quadratique est exactement le même acte qu’affirmer que vos erreurs sont gaussiennes et demander quel paramètre rend vos données les moins surprenantes. Vous faisiez cette affirmation depuis le début ; on ne vous le disait simplement pas.
L’équivalence est vérifiable, alors vérifiez-la : parcourez les mêmes six cent une pentes avec la vraisemblance logarithmique négative complète, constantes comprises, et avec l’erreur quadratique simple.
N = v.size
def nll(theta):
r = v - theta * u
return N * np.log(SIGMA * np.sqrt(2 * np.pi)) + np.sum(r ** 2) / (2 * SIGMA ** 2)
nlls = np.array([nll(t) for t in grid])
mses = np.array([mse(t) for t in grid])
print(f"argmin of the negative log-likelihood : theta={grid[nlls.argmin()]:.3f} nll={nlls.min():.6f}")
print(f"argmin of the mean squared error : theta={grid[mses.argmin()]:.3f} mse={mses.min():.6f}")
print("same index:", nlls.argmin() == mses.argmin())argmin of the negative log-likelihood : theta=0.293 nll=-17.001977
argmin of the mean squared error : theta=0.293 mse=0.010115
same index: TrueDes nombres différents sur l’axe vertical, et l’un d’eux est négatif, ce qu’une somme de carrés n’est jamais : une vraisemblance logarithmique négative peut descendre sous zéro, parce qu’une densité peut dépasser 1. Même fond de la même vallée, jusqu’au dernier point de la grille.
Afficher la dérivation complète
Quels rejets sont exactement sûrs ? La même manœuvre apparaît dans chaque chapitre qui dérive une loss, et elle n’est pas toujours innocente.
Supprimer une constante additive est sûr chaque fois qu’elle ne dépend pas du paramètre que vous optimisez, et supprimer une constante multiplicative positive est sûr parce que pour tout . Les deux échouent dès que est également ajusté : alors n’est plus du tout une constante, c’est le terme qui empêche le modèle de prétendre et une plausibilité infinie. C’est exactement la section suivante.
Ils échouent encore différemment au Chapitre 3 : une constante multiplicative ne déplace pas le minimum, mais elle met le gradient à l’échelle, et le gradient est multiplié par le learning rate. Diviser par pour obtenir l’erreur quadratique moyenne plutôt que la somme est invisible pour la réponse et très visible pour l’entraînement — avec la somme, doubler la taille de votre batch double chaque pas que vous faites.
Sigma n’est pas gratuit non plus
Lien vers la section : Sigma n’est pas gratuit non plusNous avons fixé à 0,12 par décret, et personne dans l’usine ne connaît la dispersion de l’erreur de son pied à coulisse. Traitez-la comme une seconde inconnue et laissez la vraisemblance maximale la décider aussi. Ici, le terme constant que nous venons de jeter revient, parce qu’il est la seule chose qui sépare le modèle d’une prétention à la précision parfaite.
r = v - 0.293 * u
sigmas = np.arange(0.01, 1.0001, 0.0001)
nll_sigma = N * np.log(sigmas * np.sqrt(2 * np.pi)) + np.sum(r ** 2) / (2 * sigmas ** 2)
print("best sigma on the grid :", round(float(sigmas[nll_sigma.argmin()]), 4))
print("sqrt(mean squared residual) :", round(float(np.sqrt(np.mean(r ** 2))), 4))best sigma on the grid : 0.1006
sqrt(mean squared residual) : 0.1006Les deux coïncident à quatre décimales, et ce n’est pas un accident : dériver cette expression et la mettre à zéro donne exactement . L’erreur quadratique moyenne n’est donc pas simplement comme une variance. Sous ce modèle, elle est l’estimation par vraisemblance maximale de la variance du bruit — le nombre que vous minimisiez depuis le début était une estimation du bruit de votre capteur.
Une subtilité, peu coûteuse à énoncer et coûteuse à redécouvrir plus tard : cette estimation est biaisée vers le bas, parce que les résidus ont été mesurés contre un ajustement qui a lui-même été choisi pour les rendre petits. Simulez-le — deux cent mille carnets de vingt relevés chacun, tirés d’une distribution dont la vraie variance vaut exactement 1, avec l’unique paramètre de l’ajustement estimé à partir des relevés eux-mêmes. Diviser la somme des carrés par donne une moyenne de 0,9501 ; diviser par donne 1,0001 ; et vaut exactement 0,95. Chaque paramètre que vous ajustez coûte un degré de liberté, et c’est la plus petite instance visible d’un problème beaucoup plus vaste : un modèle a toujours l’air meilleur sur les données auxquelles il a été ajusté. Le Chapitre 4 en fait la discipline de garder des données de côté, et le Chapitre 6 donne son nom à l’effet.
Une loss est une hypothèse sur le bruit
Lien vers la section : Une loss est une hypothèse sur le bruitSi l’erreur quadratique affirme que le bruit est gaussien, la question suivante est de savoir ce qui se passe quand l’affirmation est fausse. Pas légèrement fausse — fausse comme les vraies mesures sont fausses.
Dans l’atelier, la plupart des lectures au pied à coulisse sont bonnes au dixième de millimètre près, et une ou deux fois par poste, un copeau se glisse sous la mâchoire et la lecture est décalée de plusieurs millimètres. Des erreurs comme celles-là ont des queues épaisses : petites la plupart du temps, parfois énormes, et énormes bien plus souvent qu’une courbe en cloche ne le permet. La distribution de Cauchy est le modèle propre standard de ce comportement, et sa densité est aussi simple que celle de la gaussienne :
La différence est la queue : la gaussienne décroît comme , brutalement vite, et la Cauchy comme , presque pas. La conséquence est plus facile à voir qu’à dire :
rng = np.random.default_rng(3)
g = 0.12 * rng.standard_normal(10 ** 6) # Gaussian noise
c = 0.12 * rng.standard_cauchy(10 ** 6) # Cauchy noise, same scale
for k in (10 ** 2, 10 ** 3, 10 ** 4, 10 ** 5, 10 ** 6):
print(f"{k:>9,} samples gaussian var {g[:k].var():.4f} cauchy var {c[:k].var():10.2f}") 100 samples gaussian var 0.0164 cauchy var 0.26
1,000 samples gaussian var 0.0146 cauchy var 59.88
10,000 samples gaussian var 0.0145 cauchy var 358.17
100,000 samples gaussian var 0.0144 cauchy var 3097.98
1,000,000 samples gaussian var 0.0144 cauchy var 32886.10La variance d’échantillon de la gaussienne se stabilise à 0,0144, c’est-à-dire , et y reste. Celle de la Cauchy grimpe, et continue de grimper aussi longtemps que vous échantillonnez, parce qu’il n’y a rien vers quoi converger : la distribution de Cauchy n’a pas de variance, ni de moyenne. L’erreur quadratique, dont toute l’activité consiste à minimiser une moyenne de carrés, se voit demander une quantité qui n’existe pas.
Voici donc un poste où le pied à coulisse a été trompé. Les mêmes vingt heures, la même lame, la même dérive de 0,30 millimètre par heure — seul le bruit est maintenant de Cauchy. Ajustez deux fois : une fois en minimisant les résidus au carré, une fois en minimisant la vraisemblance logarithmique négative du bruit qui a réellement généré les données. L’astuce du centrage n’aide pas ici — elle ne fixe l’ordonnée à l’origine que pour l’erreur quadratique — donc les deux ajustements se font par force brute sur une grille d’ordonnées à l’origine et de pentes, puisque nous n’avons toujours aucun moyen de trouver le fond d’une vallée autrement qu’en le visitant.
SWARF = np.array([
(0.5, 20.08), (1.0, 21.95), (1.5, 20.86), (2.0, 27.51), (2.5, 20.64),
(3.0, 20.75), (3.5, 21.01), (4.0, 21.03), (4.5, 21.37), (5.0, 20.60),
(5.5, 22.03), (6.0, 21.95), (6.5, 21.98), (7.0, 22.01), (7.5, 21.73),
(8.0, 22.97), (8.5, 22.60), (9.0, 22.66), (9.5, 22.44), (10.0, 22.78),
])
hs, ys = SWARF[:, 0], SWARF[:, 1]
A = np.arange(18.0, 22.001, 0.005) # 801 intercepts
B = np.arange(-0.20, 0.8001, 0.002) # 501 slopes
R = ys - (A[:, None, None] + B[None, :, None] * hs) # every line against every point
SCALE = 0.12
square = np.sum(R ** 2, axis=2) # least squares
cauchy = np.sum(np.log(1 + (R / SCALE) ** 2), axis=2) # Cauchy likelihood
for name, surface in (("least squares", square), ("Cauchy likelihood", cauchy)):
i, j = np.unravel_index(surface.argmin(), surface.shape)
print(f"{name:>18}: width = {A[i]:.3f} + {B[j]:.4f} * hours"
f" -> 23.5 mm at hour {(23.5 - A[i]) / B[j]:.2f}")
print(f"{'the truth':>18}: width = 20.000 + 0.3000 * hours"
f" -> 23.5 mm at hour {(23.5 - 20.0) / 0.30:.2f}")
print(f"{A.size * B.size:,} candidate lines evaluated")Les deux lignes surlignées sont toute la différence entre les ajustements. Prenez le logarithme de la densité de Cauchy, jetez les constantes exactement comme avant, et est ce qui reste. Même recette, autre hypothèse sur le bruit.
least squares: width = 21.380 + 0.1080 * hours -> 23.5 mm at hour 19.63
Cauchy likelihood: width = 19.935 + 0.3020 * hours -> 23.5 mm at hour 11.80
the truth: width = 20.000 + 0.3000 * hours -> 23.5 mm at hour 11.67
401,301 candidate lines evaluatedLes moindres carrés annoncent une dérive de 0,108 millimètre par heure, environ un tiers du taux réel, et concluent que la lame est bonne jusqu’à l’heure 19,6. La vraie réponse est l’heure 11,7. En agissant sur cet ajustement, l’usine fait tourner la presse huit heures de plus à fabriquer des pièces hors tolérance, sur l’autorité de la loss function la plus standard du domaine. L’ajustement de Cauchy, avec les mêmes vingt relevés, la même grille et une seule ligne de différence dans le code, tombe sur l’heure 11,8.
Deux objections méritent réponse, parce que toutes deux sont la première chose qu’un bon ingénieur dirait.
Le point aberrant est évident — il suffit de le supprimer. Vous pouvez, cela aide, et ce n’est pas suffisant. Supprimer le pire relevé déplace la pente des moindres carrés de 0,108 à 0,239, ce qui met encore le changement de lame à l’heure 13,1, avec une heure et demie de retard ; supprimer le pire, réajuster, puis supprimer ce qui est maintenant le pire vous amène à 0,286 — et notez que c’est déjà une procédure, pas une observation : supprimez plutôt les deux plus grands résidus de l’ajustement original et vous arrivez à 0,223. Mais vous avez maintenant pris des décisions de jugement que vous ne pouvez ni écrire ni défendre, et automatiser la règle ne la sauve pas : supprimer le plus grand résidu puis réajuster, sur mille postes simulés, donne une erreur médiane de pente de 0,0177 contre 0,0100 pour l’ajustement par vraisemblance, et dépasse 0,05 dans 14,7 % des postes contre 1,3 %. La suppression est un rustine posée sur une mauvaise hypothèse. La vraisemblance n’a pas besoin de rustine, parce qu’elle n’a jamais supposé que le point aberrant était impossible.
Vous avez choisi un jeu de données chanceux. Cette objection est exactement juste, c’est pourquoi la dernière expérience simule mille postes indépendants et réajuste des deux façons sur chacun.
A = np.arange(18.0, 22.001, 0.02) # a coarser grid: a thousand fits to do
B = np.arange(-0.20, 0.8001, 0.005)
lines = A[:, None, None] + B[None, :, None] * hs
rng = np.random.default_rng(2026)
err_sq, err_ca = [], []
for _ in range(1000): # 1000 independent shifts
ys = 20.00 + 0.30 * hs + SCALE * rng.standard_cauchy(hs.size)
R = ys - lines
_, j = np.unravel_index(np.sum(R ** 2, axis=2).argmin(), (A.size, B.size))
_, q = np.unravel_index(np.sum(np.log1p((R / SCALE) ** 2), axis=2).argmin(), (A.size, B.size))
err_sq.append(abs(B[j] - 0.30))
err_ca.append(abs(B[q] - 0.30))
err_sq, err_ca = np.array(err_sq), np.array(err_ca)
for name, e in (("least squares", err_sq), ("Cauchy likelihood", err_ca)):
print(f"{name:>18}: median slope error {np.median(e):.4f} mm/h"
f" off by more than 0.05 in {100 * np.mean(e > 0.05):4.1f}% of shifts"
f" worst {e.max():.3f}")
print(f"the likelihood fit is the closer of the two in {100 * np.mean(err_ca < err_sq):.1f}% of shifts") least squares: median slope error 0.0350 mm/h off by more than 0.05 in 40.4% of shifts worst 0.500
Cauchy likelihood: median slope error 0.0100 mm/h off by more than 0.05 in 1.3% of shifts worst 0.090
the likelihood fit is the closer of the two in 75.6% of shiftsMédiane, pas moyenne, pour la même raison que tout le reste dans cette section : les erreurs des moindres carrés sont entraînées par une Cauchy, donc leur moyenne n’est pas une chose stable à rapporter. Les moindres carrés se trompent lourdement deux postes sur cinq ; l’ajustement par vraisemblance se trompe lourdement un poste sur soixante-dix-sept, et son pire échec sur mille postes est inférieur à un cinquième du pire échec des moindres carrés.
Rien de tout cela ne rend l’erreur quadratique mauvaise. Cela la rend spécifique, et l’arithmétique dit exactement pourquoi. Prenez un résidu de 0,1 mm et un autre de 7 mm. Élevé au carré, le mauvais relevé contribue 4 900 fois plus au total que le bon, donc la droite est tirée de tout son corps vers lui ; sous la log-vraisemblance de Cauchy, les mêmes deux résidus contribuent 0,527 et 8,133, soit un ratio de 15,4. Le mauvais relevé compte encore, il ne décide simplement pas. C’est le début de la statistique robuste, où la loss de Huber de 1964 coupe la différence en se comportant quadratiquement pour les petits résidus et linéairement pour les grands,7 et où Tukey avait déjà montré le peu de contamination nécessaire pour faire de la variance d’échantillon un outil pire que l’écart absolu moyen.8
Une note historique, trop bonne pour être omise. Les moindres carrés ont été publiés les premiers, par Legendre en 1805, comme un dispositif algébrique commode sans autre justification que son fonctionnement.9 Quatre ans plus tard, Gauss a fait le raisonnement à l’envers : il a pris pour acquis que la moyenne arithmétique était la bonne façon de combiner des mesures répétées, a demandé quelle distribution d’erreur rendait la moyenne la valeur la plus probable, et a montré qu’essentiellement une seule le faisait — celle qui porte maintenant son nom.10 La dérivation de ce chapitre est la sienne, elle a plus de deux siècles, et c’est encore la partie que la plupart des cours laissent de côté.
Ce que vous pouvez dire maintenant, et ce que vous ne savez toujours pas faire
Lien vers la section : Ce que vous pouvez dire maintenant, et ce que vous ne savez toujours pas faireAcquis. Une loss function est une règle de score, et le classement qu’elle produit est une propriété de la règle, pas des candidats. Chaque loss dans ce cours est la vraisemblance logarithmique négative d’une hypothèse sur le bruit, constantes retirées — la gaussienne donne ici l’erreur quadratique, Bernoulli donne la cross-entropy au Chapitre 4, et une distribution catégorielle sur un vocabulaire donne la loss du prochain token au Chapitre 8. La recette ne change jamais : énoncer le bruit, écrire la vraisemblance, prendre moins le logarithme. Et quand l’hypothèse est fausse, le modèle n’est pas simplement imprécis, il est faux dans une direction que vous pouvez prédire.
Encore manquant. Nous avons trouvé le fond de la vallée en visitant chaque point qui s’y trouve. Cela a fonctionné pour un paramètre et six cents candidats, et a survécu à deux paramètres avec 401 301 candidats en un cinquième de seconde. Trois paramètres à la même résolution, c’est 201 051 801 candidats, qui ne tiennent plus dans un seul tableau ; un petit réseau au Chapitre 5 a des milliers de paramètres, et les modèles auxquels le Chapitre 10 attribue un prix en ont des milliards. La force brute ici n’est pas lente, elle est arithmétiquement impossible, et rien dans ce chapitre ne suggère d’alternative.
Revenez pourtant à la vallée. Debout à avec une loss de 0,0822, la direction de « descente » n’a rien de mystérieux — vous la voyez sur la page, la courbe descend vers la droite. Si vous pouviez demander à la loss function dans quel sens elle penche au point où vous vous trouvez, sans l’évaluer ailleurs, vous pourriez faire un pas dans cette direction, demander à nouveau, et répéter jusqu’à ce que le sol soit plat.
Cette question a un nom. La pente d’une fonction en un point est sa dérivée, et pour une fonction de nombreux paramètres, la collection des pentes dans toutes les directions à la fois est le gradient. Le Chapitre 1 ne pouvait pas en utiliser, parce que l’erreur du perceptron était un escalier sans pente à interroger. Ce chapitre a construit quelque chose de meilleur : une loss lisse partout, issue d’une hypothèse énoncée plutôt que d’une préférence.
La question du Chapitre 3 n’est donc plus de savoir si une pente existe. Elle est de savoir comment la calculer, pourquoi se déplacer contre elle fait descendre plutôt que monter — un signe que presque tous les cours vous demandent d’accepter sur parole — et jusqu’où aller avant de demander à nouveau, ce qui s’avère être le nombre qui décide si un entraînement converge, oscille indéfiniment autour de la réponse, ou part à l’infini.
Sources et méthode
Lien vers la section : Sources et méthodeÀ lire également en parallèle de ce chapitre : Prince, Understanding Deep Learning §5.1–5.2 et Annexe C, qui construit chaque loss du livre à partir de la vraisemblance maximale dans l’ordre utilisé ici ; Goodfellow, Bengio et Courville, Deep Learning §3.1–3.11 et §5.5, dont la section sur la vraisemblance maximale dérive aussi la divergence KL dont le Chapitre 4 a besoin ; Murphy, Probabilistic Machine Learning: An Introduction chapitre 2 et §4.2, sur ce que la vraisemblance maximale garantit et ne garantit pas ; Deisenroth, Faisal et Ong, Mathematics for Machine Learning §6.1–6.4 pour la règle de somme, la règle de produit et la règle de Bayes faites correctement ; la courte note CMU de Tom Mitchell Estimating Probabilities: MLE and MAP (2016) ; et le §22.7 de Dive into Deep Learning, qui arrive au même résultat en code exécutable.
Références
Lien vers la section : Références-
Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, pp. 309–368 (1922). Où la vraisemblance est présentée comme méthode générale, avec « parameter », « statistic », suffisance et efficacité. Le nom lui-même, et la séparation d’avec la probabilité, date de l’année précédente : Fisher, R. A., On the « probable error » of a coefficient of correlation deduced from a small sample, Metron 1, pp. 3–32 (1921), pp. 24–25. ↩
-
IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Définit binary32 et binary16, ainsi que les règles d’arrondi qui font que l’expérience de sommation donne ce qu’elle donne. ↩
-
Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Les paramètres du format, et l’argument en faveur de l’échange de bits de mantisse contre des bits d’exposant. ↩
-
Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Le loss scaling, et les magnitudes de gradient mesurées qui le rendent nécessaire en float16. ↩
-
Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), pp. 5–48 (1991). Toujours la meilleure explication unique de la raison pour laquelle les deux ordres de sommation divergent. ↩
-
Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), p. 40 (1965). La sommation compensée en une demi-page. ↩
-
Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), pp. 73–101 (1964). La loss qui est quadratique près de zéro et linéaire dans les queues, dérivée plutôt que bricolée. ↩
-
Tukey, J. W. A survey of sampling from contaminated distributions, dans Contributions to Probability and Statistics (Stanford University Press, 1960), pp. 448–485. ↩
-
Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paris, 1805), appendice Sur la méthode des moindres quarrés. La première publication des moindres carrés, comme dispositif de calcul. ↩
-
Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Livre II, §§175–179. Le raisonnement partant de la moyenne arithmétique vers la loi d’erreur normale, puis de là vers les moindres carrés. ↩