Ugrás a tartalomra
2/302/30. fejezet

Honnan ered egy veszteségfüggvény: likelihood, nem konvenció

Három szemre húzott egyenes ugyanarra a húsz mérésre, és három szabály három győztessel. A négyzetes hiba választás.

Ezen az oldalon

Az alkatrészeket vágó penge kopik. Egy tízórás műszak alatt annyit veszít az éléből, hogy a szalagról lejövő darabok a kezdetinél a milliméter töredékével szélesebbek lesznek, és amint átlépik a 23,5 millimétert, az ellenőrzés selejtezi őket. Az üzemben senki sem tudja, ez mikor történik meg. Ami van: egy tolómérő, egy jegyzetfüzet és húsz múlt keddi leolvasás: a penge cseréje óta eltelt órák, illetve az adott pillanatban mért alkatrészszélesség.

Valaki húz egy egyenest a pontokon keresztül. Valaki más húz egy kicsit másikat. Egy harmadik ember egy harmadikat. Papíron mindhárom ésszerűnek tűnik, de több órával eltérnek abban, mikor kellene pengét cserélni — ebben az üzemben ez a különbség egy nyugodt hét és egy leselejtezett tétel között.

Melyik egyenes a jobb?

Így feltéve erre a kérdésre nincs válasz. Nem nehéz válasz nincs — semmilyen válasz nincs. A „jobb” nem olyan tulajdonsága egy egyenesnek, mint a meredeksége; egy egyenes tulajdonsága együtt az egyeneseket pontozó szabállyal, és amíg valaki le nem írja ezt a szabályt, nincs mit kiszámolni. Ez a fejezet komolyan veszi ezt a mondatot, és azzal a felismeréssel zárul, hogy a gépi tanulás leggyakoribb szabálya nem konvenció, hanem egy világra vonatkozó állítás következménye — olyan állításé, amely tesztelhető, és amely néha hamis.

Egy vallomás az első kódsor előtt. Ez a húsz leolvasás nem valódi gyárból származik: egy általam választott egyenesből generáltam őket, width=20.00+0.30h\text{width} = 20.00 + 0.30 \cdot h, nagyjából egytized milliméter szórású véletlen zajjal. Ez számít, mert lent minden arról szól, hogy egy módszer visszanyer-e egy igazságot, és ezt csak úgy lehet ellenőrizni, ha az igazságot előre ismerjük. Tehát: a könyv végén szereplő megoldás 0,30 milliméter óránként. Használni nem szabad, csak ellenőrizni vele.

Itt vannak a leolvasások és a három egyenes, háromféleképpen pontozva: négyzetes hibával, amihez mindenki ösztönösen nyúl; abszolút hibával, amihez egy statisztikus nyúlhatna; és legrosszabb hibával, amihez a gépkezelő nyúlna, mert az ellenőrt nem érdekli az átlagod — azt az egy alkatrészt utasítja el, amelyik kívül esik a tűrésen.

A NumPy itt érkezik meg, egy fejezettel a tiszta Python perceptron után, egyetlen okból: a fejezet végére négyszázezer jelölt egyenest értékelünk ki egyenként húsz leolvasáson, és erre a Python loop rossz eszköz. Ráadásul ez az a jelölésmód is, amelyben az alább idézett források mind írnak.

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}")               

A kiemelt sorokban szereplő mennyiség a reziduum: amit az egyenes mondott, mínusz amit a tolómérő mondott, leolvasásonként egy szám. Ebben a fejezetben minden pontozási szabály, és az utána következő huszonnyolc fejezet minden veszteségfüggvénye, valamilyen módon egy reziduumlistát nyom össze egyetlen számmá. Csak abban különböznek, hogyan nyomják össze.

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

Az oszlopokat olvasd, ne a sorokat. A négyzetes hiba szerint B, az abszolút hiba szerint A, a legrosszabb hiba szerint C nyer: három szabály, három győztes, ugyanazon a húsz ponton.

Ezt a három egyenest úgy választottam, hogy ne értsenek egyet, és ezt nyíltan ki kell mondanom. A lényeg az, milyen könnyű volt — néhány perc keresés ésszerűnek tűnő tengelymetszetek és meredekségek között, és máris százával kerülnek elő ilyen hármasok. A rangsor a választott szabály tulajdonsága, nem tény az egyenesekről, ezért a szabály nem implementációs részlet: ez a probléma definíciója. Ez veti fel azt a kérdést, amelynek megválaszolására ez a fejezet létezik: milyen alapon választod ki?

Előbb egy kisebb ügy, mert nem három egyenes van, hanem végtelen sok. Vegyük most a négyzetes hibát, mivel mindenki azt veszi, és zsugorítsuk a problémát egyetlen számra azzal a trükkel, amely a perceptronnak tizenegyezer epochot spórolt meg az 1. fejezetben: vonjuk ki az átlagot mindkét oszlopból. Miután a pontfelhő középpontja az origóra kerül, a négyzetes hiba szerinti legjobb egyenes pontosan átmegy az origón — tehát a tengelymetszet eldőlt, és csak a meredekséget kell kiválasztani.

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

Hatszázegy jelölt meredekség, egy győztes: 0,293 milliméter óránként, szemben a 0,300-as igazsággal. Húsz zajos leolvasás és egy for-loop egy század milliméter per órán belülre jutott — két és egyharmad százalékra.

Az érdekes rész nem a győztes, hanem a keresés alakja. Nyomtasd ki a teljes görbét, elforgatva úgy, hogy a veszteség balról jobbra fusson:

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

Ez egy völgy, oldalról nézve. Egyetlen alja van, a falak mindkét oldalon simán emelkednek, és — ezt nem tudta kínálni az 1. fejezet lépcsője — minden egyes pontján jól definiált a „lefelé” iránya. Jegyezd meg ezt az alakot. A 3. fejezet teljes egészében arról szól, hogyan lehet lemenni rajta anélkül, hogy mind a hatszázegy pontot meglátogatnánk, és mi változik, amikor egy völgynek több alja van.

Azért van völgyünk, mert négyzetre emeltünk. Az abszolút hiba törést adott volna az alján; a legrosszabb hiba lapos szakaszokat adott volna, ahol az egyenes mozgatása semmit sem változtat. A négyzetre emelés tagadhatatlanul kényelmes — és nagyjából a kényelem az az ok, amit a legtöbb kurzus ad, négyféleképpen felöltöztetve: pozitívvá teszi a hibákat (az abszolútérték is); jobban bünteti a nagy hibákat (miért kellene?); differenciálható (a negyedik hatvány is); mindenki ezt használja (igen, és ez nem érv).

Az őszinte álláspont ez. A négyzetes hiba B egyenest választotta, az abszolút hiba A egyenest. Az egyik helyes ebben a gyárban, a másik téves, és az eddig elhangzottakból semmi sem mondja meg, melyik melyik. A szabály kiválasztásához tudnod kell valamit arról, hogyan tértek el a leolvasások az egyenestől, ez pedig a világról szóló kérdés, nem matematikáról. A megválaszolásához egy kis gépezet kell.

Íme az állítás, amely a „melyik egyenes jobb” kérdésből megválaszolható kérdést csinál.

Tegyük fel, hogy egy alkatrész szélessége az egyenes plusz egy véletlen hiba, és tegyük fel, hogy ez a hiba Gauss-eloszlásból — a haranggörbéből — származik, nulla átlaggal és σ\sigma szórással:

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

A Gauss-eloszlás sűrűsége

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

Most tegyünk olyat, amit a perceptron nem tudott. Egy adott jelölt meredekségre θ\theta minden leolvasásnak van reziduuma, és a fenti képlet ezt a reziduumot számmá alakítja: mennyire hihető pontosan ekkora hiba, ha ez a meredekség az igazság? Egy egyenesen lévő leolvasás nagy számot kap, egy fél milliméterrel mellé eső kicsit.

A leolvasások függetlenek — a tolómérő nem emlékszik az előző alkatrészre —, ezért a szorzatszabály szerint a teljes jegyzetfüzet hihetősége az egyedi sűrűségek szorzata. Ez a szorzat θ\theta likelihoodja.1 Figyeld meg az irányt, mert Bayes szabálya is erről az irányról szól: az adat rögzített és ismert, a paraméter az, ami változik. Ez nem „a meredekség valószínűsége”. Ez az a valószínűség, amelyet a modell a ténylegesen kapott adatokhoz rendel, a meredekség függvényeként olvasva.

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

A 0,293-as meredekség negyvenhatezerszer hihetőbbé teszi ezt a jegyzetfüzetet, mint a 0,25-ös, és százhuszonhétmilliószor hihetőbbé, mint a 0,35-ös. A maximum likelihood elve szerint azt a paramétert választod, amely a ténylegesen megfigyelt dolgokat a lehető legkevésbé meglepővé teszi. Ez nem tétel, hanem javaslat arról, mit jelentsen a „legjobb” — tartalommal bíró javaslat, mert rákényszerít, hogy kimondjad a zajra vonatkozó feltételezésedet, mielőtt bármit pontozhatnál.

Futtasd ugyanazt a három kódsort egyetlen műszak helyett egy hónapnyi műszakon, és a módszer összeomlik.

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

Kétezer szorzás, és a válasz inf. Változtass meg egy konstansot — legyen pontatlanabb a tolómérő, hogy a sűrűségek 1-nél kisebbek legyenek, ne nagyobbak —, és ugyanaz a kód 0.0 értéket ad vissza. Mindkét válasz rossz, ellentétes irányban, egyik sem dob elcsíphető kivételt, a második pedig még figyelmeztetést sem ír ki.

A matematikával semmi baj. A likelihood ezeknél a beállításoknál tökéletesen jól definiált véges szám: természetes logaritmusa 1400,91, tehát maga a szám körülbelül 1060810^{608}. A probléma az, hogy a számítógépednek nincs ilyen száma, és érdemes pontosan megérteni, milyen számai vannak, mert nem ez lesz az utolsó alkalom, amikor ez eldönti az eredményt.

A robbanó szorzat javítása a szokásos: vegyünk logaritmusokat. A logaritmus a szorzatokat összegekké alakítja, szigorúan növekvő, ezért nem mozdíthatja el a maximum helyét, és kétezer mérsékelt szám összege olyasmi, amit a float64 panasz nélkül kezel. Konvenció szerint a negatív log-likelihoodot vesszük, hogy a jobb kisebbet jelentsen. Most helyettesítsd be a Gauss-sűrűséget, és nézd meg, mi történik.

  1. Indulj a szorzatból. A likelihood L(θ)=i=1Np(yiθxi)\mathcal{L}(\theta) = \prod_{i=1}^{N} p(y_i - \theta x_i), ahol pp a fenti Gauss-sűrűség.

  2. Vedd a log mínuszát. A szorzat összeggé válik, és a sűrűségben lévő exponenciális tagot a logaritmus egyszerűen kioltja:

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. Dobj el mindent, ami nem tartalmazza θ\theta-t. Az első tag konstans. Az összeg előtti 1/2σ21/2\sigma^2 pozitív konstans, és egy függvény pozitív konstanssal való skálázása nem mozdíthatja el, hol van a minimuma. Ami marad:
i=1N(yiθxi)2\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2

ez a reziduumok négyzetösszege — az a dolog, amellyel azért kezdtük a fejezetet, mert mindenkinek ez jut először eszébe.

Ez az az eredmény, amelyért a fejezet létezik, és érdemes kertelés nélkül kimondani: a négyzetes hiba nem konvenció. Egy Gauss-eloszlás negatív log-likelihoodja, a konstansok eltávolítása után. A négyzetes hiba minimalizálása pontosan ugyanaz a cselekedet, mint kijelenteni, hogy a hibáid Gauss-eloszlásúak, majd megkérdezni, melyik paraméter teszi az adataidat a legkevésbé meglepővé. Végig ezt az állítást tetted; csak nem mondták meg neked.

Az ekvivalencia ellenőrizhető, tehát ellenőrizd: pásztázd végig ugyanazt a hatszázegy meredekséget a teljes negatív log-likelihooddal, konstansokkal együtt, és a sima négyzetes hibával.

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

Más számok a függőleges tengelyen, és az egyik negatív, ami egy négyzetösszeg sosem lehet: a negatív log-likelihood mehet nulla alá, mert egy sűrűség lehet nagyobb 1-nél. Ugyanannak a völgynek ugyanaz az alja, az utolsó rácspontig.

Teljes levezetés megjelenítése

Pontosan mely eldobások biztonságosak? Ugyanez a manőver minden fejezetben előkerül, amely loss-t vezet le, és nem mindig ártatlan.

Additív konstans elhagyása biztonságos, ha nem függ az optimalizált paramétertől, pozitív multiplikatív konstans elhagyása pedig azért biztonságos, mert argminθcf(θ)=argminθf(θ)\arg\min_\theta c\,f(\theta) = \arg\min_\theta f(\theta) bármely c>0c > 0 esetén. Mindkettő elbukik abban a pillanatban, amikor σ\sigma-t is illesztjük: ekkor N2log(2πσ2)\frac{N}{2}\log(2\pi\sigma^2) egyáltalán nem konstans, hanem az a tag, amely megakadályozza, hogy a modell σ=0\sigma = 0-t és végtelen hihetőséget állítson. Pontosan erről szól a következő szakasz.

A 3. fejezetben megint másképp buknak el: egy multiplikatív konstans nem mozdítja el a minimumot, de skálázza a gradientet, a gradientet pedig megszorozzuk a learning rate-tel. NN-mal osztani, hogy átlagos négyzetes hibát kapjunk az összeg helyett, láthatatlan a válasz számára, de nagyon is látható a training run számára — az összeggel, ha megduplázod a batch méretét, minden lépésed is megduplázódik.

σ\sigma értékét önkényesen 0,12-re rögzítettük, és az üzemben senki sem ismeri a tolómérő hibájának szórását. Kezeld második ismeretlenként, és hagyd, hogy a maximum likelihood döntsön róla is. Itt az imént eldobott konstans tag visszatér, mert ez az egyetlen dolog, ami a modell és a tökéletes pontosság állítása között áll.

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

A kettő négy tizedesjegyig egyezik, és nem véletlenül: ezt a kifejezést deriválva és nullával egyenlővé téve pontosan σ^2=1Nri2\hat{\sigma}^2 = \frac{1}{N}\sum r_i^2 adódik. Tehát az átlagos négyzetes hiba nem pusztán olyan, mint egy variancia. Ebben a modellben ez a zaj varianciájának maximum-likelihood becslése — az a szám, amelyet végig minimalizáltál, valójában annak becslése volt, mennyire zajos a szenzorod.

Egy apró csavar, olcsó kimondani és drága később újra felfedezni: ez a becslés lefelé torzított, mert a reziduumokat egy olyan illesztéshez képest mértük, amelyet maga is úgy választottunk, hogy kicsivé tegye őket. Szimuláld — kétszázezer jegyzetfüzetet, mindegyikben húsz leolvasással, olyan eloszlásból húzva, amelynek valódi varianciája pontosan 1, miközben az illesztés egyetlen paraméterét magukból a leolvasásokból becsüljük. A négyzetösszeget NN-nal osztva az átlag 0,9501; N1N-1-tel osztva 1,0001; és (N1)/N(N-1)/N pontosan 0,95. Minden illesztett paraméter egy szabadságfokba kerül, és ez a legkisebb látható példája egy sokkal nagyobb problémának: egy modell mindig jobbnak tűnik azon az adaton, amelyhez illesztették. A 4. fejezet ebből csinálja meg az adatok visszatartásának fegyelmét, a 6. fejezet pedig nevet ad a hatásnak.

Ha a négyzetes hiba azt állítja, hogy a zaj Gauss-eloszlású, a következő kérdés az, mi történik, amikor az állítás hamis. Nem kicsit hamis — úgy hamis, ahogy a valódi mérések hamisak.

A műhelyben a legtöbb tolómérős leolvasás tizedmilliméter pontosságú, de műszakonként egyszer-kétszer egy forgácsdarab kerül a pofák alá, és a leolvasás több milliméterrel félremegy. Az ilyen hibák vastag farkúak: legtöbbször kicsik, időnként óriásiak, és sokkal gyakrabban óriásiak, mint amit a haranggörbe megenged. A Cauchy-eloszlás ennek a viselkedésnek a szokásos tiszta modellje, sűrűsége pedig épp olyan egyszerű, mint a Gauss-é:

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

A különbség a farok: a Gauss-eloszlás eε2e^{-\varepsilon^2} szerint esik le, brutálisan gyorsan, a Cauchy pedig 1/ε21/\varepsilon^2 szerint, alig. A következményt könnyebb látni, mint kimondani:

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

A Gauss minta-varianciája beáll 0,0144-re, ami 0.1220.12^2, és ott marad. A Cauchy-é emelkedik, és addig emelkedik, amíg mintázol, mert nincs mihez konvergálnia: a Cauchy-eloszlásnak nincs varianciája, és átlaga sincs. A négyzetes hibát, amelynek teljes feladata négyzetek átlagának minimalizálása, olyan mennyiségről kérdezzük, amely nem létezik.

Íme tehát egy műszak, amikor a tolómérőt becsapta valami. Ugyanaz a húsz óra, ugyanaz a penge, ugyanaz a 0,30 milliméter per órás sodródás — csak a zaj most Cauchy. Illeszd kétszer: egyszer a négyzetes reziduumok minimalizálásával, egyszer annak a zajnak a negatív log-likelihoodját minimalizálva, amely ténylegesen generálta az adatokat. A központosítási trükk itt nem segít — csak a négyzetes hiba esetén rögzíti a tengelymetszetet —, ezért mindkét illesztés brute force módon megy tengelymetszetek és meredekségek rácsán, mivel még mindig nincs módszerünk megtalálni egy völgy alját azon kívül, hogy meglátogatjuk.

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")

A két kiemelt sor a teljes különbség az illesztések között. Vedd a Cauchy-sűrűség logaritmusát, dobd el a konstansokat pontosan úgy, mint korábban, és log(1+(r/s)2)\sum \log\left(1 + (r/s)^2\right) marad meg. Ugyanaz a recept, más állítás a zajról.

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

A legkisebb négyzetek 0,108 milliméter per órás sodródást jelent, nagyjából a valódi arány harmadát, és arra következtet, hogy a penge a 19,6. óráig jó. A valódi válasz a 11,7. óra. Ha az üzem erre az illesztésre hallgat, nyolc órával tovább járatja a prést, tűrésen kívüli alkatrészeket gyártva, a terület legszokványosabb veszteségfüggvényének tekintélyére támaszkodva. A Cauchy-illesztés ugyanazzal a húsz leolvasással, ugyanazzal a ráccsal és a kódban egyetlen sornyi különbséggel a 11,8. órára érkezik.

Két ellenvetés válaszokat érdemel, mert mindkettő az első dolog, amit egy jó mérnök mond.

A kiugró érték nyilvánvaló — csak töröld. Megteheted, segít is, és nem elég. Az egyetlen legrosszabb leolvasás törlése a legkisebb négyzetek meredekségét 0,108-ról 0,239-re viszi, ami még mindig a 13,1. órára teszi a pengecserét, másfél órával későre; a legrosszabb törlése, újraillesztés, majd az akkor legrosszabb törlése 0,286-ig visz — és vedd észre, hogy ez már eljárás, nem megfigyelés: ha inkább az eredeti illesztés két legnagyobb reziduumát törlöd, 0,223-nál kötsz ki. De most már olyan ítéleti döntéseket hoztál, amelyeket nem tudsz leírni vagy megvédeni, és a szabály automatizálása sem menti meg: a legnagyobb-reziduum-eldobása-majd-újraillesztés ezer szimulált műszakon futtatva 0,0177 medián meredekséghibát ad a likelihood illesztés 0,0100-jával szemben, és a műszakok 14,7%-ában téved több mint 0,05-tel, szemben az 1,3%-kal. A törlés folt egy rossz feltételezés tetején. A likelihoodnak nincs szüksége foltra, mert sosem feltételezte, hogy a kiugró lehetetlen.

Szerencsés datasetet választottál. Ez az ellenvetés pontosan jogos, ezért az utolsó kísérlet ezer független műszakot szimulál, és mindkét módon újrailleszt mindegyiken.

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, nem átlag, ugyanabból az okból, mint ebben a szakaszban minden más: a legkisebb négyzetek hibáit Cauchy hajtja, ezért az átlaguk nem stabil jelentendő mennyiség. A legkisebb négyzetek öt műszakból kettőben súlyosan téved; a likelihood illesztés hetvenhét műszakból egyben, és ezer műszak alatti legrosszabb kudarca kevesebb, mint a legkisebb négyzetek legrosszabbjának egyötöde.

Ettől a négyzetes hiba nem lesz rossz. Specifikus lesz, és az aritmetika pontosan megmondja, miért. Vegyél egy 0,1 mm-es és egy 7 mm-es reziduumot. Négyzetre emelve a rossz leolvasás 4 900-szor annyit tesz hozzá a teljes összeghez, mint a jó, ezért az egyenest testestül magához rántja; a Cauchy log-likelihood alatt ugyanez a két reziduum 0,527-et és 8,133-at ad hozzá, az arány 15,4. A rossz leolvasás továbbra is számít, csak nem dönthet. Ez a robusztus statisztika kezdete, ahol Huber 1964-es loss-a úgy vágja ketté a különbséget, hogy kis reziduumoknál kvadratikusan, nagyoknál lineárisan viselkedik,7 és ahol Tukey már megmutatta, milyen kevés szennyezés elég ahhoz, hogy a minta-variancia rosszabb eszköz legyen, mint az átlagos abszolút eltérés.8

Egy történeti megjegyzés is van, túl jó ahhoz, hogy kihagyjuk. A legkisebb négyzeteket először Legendre publikálta 1805-ben, kényelmes algebrai eszközként, azon túlmenő igazolás nélkül, hogy működött.9 Négy évvel később Gauss visszafelé futtatta az érvelést: adottnak vette, hogy az aritmetikai átlag a helyes módja ismételt mérések összekombinálásának, megkérdezte, mely hibaeloszlás teszi az átlagot a legvalószínűbb értékké, és megmutatta, hogy lényegében csak egy ilyen van — az, amelyet ma róla nevezünk.10 A fejezetbeli levezetés az övé, több mint két évszázados, és még mindig ez az a rész, amelyet a legtöbb kurzus kihagy.

Amit most már ki tudsz mondani, és amit még mindig nem tudsz megtenni

Link a szakaszhoz: Amit most már ki tudsz mondani, és amit még mindig nem tudsz megtenni

Megszerezted. A veszteségfüggvény pontozási szabály, és az általa előállított rangsor a szabály tulajdonsága, nem a jelölteké. Ebben a kurzusban minden loss valamilyen zajfeltételezés negatív log-likelihoodja, a konstansok eldobása után — itt a Gauss négyzetes hibát ad, a Bernoulli a 4. fejezetben cross-entropyt, egy szókészlet feletti kategorikus eloszlás pedig a 8. fejezetben next-token loss-t. A recept sosem változik: mondd ki a zajt, írd fel a likelihoodot, vedd a log mínuszát. És amikor a feltételezés rossz, a modell nem pusztán pontatlan, hanem olyan irányban téved, amelyet előre meg tudsz mondani.

Még hiányzik. Úgy találtuk meg a völgy alját, hogy minden pontját meglátogattuk. Ez működött egy paraméterrel és hatszáz jelölttel, és túlélt két paramétert 401 301 jelölttel egyötöd másodperc alatt. Három paraméter ugyanilyen felbontással 201 051 801 jelölt, és már nem fér bele egy arraybe; egy kis hálónak az 5. fejezetben több ezer paramétere van, a modelleknek pedig, amelyekhez a 10. fejezet árat rendel, milliárdnyi. A brute force itt nem lassú, hanem aritmetikailag lehetetlen, és ebben a fejezetben semmi sem sugall alternatívát.

Nézz vissza mégis a völgyre. θ=0.20\theta = 0.20 pontban állva, 0,0822 veszteséggel, a „lefelé” iránya nem rejtély — látod a lapon, a görbe jobbra lefelé lejt. Ha meg tudnád kérdezni a veszteségfüggvényt, merre lejt abban a pontban, ahol állsz, anélkül, hogy bárhol máshol kiértékelnéd, tehetnél egy lépést arra, megkérdezhetnéd újra, és ismételhetnéd, amíg a talaj sík nem lesz.

Ennek a kérdésnek neve van. Egy függvény meredeksége egy pontban a deriváltja, és sokparaméteres függvény esetén az összes iránybeli meredekség gyűjteménye egyszerre a gradient. Az 1. fejezet nem tudott ilyet használni, mert a perceptron hibája lépcső volt, amelynek nem volt megkérdezhető meredeksége. Ez a fejezet jobbat épített: olyan veszteséget, amely mindenhol sima, és amely kimondott feltételezésből származik, nem preferenciából.

A 3. fejezet kérdése tehát már nem az, hogy létezik-e meredekség. Hanem az, hogyan számoljuk ki, miért visz lefelé, ha ellene mozdulunk, nem felfelé — egy előjel, amelyet szinte minden kurzus hitből kér elfogadni —, és mekkorát lépjünk, mielőtt újra megkérdezzük; ez lesz az az egyetlen szám, amely eldönti, hogy egy training run konvergál, örökké az eredmény körül oszcillál, vagy elszáll a végtelenbe.


Érdemes e fejezet mellé olvasni még: Prince, Understanding Deep Learning §5.1–5.2 és C függelék, amely a könyv minden loss-át maximum likelihoodból építi fel az itt használt sorrendben; Goodfellow, Bengio és Courville, Deep Learning §3.1–3.11 és §5.5, amelynek maximum-likelihood szakasza a 4. fejezethez szükséges KL-divergenciát is levezeti; Murphy, Probabilistic Machine Learning: An Introduction 2. fejezet és §4.2 arról, mit garantál és mit nem garantál a maximum likelihood; Deisenroth, Faisal és Ong, Mathematics for Machine Learning §6.1–6.4 a sum rule, product rule és Bayes szabályának rendes tárgyalásához; Tom Mitchell rövid CMU-jegyzete, Estimating Probabilities: MLE and MAP (2016); valamint a Dive into Deep Learning §22.7 szakasza, amely futtatható kódban jut ugyanerre az eredményre.

  1. Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, 309–368. o. (1922). Itt jelenik meg a likelihood általános módszerként, a „paraméter”, „statisztika”, elégségesség és hatékonyság mellett. Maga az elnevezés és a valószínűségtől való elválasztás egy évvel korábbi: Fisher, R. A., On the „probable error” of a coefficient of correlation deduced from a small sample, Metron 1, 3–32. o. (1921), 24–25. o.

  2. IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Definiálja a binary32-t és binary16-ot, valamint azokat a kerekítési szabályokat, amelyek miatt az összegzési kísérlet úgy alakul, ahogy.

  3. Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). A formátum paraméterei, és az érv amellett, hogy mantisszabiteket exponensbitekre cseréljünk.

  4. Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling, és azok a mért gradient-nagyságok, amelyek float16-ban szükségessé teszik.

  5. Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), 5–48. o. (1991). Még mindig a legjobb önálló magyarázat arra, miért tér el a két összegzési sorrend.

  6. Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), 40. o. (1965). Kompenzált összegzés fél oldalban.

  7. Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), 73–101. o. (1964). A loss, amely nulla közelében kvadratikus, a farokban lineáris, levezetve, nem összefoltozva.

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

  9. Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Párizs, 1805), függelék: Sur la méthode des moindres quarrés. A legkisebb négyzetek első publikációja számítási eszközként.

  10. Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), II. könyv, §§175–179. Az érvelés az aritmetikai átlagtól a normális hibatörvényig, onnan pedig a legkisebb négyzetekig.


Készítette

David Vicente Campos

A NeuraLIA Labs alapítója és a MyRealFood társalapítója

Mérnökinformatikus vagyok, a Leóni Egyetemen végeztem. Társalapítottam a MyRealFoodot, ahol CTO-ként felépítettem azt az alkalmazást, amelyet emberek milliói használtak arra, hogy egészségesebben táplálkozzanak, és megalapítottam a NeuraLIA Labst, ahol AI-termékeket fejlesztek. Itt arról írok, amit menet közben meg kellett értenem, úgy, ahogy szerettem volna, hogy valaki elmagyarázza nekem.

Továbbiak a szerzőről

Közzétette a NeuraLIA Labs.

Kapj új bejegyzéseket a postaládádba

AI-hírek, útmutatók és termékfrissítések — rövid email, amikor valami igazán hasznosat publikálunk.

Kurzusindex

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev11 perc olvasás

A Jev AI-modell döntésekre készült, nem prózára

A TypeSafe AI Jev modellje azért kap figyelmet, mert a szoftveres intelligenciát valószínűségi problémaként kezeli: válaszd ki a megfelelő ágat, rendelj hozzá bizalmi szintet, és ne fizess egy LLM-nek szövegírásért, amikor a kódnak döntésre van szüksége.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering11 perc olvasás

Kontextustervezés hosszú távú AI-ügynökökhöz

A hosszú ideig futó ügynökök nem csak azért vallanak kudarcot, mert kicsi az ablak. Akkor hibáznak, amikor a fájlok, eszközkimenetek és elavult előzmények kiszorítják azt a feladatot, amelyet az ügynöknek be kellett volna fejeznie.

Készen állsz, hogy a LIA válasszon helyetted?

Építs az összes AI-modellel egy helyen – kezdd el ma, ingyen.