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

Luokittelu, ristientropia ja miten et huijaa itseäsi

Rakenna logistinen luokitin luvun 2 häviöstä ja luvun 3 laskeutumisesta — ja näe, miksi 98 % accuracy voi olla arvoton.

Tällä sivulla

Malli, joka vastaa tämä osa on kunnossa jokaisesta hihnalta tulevasta osasta, on oikeassa 98,15 % ajasta. Se on myös hyödytön: testijoukon 74 viallisesta osasta se ei löydä yhtäkään.

Molemmat lauseet kuvaavat samaa mallia. Niiden välinen matka on tämä luku.

Ensimmäinen puolikas rakentaa luokittimen. Se tarvitsee lähes mitään uutta: luku 2 antoi reseptin, jolla oletus datan syntytavasta muutetaan häviöfunktioksi, ja luku 3 antoi koneiston, jolla kävellään alamäkeen millä tahansa häviöllä, jonka resepti antaa. Sovella molempia kyllä/ei-kysymykseen, ja logistinen regressio putoaa ulos — sekä yksi uusi ajatus, logit, josta laskutetaan uudelleen luvussa 17.

Toinen puolikas on vaikeampi. Tästä eteenpäin kurssilla kaikki arvioidaan jollakin mitatulla luvulla, ja jos et erota todellista parannusta mittausartefaktista, jokainen seuraava luku on koristelua. Siis: sekaannusmatriisi, precision ja recall, kolme jakoa, leakage ja kysymys, johon lähes kukaan ei vastaa rehellisesti — montako testiesimerkkiä oikeasti tarvitsen?

Tässä aritmetiikka kulkee 20 000 rivin yli, joten se on kauttaaltaan vektoroitu — NumPy on tehnyt työn luvusta 2 asti, eikä tästä eteenpäin ole enää mainitsemisen arvoista huomauttaa siitä.

Hihna, harvinaisemmalla kysymyksellä

Linkki osioon: Hihna, harvinaisemmalla kysymyksellä

Sama tehdas kuin luvussa 1, vaikeampi kysymys. Sen sijaan, että kysyttäisiin hyväksy vai hylkää, kysymys on onko tämä osa viallinen — ja viat ovat harvinaisia, mikä tekee tämän luvun mittauspuolesta vaikean ja mallinnuspuolesta petollisen helpon.

belt.pyPYTHON
import numpy as np

rng = np.random.default_rng(4)
N = 20_000
width  = rng.normal(22.0, 0.9, N)      # millimetres
weight = rng.normal(57.0, 3.0, N)      # grams

z_true = -5.90 + 1.90 * (width - 22.0) + 0.42 * (weight - 57.0)
y = (rng.random(N) < 1 / (1 + np.exp(-z_true))).astype(float)

perm = rng.permutation(N)
train, val, test = perm[:12_000], perm[12_000:16_000], perm[16_000:]
TEXT
N = 20000  defects = 337  base rate = 0.0169
defects per split = 203 60 74

Kolme jakoa, ei kahta. Syy ansaitsee oman osionsa ja saa sellaisen alempana; toistaiseksi opeta ensimmäisellä, säädä toisella äläkä katso kolmanteen.

Piirteet standardoidaan — keskiarvo vähennetään ja jaetaan keskihajonnalla — käyttäen vain opetusjoukon tilastoja, siitä syystä jonka luku 1 näytti perceptronin konvergenssirajalla: keskittämätön data tekee geometriasta vihamielisen. Miltä riveiltä tuon keskiarvon saa laskea, muuttuu myöhemmin tässä luvussa eläväksi kysymykseksi.

Perceptron palautti etumerkin. Etumerkki ei erota tapausta hylkää tapauksesta hylkää, mutta juuri ja juuri, ja juuri sitä eroa tehdas tarvitsee päättääkseen, mitkä osat ihmisen pitäisi tarkastaa uudelleen ensin.

Seuraa siis luvun 2 reseptiä kirjaimellisesti. Kirjoita ylös väitteesi siitä, miten label syntyy, ota likelihood, ota logaritmi, vaihda etumerkki, ja sinulla on häviö. Kyllä/ei-tulokselle väite on Bernoulli-jakauma: on todennäköisyys pp, että osa on viallinen, ja

P(yp)=py(1p)1yP(y \mid p) = p^{\,y}\,(1-p)^{\,1-y}

mikä on vain tiivis tapa kirjoittaa "pp jos y=1y = 1, ja 1p1-p jos y=0y = 0". Ota siitä logaritmi ja vaihda etumerkki, ja yhden esimerkin häviö on

L=[ylogp+(1y)log(1p)]L = -\big[\,y \log p + (1 - y)\log(1 - p)\,\big]

Tämä on binäärinen ristientropia. Sitä ei valittu siksi, että se olisi kätevä; se on ainoa mahdollinen kolikonheiton jakauman negatiivinen log-likelihood. Mitään muuta ei ollut tarjolla.

Vielä puuttuu, mistä pp tulee. Malli laskee painotetun summan s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b, joka on reaaliluku ja kulkee koko lukusuoran yli, kun taas todennäköisyyden täytyy elää välillä (0,1)(0,1). Funktio, joka liikkuu niiden välillä, on logistinen sigmoid:

σ(s)=11+es\sigma(s) = \frac{1}{1 + e^{-s}}
TEXT
logit -4.0  ->  p = 0.0180        loss when y=1 and p=0.9  : 0.1054
logit -1.0  ->  p = 0.2689        loss when y=1 and p=0.5  : 0.6931
logit  0.0  ->  p = 0.5000        loss when y=1 and p=0.01 : 4.6052
logit  4.0  ->  p = 0.9820

Lue oikeanpuoleinen sarake hinnastona. Oikeassa oleminen 90 % varmuudella maksaa 0,105. Kieltäytyminen sitoutumasta maksaa 0,693 — eli log2\log 2, olankohautuksen hinta. Varmasti väärässä oleminen maksaa 4,6, neljäkymmentäneljä kertaa enemmän, ja hinta nousee rajatta, kun malli tulee yhä varmemmaksi virheestään. Ristientropia ei vain laske virheitä: se veloittaa ylimielisyydestä.

Gradientti on ennuste miinus totuus

Linkki osioon: Gradientti on ennuste miinus totuus

Luku 3 sanoi: jotta voit opettaa mitä tahansa, hanki häviön derivaatta kunkin parametrin suhteen. Tee se yhdelle esimerkille. Kun s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b ja p=σ(s)p = \sigma(s):

Ls=py,Lw=(py)x,Lb=py\frac{\partial L}{\partial s} = p - y, \qquad \frac{\partial L}{\partial \mathbf{w}} = (p - y)\,\mathbf{x}, \qquad \frac{\partial L}{\partial b} = p - y
Näytä lisätiedot

Kaksi riviä, jotka saavat sotkun kumoutumaan. Sigmoidilla on poikkeuksellisen miellyttävä derivaatta, σ(s)=σ(s)(1σ(s))=p(1p)\sigma'(s) = \sigma(s)\,(1 - \sigma(s)) = p(1-p). Ja häviö derivoituu muotoon

Lp=yp+1y1p=pyp(1p)\frac{\partial L}{\partial p} = -\frac{y}{p} + \frac{1-y}{1-p} = \frac{p - y}{p\,(1-p)}

Kerro nämä kaksi ketjusäännöllä, ja p(1p)p(1-p) ilmestyy kerran ylös ja kerran alas. Se kumoutuu täsmälleen, ja jäljelle jää pyp - y. Tuo kumoutuminen ei ole sattumaa — niin tapahtuu aina, kun häviö on jakauman negatiivinen log-likelihood ja ulostulofunktio on se, jota kyseinen jakauma luontevasti käyttää. Tällä parilla on nimi — yleistetty lineaarinen malli — ja siisti gradientti on sen sormenjälki.1

Päivitys on siis ennuste miinus totuus, kertaa syöte. Ei muuta. Tässä on koko trainer, joka on luvun 3 descent yhdellä muutetulla rivillä:

logistic.pyPYTHON
def sigmoid(z):
    return np.where(z >= 0, 1.0 / (1.0 + np.exp(-z)),
                    np.exp(np.minimum(z, 0)) / (1.0 + np.exp(np.minimum(z, 0))))


def fit_logistic(X, y, lr=0.5, epochs=4000):
    w, b = np.zeros(X.shape[1]), 0.0
    for _ in range(epochs):
        p = sigmoid(X @ w + b)
        g = p - y                        
        w -= lr * (X.T @ g) / len(y)     
        b -= lr * g.sum() / len(y)       
    return w, b

np.where kohdassa sigmoid ei ole kosmeettinen. Laskeminen 1/(1+es)1/(1+e^{-s}) suoraan ylivuotaa suurilla negatiivisilla ss-arvoilla; haara valitsee sen algebrallisesti identtisen muodon, joka pitää eksponentin negatiivisena. Tämä on luvun 2 liukulukulaatikko perimässä ensimmäistä velkaansa, ja se perii isomman kahden osion päästä.

Miksei neliövirhe, ja miksi vastaus liittyy gradienttiin

Linkki osioon: Miksei neliövirhe, ja miksi vastaus liittyy gradienttiin

Tavanomainen selitys ristientropian suosimiselle neliövirheen sijaan on yllä oleva likelihood-argumentti: neliövirhe on se, mitä saat olettamalla Gaussista kohinaa, labelit eivät ole Gaussisia, joten älä tee niin. Se on oikein eikä vakuuta ketään, koska voit kirjoittaa L=(py)2L = (p - y)^2 sigmoidin päälle, ja se kyllä oppii.

Perille menevä argumentti koskee gradienttia. Laita neliövirhe sigmoidin päälle, ja ketjusääntö antaa

Ls=2(py)p(1p)\frac{\partial L}{\partial s} = 2\,(p - y)\,p\,(1-p)

Tuo ylimääräinen p(1p)p(1-p) on se, joka aiemmin kumoutui. Nyt se ei kumoudu, ja se menee nollaan aina, kun malli on varma — myös silloin, kun malli on varmasti väärässä. Arvioi molemmat muutamalla pisteellä esimerkille, jonka todellinen label on 1:

piste ssppristientropia L/s\partial L/\partial sneliövirhe L/s\partial L/\partial ssuhde
8-80.0003350.999665-0.9996650.000670-0.0006701,491
4-40.0179860.982014-0.9820140.034690-0.03469028.3
2-20.1192030.880797-0.8807970.184956-0.1849564.8
000.5000000.500000-0.5000000.250000-0.2500002.0
+2+20.8807970.119203-0.1192030.025031-0.0250314.8

Kohdassa s=8s = -8 malli on niin väärässä kuin mahdollista, ja neliövirhe vastaa gradientilla, joka on 1 491 kertaa pienempi kuin ristientropian. Mitä pahempi virhe, sitä vähemmän malli oppii siitä. Ristientropian gradientti puolestaan saturoituu arvoon 1-1: maksimaalisen väärä tuottaa maksimaalisen suuren signaalin, eikä suurempaa.

Aja kilpailu. Kaksituhatta tasapainotettua pistettä, identtiset aloituspainot valittuina olemaan varmasti väärässä (w=[6,6]\mathbf{w} = [-6, -6]), identtinen oppimisnopeus, vain häviö eroaa. Molemmat ajot pisteytetään ristientropialla, jotta sarakkeet ovat vertailukelpoisia.

epochristientropiahäviöaccuracyneliövirhehäviöaccuracy
15.48650.23005.94990.2290
101.55250.24605.90420.2290
500.46420.77805.69130.2320
1000.46390.77705.39550.2410
2000.46390.77704.63110.2745
5000.46390.77700.52910.7660
1,0000.46390.77700.46400.7765

Ristientropia on valmis epochilla 50. Neliövirhe on vielä 24 % accuracyssa epochilla 100 — eikä ollut liikkunut 23 %:sta epochilla 10 — arvaamista huonompi, koska se aloitti varmasti väärässä ja sen pelastava gradientti oli kerrottu luvulla 0,0007. Se pääsee pakoon noin epochilla 500 ja päätyy samaan paikkaan. Rehellinen yhteenveto on siis, että neliövirhe sigmoidin päällä ei ole väärin; se on hidas juuri siellä, missä nopeudella on eniten väliä. Kahden parametrin mallissa menetät 450 epochia. Sadan kerroksen verkossa, jossa jokin yksikkö jossakin on aina varmasti väärässä, menetät koko opetuksen.

Entropia, ristientropia ja KL yhdellä sivulla

Linkki osioon: Entropia, ristientropia ja KL yhdellä sivulla

Kolme suuretta, joita tarvitaan kunnolla luvussa 8 perplexityyn ja luvussa 11 rangaistukseen, joka pitää fine-tuned policy lähellä referenssiään. Ne ovat helpompia kuin maineensa.2

Entropia on bittien keskimääräinen määrä, joka sinun täytyy käyttää jakaumasta tehdyn arvonnan viestimiseen, jos käytät sille parasta mahdollista koodia:

H(p)=ipilog2piH(p) = -\sum_i p_i \log_2 p_i

Ristientropia on se, mitä käytät, kun käytät jakaumalle qq rakennettua koodia dataan, joka oikeasti tulee jakaumasta pp:

H(p,q)=ipilog2qiH(p, q) = -\sum_i p_i \log_2 q_i

KL-divergenssi on ylijäämä — hukka bitteinä, jonka aiheuttaa uskominen jakaumaan qq, kun totuus on pp:

DKL(pq)=H(p,q)H(p)D_{\mathrm{KL}}(p \parallel q) = H(p,q) - H(p)

Tarkista kaikki kolme hihnalla:

TEXT
test defect rate                                = 0.0185
entropy of that coin                            = 0.1329 bits
cross-entropy of the constant predictor on test = 0.1330 bits
KL(test coin || fair coin)                      = 0.8671 bits
H + KL                                          = 1.0000 bits
cross-entropy of the p=0.5 predictor on test    = 1.0000 bits

Kaksi asiaa näkyy siinä. Ensinnäkin malli, joka vain raportoi opetusjoukon perusosuuden, 1,69 %, saavuttaa ristientropian 0,1330 bittiä, melkein täsmälleen testilabelien entropian — kuten pitääkin, koska sillä on oikea jakauma eikä mitään muuta tietoa. Entropia on lattia, jonka yksilöstä tietämättömyys ostaa sinulle. Toiseksi malli, joka kohauttaa olkiaan ja sanoo 0,5, maksaa täsmälleen 1 bitin, ja näiden kahden väli, 0,8671 bittiä, on täsmälleen KL-divergenssi. H+DKL=H(p,q)H + D_{\mathrm{KL}} = H(p,q) ei ole identiteetti ulkoa opeteltavaksi; se on lasku, jonka kertymistä voit katsoa.

Ja yhteys takaisin opetukseen: kun label on yksi tunnettu luokka, "todellinen" jakauma on one-hot, sen entropia on nolla, ja ristientropia on yhtä kuin KL-divergenssi. Ristientropian minimointi ja mallin jakauman vetäminen kohti totuutta ovat sama teko.

Enemmän kuin kaksi vastausta: softmax ja siirto, joka ei maksa mitään

Linkki osioon: Enemmän kuin kaksi vastausta: softmax ja siirto, joka ei maksa mitään

Viallinen ei ole yksi asia. Valussa osa voi tulla ulos vajaatäyttönä (liian vähän materiaalia), purseena (liikaa, puristuneena ulos muotista) tai palamana. Neljä tulosta, siis neljä logits, ja niistä täytyy tulla neljä todennäköisyyttä, joiden summa on yksi. Se on softmax:

softmax(z)i=ezijezj\operatorname{softmax}(\mathbf{z})_i = \frac{e^{z_i}}{\sum_j e^{z_j}}

Sillä on ominaisuus, joka näyttää vahingolta mutta on itse asiassa koko toteutus:

softmax(z+c)=softmax(z)\operatorname{softmax}(\mathbf{z} + c) = \operatorname{softmax}(\mathbf{z})

millä tahansa vakiolla cc, koska ezi+c=ecezie^{z_i + c} = e^{c} e^{z_i} ja ece^c kumoutuu ylhäällä ja alhaalla. Vain logitsien erot merkitsevät mitään. Absoluuttinen taso ei ole informaatiota.

Onneksi, koska absoluuttinen taso on se, joka rikkoo tietokoneen:

TEXT
logits            = [800. 801. 799.]
naive softmax     = [nan nan nan]
shifted by -max   = [0.2447 0.6652 0.09  ]
same softmax after adding 1000 to every logit: True

e800e^{800} ylivuotaa 64-bittisen liukuluvun, summa muuttuu äärettömäksi, ja ääretön jaettuna äärettömällä on nan — ei virhe, ei kaatuminen, vain hiljainen aukko siinä, missä kolmen todennäköisyyden piti olla. Suurimman logit vähentäminen ei muuta matemaattisesti mitään ja numeerisesti kaiken, koska suurimmasta eksponentista tulee täsmälleen e0=1e^0 = 1. Tämä on luvun 2 logsumexp-temppu työvaatteissaan, ja jokainen vakava toteutus tekee sen:

softmax.pyPYTHON
def softmax(Z):
    Z = Z - Z.max(axis=1, keepdims=True)   
    E = np.exp(Z)
    return E / E.sum(axis=1, keepdims=True)


def fit_softmax(X, Y, lr=1.0, epochs=6000):
    W, b = np.zeros((X.shape[1], Y.shape[1])), np.zeros(Y.shape[1])
    for _ in range(epochs):
        G = (softmax(X @ W + b) - Y) / len(X)   
        W -= lr * (X.T @ G)
        b -= lr * G.sum(0)
    return W, b

Gradientti on taas ennuste miinus totuus, nyt kun YY on one-hot. Binääritapaus oli koko ajan erikoistapaus.

Opetettuna 3 000 osalla ja testattuna 1 000:lla, kolmella mittauksella kullekin (leveys, paino, sulalämpötila), se saavuttaa 94,00 % accuracyn. Tässä on, mitä tuo luku piilottaa:

totuus ↓ / ennustettu →okvajaatäyttöpursepalamarecall
ok8505900.984
vajaatäyttö2221000.488
purse2003010.588
palama300390.929
precision0.9500.8080.7690.975

Malli löytää alle puolet vajaatäytöistä. Accuracy ei näe tätä, koska 86 % osista on kunnossa, ja niiden oikein saaminen riittää kantamaan keskiarvon. Macro F1 — luokkakohtaisten F1-pisteiden keskiarvo, joka painottaa harvinaista luokkaa samalla tavalla kuin yleistä — on 0,7983, kun micro F1 on 0,9400 ja määritelmän mukaan identtinen accuracyn kanssa. Aina kun joku raportoi yhden F1-luvun, kysy mikä.

Siihen päättyy mallinnus. Luvun loppu käsittelee lukuja.

Ota opetettu binäärimalli ja tee kaksi varianttia kertomalla jokainen logit vakiolla: 0,35 epäröivälle versiolle, 4 ylivarmalle. Positiivisella luvulla kertominen ei voi muuttaa yhtään etumerkkiä, joten kaikki kolme mallia ennustavat täsmälleen saman labelin kaikille 4 000 testiosalle. Accuracy ei erota niitä toisistaan. Ristientropialla ei ole minkäänlaista vaikeutta:

malliaccuracyristientropiakeskihäviö oikein ollessakeskihäviö väärin ollessapahin yksittäinen häviö
epäröivä (logits × 0.35)0.98300.15490.13691.19902.80
kuten opetettu0.98300.05640.01472.46897.82
yliluottavainen (logits × 4)0.98300.15630.00099.142727.63

Epäröivä malli maksaa pienen veron jokaisesta osasta, myös niistä tuhansista, jotka se saa oikein. Ylivarma malli on lähes ilmainen ollessaan oikeassa ja katastrofaalinen ollessaan väärässä — yksi osa tuossa testijoukossa maksaa sille yksin 27,63 natsia. Nämä kaksi päätyvät lähes samaan kokonaismäärään vastakkaisia reittejä, ja opetettu malli, jonka todennäköisyydet on kalibroitu dataan, istuu kolme kertaa alempana kuin molemmat.

Tämä on terävin tapa sanoa ero häviön ja metriikan välillä. Häviö on se, mitä optimoit: sen täytyy olla derivoituva, ja se näkee kaiken, mitä malli sanoi, myös sen kuinka varma se oli. Metriikka on se, jolla sinut arvioidaan: se voi olla askelfunktio, liiketoimintasääntö, laskuri ohitetuista vioista. Ne eivät ole sama objekti eivätkä aina ole samaa mieltä — siksi määrittelet molemmat ennen aloittamista etkä koskaan anna häviön korvata metriikkaa vain siksi, että se sattuu olemaan ruudulla.

Ennen mitään mallia vaatimus: mihin laiskin mahdollinen vastaus yltää? Tällä hihnalla sano aina kunnossa:

TEXT
always-say-fine baseline: accuracy = 0.9815
confusion (tn, fp, fn, tp) = (3926, 0, 74, 0)

98,15 %. Nyt opetettu logistinen malli, oletuskynnyksellä 0,5:

TEXT
logistic @0.5: accuracy=0.9830 precision=0.8000 recall=0.1081 F1=0.1905
confusion (tn, fp, fn, tp) = (3924, 2, 66, 8)

98,30 %. Se voitti baselinen 0,15 prosenttiyksiköllä, ja mikä tahansa raportti, joka pysähtyy accuracyyn, kutsuu sitä voitoksi. Sekaannusmatriisi kertoo, mitä oikeasti tapahtui:

ennustettu kunnossaennustettu viallinen
oikeasti kunnossa3,9242
oikeasti viallinen668

Kolme lukua nimeää kolme tapaa lukea tuota taulukkoa:

  • Precision =TP/(TP+FP)=8/10=0.800= \mathrm{TP}/(\mathrm{TP}+\mathrm{FP}) = 8/10 = 0.800. Kuinka moni sen merkitsemistä osista oli oikeasti viallinen. Tämä on hukattujen tarkastusten kustannus.
  • Recall =TP/(TP+FN)=8/74=0.108= \mathrm{TP}/(\mathrm{TP}+\mathrm{FN}) = 8/74 = 0.108. Kuinka monta viallisista osista se sai kiinni. Tämä on huonon osan asiakkaalle lähettämisen kustannus.
  • F1 =2PR/(P+R)=0.190= 2PR/(P+R) = 0.190, niiden harmoninen keskiarvo, joka pysyy lähellä pienempää ja kieltäytyy siksi tulemasta imarrelluksi vain toisesta.

Mikä merkitsee, riippuu tehtaasta, ei matematiikasta: tarkastus maksaa muutaman sekunnin ja toimitettu viallinen osa maksaa takaisinkutsun, joten tässä recall hallitsee ja 0,108 on epäonnistuminen.

Mutta malli ei ole ongelma. Kynnys on, eikä kynnys ole osa mallia — se on liiketoimintapäätös, joka sovelletaan jälkikäteen todennäköisyyteen. Pyyhkäise se:

kynnysTPFPFNaccuracyprecisionrecallF1
0.50082660.98300.8000.1080.190
0.2002728470.98120.4910.3650.419
0.10042118320.96250.2630.5680.359
0.05054236200.93600.1860.7300.297
0.0206757070.85580.1050.9050.188
0.005711,36030.65930.0500.9590.094

Lue accuracy-saraketta alaspäin. Se laskee koko matkan — 98,30 %:sta 65,93 %:iin — samalla kun malli siirtyy löytämään 8 vikaa 71 vikaan 74:stä. Jokainen hyödyllinen asia, jonka tämä malli voi tehdä, tekee sen accuracysta huonomman. Tiimi, joka optimoi otsikkolukua, lähettäisi version, joka ei löydä mitään.

Näytä lisätiedot

Luokkapainotus ei luo signaalia, se siirtää toimintapistettä. Tavallinen ensimmäinen refleksi epätasapainoisissa luokissa on painottaa harvinaista luokkaa häviössä. Kun niin tehdään painoilla 1, 10 ja 60 positiivisille:

paino positiivisilleaccuracyprecisionrecallF1AUC
10.98300.8000.1080.1900.9363
100.96050.2530.5810.3520.9361
600.82900.0910.9190.1660.9361

Precision ja recall liikkuvat pitkälle. AUC — todennäköisyys, että malli sijoittaa satunnaisen viallisen osan satunnaisen hyvän yläpuolelle, ja joka sivuuttaa kynnyksen kokonaan — liikkuu 0,0002, mikä ei ole mitään. Uudelleenpainotus liu'utti samaa mallia samaa vaihtokäyrää pitkin. Se on usein juuri sitä, mitä haluat, eikä se koskaan ole uutta informaatiota: jos järjestys on huono, mikään painotuskaava ei pelasta sitä.

Kolme jakoa ja vuoto, jonka olet löytämässä

Linkki osioon: Kolme jakoa ja vuoto, jonka olet löytämässä

Miksi kolme jakoa eikä kaksi? Koska sillä hetkellä, kun käytät esimerkkijoukkoa valitsemaan jotakin — kynnyksen, oppimisnopeuden, minkä kuudesta mallista toimitat — sitä joukkoa on käytetty sovittamiseen, ja sen pistemäärä lakkaa olemasta harhaton.3 Tällä hihnalla mitattuna: kynnyksen pyyhkäisy validointijoukolla valitsee 0,196, ja malli saa sitten koskemattomalla testijoukolla F1 = 0,4122. Jos pyyhkäisy olisi ajettu suoraan testijoukolla, paras siellä saavutettavissa oleva oli 0,4186 — luku, jota kenelläkään ei ole oikeutta raportoida.

Ero on tässä pieni, 0,006, koska kyseessä on yksi hyperparametri, joka pyyhkäistiin kerran 4 000 validointiesimerkkiä vasten. Se kasvaa jokaisella lisäpäätöksellä ja jokaisella validointijoukon kutistumisella. Huomaa myös, ettei suunta ole taattu yksittäisessä ajossa: valittu kynnys sai validoinnissa 0,3902 ja testissä 0,4122, joten validointi aliraportoi sen tällä kertaa. Harha on systemaattinen monien päätösten yli, ei näkyvä yhdessä.4

Nyt harjoitus. Hihnaloki saapuu kolmannen sarakkeen kanssa, station_seconds: kuinka kauan kukin osa vietti tarkastusasemalla. Sen lisääminen on yhden rivin muutos esikäsittelyyn. Tässä, mitä se tekee:

malliaccuracyprecisionrecallF1ristientropiaAUC
leveys + paino0.98300.8000.1080.1900.05640.9363
+ station_seconds0.99200.7920.7700.7810.02360.9970

Recall nousee 10,8 %:sta 77,0 %:iin. F1 yli nelinkertaistuu. Ja huomaa, mitä accuracy teki: 98,30 % → 99,20 %, yhdeksän kymmenesosan voitto, eli sellainen luku, joka pyöristetään yhteenvetokalvolla muotoon "noin 99 % joka tapauksessa". Accuracy ei nähnyt epäonnistumista aiemmin eikä nyt näe petosta.

Ennen kuin luet eteenpäin: malli huijaa. Selvitä miten.

Miten metsästät vuodon siinä järjestyksessä, joka löytää sen nopeimmin.

  1. Vertaa opetusta ja testiä. Ylisovitus näkyy suurena erona. Tässä: rehellinen malli 0,9838 opetus / 0,9830 testi; vuotava malli 0,9936 opetus / 0,9920 testi. Molemmat erot ovat alle 0,2 pistettä. Vuoto ei näytä ylisovitukselta — vuotava piirre on yhtä lailla saatavilla testiaikana, joten malli yleistää kauniisti maailmaan, jota ei ole olemassa.

  2. Opeta yksi malli per piirre, yksinään. Kaikki, mikä kantaa vastauksen, ilmoittaa itsestään:

    piirre yksinaccuracyrecallF1AUC
    leveys0.98150.0140.0260.8691
    paino0.98150.0000.0000.7914
    station_seconds0.98500.4050.5000.9960

    Yksi sarake yksinään järjestää viat AUC:lla 0,9960. Kaksi mittausta, jotka on otettu työntömitalla ja vaa'alla, yltävät 0,87:ään ja 0,79:ään. Tuo epäsymmetria on hälytys.

  3. Kysy, milloin kukin luku kirjoitettiin muistiin. Keskimääräinen viipymäaika: 2,23 sekuntia läpäisseille osille, 15,56 sekuntia hylätyille osille. Tietysti. Osa viipyy asemalla koska tarkastaja veti sen pois hihnalta — mikä tapahtuu sen jälkeen ja vain siksi, että joku päätti sen olevan viallinen. Sarake ei ole osan mittaus. Se on tuomion mittaus.

the planted leakPYTHON
station = 1.8 + rng.exponential(0.35, N)                     # a part just passing through
audited = rng.random(N) < 0.006                              # random spot checks
station[audited] += rng.uniform(6.0, 26.0, audited.sum())
station[y == 1] = 9.0 + rng.exponential(7.0, (y == 1).sum())  

Korostettu rivi on vuoto: viallisen osan viipymäaika arvotaan eri jakaumasta, koska ihminen otti sen pois hihnalta. Tämä on sovelletun koneoppimisen yleisin vakava bugi, ja sillä on nimi: target leakage — opetuspiirteissä oleva informaatio, joka ei olisi saatavilla sillä hetkellä, kun ennuste täytyy tehdä.5 Se ei heitä poikkeusta. Se tuottaa paremman luvun. Jokainen projektin kannustin osoittaa sen säilyttämiseen.

Puolustus on yksi kysymys, joka kysytään jokaisesta sarakkeesta: sillä hetkellä, kun tarvitsen tämän ennusteen, onko tämä arvo jo olemassa? Elävällä hihnalla station_seconds on tuntematon siihen asti, kun osa on tarkastettu — mikä oli asia, jonka mallin piti korvata.

Montako testiesimerkkiä tarvitsen?

Linkki osioon: Montako testiesimerkkiä tarvitsen?

Oletetaan, että pisteytät mallin 20 esimerkillä ja se saa 17 oikein. Raportoit 85 %.

TEXT
17 correct out of 20 -> accuracy 0.8500
  Wilson    95% CI : [0.6396, 0.9476]
  bootstrap 95% CI : [0.7000, 1.0000]
  P(a 65% model scores 17 or more out of 20) = 0.0444
  P(an 85% model scores 17 or more out of 20) = 0.6477

Rehellinen lukutapa 17/20:lle on jossakin 64 %:n ja 95 %:n välillä. Aidosti 65 %:n malli tuottaa tämän tuloksen 4,4 % ajasta — yksi ajo kahdestakymmenestäkolmesta — ja jos kokeilit kourallista prompts ja raportoit parhaan, valmistit tuon ajon itse. Seitsemäntoista kahdestakymmenestä ei erota 85 %:n mallia 65 %:n mallista.

Kaksi tapaa asettaa väli osuudelle, ja molemmat kuuluvat työkalupakkiisi:

uncertainty.pyPYTHON
def wilson(k, n, z=1.959963985):
    """95% interval for k successes in n trials. Correct at small n; no simulation."""
    ph, d = k / n, 1 + z * z / n
    centre = (ph + z * z / (2 * n)) / d
    half = z * (ph * (1 - ph) / n + z * z / (4 * n * n)) ** 0.5 / d
    return centre - half, centre + half


def bootstrap_ci(correct, n_resamples=10_000, alpha=0.05, seed=0):
    """95% interval for the mean of any per-example score array. Works on F1 too."""
    rng = np.random.default_rng(seed)
    correct = np.asarray(correct, dtype=float)
    draws = correct[rng.integers(0, len(correct), size=(n_resamples, len(correct)))]
    lo, hi = np.quantile(draws.mean(axis=1), [alpha / 2, 1 - alpha / 2])
    return float(correct.mean()), float(lo), float(hi)

Käytä Wilsonia6 tavalliselle onnistumisprosentille; se pysyy hyvin käyttäytyvänä millä tahansa nn eikä tarvitse satunnaisuutta. Huomaa yllä, että kohdassa n=20n = 20 bootstrapin yläpää on 1,0000 — 20 pisteen uudelleenotanta voi helposti nostaa 20 oikeaa, joten se ei voi esittää väliä, joka olisi kapeampi kuin sen oma rakeisuus. Käytä bootstrapia7, kun kaavaa ei ole, mikä kattaa useimmat kiinnostavat tapaukset: F1, makrokeskiarvot, BLEU, pass@1, rubriikkipohjaisen tuomarin piste. Tällä hihnalla säädetyn mallin F1 0,4122 kantaa bootstrap-väliä [0.3009, 0.5156] — ja juuri tuon luvun pitäisi näkyä raportissa, koska pelkkä piste-estimaatti kutsuu vertailuun, jota se ei voi tukea.

Vielä yksi mittaus, koska se muuttaa sitä, miten kahta mallia pitäisi verrata. Kaksi mallia pisteytettynä samoilla 500 esimerkillä:

TEXT
model A: 0.8580  95% CI [0.8260, 0.8880]
model B: 0.8120  95% CI [0.7780, 0.8460]
the two intervals overlap: True
paired difference A-B: 0.0460  95% CI [0.0260, 0.0680]
they disagree on 31 of 500 examples (A right 27, B right 4)

Niiden välit menevät päällekkäin, ja kansansääntö — päällekkäiset virhepalkit tarkoittavat, ettei merkittävää eroa ole — kutsuisi vertailua epäselväksi. Se ei ole. Kaksi mallia ajettiin samoilla esimerkeillä, joten oikea suure on esimerkkikohtainen ero, jonka väli on [0.0260, 0.0680], mukavasti nollan yläpuolella. Ne ovat eri mieltä vain 31:stä 500 kohteesta, ja A voittaa 27 noista erimielisyyksistä; yhteiset esimerkit, helpot ja vaikeat, kumoutuvat sen sijaan että lisäisivät kohinaa. Vertaa malleja pareittain, ja pääset samaan johtopäätökseen murto-osalla datasta.

Sinulla on nyt malli, joka tuottaa kalibroituja todennäköisyyksiä, häviö, joka on johdettu väitteestä dataa koskien eikä valittu kätevyyden vuoksi, gradientti, joka on kirjaimellisesti ennuste miinus totuus, ja — tärkeämpänä — koneisto sen selvittämiseen, toimiiko mikään siitä. Yllä oleva kymmenen rivin Wilson-väli käytetään sellaisenaan uudelleen: se kantaa prompt-variantit luvussa 15, retrieval-taulukot luvussa 19 ja golden setin luvussa 29. Bootstrap on se, johon tartut, kun kaavaa ei ole.

Mutta malli on yhä yksi kerros. Se piirtää viivan, ja luku 1 todisti neljällä XOR-rivillä, ettei viiva riitä. Korjaus on pinota: ensimmäinen kerros, joka taivuttaa avaruutta, toinen, joka piirtää viivan taivutettuun avaruuteen.

Siihen tämän luvun siisti gradientti loppuu. Kaikki yllä toimi, koska L/s=py\partial L/\partial s = p - y voitiin kirjoittaa käsin kerran mallille, jossa on yksi kerros syötteen ja häviön välissä. Laita toinen kerros keskelle, ja kysymys muuttaa muotoaan: mikä on häviön derivaatta sellaisen painon suhteen, joka ei koske ulostuloa lainkaan — jonka vaikutus saapuu vain toisen kerroksen kautta, mahdollisesti useita polkuja yhtä aikaa?

Tuo derivaatta on olemassa. Sen laskeminen käsin on toivotonta kaikelle lelua suuremmalle, ja sen laskeminen parametri kerrallaan on toivotonta eri mittakaavassa. Tarvitaan menetelmä, joka saa jokaisen verkon derivaatan yhdestä backward passista saman graafin yli, jonka forward pass juuri kulki.

Se on luku 5, ja se on moottori, jolla loppu kurssi käy.


Tämän luvun rinnalla kannattaa lukea myös: Bishop, Pattern Recognition and Machine Learning §1.2, §1.5, §1.6 ja §4.3, joka käsittelee todennäköisyyttä, päätösteoriaa, informaatioteoriaa ja lineaarista luokittelua siinä järjestyksessä, jota tämä luku seuraa; Murphy, Probabilistic Machine Learning: An Introduction, luvut 6 ja 10; Prince, Understanding Deep Learning §5.4–5.7; sekä Saito ja Rehmsmeier, The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets (PLOS ONE, 2015) — miksi yllä lainatun AUC:n ei pitäisi olla ainoa kynnyksetön luku, jota katsot, kun 1,7 % osista on viallisia.

  1. Ma, T. ja Ng, A. CS229 Lecture Notes, Stanford University, luvut 2 ja 3. Siellä kumoutuminen, joka tuottaa pyp - y, lakkaa näyttämästä tuurilta: valitse eksponentiaaliperheen jakauma, joka vastaa ulostuloasi, käytä sen kanonista linkkiä, ja gradientti on aina ennuste miinus totuus.

  2. Olah, C. Visual Information Theory (2015), colah.github.io/posts/2015-09-Visual-Information. Selkein saatavilla oleva selitys entropiasta, ristientropiasta ja KL-divergenssistä bittikustannuksina eikä kaavoina.

  3. Abu-Mostafa, Y. S., Magdon-Ismail, M. ja Lin, H.-T. Learning From Data (AMLBook, 2012), Caltech-kurssin luennot 13 ja 17. Luento 13 on validointi; luento 17, kolmesta oppimisperiaatteesta, on paikka, jossa data snooping nimetään. Yhdessä ne ovat tämän luvun kurinalaisuuden lähde: jokainen vilkaisu datajoukkoon on sovituspäätös, ajoitpa optimiserin tai et.

  4. James, G., Witten, D., Hastie, T. ja Tibshirani, R. An Introduction to Statistical Learning, 2. painos (Springer, 2021), luvut 2 ja 5, bias–variance-hajotelmasta ja uudelleenotannasta. Rinnakkaisteos on paikka, jossa valinta-ansa sanotaan suoraan: Hastie, Tibshirani ja Friedman, The Elements of Statistical Learning, 2. painos, §7.10.2, The Wrong and Right Way to Do Cross-validation.

  5. Kaufman, S., Rosset, S., Perlich, C. ja Stitelman, O. Leakage in Data Mining: Formulation, Detection, and Avoidance. ACM Transactions on Knowledge Discovery from Data 6(4), 2012. Muodollinen käsittely yllä demonstroidusta epäonnistumisesta, tapaustutkimuksilla kilpailuista, jotka voitti malli, joka oli oppinut artefaktin siitä, miten data koottiin.

  6. Wilson, E. B. Probable Inference, the Law of Succession, and Statistical Inference. Journal of the American Statistical Association 22(158), s. 209–212 (1927). Score-väli, jota yllä käytettiin kohdassa wilson(), yhä oikea oletus suhteelle. Oppikirjaväli p^±zp^(1p^)/n\hat{p} \pm z\sqrt{\hat{p}(1-\hat{p})/n} on se, jota kannattaa välttää: se antaa järjettömyyksiä lähellä 0:aa ja 1:tä ja alikatetaan pahasti pienellä nn.

  7. Efron, B. Bootstrap Methods: Another Look at the Jackknife. The Annals of Statistics 7(1), s. 1–26 (1979). Ajatus, jonka avulla voit asettaa välin mille tahansa tilastolle, jonka pystyt laskemaan, myös niille, joilla ei ole otantateoriaa.


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.