Spring til indhold
4/30Kapitel 4 af 30

Klassifikation, krydsentropi og kunsten ikke at narre dig selv

Byg en logistisk klassifikator, og se hvorfor 98 % nøjagtighed kan betyde, at modellen intet finder.

På denne side

En model, der svarer denne del er fin om hver eneste del, der kommer af båndet, har ret 98,15 % af tiden. Den er også værdiløs: af de 74 defekte dele i testsættet fanger den ingen.

Begge sætninger beskriver den samme model. Afstanden mellem dem er dette kapitel.

Den første halvdel bygger klassifikatoren. Den kræver næsten intet nyt: Kapitel 2 gav opskriften på at gøre en antagelse om, hvordan data produceres, til en tabsfunktion, og Kapitel 3 gav maskineriet til at gå ned ad bakke på det tab, opskriften giver dig. Anvend begge dele på et ja/nej-spørgsmål, og logistisk regression falder ud, plus én ny idé — en logit — som der opkræves betaling for igen i Kapitel 17.

Den anden halvdel er den sværere. Alt efter dette punkt i kurset bedømmes efter et tal, som nogen har målt, og hvis du ikke kan skelne en reel forbedring fra en måleartefakt, er alle de følgende kapitler pynt. Så: forvekslingsmatricen, precision og recall, de tre splits, lækage og spørgsmålet, næsten ingen svarer ærligt på — hvor mange testeksempler har jeg faktisk brug for?

Aritmetikken her kører over 20.000 rækker, så den er vektoriseret hele vejen igennem — NumPy har gjort arbejdet siden Kapitel 2, og herfra holder det op med at være værd at bemærke.

Samme fabrik som i Kapitel 1, sværere spørgsmål. I stedet for accepter eller afvis er spørgsmålet er denne del defekt — og defekter er sjældne, hvilket gør måledelen af dette kapitel svær og modelleringsdelen bedragerisk let.

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

Tre splits, ikke to. Årsagen fortjener sin egen sektion og får en nedenfor; indtil videre: træn på den første, tun på den anden, og kig ikke på den tredje.

Features er standardiseret — middelværdi trukket fra, divideret med standardafvigelsen — kun ved hjælp af træningsstatistikkerne, af den grund Kapitel 1 demonstrerede med perceptronens konvergensgrænse: ikke-centrerede data gør geometrien fjendtlig. Hvilke rækker du må beregne den middelværdi fra, bliver et levende spørgsmål senere i dette kapitel.

Perceptronen returnerede et fortegn. Et fortegn kan ikke skelne afvis fra afvis, men kun lige akkurat, og den forskel er præcis, hvad en fabrik behøver for at beslutte, hvilke dele et menneske bør inspicere igen først.

Så følg Kapitel 2's opskrift bogstaveligt. Skriv ned, hvad du hævder om, hvordan en label produceres, tag likelihood, tag logaritmen, negér den, og så har du et tab. For et ja/nej-udfald er påstanden en Bernoulli-fordeling: der er en sandsynlighed pp for, at delen er defekt, og

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

hvilket blot er en kompakt måde at skrive "pp hvis y=1y = 1, og 1p1-p hvis y=0y = 0". Tag logaritmen af det, og negér den, og tabet for ét eksempel er

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

Dette er binær krydsentropi. Den blev ikke valgt, fordi den er praktisk; den er den negative log-likelihood for den eneste fordeling, et møntkast kan have. Der var intet andet til rådighed.

Det, der stadig mangler, er hvor pp kommer fra. Modellen beregner en vægtet sum s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b, som er et reelt tal og spænder over hele tallinjen, og en sandsynlighed skal leve i (0,1)(0,1). Funktionen, der flytter mellem dem, er den logistiske 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

Læs højre kolonne som en prisliste. At have ret med 90 % sikkerhed koster 0,105. At nægte at forpligte sig koster 0,693 — hvilket er log2\log 2, prisen for et skuldertræk. At tage selvsikkert fejl koster 4,6, fireogfyrre gange mere, og prisen stiger uden grænse, efterhånden som modellen bliver mere sikker på en fejl. Krydsentropi tæller ikke blot fejl: den opkræver betaling for arrogance.

Kapitel 3 sagde: For at træne hvad som helst skal du finde den afledte af tabet med hensyn til hver parameter. Gør det for ét eksempel. Med s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b og 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
Vis detaljer

De to linjer, der får rodet til at gå ud. Sigmoiden har en usædvanligt behagelig afledt, σ(s)=σ(s)(1σ(s))=p(1p)\sigma'(s) = \sigma(s)\,(1 - \sigma(s)) = p(1-p). Og tabet differentierer til

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

Gang de to sammen med kædereglen, og p(1p)p(1-p) dukker op én gang i tælleren og én gang i nævneren. Den går præcist ud, og pyp - y er det, der står tilbage. Den reduktion er ikke et tilfælde — det er, hvad der sker, når tabet er den negative log-likelihood for en fordeling, og outputfunktionen er den, fordelingen naturligt bruger. Den parring har et navn — en generaliseret lineær model — og den ryddelige gradient er dens fingeraftryk.1

Så opdateringen er forudsigelse minus sandhed, gange inputtet. Intet andet. Her er hele træneren, som er Kapitel 3's descent med én linje ændret:

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 i sigmoid er ikke kosmetik. At beregne 1/(1+es)1/(1+e^{-s}) direkte giver overflow for store negative ss; grenen vælger den algebraisk identiske form, der holder eksponenten negativ. Det er Kapitel 2's floating-point-boks, der indkasserer sin første gæld, og den indkasserer en større to sektioner herfra.

Hvorfor ikke kvadreret fejl, og hvorfor svaret handler om gradienten

Link til afsnittet: Hvorfor ikke kvadreret fejl, og hvorfor svaret handler om gradienten

Standardforklaringen på at foretrække krydsentropi frem for kvadreret fejl er likelihood-argumentet ovenfor: kvadreret fejl er det, du får ved at antage Gaussisk støj, labels er ikke Gaussiske, derfor lad være. Det er korrekt, og det overbeviser ingen, fordi du kan skrive L=(py)2L = (p - y)^2 oven på en sigmoid, og den vil træne.

Argumentet, der lander, handler om gradienten. Læg kvadreret fejl oven på en sigmoid, og kædereglen giver

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

Den ekstra p(1p)p(1-p) er den, der gik ud før. Nu gør den ikke, og den går mod nul, når modellen er selvsikker — også når modellen er selvsikkert forkert. Evaluer begge ved nogle få scorer for et eksempel, hvis sande label er 1:

score ssppkrydsentropi L/s\partial L/\partial skvadreret fejl L/s\partial L/\partial sforhold
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

Ved s=8s = -8 tager modellen så meget fejl, som det er muligt at tage, og kvadreret fejl svarer med en gradient, der er 1,491 gange mindre end krydsentropiens. Jo værre fejlen er, desto mindre lærer modellen af den. Krydsentropiens gradient mætter imens ved 1-1: maksimalt forkert giver et maksimalt stort signal, og ikke større.

Kør løbet. To tusind balancerede punkter, identiske startvægte valgt til at være selvsikkert forkerte (w=[6,6]\mathbf{w} = [-6, -6]), identisk læringsrate, kun tabet er forskelligt. Begge kørsler scores med krydsentropi, så kolonnerne kan sammenlignes.

epochkrydsentropitabnøjagtighedtab ved kvadreret fejlnøjagtighed
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

Krydsentropi er færdig ved epoch 50. Kvadreret fejl ligger stadig på 24 % nøjagtighed ved epoch 100 — og havde ikke flyttet sig fra 23 % ved epoch 10 — — værre end at gætte, fordi den startede selvsikkert forkert, og gradienten, der skulle redde den, er blevet ganget med 0,0007. Den slipper fri omkring epoch 500 og ender samme sted. Så den ærlige opsummering er, at kvadreret fejl over en sigmoid ikke er forkert; den er langsom præcis der, hvor hastighed betyder mest. På en model med to parametre mister du 450 epochs. På et netværk med hundrede lag, hvor en eller anden enhed et eller andet sted altid tager selvsikkert fejl, mister du træningskørslen.

Tre størrelser, der skal bruges ordentligt i Kapitel 8 til perplexity og i Kapitel 11 til den straf, der holder en fine-tuned policy tæt på dens reference. De er lettere end deres ry.2

Entropi er det gennemsnitlige antal bits, du skal bruge for at kommunikere et træk fra en fordeling, hvis du bruger den bedst mulige kode til den:

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

Krydsentropi er det, du bruger, når du anvender en kode bygget til qq på data, der faktisk kommer fra pp:

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

KL-divergens er overskuddet — spildet, i bits, forårsaget af at tro på qq, når sandheden er pp:

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

Tjek alle tre på båndet:

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

To ting er synlige dér. For det første opnår en model, der blot rapporterer træningens basisrate, 1,69 %, en krydsentropi på 0,1330 bits, næsten præcis entropien for test-labels — som den må, eftersom den har den rigtige fordeling og ingen anden information. Entropi er det gulv, som uvidenhed om individet køber dig. For det andet betaler en model, der trækker på skuldrene og siger 0,5, præcis 1 bit, og afstanden mellem de to, 0,8671 bits, er netop KL-divergensen. H+DKL=H(p,q)H + D_{\mathrm{KL}} = H(p,q) er ikke en identitet, der skal huskes; det er en regning, du kan se blive lagt sammen.

Og forbindelsen tilbage til træning: Når labelen er en enkelt kendt klasse, er den "sande" fordeling one-hot, dens entropi er nul, og krydsentropi er lig med KL-divergensen. At minimere krydsentropi og trække modellens fordeling mod sandheden er den samme handling.

Mere end to svar: softmax, og skiftet der ikke koster noget

Link til afsnittet: Mere end to svar: softmax, og skiftet der ikke koster noget

Defekt er ikke én ting. I støbning kan en del komme ud som et short shot (ikke nok materiale), flash (for meget, presset ud af formen) eller burn. Fire udfald, så fire logits, og de skal blive til fire sandsynligheder, der summerer til én. Det er softmax:

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

Den har en egenskab, der ligner et tilfælde, men som i virkeligheden er hele implementeringen:

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

for enhver konstant cc, fordi ezi+c=ecezie^{z_i + c} = e^{c} e^{z_i} og ece^c går ud i top og bund. Kun forskelle mellem logits betyder noget. Det absolutte niveau er ikke information.

Heldigvis, for det absolutte niveau er det, der ødelægger computeren:

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} giver overflow i en 64-bit float, summen bliver uendelig, og uendelig divideret med uendelig er nan — ikke en fejl, ikke et crash, bare et tavst hul dér, hvor tre sandsynligheder plejede at være. At trække den største logit fra ændrer intet matematisk og alt numerisk, fordi den største eksponent bliver præcis e0=1e^0 = 1. Det er Kapitel 2's logsumexp-trick i arbejdstøj, og enhver seriøs implementering gør det:

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

Gradienten er igen forudsigelse minus sandhed, nu med YY one-hot. Det binære tilfælde var hele tiden et specialtilfælde.

Trænet på 3.000 dele og testet på 1.000, med tre målinger hver (bredde, vægt, smeltetemperatur), når den 94,00 % nøjagtighed. Her er, hvad det tal skjuler:

sandhed ↓ / forudsagt →okshort shotflashburnrecall
ok8505900.984
short shot2221000.488
flash2003010.588
burn300390.929
precision0.9500.8080.7690.975

Modellen finder færre end halvdelen af short shots. Nøjagtighed kan ikke se det, fordi 86 % af delene er fine, og at få dem rigtigt er nok til at bære gennemsnittet. Macro F1 — gennemsnittet af F1-scorerne per klasse, som vægter en sjælden klasse på samme måde som en almindelig — er 0,7983, mod en micro F1 på 0,9400, som per definition er identisk med nøjagtighed. Når nogen rapporterer ét F1-tal, så spørg hvilket.

Det er det sidste af modelleringen. Resten af kapitlet handler om tallene.

Tag den trænede binære model, og lav to varianter ved at gange hver logit med en konstant: 0,35 for en tøvende version, 4 for en overmodig. At gange med et positivt tal kan ikke ændre noget fortegn, så alle tre modeller forudsiger præcis den samme label for alle 4.000 testdele. Nøjagtighed kan ikke skelne dem fra hinanden. Krydsentropi har ingen problemer overhovedet:

modelnøjagtighedkrydsentropigennemsnitligt tab ved rigtigt svargennemsnitligt tab ved forkert svarværste enkelttab
tøvende (logits × 0.35)0.98300.15490.13691.19902.80
som trænet0.98300.05640.01472.46897.82
overmodig (logits × 4)0.98300.15630.00099.142727.63

Den tøvende model betaler en lille skat på hver del, inklusive de tusinder, den får rigtigt. Den overmodige er næsten gratis, når den har ret, og katastrofal, når den tager fejl — én del i det testsæt koster den 27,63 nats alene. De to ender på næsten samme total ad modsatte veje, og den trænede model, hvis sandsynligheder er kalibreret til dataene, ligger tre gange under begge.

Dette er den skarpeste måde at beskrive forskellen mellem et tab og en metric. Tabet er det, du optimerer: det skal være differentiabelt, og det ser alt, modellen sagde, inklusive hvor sikker den var. Metric er det, du bliver bedømt på: den kan være en trinfunktion, en forretningsregel, en optælling af oversete defekter. De er ikke det samme objekt, og de er ikke altid enige — derfor definerer du begge, før du starter, og lader aldrig tabet stå i stedet for metric, bare fordi det tilfældigvis er på skærmen.

Før enhver model kommer kravet: hvad scorer det mest dovne mulige svar? På dette bånd: sig altid fin:

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

98,15 %. Nu den trænede logistiske model ved standardgrænsen 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 %. Den slog baseline med 0,15 procentpoint, og enhver rapport, der stopper ved nøjagtighed, vil kalde det en sejr. Forvekslingsmatricen siger, hvad der faktisk skete:

forudsagt finforudsagt defekt
faktisk fin3,9242
faktisk defekt668

Den fandt 8 defekte dele ud af 74 og lod 66 slippe igennem. Tre tal navngiver de tre måder at læse tabellen på:

  • Precision =TP/(TP+FP)=8/10=0.800= \mathrm{TP}/(\mathrm{TP}+\mathrm{FP}) = 8/10 = 0.800. Af de dele, den markerede, hvor mange var faktisk defekte. Det er omkostningen ved spildte inspektioner.
  • Recall =TP/(TP+FN)=8/74=0.108= \mathrm{TP}/(\mathrm{TP}+\mathrm{FN}) = 8/74 = 0.108. Af de defekte dele, hvor mange fangede den. Det er omkostningen ved at sende en dårlig del til en kunde.
  • F1 =2PR/(P+R)=0.190= 2PR/(P+R) = 0.190, deres harmoniske middel, som bliver tæt på den mindste af de to og derfor nægter at blive smigret af én af dem alene.

Hvad der betyder noget, afhænger af fabrikken, ikke af matematikken: en inspektion koster nogle få sekunder, og en sendt defekt koster en tilbagekaldelse, så her dominerer recall, og 0,108 er en fiasko.

Men modellen er ikke problemet. Grænsen er, og grænsen er ikke en del af modellen — den er en forretningsbeslutning, der anvendes bagefter på en sandsynlighed. Sweep den:

grænseTPFPFNnøjagtighedprecisionrecallF1
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

Læs nøjagtighedskolonnen nedad. Den falder hele vejen — fra 98,30 % til 65,93 % — mens modellen går fra at fange 8 defekter til at fange 71 af 74. Alt nyttigt, denne model kan gøre, gør dens nøjagtighed værre. Et team, der optimerer overskriftstallet, ville shippe versionen, der intet finder.

Vis detaljer

Klassevægtning skaber ikke signal, den flytter driftspunktet. Den sædvanlige første refleks med ubalancerede klasser er at vægte den sjældne klasse i tabet. Gør man det med vægte på 1, 10 og 60 på de positive:

vægt på positivenøjagtighedprecisionrecallF1AUC
10.98300.8000.1080.1900.9363
100.96050.2530.5810.3520.9361
600.82900.0910.9190.1660.9361

Precision og recall flytter sig langt. AUC — sandsynligheden for, at modellen rangerer en tilfældig defekt del over en tilfældig god del, hvilket ignorerer grænsen fuldstændigt — flytter sig med 0,0002, hvilket er ingenting. Omvægtning skubbede den samme model langs den samme trade-off-kurve. Det er ofte det, du vil have, og det er aldrig ny information: Hvis rangeringen er dårlig, redder ingen vægtningsordning den.

Hvorfor tre splits og ikke to? Fordi i det øjeblik du bruger et sæt eksempler til at vælge noget — en grænse, en læringsrate, hvilken af seks modeller der skal shippes — er det sæt blevet brugt til fitting, og dets score holder op med at være unbiased.3 Målt på dette bånd: at sweep'e grænsen på valideringssættet vælger 0,196, og modellen scorer derefter F1 = 0,4122 på det urørte testsæt. Havde sweepet kørt direkte på testsættet, var det bedst opnåelige dér 0,4186 — et tal, ingen har ret til at rapportere.

Afstanden er lille her, 0,006, fordi det er én hyperparameter sweepet én gang mod 4.000 valideringseksempler. Den vokser med hver ekstra beslutning og hver indskrænkning af valideringssættet. Bemærk også, at retningen ikke er garanteret i en enkelt kørsel: den valgte grænse scorede 0,3902 på validering og 0,4122 på test, så validering underestimerede den denne gang. Biasen er systematisk på tværs af mange beslutninger, ikke synlig i én.4

Nu øvelsen. Båndloggen ankommer med en tredje kolonne, station_seconds: hvor længe hver del tilbragte ved inspektionsstationen. At tilføje den er en ændring på én linje i preprocessingen. Her er, hvad den gør:

modelnøjagtighedprecisionrecallF1krydsentropiAUC
bredde + vægt0.98300.8000.1080.1900.05640.9363
+ station_seconds0.99200.7920.7700.7810.02360.9970

Recall går fra 10,8 % til 77,0 %. F1 mere end firedobles. Og læg mærke til, hvad nøjagtighed gjorde: 98,30 % → 99,20 %, en gevinst på ni tiendedele af et point, hvilket er den slags tal, der bliver rundet til "omkring 99 % uanset" på en opsummeringsslide. Nøjagtighed kunne ikke se fiaskoen før og kan nu ikke se bedraget.

Før du læser videre: modellen snyder. Find ud af hvordan.

Sådan jagter du en lækage, i den rækkefølge der finder den hurtigst.

  1. Sammenlign træning og test. Overfitting viser sig som et stort gap. Her: ærlig model 0,9838 træning / 0,9830 test; lækkende model 0,9936 træning / 0,9920 test. Begge gaps er under 0,2 point. En lækage ligner ikke overfitting — den lækkende feature er lige så tilgængelig ved testtid, så modellen generaliserer smukt til en verden, der ikke findes.

  2. Træn én model per feature, alene. Alt, der bærer svaret, vil afsløre sig selv:

    feature alenenøjagtighedrecallF1AUC
    bredde0.98150.0140.0260.8691
    vægt0.98150.0000.0000.7914
    station_seconds0.98500.4050.5000.9960

    Én kolonne rangerer på egen hånd defekter ved AUC 0,9960. To målinger taget med en skydelære og en vægt klarer 0,87 og 0,79. Den asymmetri er alarmen.

  3. Spørg, hvornår hvert tal blev skrevet ned. Gennemsnitlig opholdstid: 2,23 sekunder for dele, der bestod, 15,56 sekunder for dele, der fejlede. Selvfølgelig. En del opholder sig ved stationen, fordi en inspektør trak den af båndet — hvilket sker efter, og kun fordi, nogen besluttede, at den var defekt. Kolonnen er ikke en måling af delen. Den er en måling af dommen.

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

Den markerede linje er lækken: En defekt dels opholdstid trækkes fra en anden fordeling, fordi et menneske tog den af båndet. Dette er den mest almindelige alvorlige bug i anvendt machine learning, og den har et navn: target leakage — information i træningsfeatures, som ikke ville være tilgængelig i det øjeblik, forudsigelsen skal foretages.5 Den kaster ingen exception. Den producerer et bedre tal. Ethvert incitament i et projekt peger mod at beholde den.

Forsvaret er ét spørgsmål, stillet til hver kolonne: I det øjeblik jeg har brug for denne forudsigelse, findes denne værdi så allerede? På et live bånd er station_seconds ukendt, indtil efter delen er blevet inspiceret — hvilket er det, modellen skulle erstatte.

Hvor mange testeksempler har jeg brug for?

Link til afsnittet: Hvor mange testeksempler har jeg brug for?

Antag, at du scorer en model på 20 eksempler, og den får 17 rigtige. Du rapporterer 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

Den ærlige læsning af 17/20 er et sted mellem 64 % og 95 %. En ægte 65 %-model producerer dette resultat 4,4 % af tiden — én kørsel ud af treogtyve — og hvis du prøvede en håndfuld prompts og rapporterede den bedste, fremstillede du selv den kørsel. Sytten ud af tyve kan ikke skelne en 85 %-model fra en 65 %-model.

To måder at sætte et interval på en rate, og begge hører hjemme i din værktøjskasse:

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)

Brug Wilson6 til en almindelig succesrate; den opfører sig pænt ved enhver nn og kræver ingen tilfældighed. Bemærk ovenfor, at ved n=20n = 20 er bootstrappens øvre ende 1,0000 — resampling af 20 punkter kan let trække 20 korrekte, så den kan ikke repræsentere et interval smallere end sin egen granularitet. Brug bootstrap7, hvor der ikke findes nogen formel, hvilket er de fleste interessante tilfælde: F1, makrogennemsnit, BLEU, pass@1, scoren fra en rubrikbaseret dommer. På dette bånd har den tunede models F1 på 0,4122 et bootstrap-interval på [0.3009, 0.5156] — hvilket er det tal, der bør stå i rapporten, fordi punktestimatet alene inviterer til en sammenligning, det ikke kan understøtte.

Én måling mere, fordi den ændrer, hvordan du bør sammenligne to modeller. To modeller scoret på de samme 500 eksempler:

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)

Deres intervaller overlapper, og folkereglen — overlappende fejlstolper betyder ingen signifikant forskel — ville kalde sammenligningen uafklaret. Det er den ikke. De to modeller kørte på de samme eksempler, så den rigtige størrelse er forskellen per eksempel, hvis interval er [0.0260, 0.0680], komfortabelt over nul. De er kun uenige om 31 af 500 items, og A vinder 27 af de uenigheder; de fælles eksempler, lette og svære, går ud i stedet for at tilføje støj. Sammenlign modeller parret, og du når samme konklusion fra en brøkdel af dataene.

Du har nu en model, der outputter kalibrerede sandsynligheder, et tab afledt af en påstand om dataene i stedet for valgt af bekvemmelighed, en gradient, der bogstaveligt er forudsigelse minus sandhed, og — endnu vigtigere — maskineriet til at finde ud af, om noget af det virker. Wilson-intervallet på ti linjer ovenfor genbruges ordret: det bærer prompt-varianterne i Kapitel 15, retrieval-tabellerne i Kapitel 19 og golden set i Kapitel 29. Bootstrap er det, du griber efter, når der ikke findes nogen formel.

Men modellen er stadig ét lag. Den tegner en linje, og Kapitel 1 beviste med fire rækker XOR, at en linje ikke er nok. Løsningen er at stable: et første lag, der bøjer rummet, et andet, der tegner linjen i det bøjede rum.

Det er dér, den ryddelige gradient fra dette kapitel slipper op. Alt ovenfor virkede, fordi L/s=py\partial L/\partial s = p - y kunne skrives ned i hånden, én gang, for en model med ét lag mellem inputtet og tabet. Sæt et andet lag ind i midten, og spørgsmålet ændrer form: Hvad er den afledte af tabet med hensyn til en vægt, der slet ikke rører outputtet — en hvis indflydelse kun ankommer gennem et andet lag, muligvis ad flere veje på én gang?

Den afledte findes. At beregne den i hånden er håbløst for alt større end et legetøj, og at beregne den én parameter ad gangen er håbløst i en anden skala. Det, der behøves, er en procedure, der får hver afledt i netværket fra én enkelt baglæns passage over den samme graf, som den fremadrettede passage lige gik igennem.

Det er Kapitel 5, og det er motoren, resten af dette kursus kører på.


Også værd at læse sammen med dette kapitel: Bishop, Pattern Recognition and Machine Learning §1.2, §1.5, §1.6 og §4.3, som dækker sandsynlighed, beslutningsteori, informationsteori og lineær klassifikation i den rækkefølge, dette kapitel følger; Murphy, Probabilistic Machine Learning: An Introduction, kapitlerne 6 og 10; Prince, Understanding Deep Learning §5.4–5.7; og Saito og Rehmsmeier, The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets (PLOS ONE, 2015) — hvorfor AUC'en citeret ovenfor ikke bør være det eneste tærskelfrie tal, du ser på, når 1,7 % af delene er defekte.

  1. Ma, T. og Ng, A. CS229 Lecture Notes, Stanford University, kapitlerne 2 og 3. Hvor reduktionen, der producerer pyp - y, holder op med at ligne held: vælg den eksponentielle-familie-fordeling, der matcher dit output, brug dens kanoniske link, og gradienten er altid forudsigelse minus sandhed.

  2. Olah, C. Visual Information Theory (2015), colah.github.io/posts/2015-09-Visual-Information. Den klareste tilgængelige forklaring af entropi, krydsentropi og KL-divergens som omkostninger i bits snarere end som formler.

  3. Abu-Mostafa, Y. S., Magdon-Ismail, M. og Lin, H.-T. Learning From Data (AMLBook, 2012), forelæsning 13 og 17 i Caltech-kurset. Forelæsning 13 er validering; forelæsning 17, om de tre læringsprincipper, er dér, hvor data snooping får navn. Tilsammen er de kilden til disciplinen i dette kapitel: Hvert blik på et datasæt er en fitting-beslutning, uanset om du kørte en optimiser eller ej.

  4. James, G., Witten, D., Hastie, T. og Tibshirani, R. An Introduction to Statistical Learning, 2. udgave (Springer, 2021), kapitlerne 2 og 5, for bias–variance-dekompositionen og for resampling. Følgevolumenet er dér, hvor selektionsfælden siges direkte: Hastie, Tibshirani og Friedman, The Elements of Statistical Learning, 2. udgave, §7.10.2, The Wrong and Right Way to Do Cross-validation.

  5. Kaufman, S., Rosset, S., Perlich, C. og Stitelman, O. Leakage in Data Mining: Formulation, Detection, and Avoidance. ACM Transactions on Knowledge Discovery from Data 6(4), 2012. En formel behandling af fejlen demonstreret ovenfor, med casestudier fra konkurrencer vundet af en model, der havde lært en artefakt af, hvordan dataene blev samlet.

  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). Scoreintervallet brugt i wilson() ovenfor, stadig det rigtige standardvalg for en proportion. Lærebogsintervallet p^±zp^(1p^)/n\hat{p} \pm z\sqrt{\hat{p}(1-\hat{p})/n} er det, du skal undgå: det giver nonsens tæt på 0 og 1 og underdækker voldsomt ved små nn.

  7. Efron, B. Bootstrap Methods: Another Look at the Jackknife. The Annals of Statistics 7(1), s. 1–26 (1979). Ideen, der lader dig sætte et interval på enhver statistik, du kan beregne, inklusive dem uden samplingteori.


Skabt af

David Vicente Campos

Grundlægger af NeuraLIA Labs og medstifter af MyRealFood

Jeg er dataingeniør fra Universitetet i León. Jeg var med til at stifte MyRealFood, hvor jeg som CTO byggede den app, som millioner af mennesker har brugt til at spise bedre, og jeg grundlagde NeuraLIA Labs, hvor jeg bygger AI-produkter. Her skriver jeg om det, jeg har måttet forstå undervejs, sådan som jeg ville ønske, nogen havde forklaret det for mig.

Mere om forfatteren

Udgivet af NeuraLIA Labs.

Få nye indlæg i din indbakke

AI-nyheder, guides og produktopdateringer — en kort mail, når vi udgiver noget, der er værd at bruge tid på.

Vil du hellere have beskeder? De samme indlæg, her:WhatsApp-fællesskab (åbnes i en ny fane)Telegram-kanal (åbnes i en ny fane)

Kursusindeks

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev11 min læsning

Jev AI-modellen er bygget til beslutninger, ikke prosa

TypeSafe AI’s Jev får opmærksomhed, fordi den behandler softwareintelligens som et sandsynlighedsproblem: vælg den rigtige gren, tilføj tillid, og undgå at betale en LLM for at skrive tekst, når kode har brug for en beslutning.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering11 min læsning

Kontekstteknik til langsigtede AI-agenter

Langvarige agenter fejler ikke kun, fordi vinduet er lille. De fejler, når filer, tool-outputs og forældet historik fortrænger den opgave, agenten skulle færdiggøre.

Klar til at lade LIA vælge for dig?

Byg med alle AI-modeller ét sted — kom gratis i gang i dag.