Siirry sisältöön
2/30Luku 2/30

Mistä häviöfunktio syntyy: likelihood, ei käytäntö

Kolme viivaa samoille 20 mittaukselle ja kolme pisteytyssääntöä, jotka valitsevat eri voittajat. Squared error on valinta.

Tällä sivulla

Osia leikkaava terä kuluu. Kymmenen tunnin vuoron aikana se menettää terävyyttään sen verran, että hihnalta tulevat osat ovat lopulta millimetrin murto-osan leveämpiä kuin alussa, ja kun ne ylittävät 23,5 millimetriä, tarkastus hylkää ne. Kukaan tehtaalla ei tiedä, milloin se tapahtuu. Heillä on työntömitta, muistivihko ja kaksikymmentä mittausta viime tiistailta: tunnit terän vaihdosta ja osan leveys sillä hetkellä.

Joku piirtää pisteiden läpi viivan. Joku toinen piirtää hieman erilaisen. Kolmas piirtää kolmannen. Kaikki kolme näyttävät paperilla järkeviltä, ja ne ovat eri mieltä terän vaihtoajasta useiden tuntien verran — tässä tehtaassa se on ero rauhallisen viikon ja romutetun erän välillä.

Mikä viiva on parempi?

Näin esitettynä kysymykseen ei ole vastausta. Ei vaikeaa vastausta — ei vastausta lainkaan. ”Parempi” ei ole viivan ominaisuus samalla tavalla kuin sen kulmakerroin on; se on viivan ominaisuus yhdessä viivojen pisteytyssäännön kanssa, ja ennen kuin joku kirjoittaa säännön ylös, ei ole mitään laskettavaa. Tämä luku ottaa tuon lauseen vakavasti ja päättyy havaintoon, että koneoppimisen yleisin sääntö ei ole käytäntö vaan seuraus maailmaa koskevasta väitteestä — väitteestä, jonka voi testata ja joka on joskus väärä.

Yksi tunnustus ennen ensimmäistä koodiriviä. Nämä kaksikymmentä mittausta eivät ole oikeasta tehtaasta: generoin ne valitsemastani suorasta, width=20.00+0.30h\text{width} = 20.00 + 0.30 \cdot h, sekä satunnaisesta kohinasta, jonka hajonta on noin millimetrin kymmenesosa. Sillä on väliä, koska kaikki alla käsittelee sitä, palauttaako menetelmä totuuden, ja sen tarkistamiseen totuus on tiedettävä etukäteen. Siispä: 0,30 millimetriä tunnissa on kirjan takaosan vastaus. Et saa käyttää sitä, vain tarkistaa sitä vasten.

Kolme sääntöä, kolme voittajaa

Linkki osioon: Kolme sääntöä, kolme voittajaa

Tässä ovat mittaukset ja kolme viivaa, pisteytettynä kolmella tavalla: squared error, johon kaikki tarttuvat; absolute error, johon tilastotieteilijä saattaisi tarttua; ja worst error, johon koneistaja tarttuisi, koska tarkastajaa ei kiinnosta keskiarvosi — hän hylkää yksittäisen toleranssin ylittävän osan.

NumPy tulee mukaan tässä, yhden luvun puhdas-Python-perceptronin jälkeen, yhdestä syystä: tämän luvun lopussa arvioimme neljäsataatuhatta ehdokasviivaa jokaista kahtakymmentä mittausta vasten, ja Python-silmukka on siihen väärä työkalu. Se on myös notaatio, jolla jokainen alla viitattu lähde on kirjoitettu.

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

Korostettujen rivien suure on residuaali: se, mitä viiva sanoi, miinus se, mitä työntömitta sanoi, yksi luku kutakin mittausta kohti. Jokainen tämän luvun pisteytyssääntö ja jokainen häviöfunktio sitä seuraavissa kahdessakymmenessäkahdeksassa luvussa on jokin tapa puristaa residuaalien lista yhdeksi luvuksi. Ne eroavat vain siinä, miten ne puristavat.

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

Lue sarakkeita, älä rivejä. Squared error sanoo B, absolute error sanoo A, worst error sanoo C: kolme sääntöä, kolme voittajaa samoilla kahdellakymmenellä pisteellä.

Valitsin nämä kolme viivaa niin, että ne olisivat eri mieltä, ja se on syytä sanoa suoraan. Olennaista on, kuinka helppoa se oli — muutaman minuutin haku järkevän näköisten vakiotermien ja kulmakertoimien joukosta tuottaa satoja tällaisia kolmikkoja. Järjestys on valitsemasi säännön ominaisuus, ei viivoja koskeva tosiasia, joten sääntö ei ole toteutuksen yksityiskohta: se on ongelman määritelmä. Tämä nostaa esiin kysymyksen, jota varten tämä luku on olemassa: millä perusteella valitset sen?

Ensin pienempi asia, koska viivoja ei ole kolme vaan äärettömän monta. Otetaan toistaiseksi squared error, koska kaikki ottavat sen, ja kutistetaan ongelma yhdeksi luvuksi samalla tempulla, joka säästi perceptronilta yksitoistatuhatta epookkia luvussa 1: vähennetään keskiarvo molemmista sarakkeista. Kun pistepilvi on keskitetty origoon, paras viiva squared error -säännön alla kulkee täsmälleen origon kautta — joten vakiotermi on ratkaistu ja jäljelle jää vain kulmakerroin.

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

Kuusisataayksi ehdokaskulmakerrointa, yksi voittaja: 0,293 millimetriä tunnissa totuutta 0,300 vastaan. Kaksikymmentä kohinaista mittausta ja for-silmukka pääsivät sadanneksen millimetrin tuntivauhdin päähän — kaksi ja kolmasosa prosenttia.

Kiinnostava osa ei ole voittaja vaan haun muoto. Tulosta koko käyrä käännettynä niin, että loss kulkee vasemmalta oikealle:

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

Se on laakso sivulta nähtynä. Sillä on yksi pohja, seinämät nousevat pehmeästi molemmin puolin, ja — tämä on se osa, jota luvun 1 portaikko ei voinut tarjota — jokaisessa sen pisteessä on hyvin määritelty ”alamäen” suunta. Muista tuo muoto. Luku 3 käsittelee kokonaan sitä, miten sitä kävellään alas käymättä kaikissa kuudessasadaassayhdessä pisteessä, ja sitä, mikä muuttuu, kun laaksolla on useampi kuin yksi pohja.

Meillä on laakso, koska korotimme neliöön. Absolute error olisi tehnyt sen pohjaan kulman; worst error olisi tuottanut tasaisia osuuksia, joilla viivan liikuttaminen ei muuta mitään. Neliöiminen on kiistatta kätevää — ja kätevyys on suunnilleen se syy, jonka useimmat kurssit antavat, neljällä tavalla puettuna: se tekee virheistä positiivisia (niin tekee itseisarvokin); se rankaisee suuria virheitä enemmän (miksi pitäisi?); se on derivoituva (niin on neljäs potenssikin); sitä kaikki käyttävät (niin käyttävät, eikä se ole argumentti).

Rehellinen kanta on tämä. Squared error valitsi viivan B ja absolute error valitsi viivan A. Toinen niistä on oikea tälle tehtaalle ja toinen väärä, eikä mikään tähän mennessä sanottu kerro kumpi. Säännön valitsemiseksi sinun on tiedettävä jotain siitä, miten mittaukset päätyivät poikkeamaan viivasta, ja se on kysymys maailmasta, ei matematiikasta. Siihen vastaaminen tarvitsee yhden pienen koneiston osan.

Tässä on väite, joka muuttaa kysymyksen ”mikä viiva on parempi” kysymykseksi, johon on vastaus.

Oletetaan, että osan leveys on viiva plus satunnainen virhe, ja oletetaan, että virhe on peräisin Gaussisesta jakaumasta — kellokäyrästä — jonka keskiarvo on nolla ja keskihajonta σ\sigma:

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

Gaussisen jakauman tiheys on

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

Tee nyt jotain, mihin perceptron ei pystynyt. Annetulle ehdokaskulmakertoimelle θ\theta jokaisella mittauksella on residuaali, ja yllä oleva kaava muuttaa tuon residuaalin luvuksi: kuinka uskottava täsmälleen tämän kokoinen virhe on, jos tämä kulmakerroin on totuus? Viivalla oleva mittaus saa suuren luvun, puoli millimetriä sivussa oleva pienen.

Mittaukset ovat riippumattomia — työntömitta ei muista edellistä osaa — joten tulosääntö sanoo, että koko vihkon uskottavuus on yksittäisten tiheyksien tulo. Tuo tulo on parametrin θ\theta likelihood.1 Huomaa suunta, koska juuri siitä Bayesin säännössä on kyse: data on kiinteä ja tunnettu, ja parametri vaihtelee. Tämä ei ole ”kulmakertoimen todennäköisyys”. Se on todennäköisyys, jonka malli antaa saamallesi datalle, luettuna kulmakertoimen funktiona.

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

Kulmakerroin 0,293 tekee tästä vihkosta 46 000 kertaa uskottavamman kuin 0,25 ja 127 miljoonaa kertaa uskottavamman kuin 0,35. Maximum likelihood on periaate, jonka mukaan valitset parametrin, joka tekee todella havaitsemastasi mahdollisimman vähän yllättävää. Se ei ole teoreema vaan ehdotus siitä, mitä ”paras” pitäisi tarkoittaa — ehdotus, jolla on sisältöä, koska se pakottaa sinut sanomaan oletuksesi kohinasta ennen kuin saat pisteyttää mitään.

Aja samat kolme koodiriviä yhden vuoron sijasta kuukauden vuoroille, ja menetelmä kaatuu.

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

Kaksituhatta kertolaskua ja vastaus on inf. Muuta yhtä vakiota — epätarkempi työntömitta, jolloin tiheydet ovat pienempiä kuin 1 eivätkä suurempia — ja sama koodi palauttaa 0.0. Molemmat vastaukset ovat väärin, vastakkaisiin suuntiin, kumpikaan ei nosta poikkeusta, jonka voisit napata, eikä jälkimmäinen edes tulosta varoitusta.

Matematiikassa ei ole mitään vikaa. Likelihood noilla asetuksilla on täysin hyvin määritelty äärellinen luku: sen luonnollinen logaritmi on 1400,91, joten itse luku on noin 1060810^{608}. Ongelma on, ettei tietokoneellasi ole tuota lukua, ja kannattaa ymmärtää tarkasti, mitkä luvut sillä on, koska tämä ei ole viimeinen kerta, kun se päättää lopputuloksen.

Räjähtävän tulon korjaus on tavallinen: otetaan logaritmit. Logaritmi muuttaa tulot summiksi, se on aidosti kasvava, joten se ei voi siirtää maksimin sijaintia, ja kahdentuhannen maltillisen luvun summa on jotain, minkä float64 käsittelee valittamatta. Käytännön mukaan otamme negatiivisen log-likelihoodin, jotta parempi tarkoittaa pienempää. Sijoita nyt Gaussinen tiheys ja katso, mitä tapahtuu.

  1. Aloita tulosta. Likelihood on L(θ)=i=1Np(yiθxi)\mathcal{L}(\theta) = \prod_{i=1}^{N} p(y_i - \theta x_i), missä pp on yllä oleva Gaussinen tiheys.

  2. Ota miinus logaritmi. Tulosta tulee summa, ja tiheyden eksponenttifunktio kumoutuu logaritmin kanssa suoraan:

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. Heitä pois kaikki, mikä ei sisällä termiä θ\theta. Ensimmäinen termi on vakio. Summan edessä oleva 1/2σ21/2\sigma^2 on positiivinen vakio, eikä funktion skaalaaminen positiivisella vakiolla voi siirtää sen minimin paikkaa. Jäljelle jää
i=1N(yiθxi)2\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2

mikä on neliöityjen residuaalien summa — se asia, jolla aloitimme luvun, koska se on ensimmäinen asia, joka kenelle tahansa tulee mieleen.

Tämä on tulos, jota varten luku on olemassa, ja se ansaitsee tulla sanotuksi ilman varauksia: squared error ei ole käytäntö. Se on Gaussisen jakauman negatiivinen log-likelihood, kun vakiot on poistettu. Squared error -arvon minimointi on täsmälleen sama teko kuin väittää, että virheesi ovat Gaussisia, ja kysyä, mikä parametri tekee datastasi vähiten yllättävää. Teit tuon väitteen koko ajan; sinulle ei vain kerrottu sitä.

Ekvivalenssi on tarkistettavissa, joten tarkista se: käy läpi samat kuusisataayksi kulmakerrointa täydellä negatiivisella log-likelihoodilla, vakioineen kaikkineen, ja tavallisella squared error -arvolla.

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

Eri luvut pystyakselilla, ja toinen niistä on negatiivinen, mitä neliösumma ei koskaan ole: negatiivinen log-likelihood voi mennä alle nollan, koska tiheys voi ylittää arvon 1. Sama laakson pohja, samaan viimeiseen ruudukon pisteeseen asti.

Näytä koko derivointi

Mitkä poisheitot ovat täsmälleen turvallisia? Sama liike esiintyy jokaisessa luvussa, joka johtaa lossin, eikä se ole aina viaton.

Additiivisen vakion pudottaminen on turvallista aina, kun se ei riipu optimoimastasi parametrista, ja positiivisen kertovan vakion pudottaminen on turvallista, koska argminθcf(θ)=argminθf(θ)\arg\min_\theta c\,f(\theta) = \arg\min_\theta f(\theta) mille tahansa c>0c > 0. Molemmat epäonnistuvat heti, kun myös σ\sigma sovitetaan: silloin N2log(2πσ2)\frac{N}{2}\log(2\pi\sigma^2) ei ole lainkaan vakio, vaan termi, joka estää mallia väittämästä σ=0\sigma = 0 ja ääretöntä uskottavuutta. Se on täsmälleen seuraava osio.

Ne epäonnistuvat taas eri tavalla luvussa 3: kertova vakio ei siirrä minimiä, mutta se skaalaa gradientin, ja gradient kerrotaan learning rate -arvolla. Jakaminen luvulla NN, jotta saadaan mean squared error eikä sum, on vastaukselle näkymätöntä ja koulutusajolle erittäin näkyvää — summalla batch-koon kaksinkertaistaminen kaksinkertaistaa jokaisen ottamasi askeleen.

Kiinnitimme σ\sigma-arvon 0,12:een mielivaltaisesti, eikä kukaan tehtaalla tiedä työntömittansa virheen hajontaa. Käsittele sitä toisena tuntemattomana ja anna maximum likelihood -periaatteen päättää sekin. Tässä äsken pois heitetty vakiotermi palaa takaisin, koska se on ainoa asia mallin ja täydellisen tarkkuusväitteen välissä.

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

Nämä kaksi ovat samaa mieltä neljän desimaalin tarkkuudella, eivätkä sattumalta: derivoimalla tuon lausekkeen ja asettamalla sen nollaksi saadaan täsmälleen σ^2=1Nri2\hat{\sigma}^2 = \frac{1}{N}\sum r_i^2. Siis mean squared error ei ole vain varianssin kaltainen. Tässä mallissa se on kohinan varianssin maximum-likelihood-estimaatti — luku, jota olet koko ajan minimoinut, oli arvio siitä, kuinka kohinainen anturisi on.

Yksi mutka, helppo sanoa ja kallis löytää myöhemmin uudelleen: tuo estimaatti on alaspäin harhainen, koska residuaalit mitattiin sovitetta vasten, joka oli itse valittu tekemään niistä pieniä. Simuloi se — kaksisataatuhatta vihkoa, joissa kussakin on kaksikymmentä mittausta, vedettynä jakaumasta, jonka todellinen varianssi on täsmälleen 1, ja jossa sovitteen yksi parametri estimoidaan itse mittauksista. Neliösumman jakaminen arvolla NN antaa keskiarvoksi 0,9501; jakaminen arvolla N1N-1 antaa 1,0001; ja (N1)/N(N-1)/N on tasan 0,95. Jokainen sovittamasi parametri maksaa yhden vapausasteen, ja tämä on pienin näkyvä esimerkki paljon suuremmasta ongelmasta: malli näyttää aina paremmalta sillä datalla, johon se sovitettiin. Luku 4 muuttaa tämän datan sivuun pitämisen kurinalaisuudeksi, ja luku 6 antaa ilmiölle nimen.

Jos squared error väittää, että kohina on Gaussista, seuraava kysymys on, mitä tapahtuu, kun väite on väärä. Ei hieman väärä — vaan väärä sillä tavalla kuin oikeat mittaukset ovat vääriä.

Tehtaan lattialla useimmat työntömittalukemat ovat oikein millimetrin kymmenesosan tarkkuudella, ja kerran tai pari vuorossa lastun pala jää leuan alle ja lukema heittää useita millimetrejä. Tällaiset virheet ovat paksuhäntäisiä: suurimman osan ajasta pieniä, toisinaan valtavia, ja valtavia paljon useammin kuin kellokäyrä sallii. Cauchyn jakauma on tuon käyttäytymisen standardi puhdas malli, ja sen tiheys on yhtä yksinkertainen kuin Gaussisen:

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

Ero on hännässä: Gaussinen pienenee muodossa eε2e^{-\varepsilon^2}, raa'an nopeasti, ja Cauchy muodossa 1/ε21/\varepsilon^2, tuskin lainkaan. Seuraus on helpompi nähdä kuin sanoa:

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

Gaussisen otosvarianssi asettuu arvoon 0,0144, joka on 0.1220.12^2, ja pysyy siinä. Cauchyn nousee ja jatkaa nousua niin kauan kuin otostat, koska sillä ei ole mitään, mihin konvergoida: Cauchyn jakaumalla ei ole varianssia eikä edes keskiarvoa. Squared error, jonka koko tehtävä on minimoida neliöiden keskiarvoa, pyytää suuretta, jota ei ole olemassa.

Tässä siis yksi vuoro, jossa työntömittaa huijattiin. Samat kaksikymmentä tuntia, sama terä, sama 0,30 millimetriä tunnissa oleva drift — vain kohina on nyt Cauchy. Sovita kahdesti: kerran minimoimalla neliöidyt residuaalit, kerran minimoimalla datan oikeasti tuottaneen kohinan negatiivinen log-likelihood. Keskittämistemppu ei auta tässä — se kiinnittää vakiotermin vain squared error -tapauksessa — joten molemmat sovitteet tehdään raa'alla voimalla vakiotermien ja kulmakertoimien ruudukon yli, koska meillä ei vieläkään ole keinoa löytää laakson pohjaa muuten kuin käymällä siellä.

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

Kaksi korostettua riviä ovat koko ero sovitteiden välillä. Ota Cauchyn tiheyden logaritmi, pudota vakiot täsmälleen kuten ennen, ja log(1+(r/s)2)\sum \log\left(1 + (r/s)^2\right) on se, mikä jää. Sama resepti, eri väite kohinasta.

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

Pienimmät neliöt ilmoittaa driftiksi 0,108 millimetriä tunnissa, suunnilleen kolmasosan todellisesta vauhdista, ja päättelee, että terä kelpaa tuntiin 19,6 asti. Todellinen vastaus on tunti 11,7. Tuon sovitteen perusteella tehdas ajaa prässiä kahdeksan ylimääräistä tuntia ja valmistaa toleranssin ylittäviä osia alan standardeimman häviöfunktion arvovallalla. Cauchy-sovite, joka käyttää samoja kahtakymmentä mittausta, samaa ruudukkoa ja yhden rivin eroa koodissa, osuu tuntiin 11,8.

Kaksi vastalausetta ansaitsee vastaukset, koska molemmat ovat ensimmäinen asia, jonka hyvä insinööri sanoo.

Poikkeava havainto on ilmeinen — poista se. Voit tehdä niin, ja se auttaa, eikä se riitä. Yhden huonoimman mittauksen poistaminen siirtää pienimpien neliöiden kulmakertoimen arvosta 0,108 arvoon 0,239, mikä silti asettaa terän vaihdon tuntiin 13,1, puolitoista tuntia myöhään; huonoimman poistaminen, uudelleensovitus ja sen poistaminen, mikä on nyt huonoin, vie arvoon 0,286 — ja huomaa, että tämä on jo menettely, ei havainto: poista alkuperäisen sovitteen kaksi suurinta residuaalia sen sijaan, ja päädyt arvoon 0,223. Olet nyt kuitenkin tehnyt harkintapäätöksiä, joita et voi kirjoittaa ylös tai puolustaa, eikä säännön automatisointi pelasta sitä: pudota-suurin-residuaali-ja-sovita-uudelleen, ajettuna tuhannella simuloidulla vuorolla, saa mediaanikulmakerroinvirheeksi 0,0177 likelihood-sovitteen arvoa 0,0100 vastaan, ja on pielessä yli 0,05:llä 14,7 prosentissa vuoroista likelihoodin 1,3 prosenttia vastaan. Poistaminen on paikka väärän oletuksen päällä. Likelihood ei tarvitse paikkaa, koska se ei koskaan olettanut poikkeamaa mahdottomaksi.

Valitsit onnekkaan datasarjan. Tuo vastalause on täsmälleen oikea, minkä vuoksi viimeinen koe simuloi tuhat riippumatonta vuoroa ja sovittaa molemmilla tavoilla jokaisen.

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

Mediaani, ei keskiarvo, samasta syystä kuin kaikki muukin tässä osiossa: pienimpien neliöiden virheitä ajaa Cauchy, joten niiden keskiarvo ei ole vakaa raportoitava asia. Pienimmät neliöt on pahasti väärässä kahdessa vuorossa viidestä; likelihood-sovite on pahasti väärässä yhdessä vuorossa seitsemästäkymmenestäseitsemästä, ja sen pahin epäonnistuminen tuhannessa vuorossa on alle viidesosa pienimpien neliöiden pahimmasta.

Mikään tästä ei tee squared error -säännöstä huonoa. Se tekee siitä tarkan, ja aritmetiikka kertoo täsmälleen miksi. Ota residuaali 0,1 mm ja toinen 7 mm. Neliöitynä huono lukema vaikuttaa kokonaisuuteen 4 900 kertaa niin paljon kuin hyvä, joten viiva raahautuu kokonaisena sitä kohti; Cauchyn log-likelihoodin alla samat kaksi residuaalia tuottavat 0,527 ja 8,133, suhteen 15,4. Huono lukema lasketaan edelleen, se ei vain saa päättää. Tämä on robustin tilastotieteen alku, jossa Huberin vuoden 1964 loss jakaa eron käyttäytymällä kvadraattisesti pienillä residuaaleilla ja lineaarisesti suurilla,7 ja jossa Tukey oli jo osoittanut, kuinka vähän kontaminaatiota tarvitaan tekemään otosvarianssista huonompi työkalu kuin keskimääräinen absoluuttinen poikkeama.8

Yksi historiallinen huomio, liian hyvä jätettäväksi pois. Pienimmät neliöt julkaisi ensin Legendre vuonna 1805 kätevänä algebrallisena välineenä ilman muuta perustelua kuin että se toimi.9 Neljä vuotta myöhemmin Gauss ajoi argumentin takaperin: hän otti annettuna, että aritmeettinen keskiarvo on oikea tapa yhdistää toistomittauksia, kysyi, mikä virhejakauma tekee keskiarvosta todennäköisimmän arvon, ja näytti, että olennaisesti vain yksi tekee niin — se, joka on nyt nimetty hänen mukaansa.10 Tämän luvun johtaminen on hänen, se on yli kaksi vuosisataa vanha, ja se on yhä se osa, jonka useimmat kurssit jättävät pois.

Mitä voit nyt sanoa ja mitä et vieläkään osaa tehdä

Linkki osioon: Mitä voit nyt sanoa ja mitä et vieläkään osaa tehdä

Ansaittu. Häviöfunktio on pisteytyssääntö, ja sen tuottama järjestys on säännön, ei ehdokkaiden, ominaisuus. Jokainen tämän kurssin loss on jonkin kohinaa koskevan oletuksen negatiivinen log-likelihood, vakiot pois heitettyinä — Gaussinen antaa tässä squared error -säännön, Bernoulli antaa cross-entropyn luvussa 4, ja kategorinen jakauma sanaston yli antaa next-token loss -arvon luvussa 8. Resepti ei koskaan muutu: sano kohina, kirjoita likelihood, ota miinus logaritmi. Ja kun oletus on väärä, malli ei ole vain epätarkka, vaan väärässä suuntaan, jonka voit ennustaa.

Vielä puuttuu. Löysimme laakson pohjan käymällä sen jokaisessa pisteessä. Se toimi yhdelle parametrille ja kuudellesadalle ehdokkaalle, ja selvisi kahdesta parametrista 401 301 ehdokkaalla viidesosasekunnissa. Kolme parametria samalla resoluutiolla on 201 051 801 ehdokasta eikä enää mahdu yhteen taulukkoon; pienessä verkossa luvussa 5 on tuhansia parametreja, ja malleissa, joille luku 10 laskee hinnan, on miljardeja. Raaka voima ei ole tässä hidasta, se on aritmeettisesti mahdotonta, eikä mikään tässä luvussa ehdota vaihtoehtoa.

Katso silti takaisin laaksoon. Kun seisot kohdassa θ=0.20\theta = 0.20 loss-arvolla 0,0822, ”alamäen” suunta ei ole mysteeri — näet sen sivulla, käyrä laskee oikealle. Jos voisit kysyä häviöfunktiolta, mihin suuntaan se kallistuu siinä pisteessä, jossa seisot, arvioimatta sitä missään muualla, voisit ottaa askeleen siihen suuntaan, kysyä uudelleen ja toistaa, kunnes maa on tasainen.

Tuolla kysymyksellä on nimi. Funktion kulmakerroin pisteessä on sen derivaatta, ja monen parametrin funktiolle kaikkien suuntien kulmakertoimien kokoelma kerralla on gradient. Luku 1 ei voinut käyttää sellaista, koska perceptronin virhe oli portaikko, jolla ei ollut kysyttävää kulmakerrointa. Tämä luku on rakentanut jotain parempaa: loss-arvon, joka on sileä kaikkialla ja joka tuli julkilausutusta oletuksesta eikä mieltymyksestä.

Siksi luvun 3 kysymys ei ole enää, onko kulmakerrointa olemassa. Se on, miten se lasketaan, miksi liikkuminen sitä vastaan vie alamäkeen eikä ylämäkeen — merkki, jonka melkein jokainen kurssi pyytää ottamaan uskolla — ja kuinka pitkälle pitää astua ennen kuin kysyy uudelleen, mikä osoittautuu yhdeksi luvuksi, joka päättää konvergoiko koulutusajo, värähteleekö se vastauksen ympärillä ikuisesti vai juokseeko se äärettömyyteen.


Tämän luvun rinnalla kannattaa lukea myös: Prince, Understanding Deep Learning §5.1–5.2 ja liite C, joka rakentaa kirjan jokaisen loss-arvon maximum likelihood -periaatteesta tässä käytetyssä järjestyksessä; Goodfellow, Bengio ja Courville, Deep Learning §3.1–3.11 ja §5.5, jonka maximum-likelihood-osio johtaa myös luvun 4 tarvitseman KL-divergenssin; Murphy, Probabilistic Machine Learning: An Introduction luku 2 ja §4.2 siitä, mitä maximum likelihood takaa ja mitä ei; Deisenroth, Faisal ja Ong, Mathematics for Machine Learning §6.1–6.4 summasäännön, tulosäännön ja Bayesin säännön kunnolliseen käsittelyyn; Tom Mitchellin lyhyt CMU-muistio Estimating Probabilities: MLE and MAP (2016); sekä Dive into Deep Learning -teoksen §22.7, joka päätyy samaan tulokseen ajettavalla koodilla.

  1. Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, s. 309–368 (1922). Teos, jossa likelihood esitetään yleisenä menetelmänä yhdessä käsitteiden ”parameter”, ”statistic”, riittävyys ja tehokkuus kanssa. Itse nimeäminen ja erottaminen todennäköisyydestä on vuotta aiempi: 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. Määrittelee binary32- ja binary16-muodot sekä pyöristyssäännöt, joiden vuoksi summauskoe päätyy tulokseensa.

  3. Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Muodon parametrit ja perustelu mantissabittien vaihtamiselle eksponenttibitteihin.

  4. Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling ja mitatut gradienttien suuruudet, jotka tekevät siitä välttämättömän float16:ssa.

  5. Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), s. 5–48 (1991). Yhä paras yksittäinen selitys sille, miksi kaksi summausjärjestystä ovat eri mieltä.

  6. Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), s. 40 (1965). Kompensoitu summaus puolessa sivussa.

  7. Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), s. 73–101 (1964). Loss, joka on kvadraattinen lähellä nollaa ja lineaarinen hännissä, johdettuna eikä paikattuna kasaan.

  8. Tukey, J. W. A survey of sampling from contaminated distributions, teoksessa 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 (Pariisi, 1805), liite Sur la méthode des moindres quarrés. Ensimmäinen pienimpien neliöiden julkaisu laskennallisena välineenä.

  10. Gauss, C. F. Theoria Motus Corporum Coelestium (Hampuri, 1809), kirja II, §§175–179. Argumentti aritmeettisesta keskiarvosta normaalin virhelakiin ja siitä pienimpiin neliöihin.


Tekijä

David Vicente Campos

NeuraLIA Labsin perustaja ja MyRealFoodin toinen perustaja

Olen valmistunut tietotekniikan insinööriksi Leónin yliopistosta. Olin mukana perustamassa MyRealFoodia, jossa teknologiajohtajana rakensin sovelluksen, jota miljoonat ihmiset ovat käyttäneet syödäkseen paremmin, ja perustin NeuraLIA Labsin, jossa rakennan tekoälytuotteita. Täällä kirjoitan siitä, mitä minun on pitänyt ymmärtää matkan varrella, niin kuin olisin toivonut jonkun selittävän asiat minulle.

Lisää kirjoittajasta

Julkaisija: NeuraLIA Labs.

Uudet julkaisut suoraan sähköpostiisi

AI-uutisia, oppaita ja tuoteuutisia — lyhyt sähköposti, kun julkaisemme jotain aikasi arvoista.

Kurssin hakemisto

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev9 min lukuaikaa

Jev AI -malli on rakennettu päätöksiä, ei proosaa varten

TypeSafe AI:n Jev herättää huomiota, koska se käsittelee ohjelmistojen älykkyyttä todennäköisyysongelmana: valitse oikea haara, liitä mukaan varmuus ja vältä maksamasta LLM:lle tekstin kirjoittamisesta, kun koodi tarvitsee päätöksen.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering9 min lukuaikaa

Kontekstisuunnittelu pitkän aikavälin AI-agenteille

Pitkäkestoiset agentit eivät epäonnistu vain siksi, että ikkuna on pieni. Ne epäonnistuvat, kun tiedostot, työkalujen tulosteet ja vanhentunut historia syrjäyttävät tehtävän, joka agentin piti saada valmiiksi.

Valmis antamaan LIA:n valita puolestasi?

Rakenna kaikilla tekoälymalleilla yhdessä paikassa — aloita ilmaiseksi jo tänään.