Hvor en tabsfunktion kommer fra: likelihood, ikke konvention
Tre linjer over de samme 20 målinger og tre scoringsregler, der kårer hver sin vinder. Kvadreret fejl er et valg.
På denne side
Klingen, der skærer delene, slides ned. Over et ti-timers skift mister den nok skarphed til, at delene kommer af båndet en brøkdel af en millimeter bredere, end de startede, og når de passerer 23,5 millimeter, afviser kontrollen dem. Ingen på fabrikken ved, hvornår det sker. Det, de har, er en skydelære, en notesbog og tyve aflæsninger fra sidste tirsdag: timerne siden klingen blev skiftet, og bredden på delen målt i det øjeblik.
Nogen tegner en linje gennem punkterne. En anden tegner en lidt anden. En tredje person tegner en tredje. Alle tre ser rimelige ud på papiret, og de er uenige med flere timer om, hvornår klingen skal skiftes — på denne fabrik forskellen mellem en rolig uge og et kasseret batch.
Hvilken linje er bedre?
Som spørgsmålet står, har det intet svar. Ikke et svært svar — slet intet svar. »Bedre« er ikke en egenskab ved en linje på samme måde som dens hældning er; det er en egenskab ved en linje sammen med en regel for at score linjer, og indtil nogen skriver reglen ned, er der intet at beregne. Dette kapitel tager den sætning alvorligt og ender med opdagelsen af, at den mest almindelige regel i machine learning ikke er en konvention, men konsekvensen af en påstand om verden — en, du kan teste, og en, der nogle gange er falsk.
En indrømmelse før den første kodelinje. Disse tyve aflæsninger er ikke fra en virkelig fabrik: Jeg genererede dem fra en linje, jeg valgte, , plus tilfældig støj med en spredning på omkring en tiendedel millimeter. Det betyder noget, fordi alt nedenfor handler om, hvorvidt en metode genfinder en sandhed, og den eneste måde at kontrollere det på er at kende sandheden på forhånd. Så: 0,30 millimeter i timen er svaret bag i bogen. Du må ikke bruge det, kun kontrollere mod det.
Tre regler, tre vindere
Link til afsnittet: Tre regler, tre vindereHer er aflæsningerne og de tre linjer, scoret på tre måder: kvadreret fejl, som alle rækker ud efter; absolut fejl, som en statistiker måske ville; og værste fejl, som maskinarbejderen ville, fordi inspektøren er ligeglad med dit gennemsnit — han afviser den ene del, der er uden for tolerance.
NumPy kommer ind her, ét kapitel efter den rene Python-perceptron, af én grund: Ved slutningen af dette kapitel evaluerer vi fire hundrede tusind kandidatlinjer mod tyve aflæsninger hver, og et Python-loop er det forkerte værktøj til det. Det er også den notation, alle kilderne citeret nedenfor er skrevet i.
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}") Størrelsen i de fremhævede linjer er residualet: det, linjen sagde, minus det, skydelæren sagde, ét tal per aflæsning. Hver scoringsregel i dette kapitel, og hver tabsfunktion i de otteogtyve kapitler efter det, er en måde at mase en liste af residualer ned til ét enkelt tal. De adskiller sig kun i, hvordan de maser.
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.320Læs kolonnerne, ikke rækkerne. Kvadreret fejl siger B, absolut fejl siger A, værste fejl siger C: tre regler, tre vindere, på de samme tyve punkter.
Jeg valgte disse tre linjer, så de ville være uenige, og det bør jeg sige ligeud. Pointen er, hvor let det var — nogle få minutters søgning over intercepts og hældninger, der ser fornuftige ud, finder hundredvis af sådanne tripler. Rangeringen er en egenskab ved den regel, du valgte, ikke et faktum om linjerne, så reglen er ikke en implementeringsdetalje: Den er definitionen af problemet. Hvilket rejser det spørgsmål, dette kapitel findes for at besvare: På hvilket grundlag vælger du den?
Én parameter og en dal
Link til afsnittet: Én parameter og en dalFørst en mindre sag, for der er ikke tre linjer, men uendeligt mange. Tag kvadreret fejl indtil videre, eftersom det er det, alle tager, og krymp problemet til et enkelt tal ved hjælp af tricket, der sparede perceptronen elleve tusind epoker i kapitel 1: Træk gennemsnittet fra begge kolonner. Når punktskyen er centreret om origo, går den bedste linje under kvadreret fejl præcis gennem origo — så interceptet er afgjort, og kun hældningen er tilbage at vælge.
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.010115Seks hundrede og én kandidathældninger, én vinder: 0,293 millimeter i timen mod en sandhed på 0,300. Tyve støjende aflæsninger og et for-loop kom inden for en hundrededel millimeter i timen — to og en tredjedel procent.
Det interessante er ikke vinderen, men formen på søgningen. Print hele kurven, roteret så tabet løber fra venstre mod højre:
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.7928Det er en dal, set fra siden. Den har én bund, væggene stiger jævnt på begge sider, og — dette er den del, trappen i kapitel 1 ikke kunne tilbyde — på hvert eneste punkt på den findes der en veldefineret retning »nedad«. Husk den form. Kapitel 3 handler udelukkende om at gå ned ad den uden at besøge alle seks hundrede og ét punkter, og om hvad der ændrer sig, når en dal har mere end én bund.
Så hvorfor kvadreret?
Link til afsnittet: Så hvorfor kvadreret?Vi har en dal, fordi vi kvadrerede. Absolut fejl ville have givet den et knæk i bunden; værste fejl ville have givet den flade stræk, hvor det slet ikke ændrer noget at flytte linjen. Kvadrering er unægteligt bekvemt — og bekvemmelighed er omtrent den grund, de fleste kurser giver, pyntet på fire måder: Det gør fejl positive (det gør absolutværdi også); det straffer store fejl mere (hvorfor skulle det?); det er differentiabelt (det er fjerde potens også); det er det, alle bruger (det er det, og det er ikke et argument).
Her er den ærlige position. Kvadreret fejl valgte linje B, og absolut fejl valgte linje A. En af dem er rigtig for denne fabrik, og den anden er forkert, og intet af det, der hidtil er sagt, kan fortælle dig hvilken. For at vælge reglen skal du vide noget om hvordan aflæsningerne kom til at afvige fra linjen, og det er et spørgsmål om verden, ikke om matematik. At besvare det kræver et lille stykke maskineri.
Likelihood for en linje
Link til afsnittet: Likelihood for en linjeHer er påstanden, der forvandler »hvilken linje er bedre« til et spørgsmål med et svar.
Antag, at bredden på en del er linjen plus en tilfældig fejl, og antag, at fejlen trækkes fra en Gaussisk fordeling — klokkekurven — med middelværdi nul og standardafvigelse :
Den Gaussiske tæthed er
Gør nu noget, perceptronen ikke kunne. For en given kandidathældning har hver aflæsning et residual, og formlen ovenfor forvandler det residual til et tal: Hvor plausibel er en fejl af præcis den størrelse, hvis denne hældning er sandheden? En aflæsning på linjen får et stort tal, en aflæsning en halv millimeter væk et lille.
Aflæsningerne er uafhængige — skydelæren husker ikke den sidste del — så produktreglen siger, at plausibiliteten af hele notesbogen er produktet af de individuelle tætheder. Det produkt er likelihood for .1 Bemærk retningen, for det er den retning, Bayes' regel handler om: Dataene er faste og kendte, og det er parameteren, der varierer. Dette er ikke »sandsynligheden for hældningen«. Det er den sandsynlighed, modellen tildeler de data, du faktisk fik, læst som en funktion af hældningen.
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.190312En hældning på 0,293 gør denne notesbog seksogfyrre tusind gange mere plausibel end 0,25 og hundrede og syvogtyve millioner gange mere plausibel end 0,35. Maximum likelihood er princippet om, at du vælger den parameter, der gør det, du faktisk observerede, så lidt overraskende som muligt. Det er ikke et teorem, men et forslag til, hvad »bedst« bør betyde — et forslag med indhold, fordi det tvinger dig til at angive din antagelse om støjen, før du får lov til at score noget.
Produktet går i stykker
Link til afsnittet: Produktet går i stykkerKør de samme tre kodelinjer på en måneds skift i stedet for ét, og metoden falder sammen.
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+308To tusind multiplikationer, og svaret er inf. Skift én konstant — en mere sjusket skydelære, så tæthederne bliver mindre end 1 i stedet for større — og den samme kode returnerer 0.0. Begge svar er forkerte, i hver sin retning, ingen af dem rejser en exception, du kan fange, og den anden printer ikke engang en advarsel.
Der er intet galt med matematikken. Likelihood ved disse indstillinger er et perfekt veldefineret endeligt tal: Dets naturlige logaritme er 1400,91, så selve tallet er omkring . Problemet er, at din computer ikke har det tal, og det er værd at forstå præcis, hvilke tal den har, fordi det ikke er sidste gang, den afgør udfaldet.
Hvor kvadratet kommer fra
Link til afsnittet: Hvor kvadratet kommer fraLøsningen på det eksploderende produkt er den sædvanlige: Tag logaritmer. Logaritmen forvandler produkter til summer, den er strengt voksende, så den kan ikke flytte maksimums placering, og en sum af to tusind moderate tal er noget, float64 håndterer uden klage. Efter konvention tager vi den negative log-likelihood, så bedre betyder mindre. Indsæt nu den Gaussiske tæthed, og se hvad der sker.
-
Start med produktet. Likelihood er , med som den Gaussiske tæthed ovenfor.
-
Tag minus logaritmen. Produktet bliver en sum, og eksponentialleddet i tætheden ophæves direkte af logaritmen:
- Smid alt væk, der ikke indeholder . Det første led er en konstant. foran summen er en positiv konstant, og at skalere en funktion med en positiv konstant kan ikke flytte, hvor dens minimum er. Tilbage står
som er summen af kvadrerede residualer — det, vi startede kapitlet med, fordi det var det første, nogen tænker på.
Det er resultatet, kapitlet findes for, og det fortjener at blive sagt uden forbehold: Kvadreret fejl er ikke en konvention. Det er den negative log-likelihood for en Gaussisk fordeling, med konstanterne fjernet. At minimere kvadreret fejl er præcis den samme handling som at påstå, at dine fejl er Gaussiske, og spørge, hvilken parameter der gør dine data mindst overraskende. Du fremsatte den påstand hele tiden; du fik det bare ikke at vide.
Ækvivalensen kan kontrolleres, så kontroller den: Scan de samme seks hundrede og én hældninger med den fulde negative log-likelihood, konstanter og det hele, og med almindelig kvadreret fejl.
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: TrueForskellige tal på den lodrette akse, og et af dem er negativt, hvilket en sum af kvadrater aldrig er: En negativ log-likelihood kan gå under nul, fordi en tæthed kan overstige 1. Samme bund i samme dal, til sidste gitterpunkt.
Vis hele udledningen
Hvilke frasorteringer er helt præcist sikre? Den samme manøvre optræder i hvert kapitel, der udleder et tab, og den er ikke altid uskyldig.
At droppe en additiv konstant er sikkert, når den ikke afhænger af den parameter, du optimerer, og at droppe en positiv multiplikativ konstant er sikkert, fordi for enhver . Begge dele fejler i det øjeblik, også bliver fitted: Så er slet ikke en konstant, men det led, der forhindrer modellen i at påstå og uendelig plausibilitet. Det er præcis næste afsnit.
De fejler anderledes igen i kapitel 3: En multiplikativ konstant flytter ikke minimum, men den skalerer gradienten, og gradienten bliver multipliceret med learning rate. At dividere med for at få den gennemsnitlige kvadrerede fejl snarere end summen er usynligt for svaret og meget synligt for træningskørslen — med summen fordobler en fordobling af din batchstørrelse hvert skridt, du tager.
Sigma er heller ikke gratis
Link til afsnittet: Sigma er heller ikke gratisVi fastsatte til 0,12 ved dekret, og ingen på fabrikken kender spredningen i skydelærens fejl. Behandl den som en anden ukendt, og lad maximum likelihood afgøre den også. Her kommer konstantleddet, vi lige smed væk, tilbage, fordi det er det eneste, der står mellem modellen og en påstand om perfekt præcision.
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.1006De to stemmer overens til fire decimaler, og ikke ved et tilfælde: At differentiere det udtryk og sætte det lig nul giver præcis. Så den gennemsnitlige kvadrerede fejl er ikke blot som en varians. Under denne model er den maximum-likelihood-estimatet for støjens varians — det tal, du hele tiden har minimeret, var et estimat af, hvor støjende din sensor er.
Én krølle, billig at formulere og dyr at genopdage senere: Estimatet er biased lavt, fordi residualerne blev målt mod et fit, der selv var valgt for at gøre dem små. Simuler det — to hundrede tusind notesbøger med tyve aflæsninger hver, trukket fra en fordeling, hvis sande varians er præcis 1, med den ene parameter i fittet estimeret fra selve aflæsningerne. At dividere summen af kvadrater med giver et gennemsnit på 0,9501; at dividere med giver 1,0001; og er 0,95 på prikken. Hver parameter, du fitter, koster én frihedsgrad, og dette er det mindste synlige eksempel på et meget større problem: En model ser altid bedre ud på de data, den blev fitted til. Kapitel 4 gør det til disciplinen at holde data tilbage, og kapitel 6 giver effekten sit navn.
Et tab er en påstand om støjen
Link til afsnittet: Et tab er en påstand om støjenHvis kvadreret fejl påstår, at støjen er Gaussisk, er det næste spørgsmål, hvad der sker, når påstanden er falsk. Ikke lidt falsk — falsk på den måde, virkelige målinger er falske.
På fabriksgulvet er de fleste skydelæreaflæsninger gode inden for en tiendedel millimeter, og en eller to gange per skift kommer et spån under kæben, og aflæsningen er flere millimeter forkert. Den slags fejl er heavy-tailed: små det meste af tiden, lejlighedsvis enorme, og enorme langt oftere end en klokkekurve tillader. Cauchy-fordelingen er den klassiske rene model for den adfærd, og dens tæthed er lige så enkel som den Gaussiskes:
Forskellen er halen: Den Gaussiske falder som , brutalt hurtigt, og Cauchy som , næsten slet ikke. Konsekvensen er lettere at se end at sige:
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.10Den Gaussiskes sample-varians falder til ro på 0,0144, som er , og bliver der. Cauchys stiger og bliver ved med at stige, så længe du sampler, fordi der ikke er noget for den at konvergere mod: Cauchy-fordelingen har ingen varians og heller intet gennemsnit. Kvadreret fejl, hvis hele ærinde er at minimere et gennemsnit af kvadrater, bliver bedt om en størrelse, der ikke findes.
Så her er ét skift, hvor skydelæren blev narret. Samme tyve timer, samme klinge, samme drift på 0,30 millimeter i timen — kun støjen er nu Cauchy. Fit det to gange: én gang ved at minimere kvadrerede residualer, én gang ved at minimere den negative log-likelihood for den støj, der faktisk genererede dataene. Centreringstricket hjælper ikke her — det fastlåser kun interceptet for kvadreret fejl — så begge fit foretages med brute force over et gitter af intercepts og hældninger, eftersom vi stadig ikke har nogen måde at finde bunden af en dal på ud over at besøge den.
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")De to fremhævede linjer er hele forskellen mellem fittene. Tag logaritmen af Cauchy-tætheden, drop konstanterne præcis som før, og er det, der overlever. Samme opskrift, anden påstand om støjen.
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 evaluatedMindste kvadraters metode rapporterer en drift på 0,108 millimeter i timen, omtrent en tredjedel af den reelle rate, og konkluderer, at klingen er god indtil time 19,6. Det sande svar er time 11,7. Handler fabrikken på det fit, kører den pressen i otte ekstra timer og laver dele, der er uden for tolerance, med den mest standardiserede tabsfunktion i feltet som autoritet. Cauchy-fittet, med de samme tyve aflæsninger, det samme gitter og én linjes forskel i koden, lander på time 11,8.
To indvendinger fortjener svar, fordi begge er det første, en god ingeniør siger.
Outlieren er åbenlys — slet den bare. Det kan du, og det hjælper, og det er ikke nok. At slette den enkeltstående værste aflæsning flytter mindste-kvadraters-hældningen fra 0,108 til 0,239, hvilket stadig placerer klingeskiftet ved time 13,1, halvanden time for sent; at slette den værste, fitte igen og slette det, der er værst nu, bringer dig til 0,286 — og bemærk, at dette allerede er en procedure, ikke en observation: Slet de to største residualer fra det oprindelige fit i stedet, og du lander på 0,223. Men du har nu truffet skønsmæssige valg, du ikke kan skrive ned eller forsvare, og at automatisere reglen redder den ikke: drop-det-største-residual-og-fit-igen, kørt over tusind simulerede skift, har en median hældningsfejl på 0,0177 mod likelihood-fittets 0,0100 og er mere end 0,05 forkert i 14,7% af skiftene mod 1,3%. Sletning er en lap oven på en forkert antagelse. Likelihood behøver ingen lap, fordi den aldrig antog, at outlieren var umulig.
Du valgte et heldigt datasæt. Den indvending er helt rigtig, og derfor simulerer det sidste eksperiment tusind uafhængige skift og fitter på begge måder på hvert.
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 shiftsMedian, ikke gennemsnit, af samme grund som alt andet i dette afsnit: Mindste-kvadraters-fejlene drives af en Cauchy, så deres gennemsnit er ikke en stabil størrelse at rapportere. Mindste kvadraters metode er alvorligt forkert to skift ud af fem; likelihood-fittet er alvorligt forkert ét skift ud af syvoghalvfjerds, og dets værste fejl på tværs af tusind skift er mindre end en femtedel af mindste kvadraters værste.
Intet af dette gør kvadreret fejl dårlig. Det gør den specifik, og aritmetikken siger præcis hvorfor. Tag et residual på 0,1 mm og et på 7 mm. Kvadreret bidrager den dårlige aflæsning 4.900 gange så meget til totalen som den gode, så linjen bliver trukket kropsligt hen imod den; under Cauchy log-likelihood bidrager de samme to residualer med 0,527 og 8,133, et forhold på 15,4. Den dårlige aflæsning tæller stadig, den får bare ikke lov at bestemme. Dette er begyndelsen på robust statistik, hvor Hubers tab fra 1964 deler forskellen ved at opføre sig kvadratisk for små residualer og lineært for store,7 og hvor Tukey allerede havde vist, hvor lidt kontaminering der skal til for at gøre sample-variansen til et dårligere værktøj end den gennemsnitlige absolutte afvigelse.8
En historisk note, for god til at udelade. Mindste kvadraters metode blev først publiceret af Legendre i 1805 som et bekvemt algebraisk redskab uden anden begrundelse end, at det virkede.9 Fire år senere vendte Gauss argumentet om: Han tog det som givet, at det aritmetiske gennemsnit er den rigtige måde at kombinere gentagne målinger på, spurgte hvilken fejlfordeling der gør gennemsnittet til den mest sandsynlige værdi, og viste, at i det væsentlige kun én gør — den, der nu er opkaldt efter ham.10 Udledningen i dette kapitel er hans, den er mere end to århundreder gammel, og den er stadig den del, de fleste kurser udelader.
Hvad du nu kan sige, og hvad du stadig ikke kan gøre
Link til afsnittet: Hvad du nu kan sige, og hvad du stadig ikke kan gøreOptjent. En tabsfunktion er en scoringsregel, og den rangering, den producerer, er en egenskab ved reglen, ikke ved kandidaterne. Hvert tab i dette kursus er den negative log-likelihood for en eller anden antagelse om støjen, med konstanterne smidt væk — Gaussisk giver kvadreret fejl her, Bernoulli giver cross-entropy i kapitel 4, og en kategorisk fordeling over et vokabular giver next-token loss i kapitel 8. Opskriften ændrer sig aldrig: Angiv støjen, skriv likelihood, tag minus logaritmen. Og når antagelsen er forkert, er modellen ikke blot upræcis, den er forkert i en retning, du kan forudsige.
Mangler stadig. Vi fandt bunden af dalen ved at besøge hvert punkt i den. Det virkede for én parameter og seks hundrede kandidater og overlevede to parametre ved 401.301 kandidater på en femtedel af et sekund. Tre parametre med samme opløsning er 201.051.801 kandidater og passer ikke længere i ét array; et lille netværk i kapitel 5 har tusindvis af parametre, og de modeller, kapitel 10 sætter pris på, har milliarder. Brute force her er ikke langsomt, det er aritmetisk umuligt, og intet i dette kapitel antyder et alternativ.
Se dog tilbage på dalen. Når du står ved med et tab på 0,0822, er retningen »nedad« ikke nogen gåde — du kan se den på siden, kurven hælder ned mod højre. Hvis du kunne spørge tabsfunktionen, hvilken vej den hælder på det punkt, du står på, uden at evaluere den andre steder, kunne du tage et skridt den vej, spørge igen og gentage, indtil jorden er flad.
Det spørgsmål har et navn. Hældningen af en funktion i et punkt er dens afledte, og for en funktion af mange parametre er samlingen af hældninger i alle retninger på én gang gradienten. Kapitel 1 kunne ikke bruge en, fordi perceptronens fejl var en trappe uden hældning at spørge om. Dette kapitel har bygget noget bedre: et tab, der er glat overalt, og som kom fra en angivet antagelse snarere end en præference.
Så spørgsmålet for kapitel 3 er ikke længere, om en hældning findes. Det er, hvordan man beregner den, hvorfor det at bevæge sig mod den går nedad snarere end opad — et fortegn, næsten alle kurser beder dig tage på tillid — og hvor langt man skal træde, før man spørger igen, hvilket viser sig at være det ene tal, der afgør, om en træningskørsel konvergerer, oscillerer omkring svaret for evigt eller løber mod uendelig.
Kilder og metode
Link til afsnittet: Kilder og metodeOgså værd at læse sammen med dette kapitel: Prince, Understanding Deep Learning §5.1–5.2 og appendiks C, som bygger hvert tab i bogen fra maximum likelihood i den rækkefølge, der bruges her; Goodfellow, Bengio og Courville, Deep Learning §3.1–3.11 og §5.5, hvis maximum-likelihood-afsnit også udleder KL-divergensen, som kapitel 4 kræver; Murphy, Probabilistic Machine Learning: An Introduction kapitel 2 og §4.2, om hvad maximum likelihood gør og ikke garanterer; Deisenroth, Faisal og Ong, Mathematics for Machine Learning §6.1–6.4 for sumreglen, produktreglen og Bayes' regel gjort ordentligt; Tom Mitchells korte CMU-note Estimating Probabilities: MLE and MAP (2016); og §22.7 af Dive into Deep Learning, som når samme resultat i kørbar kode.
Referencer
Link til afsnittet: Referencer-
Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, s. 309–368 (1922). Hvor likelihood opstilles som en generel metode, sammen med »parameter«, »statistic«, sufficiency og efficiency. Selve navngivningen og adskillelsen fra probability er et år tidligere: Fisher, R. A., On the "probable error" of a coefficient of correlation deduced from a small sample, Metron 1, s. 3–32 (1921), s. 24–25. ↩
-
IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Definerer binary32 og binary16 samt afrundingsreglerne, der får summeringseksperimentet til at falde ud, som det gør. ↩
-
Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Formatets parametre og argumentet for at bytte mantisse-bits for eksponent-bits. ↩
-
Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling og de målte gradientstørrelser, der gør det nødvendigt i float16. ↩
-
Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), s. 5–48 (1991). Stadig den bedste enkeltstående forklaring på, hvorfor de to summeringsrækkefølger er uenige. ↩
-
Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), s. 40 (1965). Kompenseret summering på en halv side. ↩
-
Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), s. 73–101 (1964). Tabet, der er kvadratisk nær nul og lineært i halerne, udledt snarere end lappet sammen. ↩
-
Tukey, J. W. A survey of sampling from contaminated distributions, i Contributions to Probability and Statistics (Stanford University Press, 1960), s. 448–485. ↩
-
Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paris, 1805), appendiks Sur la méthode des moindres quarrés. Den første publicering af mindste kvadraters metode som et beregningsredskab. ↩
-
Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), bog II, §§175–179. Argumentet fra det aritmetiske gennemsnit til den normale fejllov og derfra til mindste kvadraters metode. ↩