Přeskočit na obsah
2/30Kapitola 2 z 30

Odkud se bere ztrátová funkce: z věrohodnosti, ne z konvence

Tři čáry od oka nad stejnými měřeními a tři skórovací pravidla vyberou tři vítěze. Kvadratická chyba je volba.

Na této stránce

Čepel, která řeže díly, se opotřebovává. Během desetihodinové směny ztratí ostří natolik, že díly sjíždějí z pásu o zlomek milimetru širší než na začátku, a jakmile překročí 23,5 milimetru, kontrola je vyřadí. Nikdo v továrně neví, kdy se to stane. Mají posuvné měřítko, zápisník a dvacet údajů z minulého úterý: hodiny od výměny čepele a šířku dílu naměřenou v daném okamžiku.

Někdo body protáhne přímku. Někdo jiný nakreslí trochu jinou. Třetí člověk nakreslí třetí. Všechny tři vypadají na papíře rozumně a liší se v tom, kdy čepel vyměnit, o několik hodin — v této továrně je to rozdíl mezi klidným týdnem a zmetkovou šarží.

Která přímka je lepší?

Takto položená otázka nemá odpověď. Ne obtížnou odpověď — vůbec žádnou. „Lepší“ není vlastnost přímky tak jako její směrnice; je to vlastnost přímky spolu s pravidlem pro skórování přímek, a dokud někdo toto pravidlo nezapíše, není co počítat. Tato kapitola bere tu větu vážně a končí zjištěním, že nejběžnější pravidlo v machine learning není konvence, ale důsledek tvrzení o světě — tvrzení, které můžete otestovat a které je někdy nepravdivé.

Jedno přiznání před prvním řádkem kódu. Těchto dvacet měření nepochází ze skutečné továrny: vygeneroval jsem je z přímky, kterou jsem zvolil, width=20.00+0.30h\text{width} = 20.00 + 0.30 \cdot h, plus náhodný šum s rozptylem zhruba desetiny milimetru. Na tom záleží, protože všechno níže je o tom, zda metoda dokáže obnovit pravdu, a jediný způsob, jak to ověřit, je znát pravdu předem. Takže: 0,30 milimetru za hodinu je odpověď na konci učebnice. Nesmíte ji použít, jen se proti ní kontrolovat.

Tady jsou měření a tři přímky, ohodnocené třemi způsoby: kvadratickou chybou, po které sáhne skoro každý; absolutní chybou, po které by sáhl statistik; a nejhorší chybou, po které by sáhl obráběč, protože inspektora nezajímá váš průměr — odmítne jediný díl mimo toleranci.

NumPy sem přichází jednu kapitolu po čistě pythonovém perceptronu z jediného důvodu: na konci této kapitoly vyhodnocujeme čtyři sta tisíc kandidátních přímek proti dvaceti měřením každou a pythonová smyčka je na to špatný nástroj. Je to také notace, ve které jsou napsané všechny níže citované zdroje.

loss.pyPYTHON
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}")               

Veličina ve zvýrazněných řádcích je reziduum: co řekla přímka minus co řeklo posuvné měřítko, jedno číslo na měření. Každé skórovací pravidlo v této kapitole a každá loss function v následujících osmadvaceti kapitolách je nějaký způsob, jak seznam reziduí stlačit do jednoho čísla. Liší se jen v tom, jak stlačují.

TEXT
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.320

Čtěte sloupce, ne řádky. Kvadratická chyba říká B, absolutní chyba říká A, nejhorší chyba říká C: tři pravidla, tři vítězové, na stejných dvaceti bodech.

Tyto tři přímky jsem vybral tak, aby se neshodly, a měl bych to říct otevřeně. Pointa je, jak snadné to bylo — pár minut hledání mezi rozumně vypadajícími absolutními členy a směrnicemi najde stovky takových trojic. Pořadí je vlastností pravidla, které jste si vybrali, ne faktem o přímkách, takže pravidlo není implementační detail: ono je definicí problému. Což vyvolává otázku, kvůli níž tato kapitola existuje: na jakém základě si ho vybrat?

Nejdřív menší věc, protože přímky nejsou tři, ale nekonečně mnoho. Prozatím vezměte kvadratickou chybu, protože tu bere každý, a zmenšete problém na jediné číslo pomocí triku, který perceptronu ušetřil jedenáct tisíc epoch v kapitole 1: odečtěte průměr z obou sloupců. Jakmile je mrak bodů vystředěný do počátku, nejlepší přímka podle kvadratické chyby prochází přesně počátkem — takže absolutní člen je vyřešený a zbývá zvolit jen směrnici.

loss.py (continued)PYTHON
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}")
TEXT
601 candidates -> theta=0.293 mse=0.010115

Šest set jedna kandidátní směrnice, jeden vítěz: 0,293 milimetru za hodinu proti pravdě 0,300. Dvacet zašuměných měření a for-loop se dostaly na setinu milimetru za hodinu — dvě a třetinu procenta.

Zajímavá není vítězná hodnota, ale tvar hledání. Vytiskněte celou křivku, otočenou tak, aby loss běžela zleva doprava:

loss.py (continued)PYTHON
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}")
TEXT
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.7928

To je údolí, viděné z boku. Má jedno dno, stěny na obou stranách hladce stoupají a — to je část, kterou schodiště z kapitoly 1 nemohlo nabídnout — v každém jediném bodě na něm existuje dobře definovaný směr „dolů“. Ten tvar si zapamatujte. Kapitola 3 je celá o tom, jak po něm scházet, aniž byste navštívili všech šest set jedna bodů, a o tom, co se změní, když má údolí víc než jedno dno.

Máme údolí, protože jsme umocňovali na druhou. Absolutní chyba by mu na dně dala zlom; nejhorší chyba by dala ploché úseky, kde posun přímky nezmění vůbec nic. Umocňování na druhou je nepopiratelně pohodlné — a pohodlí je zhruba důvod, který uvádí většina kurzů, jen oblečený čtyřmi způsoby: dělá chyby kladné (absolutní hodnota také); trestá velké chyby víc (proč by měla?); je diferencovatelné (čtvrtá mocnina také); používají ho všichni (ano, a to není argument).

Poctivá pozice je tato. Kvadratická chyba vybrala přímku B a absolutní chyba vybrala přímku A. Jedna z nich je pro tuto továrnu správná a druhá špatná a nic z toho, co zatím zaznělo, vám neřekne která. Abyste zvolili pravidlo, musíte vědět něco o tom, jak se měření začala lišit od přímky, a to je otázka o světě, ne o matematice. Odpověď vyžaduje jeden malý kus aparátu.

Tady je tvrzení, které mění „která přímka je lepší“ na otázku s odpovědí.

Předpokládejte, že šířka dílu je přímka plus náhodná chyba, a předpokládejte, že tato chyba pochází z Gaussova rozdělení — zvonové křivky — se střední hodnotou nula a směrodatnou odchylkou σ\sigma:

yi=θxi+εi,εiN(0,σ2)y_i = \theta x_i + \varepsilon_i, \qquad \varepsilon_i \sim \mathcal{N}(0, \sigma^2)

Hustota Gaussova rozdělení je

p(ε)=1σ2πexp ⁣(ε22σ2)p(\varepsilon) = \frac{1}{\sigma\sqrt{2\pi}} \exp\!\left(-\frac{\varepsilon^2}{2\sigma^2}\right)

Teď udělejte něco, co perceptron neuměl. Pro danou kandidátní směrnici θ\theta má každé měření reziduum a výše uvedený vzorec toto reziduum převádí na číslo: jak věrohodná je chyba přesně této velikosti, pokud je tato směrnice pravda? Měření na přímce dostane velké číslo, měření o půl milimetru mimo malé.

Měření jsou nezávislá — posuvné měřítko si nepamatuje poslední díl — takže součinové pravidlo říká, že věrohodnost celého zápisníku je součin jednotlivých hustot. Tento součin je likelihood θ\theta.1 Všimněte si směru, protože přesně o ten jde v Bayesově pravidle: data jsou pevná a známá a mění se parametr. Tohle není „pravděpodobnost směrnice“. Je to pravděpodobnost, kterou model přiřadí datům, která jste skutečně dostali, čtená jako funkce směrnice.

likelihood.pyPYTHON
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}")
TEXT
theta=0.25   likelihood = 521.952
theta=0.293   likelihood = 2.42028e+07
theta=0.35   likelihood = 0.190312

Směrnice 0,293 dělá tento zápisník čtyřicet šest tisíckrát věrohodnější než 0,25 a sto dvacet sedmmilionkrát věrohodnější než 0,35. Maximum likelihood je princip, podle kterého vyberete parametr, díky němuž je to, co jste skutečně pozorovali, co nejméně překvapivé. Není to věta, ale návrh toho, co by „nejlepší“ mělo znamenat — návrh s obsahem, protože vás nutí říct předpoklad o šumu dřív, než smíte cokoli skórovat.

Spusťte stejné tři řádky kódu na měsíc směn místo jedné a metoda se zhroutí.

likelihood.py (continued)PYTHON
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)
TEXT
RuntimeWarning: overflow encountered in reduce
2000 readings, sigma = 0.12 mm : inf
2000 readings, sigma = 2.00 mm : 0.0
largest float64 : 1.7976931348623157e+308

Dva tisíce násobení a odpověď je inf. Změňte jednu konstantu — nepřesnější posuvné měřítko, takže hustoty vycházejí menší než 1 místo větší — a stejný kód vrátí 0.0. Obě odpovědi jsou špatně, opačnými směry, ani jedna nevyvolá výjimku, kterou byste mohli zachytit, a druhá dokonce ani nevytiskne varování.

S matematikou není nic špatně. Likelihood při těchto nastaveních je dokonale dobře definované konečné číslo: jeho přirozený logaritmus je 1400,91, takže číslo samotné je asi 1060810^{608}. Problém je, že váš počítač takové číslo nemá, a stojí za to přesně pochopit, která čísla má, protože tohle není naposledy, kdy rozhodne o výsledku.

Oprava explodujícího součinu je obvyklá: vezměte logaritmy. Logaritmus mění součiny na součty, je přísně rostoucí, takže nemůže posunout polohu maxima, a součet dvou tisíc umírněných čísel je něco, co float64 zvládne bez protestů. Podle konvence bereme záporný log-likelihood, aby lepší znamenalo menší. Teď dosaďte Gaussovu hustotu a sledujte, co se stane.

  1. Začněte od součinu. Likelihood je L(θ)=i=1Np(yiθxi)\mathcal{L}(\theta) = \prod_{i=1}^{N} p(y_i - \theta x_i), kde pp je výše uvedená Gaussova hustota.

  2. Vezměte minus logaritmus. Součin se změní na součet a exponenciála v hustotě se s logaritmem rovnou zruší:

logL(θ)=N2log ⁣(2πσ2)+12σ2i=1N(yiθxi)2-\log \mathcal{L}(\theta) = \frac{N}{2}\log\!\left(2\pi\sigma^2\right) + \frac{1}{2\sigma^2}\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2
  1. Zahoďte všechno, co neobsahuje θ\theta. První člen je konstanta. 1/2σ21/2\sigma^2 před součtem je kladná konstanta a škálování funkce kladnou konstantou nemůže posunout místo jejího minima. Zbývá
i=1N(yiθxi)2\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2

což je součet čtverců reziduí — věc, se kterou jsme kapitolu začali, protože ji každého napadne jako první.

To je výsledek, kvůli kterému tato kapitola existuje, a zaslouží si říct bez vytáček: kvadratická chyba není konvence. Je to záporný log-likelihood Gaussova rozdělení po odstranění konstant. Minimalizovat kvadratickou chybu je přesně totéž jako tvrdit, že vaše chyby jsou Gaussovské, a ptát se, který parametr dělá vaše data nejméně překvapivými. Toto tvrzení jste činili celou dobu; jen vám to nikdo neříkal.

Ekvivalence je ověřitelná, tak ji ověřte: projděte stejných šest set jedna směrnic s plným záporným log-likelihood, včetně konstant, a s obyčejnou kvadratickou chybou.

likelihood.py (continued)PYTHON
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())
TEXT
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: True

Jiná čísla na svislé ose a jedno z nich je záporné, což součet čtverců nikdy není: záporný log-likelihood může klesnout pod nulu, protože hustota může překročit 1. Stejné dno stejného údolí, do posledního bodu mřížky.

Zobrazit celé odvození

Která zahození jsou přesně bezpečná? Stejný manévr se objevuje v každé kapitole, která odvozuje loss, a ne vždy je nevinný.

Zahodit aditivní konstantu je bezpečné vždy, když nezávisí na parametru, který optimalizujete, a zahodit kladnou multiplikativní konstantu je bezpečné, protože argminθcf(θ)=argminθf(θ)\arg\min_\theta c\,f(\theta) = \arg\min_\theta f(\theta) pro libovolné c>0c > 0. Obojí selže ve chvíli, kdy se fituje také σ\sigma: potom N2log(2πσ2)\frac{N}{2}\log(2\pi\sigma^2) vůbec není konstanta, je to člen, který brání modelu tvrdit σ=0\sigma = 0 a nekonečnou věrohodnost. Přesně o tom je další oddíl.

Jinak selžou znovu v kapitole 3: multiplikativní konstanta neposune minimum, ale škáluje gradient a gradient se násobí learning rate. Dělení NN, aby vznikla střední kvadratická chyba místo součtu, je pro odpověď neviditelné a pro trénovací běh velmi viditelné — se součtem zdvojnásobení velikosti batche zdvojnásobí každý krok, který uděláte.

σ\sigma jsme stanovili na 0,12 z moci úřední a nikdo v továrně nezná rozptyl chyby svého posuvného měřítka. Berte ji jako druhou neznámou a nechte maximum likelihood rozhodnout i o ní. Tady se konstantní člen, který jsme právě zahodili, vrací, protože je to jediná věc stojící mezi modelem a tvrzením o dokonalé přesnosti.

likelihood.py (continued)PYTHON
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))
TEXT
best sigma on the grid       : 0.1006
sqrt(mean squared residual)  : 0.1006

Obě hodnoty se shodují na čtyři desetinná místa, a ne náhodou: derivace tohoto výrazu a položení rovné nule dá přesně σ^2=1Nri2\hat{\sigma}^2 = \frac{1}{N}\sum r_i^2. Takže střední kvadratická chyba není jen podobná rozptylu. V tomto modelu je maximum-likelihood odhad rozptylu šumu — číslo, které jste celou dobu minimalizovali, bylo odhadem toho, jak hlučný je váš senzor.

Jedna vráska, levná na vyslovení a drahá na pozdější znovuobjevení: tento odhad je vychýlený dolů, protože rezidua se měřila proti fitu, který byl sám zvolen tak, aby je zmenšil. Nasimulujte to — dvě stě tisíc zápisníků po dvaceti měřeních, tažených z rozdělení, jehož skutečný rozptyl je přesně 1, s jedním parametrem fitu odhadnutým ze samotných měření. Dělení součtu čtverců NN dá průměr 0,9501; dělení N1N-1 dá 1,0001; a (N1)/N(N-1)/N je přesně 0,95. Každý parametr, který fitujete, stojí jeden stupeň volnosti, a tohle je nejmenší viditelný případ mnohem většího problému: model vždy vypadá lépe na datech, na která byl fitován. Kapitola 4 z toho udělá disciplínu odkládání dat stranou a kapitola 6 dá efektu jméno.

Jestli kvadratická chyba tvrdí, že šum je Gaussovský, další otázka je, co se stane, když je toto tvrzení nepravdivé. Ne lehce nepravdivé — nepravdivé tak, jak jsou nepravdivá skutečná měření.

Na dílně je většina měření posuvným měřítkem dobrá na desetinu milimetru a jednou nebo dvakrát za směnu se pod čelist dostane tříska a měření je mimo o několik milimetrů. Takové chyby mají těžké chvosty: většinu času malé, občas obrovské a obrovské mnohem častěji, než dovoluje zvonová křivka. Cauchyho rozdělení je standardní čistý model takového chování a jeho hustota je stejně jednoduchá jako Gaussova:

p(ε)=1πs(1+(ε/s)2)p(\varepsilon) = \frac{1}{\pi s \left(1 + (\varepsilon/s)^2\right)}

Rozdíl je v chvostu: Gaussovo rozdělení klesá jako eε2e^{-\varepsilon^2}, brutálně rychle, a Cauchyho jako 1/ε21/\varepsilon^2, sotva vůbec. Důsledek je snazší vidět než říct:

PYTHON
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}")
TEXT
      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.10

Výběrový rozptyl Gaussova rozdělení se ustálí na 0,0144, což je 0.1220.12^2, a zůstane tam. U Cauchyho rozdělení roste a roste tak dlouho, dokud vzorkujete, protože není k čemu konvergovat: Cauchyho rozdělení nemá rozptyl a nemá ani střední hodnotu. Kvadratická chyba, jejíž celé poslání je minimalizovat průměr čtverců, je žádána o veličinu, která neexistuje.

Tady je tedy jedna směna, kdy bylo posuvné měřítko oklamáno. Stejných dvacet hodin, stejná čepel, stejný drift 0,30 milimetru za hodinu — jen šum je nyní Cauchyho. Fitujte ji dvakrát: jednou minimalizací čtverců reziduí, jednou minimalizací záporného log-likelihood šumu, který data skutečně vygeneroval. Trik s centrováním tady nepomůže — ukotví absolutní člen jen pro kvadratickou chybu — takže oba fity proběhnou hrubou silou přes mřížku absolutních členů i směrnic, protože stále nemáme způsob, jak najít dno údolí jinak než jeho navštívením.

swarf.pyPYTHON
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")

Dva zvýrazněné řádky jsou celý rozdíl mezi fity. Vezměte logaritmus Cauchyho hustoty, zahoďte konstanty přesně jako předtím a přežije log(1+(r/s)2)\sum \log\left(1 + (r/s)^2\right). Stejný recept, jiné tvrzení o šumu.

TEXT
     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 evaluated

Metoda nejmenších čtverců hlásí drift 0,108 milimetru za hodinu, zhruba třetinu skutečné rychlosti, a uzavírá, že čepel je dobrá až do hodiny 19,6. Skutečná odpověď je hodina 11,7. Pokud by se továrna tímto fitem řídila, nechá lis běžet o osm hodin navíc a vyrábí díly mimo toleranci, s autoritou nejstandardnější loss function v oboru. Cauchyho fit, se stejnými dvaceti měřeními, stejnou mřížkou a rozdílem jednoho řádku v kódu, přistane na hodině 11,8.

Dvě námitky si zaslouží odpověď, protože obě jsou první věc, kterou dobrý inženýr řekne.

Odlehlá hodnota je očividná — prostě ji smažte. Můžete, pomůže to, a nestačí to. Smazání jediného nejhoršího měření posune směrnici nejmenších čtverců z 0,108 na 0,239, což pořád klade výměnu čepele na hodinu 13,1, o hodinu a půl pozdě; smazání nejhoršího, nový fit a smazání toho, co je nejhorší teď, vás dostane na 0,286 — a všimněte si, že to už je procedura, ne pozorování: smažte místo toho dvě největší rezidua původního fitu a přistanete na 0,223. Teď jste ale udělali úsudky, které neumíte zapsat ani obhájit, a automatizace pravidla ho nezachrání: pravidlo zahodit-největší-reziduum-a-pak-refitovat, spuštěné přes tisíc simulovaných směn, má medián chyby směrnice 0,0177 proti 0,0100 u likelihood fitu a je mimo o více než 0,05 ve 14,7 % směn proti 1,3 %. Mazání je záplata na špatném předpokladu. Likelihood žádnou záplatu nepotřebuje, protože nikdy nepředpokládalo, že odlehlá hodnota je nemožná.

Vybral jste šťastný dataset. Tato námitka je přesně správná, a proto poslední experiment simuluje tisíc nezávislých směn a na každé fituje oběma způsoby.

swarf.py (continued)PYTHON
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")
TEXT
     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 shifts

Medián, ne průměr, ze stejného důvodu jako všechno ostatní v tomto oddílu: chyby nejmenších čtverců jsou řízené Cauchyho rozdělením, takže jejich průměr není stabilní věc k reportování. Nejmenší čtverce jsou výrazně špatně ve dvou směnách z pěti; likelihood fit je výrazně špatně v jedné směně ze sedmasedmdesáti a jeho nejhorší selhání napříč tisíci směnami je menší než pětina nejhoršího selhání nejmenších čtverců.

Nic z toho nedělá kvadratickou chybu špatnou. Dělá ji specifickou a aritmetika přesně říká proč. Vezměte reziduum 0,1 mm a reziduum 7 mm. Po umocnění na druhou přispěje špatné měření k celku 4 900krát víc než dobré, takže přímku tělesně přitáhne k sobě; pod Cauchyho log-likelihood stejná dvě rezidua přispějí 0,527 a 8,133, poměr 15,4. Špatné měření se stále počítá, jen nesmí rozhodnout. Tohle je začátek robustní statistiky, kde Huberova loss z roku 1964 dělí rozdíl tím, že se pro malá rezidua chová kvadraticky a pro velká lineárně,7 a kde Tukey už ukázal, jak málo kontaminace stačí k tomu, aby byl výběrový rozptyl horším nástrojem než střední absolutní odchylka.8

Jedna historická poznámka, příliš dobrá na vynechání. Metodu nejmenších čtverců publikoval jako první Legendre v roce 1805 jako pohodlný algebraický nástroj bez jiného ospravedlnění než že fungoval.9 O čtyři roky později Gauss obrátil argument pozpátku: vzal jako dané, že aritmetický průměr je správný způsob, jak kombinovat opakovaná měření, zeptal se, které rozdělení chyb dělá průměr nejpravděpodobnější hodnotou, a ukázal, že to v podstatě umí jen jedno — to, které je dnes pojmenované po něm.10 Odvození v této kapitole je jeho, je staré přes dvě století a stále je to část, kterou většina kurzů vynechává.

Co teď umíte říct a co stále neumíte udělat

Odkaz na sekci: Co teď umíte říct a co stále neumíte udělat

Získáno. Loss function je skórovací pravidlo a pořadí, které vytvoří, je vlastností pravidla, ne kandidátů. Každá loss v tomto kurzu je záporný log-likelihood nějakého předpokladu o šumu, s odhozenými konstantami — Gaussian tady dává kvadratickou chybu, Bernoulli dává cross-entropy v kapitole 4 a kategorické rozdělení nad slovníkem dává next-token loss v kapitole 8. Recept se nikdy nemění: řekněte šum, napište likelihood, vezměte minus logaritmus. A když je předpoklad špatně, model není jen nepřesný, je špatně směrem, který umíte předpovědět.

Stále chybí. Dno údolí jsme našli tím, že jsme navštívili každý jeho bod. Fungovalo to pro jeden parametr a šest set kandidátů a přežilo to dva parametry při 401 301 kandidátech za pětinu sekundy. Tři parametry ve stejném rozlišení znamenají 201 051 801 kandidátů a už se nevejdou do jednoho pole; malá síť v kapitole 5 má tisíce parametrů a modely, kterým kapitola 10 přiřazuje cenu, mají miliardy. Hrubá síla tady není pomalá, je aritmeticky nemožná, a nic v této kapitole nenaznačuje alternativu.

Podívejte se ale zpět na údolí. Když stojíte v θ=0.20\theta = 0.20 s loss 0,0822, směr „dolů“ není žádná záhada — vidíte ho na stránce, křivka klesá doprava. Kdybyste se loss function mohli zeptat, kterým směrem se svažuje v bodě, kde stojíte, aniž byste ji vyhodnocovali kdekoli jinde, mohli byste udělat krok tím směrem, zeptat se znovu a opakovat, dokud nebude zem rovná.

Tato otázka má jméno. Sklon funkce v bodě je její derivace a pro funkci mnoha parametrů je soubor sklonů ve všech směrech najednou gradient. Kapitola 1 žádný použít nemohla, protože chyba perceptronu byla schodiště bez sklonu, na který by se dalo ptát. Tato kapitola vybudovala něco lepšího: loss, která je všude hladká a která vzešla z vysloveného předpokladu, ne z preference.

Otázka pro kapitolu 3 tedy už není, zda sklon existuje. Je to, jak ho spočítat, proč pohyb proti němu vede z kopce a ne do kopce — znaménko, které po vás skoro každý kurz chce přijmout na víru — a jak daleko udělat krok, než se zeptáte znovu, což se ukáže jako jediné číslo rozhodující o tom, zda trénovací běh konverguje, osciluje kolem odpovědi navždy, nebo uteče do nekonečna.


Vedle této kapitoly stojí za přečtení také: Prince, Understanding Deep Learning §5.1–5.2 a dodatek C, který buduje každou loss v knize z maximum likelihood ve stejném pořadí jako zde; Goodfellow, Bengio a Courville, Deep Learning §3.1–3.11 a §5.5, jejichž oddíl o maximum likelihood odvozuje i KL divergenci potřebnou v kapitole 4; Murphy, Probabilistic Machine Learning: An Introduction kapitola 2 a §4.2, o tom, co maximum likelihood zaručuje a nezaručuje; Deisenroth, Faisal a Ong, Mathematics for Machine Learning §6.1–6.4 pro pořádně provedené součtové pravidlo, součinové pravidlo a Bayesovo pravidlo; krátká poznámka Toma Mitchella z CMU Estimating Probabilities: MLE and MAP (2016); a §22.7 knihy Dive into Deep Learning, která dochází ke stejnému výsledku ve spustitelném kódu.

  1. Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, s. 309–368 (1922). Kde je likelihood vyloženo jako obecná metoda, spolu s pojmy „parameter“, „statistic“, dostatečností a efektivitou. Samotné pojmenování a oddělení od pravděpodobnosti je o rok starší: 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.

  2. IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Definuje binary32 a binary16 a zaokrouhlovací pravidla, díky nimž sčítací experiment vyjde tak, jak vyjde.

  3. Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Parametry formátu a argument pro výměnu bitů mantisy za bity exponentu.

  4. Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling a naměřené velikosti gradientů, kvůli kterým je ve float16 nutný.

  5. Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), s. 5–48 (1991). Stále nejlepší samostatné vysvětlení toho, proč se dvě pořadí sčítání neshodnou.

  6. Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), s. 40 (1965). Kompenzované sčítání na půl stránce.

  7. Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), s. 73–101 (1964). Loss, která je kvadratická poblíž nuly a lineární v chvostech, odvozená, ne slepená záplatami.

  8. Tukey, J. W. A survey of sampling from contaminated distributions, in Contributions to Probability and Statistics (Stanford University Press, 1960), s. 448–485.

  9. Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paříž, 1805), dodatek Sur la méthode des moindres quarrés. První publikace metody nejmenších čtverců jako výpočetního nástroje.

  10. Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburk, 1809), kniha II, §§175–179. Argument od aritmetického průměru k normálnímu zákonu chyb a odtud k metodě nejmenších čtverců.

Necháte výběr modelu na LIA?

Tvořte se všemi modely AI na jednom místě – začněte ještě dnes zdarma.