De unde vine o funcție de pierdere: verosimilitate, nu convenție
Trei linii trasate din ochi peste aceleași 20 de măsurători. Trei reguli de scor, trei câștigători. Eroarea pătratică e o alegere.
Pe această pagină
Lama care taie piesele se tocește. Pe parcursul unui schimb de zece ore își pierde suficient din tăiș încât piesele ies de pe bandă cu o fracțiune de milimetru mai late decât la început, iar după ce trec de 23,5 milimetri inspecția le respinge. Nimeni din fabrică nu știe când se întâmplă asta. Ce au la dispoziție este un șubler, un caiet și douăzeci de citiri de marțea trecută: orele scurse de când a fost schimbată lama și lățimea piesei măsurată în acel moment.
Cineva trasează o linie printre puncte. Altcineva trasează una ușor diferită. O a treia persoană trasează o a treia. Toate trei par rezonabile pe hârtie și nu sunt de acord cu privire la momentul schimbării lamei, cu o diferență de câteva ore — în această fabrică, diferența dintre o săptămână liniștită și un lot rebutat.
Care linie este mai bună?
Așa formulată, întrebarea nu are răspuns. Nu un răspuns dificil — niciun răspuns. „Mai bună” nu este o proprietate a unei linii în felul în care este panta ei; este o proprietate a unei linii împreună cu o regulă de scor pentru linii, iar până când cineva nu scrie regula nu există nimic de calculat. Acest capitol ia în serios acea propoziție și se încheie cu descoperirea că cea mai comună regulă din machine learning nu este o convenție, ci consecința unei afirmații despre lume — una pe care o poți testa și una care uneori este falsă.
O mărturisire înainte de prima linie de cod. Aceste douăzeci de citiri nu provin dintr-o fabrică reală: le-am generat dintr-o linie aleasă de mine, , plus zgomot aleatoriu cu o dispersie de aproximativ o zecime de milimetru. Asta contează, pentru că tot ce urmează este despre dacă o metodă recuperează un adevăr, iar singurul mod de a verifica asta este să cunoști adevărul dinainte. Așadar: 0,30 milimetri pe oră este răspunsul de la finalul manualului. Nu ai voie să îl folosești, doar să verifici în raport cu el.
Trei reguli, trei câștigători
Link către secțiunea: Trei reguli, trei câștigătoriIată citirile și cele trei linii, evaluate în trei feluri: eroare pătratică, la care ajunge toată lumea; eroare absolută, la care ar putea ajunge un statistician; și eroare maximă, la care ar ajunge mecanicul, pentru că inspectorului nu îi pasă de media ta — el respinge piesa individuală care este în afara toleranței.
NumPy apare aici, la un capitol după perceptronul în Python pur, dintr-un singur motiv: până la finalul acestui capitol vom evalua patru sute de mii de linii candidate în raport cu câte douăzeci de citiri, iar o buclă Python este instrumentul greșit pentru asta. Este și notația în care este scrisă fiecare sursă citată mai jos.
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}") Cantitatea din liniile evidențiate este reziduul: ce a spus linia minus ce a spus șublerul, câte un număr pentru fiecare citire. Fiecare regulă de scor din acest capitol și fiecare funcție de pierdere din cele douăzeci și opt de capitole care urmează este un mod de a comprima o listă de reziduuri într-un singur număr. Diferă doar prin felul în care comprimă.
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.320Citește coloanele, nu rândurile. Eroarea pătratică spune B, eroarea absolută spune A, eroarea maximă spune C: trei reguli, trei câștigători, pe aceleași douăzeci de puncte.
Am ales aceste trei linii ca să nu fie de acord între ele și trebuie să o spun clar. Ideea este cât de ușor a fost — câteva minute de căutare prin interceptări și pante care arată rezonabil scot la iveală sute de astfel de triplete. Clasamentul este o proprietate a regulii pe care ai ales-o, nu un fapt despre linii, deci regula nu este un detaliu de implementare: ea este definiția problemei. Ceea ce ridică întrebarea pentru care există acest capitol: pe ce temei o alegi?
Un parametru și o vale
Link către secțiunea: Un parametru și o valeMai întâi o chestiune mai mică, pentru că nu există trei linii, ci infinit de multe. Ia deocamdată eroarea pătratică, deoarece asta ia toată lumea, și redu problema la un singur număr folosind trucul care a economisit perceptronului unsprezece mii de epoci în Capitolul 1: scade media din ambele coloane. Odată ce norul de puncte este centrat în origine, cea mai bună linie sub eroare pătratică trece exact prin origine — deci interceptarea este rezolvată și rămâne de ales doar panta.
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.010115Șase sute unu pante candidate, un câștigător: 0,293 milimetri pe oră față de un adevăr de 0,300. Douăzeci de citiri zgomotoase și o for-loop au ajuns la mai puțin de o sutime de milimetru pe oră — două virgulă trei procente.
Partea interesantă nu este câștigătorul, ci forma căutării. Afișează întreaga curbă, rotită astfel încât pierderea să curgă de la stânga la dreapta:
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.7928Aceasta este o vale, văzută din lateral. Are un singur fund, pereții urcă lin pe ambele părți și — aceasta este partea pe care scara din Capitolul 1 nu o putea oferi — în fiecare punct de pe ea există o direcție bine definită de „la vale”. Ține minte această formă. Capitolul 3 este în întregime despre cum cobori pe ea fără să vizitezi toate cele șase sute unu puncte și despre ce se schimbă când o vale are mai mult de un fund.
Atunci de ce pătratul?
Link către secțiunea: Atunci de ce pătratul?Avem o vale pentru că am ridicat la pătrat. Eroarea absolută i-ar fi dat un cot în partea de jos; eroarea maximă i-ar fi dat porțiuni plate, unde mutarea liniei nu schimbă nimic. Ridicarea la pătrat este incontestabil convenabilă — iar conveniența este, în linii mari, motivul pe care îl dau cele mai multe cursuri, împachetat în patru feluri: face erorile pozitive (și valoarea absolută face asta); pedepsește mai mult erorile mari (de ce ar trebui?); este diferențiabilă (și puterea a patra este); este ceea ce folosește toată lumea (este, iar asta nu este un argument).
Poziția onestă este aceasta. Eroarea pătratică a selectat linia B, iar eroarea absolută a selectat linia A. Una dintre ele este potrivită pentru această fabrică, iar cealaltă este greșită, și nimic din ce s-a spus până acum nu îți poate spune care. Ca să alegi regula, trebuie să știi ceva despre cum au ajuns citirile să difere de linie, iar aceasta este o întrebare despre lume, nu despre matematică. Ca să răspunzi la ea îți trebuie o mică piesă de mecanism.
Verosimilitatea unei linii
Link către secțiunea: Verosimilitatea unei liniiIată afirmația care transformă „care linie este mai bună” într-o întrebare cu răspuns.
Presupune că lățimea unei piese este linia plus o eroare aleatoare și presupune că acea eroare este extrasă dintr-o Gaussiană — curba în clopot — cu media zero și abaterea standard :
Densitatea Gaussienei este
Acum fă ceva ce perceptronul nu putea. Pentru o pantă candidată dată , fiecare citire are un reziduu, iar formula de mai sus transformă acel reziduu într-un număr: cât de plauzibilă este o eroare exact de acea mărime, dacă această pantă este adevărul? O citire pe linie primește un număr mare, o citire la jumătate de milimetru distanță primește unul mic.
Citirile sunt independente — șublerul nu își amintește piesa precedentă — deci regula produsului spune că plauzibilitatea întregului caiet este produsul densităților individuale. Acel produs este verosimilitatea lui .1 Observă direcția, pentru că este direcția despre care vorbește regula lui Bayes: datele sunt fixe și cunoscute, iar parametrul este cel care variază. Aceasta nu este „probabilitatea pantei”. Este probabilitatea pe care modelul o atribuie datelor pe care chiar le-ai obținut, citită ca funcție de pantă.
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.190312O pantă de 0,293 face acest caiet de patruzeci și șase de mii de ori mai plauzibil decât 0,25 și de o sută douăzeci și șapte de milioane de ori mai plauzibil decât 0,35. Verosimilitatea maximă este principiul conform căruia alegi parametrul care face ceea ce ai observat efectiv cât mai puțin surprinzător posibil. Nu este o teoremă, ci o propunere despre ce ar trebui să însemne „cel mai bun” — o propunere cu conținut, pentru că te obligă să îți formulezi presupunerea despre zgomot înainte să ai voie să evaluezi ceva.
Produsul se rupe
Link către secțiunea: Produsul se rupeRulează aceleași trei linii de cod pe o lună de schimburi în loc de unul singur, iar metoda cedează.
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+308Două mii de înmulțiri și răspunsul este inf. Schimbă o singură constantă — un șubler mai neglijent, astfel încât densitățile ies mai mici decât 1 în loc de mai mari — și același cod returnează 0.0. Ambele răspunsuri sunt greșite, în direcții opuse, niciunul nu ridică o excepție pe care să o poți prinde, iar al doilea nici măcar nu afișează un avertisment.
Nu este nimic în neregulă cu matematica. Verosimilitatea la acele setări este un număr finit perfect bine definit: logaritmul lui natural este 1400,91, deci numărul însuși este aproximativ . Problema este că computerul tău nu are acel număr și merită să înțelegi exact ce numere are, pentru că nu este ultima dată când va decide rezultatul.
De unde vine pătratul
Link către secțiunea: De unde vine pătratulRemediul pentru produsul care explodează este cel obișnuit: ia logaritmi. Logaritmul transformă produsele în sume, este strict crescător deci nu poate muta locul maximului, iar o sumă de două mii de numere moderate este ceva ce float64 gestionează fără să se plângă. Prin convenție luăm negativul log-verosimilității, astfel încât mai bun înseamnă mai mic. Acum înlocuiește densitatea Gaussiană și uită-te ce se întâmplă.
-
Pornește de la produs. Verosimilitatea este , cu densitatea Gaussiană de mai sus.
-
Ia minus logaritmul. Produsul devine o sumă, iar exponențiala din densitate se anulează direct cu logaritmul:
- Aruncă tot ce nu conține . Primul termen este o constantă. din fața sumei este o constantă pozitivă, iar scalarea unei funcții cu o constantă pozitivă nu poate muta locul minimului ei. Ce rămâne este
care este suma reziduurilor pătratice — lucrul cu care am început capitolul pentru că era primul lucru la care se gândește oricine.
Acesta este rezultatul pentru care există capitolul și merită spus fără rezerve: eroarea pătratică nu este o convenție. Este log-verosimilitatea negativă a unei Gaussiene, cu constantele eliminate. Minimizarea erorii pătratice este exact același act cu afirmarea că erorile tale sunt Gaussiene și întrebarea care parametru îți face datele cel mai puțin surprinzătoare. Făceai această afirmație tot timpul; doar că nu ți se spunea.
Echivalența poate fi verificată, deci verific-o: scanează aceleași șase sute unu pante cu log-verosimilitatea negativă completă, cu constante cu tot, și cu eroarea pătratică simplă.
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: TrueNumere diferite pe axa verticală, iar unul dintre ele este negativ, ceea ce o sumă de pătrate nu este niciodată: o log-verosimilitate negativă poate coborî sub zero, pentru că o densitate poate depăși 1. Același fund al aceleiași văi, până la ultimul punct al grilei.
Afișează deducerea completă
Ce eliminări sunt sigure, mai exact? Aceeași manevră apare în fiecare capitol care derivă o pierdere și nu este întotdeauna nevinovată.
Eliminarea unei constante aditive este sigură ori de câte ori nu depinde de parametrul pe care îl optimizezi, iar eliminarea unei constante multiplicative pozitive este sigură pentru că pentru orice . Ambele eșuează în momentul în care și este potrivit: atunci nu este deloc o constantă, ci termenul care oprește modelul să pretindă și plauzibilitate infinită. Exact aceasta este secțiunea următoare.
Ele eșuează diferit din nou în Capitolul 3: o constantă multiplicativă nu mută minimul, dar scalează gradientul, iar gradientul este înmulțit cu rata de învățare. Împărțirea la pentru a obține eroarea pătratică medie în loc de sumă este invizibilă pentru răspuns și foarte vizibilă pentru rularea de antrenare — cu suma, dublarea dimensiunii batch-ului dublează fiecare pas pe care îl faci.
Sigma nu este gratuită nici ea
Link către secțiunea: Sigma nu este gratuită nici eaAm fixat la 0,12 prin decret, iar nimeni din fabrică nu știe dispersia erorii șublerului. Trateaz-o ca pe o a doua necunoscută și lasă verosimilitatea maximă să o decidă și pe ea. Aici termenul constant pe care tocmai l-am eliminat revine, pentru că este singurul lucru care stă între model și o pretenție de precizie perfectă.
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.1006Cele două coincid până la patru zecimale și nu întâmplător: diferențierea acelei expresii și egalarea ei cu zero dă exact . Deci eroarea pătratică medie nu este doar ca o varianță. Sub acest model, ea este estimarea de verosimilitate maximă a varianței zgomotului — numărul pe care l-ai minimizat tot timpul era o estimare a cât de zgomotos este senzorul tău.
O nuanță, ieftin de enunțat și scump de redescoperit mai târziu: acea estimare este părtinitoare în jos, pentru că reziduurile au fost măsurate față de o potrivire aleasă ea însăși ca să le facă mici. Simulează — două sute de mii de caiete cu câte douăzeci de citiri fiecare, extrase dintr-o distribuție a cărei varianță reală este exact 1, cu unicul parametru al potrivirii estimat din citirile însele. Împărțirea sumei pătratelor la dă o medie de 0,9501; împărțirea la dă 1,0001; iar este exact 0,95. Fiecare parametru pe care îl potrivești costă un grad de libertate, iar aceasta este cea mai mică instanță vizibilă a unei probleme mult mai mari: un model arată întotdeauna mai bine pe datele pe care a fost potrivit. Capitolul 4 transformă asta în disciplina de a păstra date deoparte, iar Capitolul 6 îi dă efectului un nume.
O pierdere este o afirmație despre zgomot
Link către secțiunea: O pierdere este o afirmație despre zgomotDacă eroarea pătratică afirmă că zgomotul este Gaussian, următoarea întrebare este ce se întâmplă când afirmația este falsă. Nu ușor falsă — falsă în felul în care măsurătorile reale sunt false.
Pe podeaua atelierului, cele mai multe citiri ale șublerului sunt bune până la o zecime de milimetru, iar o dată sau de două ori pe schimb o așchie intră sub fălci și citirea greșește cu câțiva milimetri. Erorile de acest fel au cozi grele: mici de cele mai multe ori, ocazional enorme și enorme mult mai des decât permite o curbă în clopot. Distribuția Cauchy este modelul curat standard pentru acest comportament, iar densitatea ei este la fel de simplă ca a Gaussienei:
Diferența este coada: Gaussiana scade ca , brutal de repede, iar Cauchy ca , aproape deloc. Consecința este mai ușor de văzut decât de spus:
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.10Varianța eșantionului Gaussian se stabilizează la 0,0144, adică , și rămâne acolo. Cea a lui Cauchy urcă și continuă să urce cât timp eșantionezi, pentru că nu există nimic spre care să conveargă: distribuția Cauchy nu are varianță și nici medie. Eroarea pătratică, a cărei întreagă treabă este să minimizeze o medie a pătratelor, este întrebată de o cantitate care nu există.
Iată deci un schimb în care șublerul a fost păcălit. Aceleași douăzeci de ore, aceeași lamă, aceeași derivă de 0,30 milimetri pe oră — doar zgomotul este acum Cauchy. Potrivește-l de două ori: o dată minimizând reziduurile pătratice, o dată minimizând log-verosimilitatea negativă a zgomotului care a generat efectiv datele. Trucul centrării nu ajută aici — fixează interceptarea doar pentru eroarea pătratică — așa că ambele potriviri merg brute force pe o grilă de interceptări și pante, deoarece încă nu avem nicio metodă de a găsi fundul unei văi decât vizitând-o.
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")Cele două linii evidențiate sunt întreaga diferență dintre potriviri. Ia logaritmul densității Cauchy, elimină constantele exact ca înainte și este ce supraviețuiește. Aceeași rețetă, altă afirmație despre zgomot.
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 evaluatedCele mai mici pătrate raportează o derivă de 0,108 milimetri pe oră, aproximativ o treime din rata reală, și concluzionează că lama este bună până la ora 19,6. Răspunsul adevărat este ora 11,7. Acționând pe baza acelei potriviri, fabrica rulează presa încă opt ore făcând piese în afara toleranței, pe autoritatea celei mai standard funcții de pierdere din domeniu. Potrivirea Cauchy, folosind aceleași douăzeci de citiri, aceeași grilă și o diferență de o singură linie în cod, ajunge la ora 11,8.
Două obiecții merită răspunsuri, pentru că ambele sunt primul lucru pe care îl spune un inginer bun.
Valoarea aberantă este evidentă — doar șterge-o. Poți, ajută și nu este suficient. Ștergerea celei mai proaste citiri mută panta celor mai mici pătrate de la 0,108 la 0,239, ceea ce tot plasează schimbarea lamei la ora 13,1, cu o oră și jumătate întârziere; ștergerea celei mai proaste, repotrivirea și ștergerea a ceea ce este cel mai prost acum te duce la 0,286 — și observă că aceasta este deja o procedură, nu o observație: șterge în schimb cele mai mari două reziduuri ale potrivirii originale și ajungi la 0,223. Dar acum ai făcut judecăți pe care nu le poți scrie sau apăra, iar automatizarea regulii nu o salvează: elimină-cel-mai-mare-reziduu-apoi-repotrivește, rulat pe o mie de schimburi simulate, are o eroare mediană a pantei de 0,0177 față de 0,0100 pentru potrivirea prin verosimilitate și greșește cu mai mult de 0,05 în 14,7% dintre schimburi față de 1,3%. Ștergerea este un petic peste o presupunere greșită. Verosimilitatea nu are nevoie de petic, pentru că nu a presupus niciodată că valoarea aberantă era imposibilă.
Ai ales un set de date norocos. Obiecția este perfect corectă, motiv pentru care ultimul experiment simulează o mie de schimburi independente și repotrivește în ambele moduri pe fiecare.
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ă, nu medie, din același motiv ca tot restul acestei secțiuni: erorile celor mai mici pătrate sunt conduse de o Cauchy, deci media lor nu este ceva stabil de raportat. Cele mai mici pătrate greșesc grav în două schimburi din cinci; potrivirea prin verosimilitate greșește grav într-un schimb din șaptezeci și șapte, iar cel mai rău eșec al ei dintr-o mie de schimburi este mai mic de o cincime din cel mai rău eșec al celor mai mici pătrate.
Nimic din asta nu face eroarea pătratică rea. O face specifică, iar aritmetica spune exact de ce. Ia un reziduu de 0,1 mm și unul de 7 mm. Ridicat la pătrat, citirea proastă contribuie de 4.900 de ori mai mult la total decât cea bună, astfel încât linia este trasă cu totul spre ea; sub log-verosimilitatea Cauchy, aceleași două reziduuri contribuie 0,527 și 8,133, un raport de 15,4. Citirea proastă încă este luată în calcul, doar că nu mai decide. Acesta este începutul statisticii robuste, unde pierderea lui Huber din 1964 împarte diferența comportându-se pătratic pentru reziduuri mici și liniar pentru cele mari,7 și unde Tukey arătase deja cât de puțină contaminare este necesară ca varianța eșantionului să devină un instrument mai prost decât abaterea absolută medie.8
Și o notă istorică, prea bună ca să fie lăsată afară. Cele mai mici pătrate au fost publicate mai întâi de Legendre în 1805, ca un dispozitiv algebric convenabil, fără altă justificare decât că funcționa.9 Patru ani mai târziu, Gauss a rulat argumentul invers: a luat ca dat faptul că media aritmetică este modul corect de a combina măsurători repetate, a întrebat ce distribuție a erorii face media valoarea cea mai probabilă și a arătat că, în esență, doar una o face — cea care îi poartă acum numele.10 Derivarea din acest capitol este a lui, are peste două secole și este încă partea pe care cele mai multe cursuri o omit.
Ce poți spune acum și ce încă nu poți face
Link către secțiunea: Ce poți spune acum și ce încă nu poți faceCâștigat. O funcție de pierdere este o regulă de scor, iar clasamentul pe care îl produce este o proprietate a regulii, nu a candidaților. Fiecare pierdere din acest curs este log-verosimilitatea negativă a unei presupuneri despre zgomot, cu constantele aruncate — Gaussiana dă eroarea pătratică aici, Bernoulli dă cross-entropy în Capitolul 4, iar o distribuție categorială peste un vocabular dă pierderea next-token în Capitolul 8. Rețeta nu se schimbă niciodată: enunță zgomotul, scrie verosimilitatea, ia minus logaritmul. Iar când presupunerea este greșită, modelul nu este doar imprecis, ci este greșit într-o direcție pe care o poți prezice.
Încă lipsește. Am găsit fundul văii vizitând fiecare punct din ea. Asta a funcționat pentru un parametru și șase sute de candidați și a supraviețuit la doi parametri cu 401.301 candidați într-o cincime de secundă. Trei parametri la aceeași rezoluție înseamnă 201.051.801 candidați și nu mai încap într-un singur array; o rețea mică din Capitolul 5 are mii de parametri, iar modelele cărora Capitolul 10 le pune un preț au miliarde. Brute force aici nu este lent, este aritmetic imposibil, iar nimic din acest capitol nu sugerează o alternativă.
Uită-te însă înapoi la vale. Stând la cu o pierdere de 0,0822, direcția de „la vale” nu este un mister — o poți vedea pe pagină, curba coboară spre dreapta. Dacă ai putea întreba funcția de pierdere în ce direcție se înclină în punctul în care stai, fără să o evaluezi nicăieri altundeva, ai putea face un pas în acea direcție, întreba din nou și repeta până când terenul devine plat.
Această întrebare are un nume. Panta unei funcții într-un punct este derivata ei, iar pentru o funcție cu mulți parametri colecția pantelor în toate direcțiile deodată este gradientul. Capitolul 1 nu a putut folosi unul, pentru că eroarea perceptronului era o scară fără pantă despre care să poți întreba. Acest capitol a construit ceva mai bun: o pierdere care este netedă peste tot și care a venit dintr-o presupunere enunțată, nu dintr-o preferință.
Așadar, întrebarea pentru Capitolul 3 nu mai este dacă există o pantă. Este cum o calculezi, de ce deplasarea împotriva ei coboară la vale în loc să urce — un semn pe care aproape fiecare curs îți cere să îl accepți pe încredere — și cât de departe să pășești înainte să întrebi din nou, lucru care se dovedește a fi singurul număr care decide dacă o rulare de antrenare converge, oscilează în jurul răspunsului la nesfârșit sau fuge spre infinit.
Surse și metodă
Link către secțiunea: Surse și metodăMerită citite în paralel cu acest capitol și: Prince, Understanding Deep Learning §5.1–5.2 și Anexa C, care construiește fiecare pierdere din carte pornind de la verosimilitatea maximă, în ordinea folosită aici; Goodfellow, Bengio și Courville, Deep Learning §3.1–3.11 și §5.5, a căror secțiune despre verosimilitate maximă derivă și divergența KL de care are nevoie Capitolul 4; Murphy, Probabilistic Machine Learning: An Introduction capitolul 2 și §4.2, despre ce garantează și ce nu garantează verosimilitatea maximă; Deisenroth, Faisal și Ong, Mathematics for Machine Learning §6.1–6.4 pentru regula sumei, regula produsului și regula lui Bayes tratate cum se cuvine; nota scurtă CMU a lui Tom Mitchell, Estimating Probabilities: MLE and MAP (2016); și §22.7 din Dive into Deep Learning, care ajunge la același rezultat în cod rulabil.
Referințe
Link către secțiunea: Referințe-
Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, pp. 309–368 (1922). Unde verosimilitatea este formulată ca metodă generală, împreună cu „parameter”, „statistic”, suficiență și eficiență. Denumirea în sine și separarea de probabilitate apar cu un an mai devreme: 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. Definește binary32 și binary16, precum și regulile de rotunjire care fac experimentul de însumare să iasă așa cum iese. ↩
-
Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Parametrii formatului și argumentul pentru schimbul de biți de mantisă pe biți de exponent. ↩
-
Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling și magnitudinile măsurate ale gradienților care îl fac necesar în float16. ↩
-
Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), pp. 5–48 (1991). Încă cea mai bună explicație unică pentru motivul pentru care cele două ordini de însumare nu coincid. ↩
-
Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), p. 40 (1965). Însumarea compensată în jumătate de pagină. ↩
-
Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), pp. 73–101 (1964). Pierderea care este pătratică lângă zero și liniară în cozi, derivată mai degrabă decât cârpită. ↩
-
Tukey, J. W. A survey of sampling from contaminated distributions, în 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), apendicele Sur la méthode des moindres quarrés. Prima publicare a celor mai mici pătrate, ca dispozitiv computațional. ↩
-
Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Book II, §§175–179. Argumentul de la media aritmetică la legea erorii normale și de acolo la cele mai mici pătrate. ↩