İçeriğe geç
4/3030 bölümden 4. bölüm

Sınıflandırma, çapraz entropi ve kendini kandırmamanın yolları

Bölüm 2’nin loss’u ve Bölüm 3’ün descent’ıyla lojistik classifier kur; %98 accuracy’nin nasıl hiçbir şey bulmayan model olabileceğini gör.

Bu sayfada

Banttan çıkan her parça için bu parça iyi diye yanıt veren bir model, zamanın %98.15’inde haklıdır. Aynı zamanda tamamen değersizdir: test setindeki 74 hatalı parçanın hiçbirini yakalayamaz.

İki cümle de aynı modeli anlatıyor. Aralarındaki mesafe bu bölüm.

İlk yarı classifier’ı kuruyor. Neredeyse hiçbir yeni şeye ihtiyaç yok: Bölüm 2, verinin nasıl üretildiğine dair bir varsayımı loss function’a dönüştürmenin tarifini vermişti; Bölüm 3 ise bu tarifin verdiği herhangi bir loss üzerinde yokuş aşağı yürümenin mekanizmasını. İkisini bir evet/hayır sorusuna uygula; logistic regression ortaya çıkar, ayrıca yeni bir fikir gelir — bir logit — ve bunun hesabı Bölüm 17’de tekrar sorulacak.

İkinci yarı daha zor olan kısım. Kursun bundan sonraki her şeyi, birilerinin ölçtüğü bir sayıyla değerlendirilecek; gerçek bir iyileşmeyi ölçüm artefact’ından ayıramıyorsan, sonraki her bölüm sadece süs olur. O yüzden: confusion matrix, precision ve recall, üç split, leakage ve neredeyse kimsenin dürüstçe yanıtlamadığı soru — aslında kaç test örneğine ihtiyacım var?

Buradaki aritmetik 20.000 satır üzerinde çalışıyor, bu yüzden baştan sona vectorised — NumPy işi Bölüm 2’den beri yapıyor ve buradan sonra bunu ayrıca belirtmeye değmez.

Bölüm 1’deki aynı fabrika, daha zor soru. Kabul mü ret mi yerine soru şu: bu parça hatalı mı — ve hatalar nadir, bu da bu bölümün ölçme yarısını zor, modelleme yarısını ise aldatıcı biçimde kolay yapıyor.

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

İki değil, üç split. Nedeni kendi bölümünü hak ediyor ve aşağıda alıyor; şimdilik ilkinde train et, ikincisinde tune et, üçüncüsüne bakma.

Feature’lar standardize ediliyor — ortalama çıkarılıyor, standart sapmaya bölünüyor — ve bunu yalnızca training istatistikleriyle yapıyoruz. Nedeni, Bölüm 1’in perceptron’ın convergence bound’u ile gösterdiği şey: merkezlenmemiş veri geometriyi düşmanca yapar. Bu ortalamayı hangi satırlardan hesaplamaya izinli olduğun ise bu bölümün ilerleyen kısmında canlı bir soruya dönüşecek.

Perceptron bir işaret döndürüyordu. Bir işaret, ret ile ret, ama kıl payı arasındaki farkı ayırt edemez; oysa fabrikanın bir insanın hangi parçaları önce yeniden incelemesi gerektiğine karar vermek için tam da bu farka ihtiyacı vardır.

O yüzden Bölüm 2’nin tarifini kelimesi kelimesine izle. Bir label’ın nasıl üretildiğine dair iddianı yaz, likelihood’u al, log’unu al, negatifini al ve bir loss elde et. Evet/hayır çıktısı için iddia bir Bernoulli dağılımıdır: parçanın hatalı olma olasılığı pp vardır ve

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

bu da “y=1y = 1 ise pp, y=0y = 0 ise 1p1-p” yazmanın kompakt yoludur. Bunun log’unu alıp negatifini aldığında, tek örnek için loss şudur:

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

Bu binary cross-entropy’dir. Kullanışlı olduğu için seçilmedi; bir yazı-tura sonucunun sahip olabileceği tek dağılımın negative log-likelihood’udur. Başka seçenek yoktu.

Hâlâ eksik olan şey, pp’nin nereden geldiği. Model ağırlıklı bir toplam s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b hesaplar; bu gerçek bir sayıdır ve tüm doğru üzerinde gezinir, oysa bir olasılığın (0,1)(0,1) içinde yaşaması gerekir. İkisi arasında hareket eden fonksiyon logistic sigmoid’dir:

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

Sağ sütunu bir fiyat listesi gibi oku. %90 confidence ile haklı olmak 0.105’e mal olur. Karar vermeyi reddetmek 0.693’e mal olur — bu log2\log 2, yani omuz silkme bedelidir. Kendinden emin biçimde yanılmak 4.6’ya, kırk dört kat fazlasına mal olur ve model bir hata konusunda daha emin oldukça fiyat sınırsız yükselir. Cross-entropy yalnızca hataları saymaz: kibre fatura keser.

Bölüm 3 şöyle demişti: herhangi bir şeyi train etmek için loss’un her parametreye göre türevini al. Bunu tek örnek için yap. s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b ve p=σ(s)p = \sigma(s) ile:

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
Ayrıntıları göster

Dağınıklığı sadeleştiren iki satır. Sigmoid’in alışılmadık derecede hoş bir türevi vardır, σ(s)=σ(s)(1σ(s))=p(1p)\sigma'(s) = \sigma(s)\,(1 - \sigma(s)) = p(1-p). Ve loss’un türevi şuna dönüşür:

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

Zincir kuralıyla ikisini çarpınca p(1p)p(1-p) bir kez üstte, bir kez altta belirir. Tam olarak sadeleşir ve geriye pyp - y kalır. Bu sadeleşme tesadüf değildir — loss bir dağılımın negative log-likelihood’u ve output function da o dağılımın doğal olarak kullandığı fonksiyon olduğunda her zaman olan şeydir. Bu eşleşmenin bir adı vardır — generalised linear model — ve düzenli gradient onun parmak izidir.1

Yani update şudur: tahmin eksi gerçek, input ile çarpılır. Başka hiçbir şey yok. İşte trainer’ın tamamı; Bölüm 3’ün descent’ı, yalnızca bir satırı değişmiş halde:

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

sigmoid içindeki np.where kozmetik değildir. 1/(1+es)1/(1+e^{-s})’yi doğrudan hesaplamak büyük negatif ss değerlerinde overflow yapar; branch, cebirsel olarak aynı formlardan üssü negatif tutanı seçer. Bu, Bölüm 2’nin floating-point kutusunun ilk borcunu tahsil etmesidir; iki bölüm sonra daha büyüğünü tahsil edecek.

Neden squared error değil, ve neden cevap gradient hakkında

Bölüme bağlantı: Neden squared error değil, ve neden cevap gradient hakkında

Cross-entropy’nin squared error’a tercih edilmesinin standart açıklaması yukarıdaki likelihood argümanıdır: squared error, Gaussian noise varsayımından çıkar; label’lar Gaussian değildir, o halde yapma. Doğrudur ama kimseyi ikna etmez, çünkü sigmoid’in üzerine L=(py)2L = (p - y)^2 yazabilirsin ve train olur.

İşe yarayan argüman gradient hakkındadır. Sigmoid’in üstüne squared error koyarsan zincir kuralı şunu verir:

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

O fazladan p(1p)p(1-p), az önce sadeleşen şeydir. Şimdi sadeleşmez ve model ne zaman kendinden emin olsa sıfıra gider — model kendinden emin biçimde yanlış olduğunda bile. Gerçek label’ı 1 olan bir örnek için ikisini birkaç score’da değerlendir:

score ssppcross-entropy L/s\partial L/\partial ssquared error L/s\partial L/\partial soran
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

s=8s = -8’de model olabileceği kadar yanlıştır ve squared error, cross-entropy’nin gradient’ından 1.491 kat daha küçük bir gradient ile yanıt verir. Hata ne kadar kötüyse, model ondan o kadar az öğrenir. Cross-entropy’nin gradient’ı ise 1-1’da doygunluğa ulaşır: maksimum yanlışlık maksimum büyüklükte bir sinyal üretir, daha fazlasını değil.

Yarışı çalıştır. İki bin dengeli nokta, kendinden emin biçimde yanlış olacak şekilde seçilmiş aynı başlangıç ağırlıkları (w=[6,6]\mathbf{w} = [-6, -6]), aynı learning rate, yalnızca loss farklı. Sütunlar karşılaştırılabilir olsun diye iki koşu da cross-entropy ile score’lanıyor.

epochcross-entropy lossaccuracysquared-error lossaccuracy
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

Cross-entropy epoch 50’de bitmiştir. Squared error epoch 100’de hâlâ %24 accuracy’dedir — epoch 10’da %23’ten hiç hareket etmemiştir — tahminden bile kötü, çünkü kendinden emin biçimde yanlış başlamış ve onu kurtaracak gradient 0.0007 ile çarpılmıştır. Yaklaşık epoch 500’de kaçar ve aynı yere iner. Yani dürüst özet şu: sigmoid üzerinde squared error yanlış değildir; hızın en önemli olduğu yerde tam olarak yavaştır. İki parametreli bir modelde 450 epoch kaybedersin. Yüz katmanlı bir ağda, bir yerlerde bir unit her zaman kendinden emin biçimde yanlışken, tüm training run’ı kaybedersin.

Üç nicelik; Bölüm 8’de perplexity için, Bölüm 11’de ise fine-tuned bir policy’yi referansına yakın tutan ceza için düzgün şekilde gerekecek. Ünlerinden daha kolaylar.2

Entropy, bir dağılımdan çekilen bir örneği iletmek için, onun için mümkün olan en iyi kodu kullanırsan harcaman gereken ortalama bit sayısıdır:

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

Cross-entropy, aslında pp’den gelen veri üzerinde qq için kurulmuş bir kod kullandığında harcadığın şeydir:

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

KL divergence, fazlalıktır — gerçek pp iken qq’e inanmanın bit cinsinden yarattığı israf:

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

Üçünü de bant üzerinde kontrol et:

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

Orada iki şey görünür. Birincisi, yalnızca training base rate’i, %1.69’u bildiren bir model, 0.1330 bit cross-entropy elde eder; bu, test label’larının entropy’siyle neredeyse aynıdır — olması gerektiği gibi, çünkü doğru dağılıma sahiptir ve başka bilgisi yoktur. Entropy, bireyden habersizliğin sana satın aldığı tabandır. İkincisi, omuz silkerek 0.5 diyen bir model tam 1 bit öder ve ikisi arasındaki fark, 0.8671 bit, tam olarak KL divergence’dır. H+DKL=H(p,q)H + D_{\mathrm{KL}} = H(p,q) ezberlenecek bir özdeşlik değildir; eklenişini izleyebileceğin bir faturadır.

Training’e geri bağlantı da şu: label tek bir bilinen sınıf olduğunda, “true” dağılım one-hot’tır, entropy’si sıfırdır ve cross-entropy KL divergence’a eşittir. Cross-entropy’yi minimize etmek ile modelin dağılımını gerçeğe doğru çekmek aynı eylemdir.

İkiden fazla cevap: softmax ve hiçbir maliyeti olmayan shift

Bölüme bağlantı: İkiden fazla cevap: softmax ve hiçbir maliyeti olmayan shift

Hatalı olmak tek bir şey değildir. Kalıplamada bir parça short shot (yetersiz malzeme), flash (fazla malzeme, kalıptan taşmış) veya burn olarak çıkabilir. Dört sonuç, dolayısıyla dört logits; bunların toplamı bir olan dört olasılığa dönüşmesi gerekir. Bu softmax’tır:

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

Kazara gibi görünen ama aslında tüm implementation olan bir özelliği vardır:

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

herhangi bir sabit cc için, çünkü ezi+c=ecezie^{z_i + c} = e^{c} e^{z_i} ve ece^c üstte ve altta sadeleşir. Yalnızca logits arasındaki farklar bir anlam taşır. Mutlak seviye bilgi değildir.

Neyse ki öyle, çünkü bilgisayarı bozan şey mutlak seviyedir:

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}, 64-bit float’ta overflow yapar, toplam sonsuz olur ve sonsuzun sonsuza bölümü nan’dır — hata değil, crash değil, yalnızca üç olasılığın olması gereken yerde sessiz bir delik. Maksimum logit’i çıkarmak matematiksel olarak hiçbir şeyi değiştirmez, sayısal olarak her şeyi değiştirir; çünkü en büyük üs tam olarak e0=1e^0 = 1 olur. Bu, Bölüm 2’nin logsumexp numarasının iş kıyafetlerini giymiş halidir ve her ciddi implementation bunu yapar:

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

Gradient yine tahmin eksi gerçektir; bu kez YY one-hot. Binary case başından beri özel bir durumdu.

3.000 parça üzerinde train edilip 1.000 parça üzerinde test edildiğinde, her parça için üç ölçümle (genişlik, ağırlık, erime sıcaklığı), %94.00 accuracy’ye ulaşır. Bu sayının ne sakladığı burada:

gerçek ↓ / tahmin →okshort shotflashburnrecall
ok8505900.984
short shot2221000.488
flash2003010.588
burn300390.929
precision0.9500.8080.7690.975

Model short shot’ların yarısından azını buluyor. Accuracy bunu göremez, çünkü parçaların %86’sı iyidir ve bunları doğru yapmak ortalamayı taşımaya yeter. Macro F1 — nadir bir sınıfa yaygın bir sınıfla aynı ağırlığı veren, sınıf başına F1 score’larının ortalaması — 0.7983’tür, tanımı gereği accuracy ile aynı olan micro F1 0.9400’a karşı. Birisi tek bir F1 sayısı raporladığında hangisi olduğunu sor.

Modellemenin sonu bu. Bölümün geri kalanı sayılar hakkında.

Train edilmiş binary modeli al ve her logit’i bir sabitle çarparak iki varyant yap: çekingen bir versiyon için 0.35, aşırı kendinden emin bir versiyon için 4. Pozitif bir sayıyla çarpmak hiçbir işareti değiştiremez, bu yüzden üç model de 4.000 test parçasının tamamı için tam olarak aynı label’ı tahmin eder. Accuracy onları ayırt edemez. Cross-entropy hiç zorlanmaz:

modelaccuracycross-entropydoğruyken ortalama lossyanlışken ortalama lossen kötü tekil loss
çekingen (logits × 0.35)0.98300.15490.13691.19902.80
train edildiği gibi0.98300.05640.01472.46897.82
aşırı kendinden emin (logits × 4)0.98300.15630.00099.142727.63

Çekingen model, doğru yaptığı binlerce parça dahil her parçada küçük bir vergi öder. Aşırı kendinden emin olan doğruyken neredeyse bedavadır, yanlışken felakettir — o test setindeki tek bir parça tek başına 27.63 nat’a mal olur. İkisi zıt yollardan neredeyse aynı toplama iner; olasılıkları veriye calibrated olan train edilmiş model ise ikisinin de üç kat altında durur.

Bu, loss ile metric arasındaki farkı söylemenin en keskin yoludur. Loss optimize ettiğin şeydir: differentiable olmalıdır ve modelin söylediği her şeyi, ne kadar emin olduğunu da, görür. Metric yargılandığın şeydir: bir step function, bir iş kuralı, kaçırılan hata sayısı olabilir. Aynı nesne değillerdir ve her zaman anlaşmazlar — bu yüzden ikisini de başlamadan önce tanımlarsın ve sırf ekranda duruyor diye loss’un metric’in yerine geçmesine asla izin vermezsin.

Herhangi bir modelden önce gereksinim: mümkün olan en tembel cevap kaç puan alır? Bu bantta, her zaman iyi de:

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

%98.15. Şimdi train edilmiş logistic model, default threshold 0.5 ile:

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. Baseline’ı 0.15 yüzde puanı geçti ve accuracy’de duran herhangi bir rapor buna zafer diyecek. Confusion matrix gerçekte ne olduğunu söyler:

tahmin edilen iyitahmin edilen hatalı
gerçekte iyi3.9242
gerçekte hatalı668

74 hatalı parçanın 8’ini buldu ve 66’sının geçmesine izin verdi. Üç sayı bu tabloyu okumanın üç yolunu adlandırır:

  • Precision =TP/(TP+FP)=8/10=0.800= \mathrm{TP}/(\mathrm{TP}+\mathrm{FP}) = 8/10 = 0.800. Flag’lediği parçaların kaçı gerçekten hatalıydı. Bu, boşa giden incelemelerin maliyetidir.
  • Recall =TP/(TP+FN)=8/74=0.108= \mathrm{TP}/(\mathrm{TP}+\mathrm{FN}) = 8/74 = 0.108. Hatalı parçaların kaçını yakaladı. Bu, müşteriye kötü parça göndermenin maliyetidir.
  • F1 =2PR/(P+R)=0.190= 2PR/(P+R) = 0.190, ikisinin harmonic mean’i; küçüğe yakın kalır ve bu yüzden tek başına birinin kendisini pohpohlamasını reddeder.

Hangisinin önemli olduğu matematiğe değil fabrikaya bağlıdır: bir inceleme birkaç saniyeye mal olur, gönderilmiş bir hata recall notice’e; bu yüzden burada recall baskındır ve 0.108 başarısızlıktır.

Ama sorun model değildir. Sorun threshold’dur, ve threshold modelin parçası değildir — bir olasılığa sonradan uygulanan iş kararıdır. Süpür:

thresholdTPFPFNaccuracyprecisionrecallF1
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

Accuracy sütununu aşağı doğru oku. Baştan sona düşer — %98.30’dan %65.93’e — model ise 8 hata yakalamaktan 74’ün 71’ini yakalamaya gider. Bu modelin yapabileceği her faydalı şey accuracy’sini kötüleştirir. Başlık sayısını optimize eden bir ekip hiçbir şey bulmayan versiyonu ship ederdi.

Ayrıntıları göster

Class weighting sinyal yaratmaz, operating point’i taşır. Imbalanced classes karşısındaki olağan ilk refleks, rare class’a loss içinde ağırlık vermektir. Pozitiflerde 1, 10 ve 60 ağırlıklarıyla bunu yapınca:

pozitiflere verilen ağırlıkaccuracyprecisionrecallF1AUC
10.98300.8000.1080.1900.9363
100.96050.2530.5810.3520.9361
600.82900.0910.9190.1660.9361

Precision ve recall çok oynar. AUC — modelin rastgele bir hatalı parçayı rastgele bir iyi parçanın üstünde sıralama olasılığı, threshold’u tamamen yok sayar — 0.0002 oynar; bu hiçbir şeydir. Reweighting aynı modeli aynı trade-off eğrisi boyunca kaydırdı. Çoğu zaman istediğin şey budur ve asla yeni bilgi değildir: ranking kötüyse hiçbir weighting scheme onu kurtarmaz.

Neden iki değil üç split? Çünkü bir örnek setini herhangi bir şeyi seçmek için kullandığın anda — threshold, learning rate, altı modelden hangisinin ship edileceği — o set fitting için kullanılmış olur ve score’u unbiased olmayı bırakır.3 Bu bant üzerinde ölçüldü: validation set üzerinde threshold süpürmek 0.196’yı seçer ve model daha sonra dokunulmamış test setinde F1 = 0.4122 alır. Süpürme doğrudan test set üzerinde yapılsaydı, orada ulaşılabilen en iyi değer 0.4186 olurdu — kimsenin raporlamaya hakkı olmayan bir sayı.

Fark burada küçük, 0.006; çünkü 4.000 validation örneğine karşı bir hyperparameter bir kez süpürüldü. Her ekstra kararla ve validation set’in her küçülmesiyle büyür. Şunu da not et: tek bir koşuda yön garanti değildir; seçilen threshold validation’da 0.3902, test’te 0.4122 aldı, yani validation bu kez onu eksik gösterdi. Bias birçok karar genelinde sistematiktir, tek bir koşuda görünür değildir.4

Şimdi egzersiz. Bant log’u üçüncü bir sütunla geliyor, station_seconds: her parçanın inspection station’da ne kadar kaldığı. Bunu eklemek preprocessing’e tek satırlık bir değişikliktir. Yaptığı şey şu:

modelaccuracyprecisionrecallF1cross-entropyAUC
genişlik + ağırlık0.98300.8000.1080.1900.05640.9363
+ station_seconds0.99200.7920.7700.7810.02360.9970

Recall %10.8’den %77.0’ye çıkar. F1 dört kattan fazla artar. Accuracy’nin ne yaptığına da dikkat et: %98.30 → %99.20, dokuz onda puanlık bir kazanç; özet slaytta “her iki türlü de yaklaşık %99” diye yuvarlanan türden bir sayı. Accuracy az önceki başarısızlığı göremedi; şimdi de hileyi göremiyor.

Devam etmeden önce: model hile yapıyor. Nasıl yaptığını bul.

Bir leak’i en hızlı bulacak sırayla nasıl avlarsın.

  1. Train ve test’i karşılaştır. Overfitting büyük bir fark olarak görünür. Burada: dürüst model 0.9838 train / 0.9830 test; leaky model 0.9936 train / 0.9920 test. İki fark da 0.2 puanın altında. Leak overfitting gibi görünmez — leaky feature test time’da da aynı derecede erişilebilirdir, bu yüzden model var olmayan bir dünyaya harika generalise eder.

  2. Her feature için tek başına bir model train et. Cevabı taşıyan herhangi bir şey kendini duyurur:

    tek başına featureaccuracyrecallF1AUC
    genişlik0.98150.0140.0260.8691
    ağırlık0.98150.0000.0000.7914
    station_seconds0.98500.4050.5000.9960

    Tek bir sütun, kendi başına, hataları AUC 0.9960 ile sıralar. Kumpas ve teraziyle alınan iki ölçüm 0.87 ve 0.79’a ulaşır. Bu asimetri alarmdır.

  3. Her sayının ne zaman yazıldığını sor. Ortalama bekleme süresi: geçen parçalar için 2.23 saniye, kalan parçalar için 15.56 saniye. Elbette. Bir parça istasyonda bekler, çünkü bir inspector onu banttan almıştır — bu da birisi onun hatalı olduğuna karar verdikten sonra ve yalnızca bu yüzden olur. Sütun parçanın ölçümü değildir. Kararın ölçümüdür.

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

Vurgulanan satır leak’tir: hatalı bir parçanın dwell time’ı farklı bir dağılımdan çekilir, çünkü bir insan onu banttan almıştır. Bu, applied machine learning’deki en yaygın ciddi bug’dır ve bir adı vardır: target leakage — prediction’ın yapılması gereken anda mevcut olmayacak bilginin training feature’larında bulunması.5 Exception fırlatmaz. Daha iyi bir sayı üretir. Bir projedeki her incentive onu tutmaya işaret eder.

Savunma, her sütuna sorulan tek sorudur: bu prediction’a ihtiyaç duyduğum anda bu değer henüz var mı? Canlı bir bantta station_seconds, parça incelenene kadar bilinmez — modelin yerine geçmesi gereken şey tam da buydu.

Bir modeli 20 örnek üzerinde score’ladığını ve 17’sini doğru yaptığını varsay. %85 raporlarsın.

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

17/20’nin dürüst okuması şudur: %64 ile %95 arasında bir yer. Gerçekten %65’lik bir model bu sonucu zamanın %4.4’ünde üretir — yirmi üçte bir koşu — ve bir avuç prompt deneyip en iyisini raporladıysan, o koşuyu kendin üretmiş oldun. Yirmide on yedi, %85’lik bir modeli %65’lik olandan ayıramaz.

Bir oran üzerine interval koymanın iki yolu var ve ikisi de araç çantanda olmalı:

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)

Düz bir success rate için Wilson6 kullan; her nn değerinde düzgün davranır ve randomness gerektirmez. Yukarıda n=20n = 20 iken bootstrap’ın üst ucunun 1.0000 olduğuna dikkat et — 20 noktayı resample etmek kolayca 20 doğru çekebilir, dolayısıyla kendi granularity’sinden daha dar bir interval temsil edemez. Formül olmayan yerde bootstrap7 kullan; ilginç vakaların çoğu böyledir: F1, macro-averages, BLEU, pass@1, rubric-based judge score’u. Bu bantta, tuned modelin 0.4122’lik F1 değeri [0.3009, 0.5156] bootstrap interval’ı taşır — raporda görünmesi gereken sayı budur, çünkü point estimate tek başına destekleyemeyeceği bir karşılaştırmaya davetiye çıkarır.

Bir ölçüm daha, çünkü iki modeli nasıl karşılaştırman gerektiğini değiştirir. Aynı 500 örnek üzerinde score’lanan iki model:

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)

Interval’ları çakışıyor ve halk kuralı — çakışan error bar’lar anlamlı fark yok demektir — karşılaştırmayı inconclusive sayardı. Öyle değil. İki model aynı örnekler üzerinde koştu, bu yüzden doğru nicelik örnek başına farktır; onun interval’ı [0.0260, 0.0680], rahatça sıfırın üstündedir. 500 item’ın yalnızca 31’inde anlaşmazlar ve A bu anlaşmazlıkların 27’sini kazanır; kolay ve zor ortak örnekler noise eklemek yerine birbirini götürür. Modelleri paired karşılaştır, aynı sonuca verinin bir kesriyle ulaşırsın.

Artık calibrated probabilities üreten bir modelin, kolaylık için seçilmek yerine veri hakkındaki bir iddiadan türetilmiş bir loss’un, kelimenin tam anlamıyla tahmin eksi gerçek olan bir gradient’ın ve — daha önemlisi — bunların herhangi birinin çalışıp çalışmadığını öğrenme mekanizmasının var. Yukarıdaki on satırlık Wilson interval aynen yeniden kullanılır: Bölüm 15’teki prompt varyantlarını, Bölüm 19’daki retrieval tablolarını ve Bölüm 29’daki golden set’i taşır. Formül olmadığında başvuracağın şey bootstrap’tır.

Ama model hâlâ tek katman. Bir çizgi çizer ve Bölüm 1, dört satırlık XOR ile bir çizginin yetmediğini kanıtlamıştı. Çözüm stack etmektir: space’i büken bir ilk katman, bükülmüş space’te çizgiyi çizen ikinci katman.

Bu bölümün düzenli gradient’ı burada tükenir. Yukarıdaki her şey çalıştı çünkü L/s=py\partial L/\partial s = p - y, input ile loss arasında tek katmanlı bir model için bir kez elde, yazılabiliyordu. Ortaya ikinci bir katman koyunca soru şekil değiştirir: output’a hiç dokunmayan bir weight’e göre loss’un türevi nedir — etkisi yalnızca başka bir katman üzerinden, belki aynı anda birkaç yol boyunca gelen bir weight?

O türev vardır. Onu elle hesaplamak oyuncaktan büyük herhangi bir şey için umutsuzdur ve her parametre için tek tek hesaplamak başka bir ölçekte umutsuzdur. Gereken şey, forward pass’in az önce yürüdüğü aynı graph üzerinde tek bir backward pass ile ağdaki her türevi çıkaran bir prosedürdür.

Bu Bölüm 5’tir ve kursun geri kalanının üzerinde çalıştığı motordur.


Bu bölümle birlikte okumaya değer diğer kaynaklar: Bishop, Pattern Recognition and Machine Learning §1.2, §1.5, §1.6 ve §4.3; probability, decision theory, information theory ve linear classification’ı bu bölümün izlediği sırayla kapsar. Murphy, Probabilistic Machine Learning: An Introduction, bölüm 6 ve 10; Prince, Understanding Deep Learning §5.4–5.7; ve Saito ve Rehmsmeier, The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets (PLOS ONE, 2015) — parçaların %1.7’si hatalıyken yukarıda alıntılanan AUC’nin bakacağın tek threshold-free sayı olmaması gerektiğinin nedeni.

  1. Ma, T. ve Ng, A. CS229 Lecture Notes, Stanford University, bölüm 2 ve 3. pyp - y’yi üreten sadeleşmenin şans gibi görünmeyi bıraktığı yer: output’una uyan exponential-family dağılımını seç, onun canonical link’ini kullan ve gradient her zaman tahmin eksi gerçek olur.

  2. Olah, C. Visual Information Theory (2015), colah.github.io/posts/2015-09-Visual-Information. Entropy, cross-entropy ve KL divergence’ı formül yerine bit cinsinden maliyetler olarak anlatan en net kaynak.

  3. Abu-Mostafa, Y. S., Magdon-Ismail, M. ve Lin, H.-T. Learning From Data (AMLBook, 2012), Caltech kursunun 13. ve 17. dersleri. 13. ders validation’dır; üç öğrenme ilkesine dair 17. derste data snooping adlandırılır. İkisi birlikte bu bölümdeki disiplinin kaynağıdır: bir data set’e her bakış, optimiser çalıştırmış olsan da olmasan da bir fitting kararıdır.

  4. James, G., Witten, D., Hastie, T. ve Tibshirani, R. An Introduction to Statistical Learning, 2. baskı (Springer, 2021), bölüm 2 ve 5; bias–variance decomposition ve resampling için. Selection trap’in doğrudan ifade edildiği eşlik eden cilt: Hastie, Tibshirani ve Friedman, The Elements of Statistical Learning, 2. baskı, §7.10.2, The Wrong and Right Way to Do Cross-validation.

  5. Kaufman, S., Rosset, S., Perlich, C. ve Stitelman, O. Leakage in Data Mining: Formulation, Detection, and Avoidance. ACM Transactions on Knowledge Discovery from Data 6(4), 2012. Yukarıda gösterilen hatanın, verinin nasıl bir araya getirildiğine dair bir artefact öğrenmiş modelin kazandığı yarışmalardan case study’lerle birlikte formal treatment’ı.

  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). Yukarıdaki wilson() içinde kullanılan score interval; bir proportion için hâlâ doğru default. Kaçınılması gereken textbook interval p^±zp^(1p^)/n\hat{p} \pm z\sqrt{\hat{p}(1-\hat{p})/n}’tir: 0 ve 1 yakınında saçmalık üretir, küçük nn değerlerinde ciddi undercoverage yapar.

  7. Efron, B. Bootstrap Methods: Another Look at the Jackknife. The Annals of Statistics 7(1), s. 1–26 (1979). Sampling theory’si olmayanlar dahil, hesaplayabildiğin herhangi bir statistic üzerine interval koymanı sağlayan fikir.

Seçimi LIA'ya bırakmaya hazır mısın?

Tüm yapay zeka modelleriyle tek yerde üret — bugün ücretsiz başla.