Klassificering, cross-entropy och hur du inte lurar dig själv
Bygg en logistisk klassificerare med förlusten från kapitel 2 och descent från kapitel 3 – och se varför 98 % accuracy kan hitta ingenting.
På den här sidan
En modell som svarar den här delen är okej om varje del som kommer från bandet har rätt 98,15 % av gångerna. Den är också värdelös: av de 74 defekta delarna i testuppsättningen fångar den inte en enda.
Båda meningarna beskriver samma modell. Avståndet mellan dem är det här kapitlet.
Den första halvan bygger klassificeraren. Den behöver nästan inget nytt: kapitel 2 gav receptet för att göra ett antagande om hur data produceras till en förlustfunktion, och kapitel 3 gav maskineriet för att gå nedför på vilken förlust receptet än ger dig. Tillämpa båda på en ja/nej-fråga och logistisk regression faller ut, plus en ny idé — en logit — som kommer att debiteras igen i kapitel 17.
Den andra halvan är den svårare. Allt efter den här punkten i kursen bedöms av ett tal som någon har mätt, och om du inte kan skilja en verklig förbättring från en mätartefakt är varje följande kapitel dekoration. Alltså: förväxlingsmatrisen, precision och recall, de tre uppdelningarna, läckage och frågan nästan ingen svarar ärligt på — hur många testexempel behöver jag egentligen?
Aritmetiken här kör över 20 000 rader, så den är vektoriserad rakt igenom — NumPy har gjort jobbet sedan kapitel 2, och härifrån slutar det vara värt att påpeka.
Bandet, med en mer sällsynt fråga
Länk till avsnittet: Bandet, med en mer sällsynt frågaSamma fabrik som i kapitel 1, svårare fråga. I stället för acceptera eller kassera är frågan är den här delen defekt — och defekter är sällsynta, vilket gör mäthalvan av det här kapitlet svår och modelleringshalvan bedrägligt enkel.
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:]N = 20000 defects = 337 base rate = 0.0169
defects per split = 203 60 74Tre uppdelningar, inte två. Skälet förtjänar ett eget avsnitt och får ett nedan; tills vidare, träna på den första, justera på den andra och titta inte på den tredje.
Features standardiseras — medelvärdet subtraheras, dividerat med standardavvikelsen — med endast träningsstatistiken, av det skäl kapitel 1 demonstrerade med perceptronens konvergensgräns: ocentrerad data gör geometrin fientlig. Vilka rader du får beräkna medelvärdet från blir en levande fråga senare i kapitlet.
Från ett utslag till en sannolikhet
Länk till avsnittet: Från ett utslag till en sannolikhetPerceptronen returnerade ett tecken. Ett tecken kan inte skilja kassera från kassera, men precis bara, och just den skillnaden är exakt vad en fabrik behöver för att avgöra vilka delar en människa ska inspektera om först.
Följ därför receptet från kapitel 2 bokstavligt. Skriv ned vad du påstår om hur en label produceras, ta likelihood, ta loggen, negera den, och du har en förlust. För ett ja/nej-utfall är påståendet en Bernoulli-fördelning: det finns en sannolikhet att delen är defekt, och
vilket bara är ett kompakt sätt att skriva ” om , och om ”. Ta loggen av det och negera den, så blir förlusten för ett exempel
Det här är binär cross-entropy. Den valdes inte för att den är bekväm; den är den negativa log-likelihood för den enda fördelning ett myntkast kan ha. Något annat fanns inte.
Det som fortfarande saknas är var kommer ifrån. Modellen beräknar en viktad summa , vilket är ett reellt tal och sträcker sig över hela tallinjen, medan en sannolikhet måste ligga i . Funktionen som flyttar mellan dem är den logistiska sigmoiden:
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.9820Läs kolumnen till höger som en prislista. Att ha rätt med 90 % säkerhet kostar 0,105. Att vägra bestämma sig kostar 0,693 — vilket är , priset för en axelryckning. Att ha säkert fel kostar 4,6, fyrtiofyra gånger mer, och priset stiger utan gräns när modellen blir mer säker på ett misstag. Cross-entropy räknar inte bara fel: den tar betalt för arrogans.
Gradient är förutsägelse minus sanning
Länk till avsnittet: Gradient är förutsägelse minus sanningKapitel 3 sa: för att träna vad som helst, ta derivatan av förlusten med avseende på varje parameter. Gör det för ett exempel. Med och :
Visa detaljer
De två raderna som får röran att ta ut sig. Sigmoiden har en ovanligt trevlig derivata, . Och förlusten deriveras till
Multiplicera de två med kedjeregeln och dyker upp en gång i täljaren och en gång i nämnaren. Den tar ut sig exakt, och är det som blir kvar. Den elimineringen är ingen slump — det är vad som händer när förlusten är den negativa log-likelihood för en fördelning och output-funktionen är den som fördelningen naturligt använder. Den parningen har ett namn — en generaliserad linjär modell — och den prydliga gradient är dess fingeravtryck.1
Så uppdateringen är förutsägelse minus sanning, gånger input. Inget annat. Här är hela tränaren, vilket är kapitel 3:s descent med en rad ändrad:
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, bnp.where i sigmoid är inte kosmetik. Att beräkna direkt flödar över för stora negativa ; grenen väljer den algebraiskt identiska form som håller exponenten negativ. Det här är kapitel 2:s flyttalslåda som kräver in sin första skuld, och den kommer att kräva in en större två avsnitt härifrån.
Varför inte kvadratfel, och varför svaret handlar om gradient
Länk till avsnittet: Varför inte kvadratfel, och varför svaret handlar om gradientStandardförklaringen till att föredra cross-entropy framför kvadratfel är likelihood-argumentet ovan: kvadratfel är vad du får om du antar Gaussiskt brus, labels är inte Gaussiska, alltså ska du inte göra det. Det är korrekt och övertygar ingen, eftersom du kan skriva över en sigmoid och den kommer att tränas.
Argumentet som landar handlar om gradient. Lägg kvadratfel ovanpå en sigmoid så ger kedjeregeln
Den extra är den som tog ut sig tidigare. Nu gör den inte det, och den går mot noll när modellen är säker — även när modellen har säkert fel. Utvärdera båda vid några poäng, för ett exempel vars sanna label är 1:
| score | cross-entropy | kvadratfel | kvot | |
|---|---|---|---|---|
| 0,000335 | 1 491 | |||
| 0,017986 | 28,3 | |||
| 0,119203 | 4,8 | |||
| 0,500000 | 2,0 | |||
| 0,880797 | 4,8 |
Vid har modellen så fel som det går att ha, och kvadratfel svarar med en gradient som är 1 491 gånger mindre än cross-entropy:s. Ju värre misstaget är, desto mindre lär sig modellen av det. Cross-entropy:s gradient mättas däremot vid : maximalt fel ger en maximalt stor signal, och inte större.
Kör loppet. Två tusen balanserade punkter, identiska startvikter valda för att ha säkert fel (), identisk inlärningstakt, bara förlusten skiljer sig. Båda körningarna poängsätts med cross-entropy så att kolumnerna är jämförbara.
| epok | cross-entropy-förlust | accuracy | kvadratfelsförlust | accuracy |
|---|---|---|---|---|
| 1 | 5,4865 | 0,2300 | 5,9499 | 0,2290 |
| 10 | 1,5525 | 0,2460 | 5,9042 | 0,2290 |
| 50 | 0,4642 | 0,7780 | 5,6913 | 0,2320 |
| 100 | 0,4639 | 0,7770 | 5,3955 | 0,2410 |
| 200 | 0,4639 | 0,7770 | 4,6311 | 0,2745 |
| 500 | 0,4639 | 0,7770 | 0,5291 | 0,7660 |
| 1 000 | 0,4639 | 0,7770 | 0,4640 | 0,7765 |
Cross-entropy är klar vid epok 50. Kvadratfel ligger fortfarande på 24 % accuracy vid epok 100 — och hade inte rört sig från 23 % vid epok 10 — värre än att gissa, eftersom den började med säkert fel och den gradient som skulle rädda den har multiplicerats med 0,0007. Den kommer loss runt epok 500 och landar på samma plats. Så den ärliga sammanfattningen är att kvadratfel över en sigmoid inte är felaktigt; det är långsamt exakt där hastighet är viktigast. På en modell med två parametrar förlorar du 450 epoker. På ett nätverk med hundra lager, där någon enhet någonstans alltid har säkert fel, förlorar du träningskörningen.
Entropi, cross-entropy och KL, på en sida
Länk till avsnittet: Entropi, cross-entropy och KL, på en sidaTre storheter, som behövs ordentligt i kapitel 8 för perplexity och i kapitel 11 för straffet som håller en fine-tuned policy nära sin referens. De är enklare än sitt rykte.2
Entropi är det genomsnittliga antalet bitar du måste lägga på att kommunicera ett drag ur en fördelning, om du använder bästa möjliga kod för den:
Cross-entropy är vad du betalar när du använder en kod byggd för på data som egentligen kommer från :
KL-divergens är överskottet — slöseriet, i bitar, som orsakas av att tro när sanningen är :
Kontrollera alla tre på bandet:
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 bitsTvå saker syns där. För det första uppnår en modell som helt enkelt rapporterar träningsbasfrekvensen, 1,69 %, en cross-entropy på 0,1330 bitar, nästan exakt entropin för test-labels — vilket den måste, eftersom den har rätt fördelning och ingen annan information. Entropi är golvet som okunskap om individen köper dig. För det andra betalar en modell som rycker på axlarna och säger 0,5 exakt 1 bit, och gapet mellan de två, 0,8671 bitar, är precis KL-divergensen. är inte en identitet att memorera; det är en faktura du kan se läggas ihop.
Och kopplingen tillbaka till träning: när label är en enda känd klass är den ”sanna” fördelningen one-hot, dess entropi är noll, och cross-entropy är lika med KL-divergensen. Att minimera cross-entropy och dra modellens fördelning mot sanningen är samma handling.
Mer än två svar: softmax och skiftet som inte kostar något
Länk till avsnittet: Mer än två svar: softmax och skiftet som inte kostar någotDefekt är inte en sak. Vid formning kan en del komma ut som en short shot (för lite material), flash (för mycket, utpressat ur formen) eller burn. Fyra utfall, alltså fyra logits, och de måste bli fyra sannolikheter som summerar till ett. Det är softmax:
Den har en egenskap som ser ut som en olyckshändelse men i själva verket är hela implementationen:
för valfri konstant , eftersom och tar ut varandra upptill och nedtill. Bara skillnader mellan logits betyder något. Den absoluta nivån är inte information.
Lyckligtvis, för den absoluta nivån är det som får datorn att gå sönder:
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 flödar över en 64-bitars float, summan blir oändlighet, och oändlighet delat med oändlighet är nan — inte ett fel, ingen krasch, bara ett tyst hål där tre sannolikheter brukade finnas. Att subtrahera den största logit ändrar inget matematiskt och allt numeriskt, eftersom den största exponenten blir exakt . Det här är kapitel 2:s logsumexp-trick i arbetskläder, och varje seriös implementation gör det:
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, bGradient är återigen förutsägelse minus sanning, nu med one-hot. Det binära fallet var ett specialfall hela tiden.
Tränad på 3 000 delar och testad på 1 000, med tre mätningar var (bredd, vikt, smälttemperatur), når den 94,00 % accuracy. Här är vad det talet döljer:
| sanning ↓ / predikterat → | ok | short shot | flash | burn | recall |
|---|---|---|---|---|---|
| ok | 850 | 5 | 9 | 0 | 0,984 |
| short shot | 22 | 21 | 0 | 0 | 0,488 |
| flash | 20 | 0 | 30 | 1 | 0,588 |
| burn | 3 | 0 | 0 | 39 | 0,929 |
| precision | 0,950 | 0,808 | 0,769 | 0,975 |
Modellen hittar färre än hälften av short shots. Accuracy kan inte se det, eftersom 86 % av delarna är felfria och att få dem rätt räcker för att bära genomsnittet. Macro F1 — medelvärdet av F1-poängen per klass, som viktar en sällsynt klass lika mycket som en vanlig — är 0,7983, jämfört med micro F1 på 0,9400 som per definition är identisk med accuracy. När någon rapporterar ett enda F1-tal, fråga vilket.
Det var det sista av modelleringen. Resten av kapitlet handlar om talen.
Tre modeller, en accuracy
Länk till avsnittet: Tre modeller, en accuracyTa den tränade binära modellen och gör två varianter genom att multiplicera varje logit med en konstant: 0,35 för en tveksam version, 4 för en översäker. Att multiplicera med ett positivt tal kan inte ändra något tecken, så alla tre modeller predikterar exakt samma label för alla 4 000 testdelar. Accuracy kan inte skilja dem åt. Cross-entropy har inga problem alls:
| modell | accuracy | cross-entropy | genomsnittlig förlust när rätt | genomsnittlig förlust när fel | värsta enskilda förlust |
|---|---|---|---|---|---|
| tveksam (logits × 0,35) | 0,9830 | 0,1549 | 0,1369 | 1,1990 | 2,80 |
| som tränad | 0,9830 | 0,0564 | 0,0147 | 2,4689 | 7,82 |
| översäker (logits × 4) | 0,9830 | 0,1563 | 0,0009 | 9,1427 | 27,63 |
Den tveksamma modellen betalar en liten skatt på varje del, även de tusentals den får rätt. Den översäkra är nästan gratis när den har rätt och katastrofal när den har fel — en enda del i den testuppsättningen kostar den 27,63 nats på egen hand. De två landar på nästan samma total via motsatta vägar, och den tränade modellen, vars sannolikheter är kalibrerade mot datan, ligger tre gånger lägre än båda.
Det här är det skarpaste sättet att formulera skillnaden mellan en förlust och ett mått. Förlusten är det du optimerar: den måste vara deriverbar, och den ser allt modellen sade, inklusive hur säker den var. Måttet är det du bedöms på: det kan vara en stegfunktion, en affärsregel, en räkning av missade defekter. De är inte samma objekt och de är inte alltid överens — därför definierar du båda innan du börjar, och låter aldrig förlusten stå in för måttet bara för att den råkar visas på skärmen.
Den dumma baslinjen går först
Länk till avsnittet: Den dumma baslinjen går förstFöre någon modell, kravet: vad får det lataste möjliga svaret för poäng? På det här bandet, säg alltid felfri:
always-say-fine baseline: accuracy = 0.9815
confusion (tn, fp, fn, tp) = (3926, 0, 74, 0)98,15 %. Nu den tränade logistiska modellen, vid standardtröskeln 0,5:
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 baslinjen med 0,15 procentenheter, och varje rapport som stannar vid accuracy kommer att kalla det en vinst. Förväxlingsmatrisen säger vad som faktiskt hände:
| predikterat felfri | predikterat defekt | |
|---|---|---|
| faktiskt felfri | 3 924 | 2 |
| faktiskt defekt | 66 | 8 |
Den hittade 8 defekta delar av 74 och släppte igenom 66. Tre tal namnger de tre sätten att läsa tabellen:
- Precision . Av delarna den flaggade, hur många var verkligen defekta. Det här är kostnaden för bortslösade inspektioner.
- Recall . Av de defekta delarna, hur många fångade den. Det här är kostnaden för att skicka en dålig del till en kund.
- F1 , deras harmoniska medelvärde, som håller sig nära det mindre av de två och därför vägrar smickras av bara det ena.
Vilket som spelar roll beror på fabriken, inte på matematiken: en inspektion kostar några sekunder och en skickad defekt kostar en återkallelse, så här dominerar recall och 0,108 är ett misslyckande.
Men modellen är inte problemet. Tröskeln är det, och tröskeln är inte en del av modellen — den är ett affärsbeslut som appliceras efteråt på en sannolikhet. Svep den:
| tröskel | TP | FP | FN | accuracy | precision | recall | F1 |
|---|---|---|---|---|---|---|---|
| 0,500 | 8 | 2 | 66 | 0,9830 | 0,800 | 0,108 | 0,190 |
| 0,200 | 27 | 28 | 47 | 0,9812 | 0,491 | 0,365 | 0,419 |
| 0,100 | 42 | 118 | 32 | 0,9625 | 0,263 | 0,568 | 0,359 |
| 0,050 | 54 | 236 | 20 | 0,9360 | 0,186 | 0,730 | 0,297 |
| 0,020 | 67 | 570 | 7 | 0,8558 | 0,105 | 0,905 | 0,188 |
| 0,005 | 71 | 1 360 | 3 | 0,6593 | 0,050 | 0,959 | 0,094 |
Läs accuracy-kolumnen nedåt. Den faller hela vägen — från 98,30 % till 65,93 % — medan modellen går från att fånga 8 defekter till att fånga 71 av 74. Varje användbar sak den här modellen kan göra gör dess accuracy sämre. Ett team som optimerar rubriktalet skulle leverera versionen som inte hittar något.
Visa detaljer
Class weighting skapar inte signal, det flyttar driftspunkten. Den vanliga första reflexen med obalanserade klasser är att vikta den sällsynta klassen i förlusten. Gör man det, med vikter på 1, 10 och 60 på positiva:
| vikt på positiva | accuracy | precision | recall | F1 | AUC |
|---|---|---|---|---|---|
| 1 | 0,9830 | 0,800 | 0,108 | 0,190 | 0,9363 |
| 10 | 0,9605 | 0,253 | 0,581 | 0,352 | 0,9361 |
| 60 | 0,8290 | 0,091 | 0,919 | 0,166 | 0,9361 |
Precision och recall rör sig långt. AUC — sannolikheten att modellen rankar en slumpmässig defekt del över en slumpmässig bra del, vilket ignorerar tröskeln helt — rör sig med 0,0002, vilket är ingenting. Omviktning sköt samma modell längs samma trade-off-kurva. Det är ofta vad du vill, och det är aldrig ny information: om rankningen är dålig kommer inget viktningsschema att rädda den.
Tre uppdelningar och läckan du håller på att hitta
Länk till avsnittet: Tre uppdelningar och läckan du håller på att hittaVarför tre uppdelningar och inte två? För att i samma ögonblick som du använder en uppsättning exempel för att välja något — en tröskel, en inlärningstakt, vilken av sex modeller som ska levereras — har den uppsättningen använts för anpassning, och dess poäng slutar vara unbiased.3 Mätt på det här bandet: att svepa tröskeln på valideringsuppsättningen väljer 0,196, och modellen får sedan F1 = 0,4122 på den orörda testuppsättningen. Om svepet hade körts direkt på testuppsättningen var det bästa möjliga där 0,4186 — ett tal ingen har rätt att rapportera.
Gapet är litet här, 0,006, eftersom det är en hyperparameter som svepts en gång mot 4 000 valideringsexempel. Det växer med varje extra beslut och varje krympning av valideringsuppsättningen. Notera också att riktningen inte är garanterad i en enskild körning: den valda tröskeln fick 0,3902 på validering och 0,4122 på test, så validering underskattade den den här gången. Biasen är systematisk över många beslut, inte synlig i ett enda.4
Nu övningen. Bandloggen kommer med en tredje kolumn, station_seconds: hur länge varje del var vid inspektionsstationen. Att lägga till den är en rad i preprocessingen. Här är vad den gör:
| modell | accuracy | precision | recall | F1 | cross-entropy | AUC |
|---|---|---|---|---|---|---|
| bredd + vikt | 0,9830 | 0,800 | 0,108 | 0,190 | 0,0564 | 0,9363 |
| + station_seconds | 0,9920 | 0,792 | 0,770 | 0,781 | 0,0236 | 0,9970 |
Recall går från 10,8 % till 77,0 %. F1 mer än fyrdubblas. Och lägg märke till vad accuracy gjorde: 98,30 % → 99,20 %, en vinst på nio tiondelar av en punkt, vilket är den typ av tal som avrundas till ”cirka 99 % oavsett” på en sammanfattningsslide. Accuracy misslyckades med att se misslyckandet tidigare och misslyckas nu med att se fusket.
Innan du läser vidare: modellen fuskar. Ta reda på hur.
Hur du jagar en läcka, i den ordning som hittar den snabbast.
-
Jämför train och test. Overfitting syns som ett stort gap. Här: ärlig modell 0,9838 train / 0,9830 test; läckande modell 0,9936 train / 0,9920 test. Båda gapen är under 0,2 punkter. En läcka ser inte ut som overfitting — den läckande featuren är lika tillgänglig vid testtid, så modellen generaliserar vackert till en värld som inte finns.
-
Träna en modell per feature, ensam. Allt som bär svaret kommer att avslöja sig:
feature ensam accuracy recall F1 AUC bredd 0,9815 0,014 0,026 0,8691 vikt 0,9815 0,000 0,000 0,7914 station_seconds0,9850 0,405 0,500 0,9960 En kolumn, på egen hand, rankar defekter med AUC 0,9960. Två mätningar tagna med ett skjutmått och en våg klarar 0,87 och 0,79. Den asymmetrin är larmet.
-
Fråga när varje tal skrevs ned. Genomsnittlig uppehållstid: 2,23 sekunder för delar som godkändes, 15,56 sekunder för delar som underkändes. Självklart. En del stannar vid stationen för att en inspektör drog den av bandet — vilket sker efter, och bara för att, någon bestämde att den var defekt. Kolumnen är inte en mätning av delen. Den är en mätning av utslaget.
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 markerade raden är läckan: en defekt dels uppehållstid dras från en annan fördelning, eftersom en människa tog den av bandet. Det här är den vanligaste allvarliga buggen i tillämpad maskininlärning, och den har ett namn: target leakage — information i tränings-features som inte skulle vara tillgänglig i det ögonblick prediktionen måste göras.5 Den kastar inget undantag. Den producerar ett bättre tal. Varje incitament i ett projekt pekar mot att behålla den.
Försvaret är en fråga, ställd till varje kolumn: vid ögonblicket då jag behöver den här prediktionen, finns det här värdet ännu? På ett liveband är station_seconds okänd tills efter att delen har inspekterats — vilket är det modellen skulle ersätta.
Hur många testexempel behöver jag?
Länk till avsnittet: Hur många testexempel behöver jag?Anta att du poängsätter en modell på 20 exempel och den får 17 rätt. Du rapporterar 85 %.
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.6477Den ärliga läsningen av 17/20 är någonstans mellan 64 % och 95 %. En genuin 65 %-modell producerar det här resultatet 4,4 % av gångerna — en körning av tjugotre — och om du provade en handfull prompts och rapporterade den bästa tillverkade du den körningen själv. Sjutton av tjugo kan inte skilja en 85 %-modell från en 65 %-modell.
Två sätt att sätta ett intervall på en frekvens, och båda hör hemma i din verktygslåda:
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)Använd Wilson6 för en vanlig framgångsfrekvens; den beter sig väl vid varje och behöver ingen slump. Notera ovan att vid är bootstrapens övre ände 1,0000 — att resampla 20 punkter kan lätt dra 20 korrekta, så den kan inte representera ett intervall smalare än sin egen granularitet. Använd bootstrap7 där ingen formel finns, vilket är de flesta intressanta fall: F1, macro-medelvärden, BLEU, pass@1, poängen från en rubric-baserad domare. På det här bandet har den justerade modellens F1 på 0,4122 ett bootstrap-intervall på [0,3009, 0,5156] — vilket är talet som bör stå i rapporten, eftersom punktskattningen ensam inbjuder till en jämförelse den inte kan stödja.
En mätning till, eftersom den ändrar hur du bör jämföra två modeller. Två modeller poängsatta på samma 500 exempel:
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)Deras intervall överlappar, och folkregeln — överlappande felstaplar betyder ingen signifikant skillnad — skulle kalla jämförelsen ofullständig. Det är den inte. De två modellerna kördes på samma exempel, så den rätta storheten är skillnaden per exempel, vars intervall är [0.0260, 0.0680], bekvämt över noll. De är oense om bara 31 av 500 objekt, och A vinner 27 av de oenigheterna; de gemensamma exemplen, lätta och svåra, tar ut varandra i stället för att lägga till brus. Jämför modeller parat, så når du samma slutsats med en bråkdel av datan.
Vart det går härnäst
Länk till avsnittet: Vart det går härnästDu har nu en modell som matar ut kalibrerade sannolikheter, en förlust härledd från ett påstående om datan i stället för vald för bekvämlighet, en gradient som bokstavligen är förutsägelse minus sanning, och — viktigare — maskineriet för att ta reda på om något av det fungerar. Wilson-intervallet på tio rader ovan återanvänds ordagrant: det bär prompt-varianterna i kapitel 15, retrieval-tabellerna i kapitel 19 och golden set i kapitel 29. Bootstrap är det du tar till när ingen formel finns.
Men modellen är fortfarande ett lager. Den drar en linje, och kapitel 1 bevisade med fyra rader XOR att en linje inte räcker. Lösningen är att stapla: ett första lager som böjer rummet, ett andra som drar linjen i det böjda rummet.
Det är där den prydliga gradient från det här kapitlet tar slut. Allt ovan fungerade eftersom kunde skrivas ned för hand, en gång, för en modell med ett lager mellan input och förlusten. Sätt ett andra lager i mitten och frågan byter form: vad är derivatan av förlusten med avseende på en vikt som inte rör output alls — en vars påverkan bara anländer genom ett annat lager, kanske längs flera vägar samtidigt?
Den derivatan finns. Att beräkna den för hand är hopplöst för allt större än en leksak, och att beräkna den en parameter i taget är hopplöst i en annan skala. Det som behövs är en procedur som får fram varje derivata i nätverket från en enda backward pass över samma graf som forward pass just gick igenom.
Det är kapitel 5, och det är motorn som resten av den här kursen kör på.
Källor och metod
Länk till avsnittet: Källor och metodOckså värt att läsa jämte det här kapitlet: Bishop, Pattern Recognition and Machine Learning §1.2, §1.5, §1.6 och §4.3, som täcker sannolikhet, beslutsteori, informationsteori och linjär klassificering i den ordning kapitlet följer; Murphy, Probabilistic Machine Learning: An Introduction, kapitel 6 och 10; Prince, Understanding Deep Learning §5.4–5.7; och Saito och Rehmsmeier, The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets (PLOS ONE, 2015) — varför AUC som citeras ovan inte bör vara det enda tröskelfria talet du tittar på när 1,7 % av delarna är defekta.
Referenser
Länk till avsnittet: Referenser-
Ma, T. och Ng, A. CS229 Lecture Notes, Stanford University, kapitel 2 och 3. Där elimineringen som producerar slutar se ut som tur: välj exponential-family-fördelningen som matchar din output, använd dess kanoniska link, och gradient är alltid förutsägelse minus sanning. ↩
-
Olah, C. Visual Information Theory (2015),
colah.github.io/posts/2015-09-Visual-Information. Den tydligaste tillgängliga förklaringen av entropi, cross-entropy och KL-divergens som kostnader i bitar snarare än som formler. ↩ -
Abu-Mostafa, Y. S., Magdon-Ismail, M. och Lin, H.-T. Learning From Data (AMLBook, 2012), föreläsning 13 och 17 i Caltech-kursen. Föreläsning 13 är validering; föreläsning 17, om de tre inlärningsprinciperna, är där data snooping namnges. Tillsammans är de källan till disciplinen i det här kapitlet: varje titt på en datauppsättning är ett anpassningsbeslut, oavsett om du körde en optimiser eller inte. ↩
-
James, G., Witten, D., Hastie, T. och Tibshirani, R. An Introduction to Statistical Learning, 2:a upplagan (Springer, 2021), kapitel 2 och 5, för bias–variance-dekompositionen och för resampling. Systervolymen är där urvalsfällan sägs rakt ut: Hastie, Tibshirani och Friedman, The Elements of Statistical Learning, 2:a upplagan, §7.10.2, The Wrong and Right Way to Do Cross-validation. ↩
-
Kaufman, S., Rosset, S., Perlich, C. och Stitelman, O. Leakage in Data Mining: Formulation, Detection, and Avoidance. ACM Transactions on Knowledge Discovery from Data 6(4), 2012. En formell behandling av felet som demonstrerades ovan, med fallstudier från tävlingar som vanns av en modell som hade lärt sig en artefakt av hur datan sattes samman. ↩
-
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-intervallet som används i
wilson()ovan, fortfarande rätt standardval för en proportion. Läroboksintervallet är det du ska undvika: det ger nonsens nära 0 och 1, och undertäcker grovt vid små . ↩ -
Efron, B. Bootstrap Methods: Another Look at the Jackknife. The Annals of Statistics 7(1), s. 1–26 (1979). Idén som låter dig sätta ett intervall på vilken statistik som helst som du kan beräkna, även de som saknar samplingteori. ↩