مواد پر جائیں
4/30باب 4 از 30

Classification، cross-entropy، اور خود کو دھوکا نہ دینے کا طریقہ

logistic classifier بنائیں، پھر دیکھیں کہ 98% accuracy بھی ایسا model ہو سکتی ہے جو کچھ نہ پکڑے۔

اس صفحے پر

ایک model جو belt سے آنے والے ہر پرزے کے بارے میں یہ حصہ ٹھیک ہے جواب دیتا ہے، 98.15 % وقت درست ہوتا ہے۔ وہ بیکار بھی ہے: test set کے 74 defective پرزوں میں سے یہ ایک بھی نہیں پکڑتا۔

دونوں جملے اسی ایک model کو بیان کرتے ہیں۔ ان کے بیچ کا فاصلہ یہی باب ہے۔

پہلا نصف classifier بناتا ہے۔ اسے تقریباً کچھ نیا نہیں چاہیے: باب 2 نے یہ نسخہ دیا تھا کہ data کیسے پیدا ہوتا ہے اس بارے میں ایک مفروضے کو loss function میں کیسے بدلا جائے، اور باب 3 نے وہ مشینری دی تھی جس سے اس recipe کے دیے ہوئے کسی بھی loss پر نیچے کی طرف چلا جا سکے۔ دونوں کو yes/no سوال پر لگائیں تو logistic regression نکل آتی ہے، ساتھ ایک نیا خیال — ایک logit — جس کا بل باب 17 میں دوبارہ آئے گا۔

دوسرا نصف مشکل ہے۔ کورس میں اس کے بعد ہر چیز کو ایک ایسے عدد سے پرکھا جاتا ہے جو کسی نے measure کیا ہو، اور اگر آپ حقیقی بہتری کو measurement artefact سے الگ نہیں کر سکتے، تو آگے کے تمام ابواب محض سجاوٹ ہیں۔ لہٰذا: confusion matrix، precision اور recall، تین splits، leakage، اور وہ سوال جس کا ایماندار جواب تقریباً کوئی نہیں دیتا — مجھے واقعی کتنی test examples چاہئیں؟

یہاں arithmetic 20,000 rows پر چلتی ہے، اس لیے پورا کام vectorised ہے — NumPy باب 2 سے کام کر رہا ہے، اور یہاں سے آگے اس کا ذکر کرنا قابلِ ذکر نہیں رہتا۔

Belt، ایک نایاب تر سوال کے ساتھ

اس حصے کا لنک: Belt، ایک نایاب تر سوال کے ساتھ

وہی factory جو باب 1 میں تھی، مگر سوال مشکل ہے۔ accept یا reject کے بجائے سوال ہے کیا یہ پرزہ defective ہے — اور defects نایاب ہیں، جس سے اس باب کا measuring نصف مشکل اور modelling نصف دھوکے سے آسان ہو جاتا ہے۔

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

تین splits، دو نہیں۔ وجہ اپنی الگ section کی مستحق ہے اور نیچے ملے گی؛ ابھی کے لیے پہلے پر train کریں، دوسرے پر tune کریں، اور تیسرے کو نہ دیکھیں۔

Features standardised ہیں — mean منہا، standard deviation سے divide — صرف training statistics استعمال کرتے ہوئے، اسی وجہ سے جو باب 1 نے perceptron کے convergence bound کے ساتھ دکھائی تھی: uncentred data geometry کو hostile بنا دیتا ہے۔ یہ mean کن rows سے compute کرنے کی اجازت ہے، اسی باب میں آگے چل کر ایک زندہ سوال بنے گا۔

Perceptron نے sign لوٹایا تھا۔ Sign reject اور reject، مگر بمشکل میں فرق نہیں کر سکتا، اور یہی فرق factory کو یہ فیصلہ کرنے کے لیے چاہیے کہ کون سے parts human سے پہلے دوبارہ inspect کروائے جائیں۔

لہٰذا باب 2 کی recipe کو لفظی طور پر follow کریں۔ لکھیں کہ آپ label کے پیدا ہونے کے بارے میں کیا claim کرتے ہیں، likelihood لیں، log لیں، اسے negate کریں، اور آپ کے پاس loss ہے۔ yes/no outcome کے لیے claim ایک Bernoulli distribution ہے: probability pp ہے کہ part defective ہے، اور

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

جو بس یہ لکھنے کا compact طریقہ ہے کہ ”pp اگر y=1y = 1، اور 1p1-p اگر y=0y = 0“۔ اس کا log لیں اور اسے negate کریں، تو ایک example کے لیے loss ہے

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

یہ binary cross-entropy ہے۔ اسے اس لیے نہیں چنا گیا کہ یہ convenient ہے؛ یہ اس واحد distribution کی negative log-likelihood ہے جو coin flip کے پاس ہو سکتی ہے۔ کوئی اور چیز دستیاب ہی نہیں تھی۔

اب بھی یہ رہ گیا ہے کہ pp کہاں سے آتا ہے۔ model ایک weighted sum s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b compute کرتا ہے، جو real number ہے اور پوری line پر range کرتا ہے، جبکہ probability کو (0,1)(0,1) میں رہنا ہوتا ہے۔ ان دونوں کے بیچ حرکت کرانے والا function logistic 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

دائیں ہاتھ والے column کو price list سمجھ کر پڑھیں۔ 90 % confidence کے ساتھ درست ہونے کی قیمت 0.105 ہے۔ commit نہ کرنے کی قیمت 0.693 ہے — یعنی log2\log 2، کندھے اچکانے کی قیمت۔ confidence کے ساتھ غلط ہونے کی قیمت 4.6 ہے، چوالیس گنا زیادہ، اور جیسے جیسے model اپنی غلطی پر زیادہ یقین کرتا ہے، قیمت لا محدود بڑھتی ہے۔ Cross-entropy صرف errors نہیں گنتی: یہ تکبر کا بل بناتی ہے۔

باب 3 نے کہا: کسی بھی چیز کو train کرنے کے لیے، loss کی ہر parameter کے respect میں derivative حاصل کریں۔ اسے ایک example کے لیے کریں۔ s=wx+bs = \mathbf{w}\cdot\mathbf{x} + b اور 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
تفصیلات دکھائیں

وہ دو lines جو mess کو cancel کر دیتی ہیں۔ sigmoid کی derivative غیر معمولی طور پر خوشگوار ہے، σ(s)=σ(s)(1σ(s))=p(1p)\sigma'(s) = \sigma(s)\,(1 - \sigma(s)) = p(1-p)۔ اور loss differentiate ہو کر بنتا ہے

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

chain rule سے دونوں کو multiply کریں تو p(1p)p(1-p) اوپر ایک بار اور نیچے ایک بار آتا ہے۔ یہ ٹھیک ٹھیک cancel ہو جاتا ہے، اور pyp - y بچتا ہے۔ یہ cancellation اتفاق نہیں — یہ تب ہوتا ہے جب loss کسی distribution کی negative log-likelihood ہو اور output function وہ ہو جسے وہ distribution قدرتی طور پر استعمال کرتی ہے۔ اس pairing کا نام ہے — generalised linear model — اور صاف gradient اس کا fingerprint ہے۔1

لہٰذا update ہے prediction minus truth، times input۔ اور کچھ نہیں۔ یہ پورا trainer ہے، جو باب 3 کا descent ہے صرف ایک line بدل کر:

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 میں np.where cosmetic نہیں ہے۔ 1/(1+es)1/(1+e^{-s}) کو directly compute کرنا large negative ss کے لیے overflow کر جاتا ہے؛ branch وہ algebraically identical form چنتی ہے جو exponent کو negative رکھے۔ یہ باب 2 کا floating-point box اپنا پہلا قرض وصول کر رہا ہے، اور دو sections بعد بڑا قرض وصول کرے گا۔

Squared error کیوں نہیں، اور جواب gradient کے بارے میں کیوں ہے

اس حصے کا لنک: Squared error کیوں نہیں، اور جواب gradient کے بارے میں کیوں ہے

Cross-entropy کو squared error پر prefer کرنے کی standard explanation اوپر والا likelihood argument ہے: squared error Gaussian noise assume کرنے سے ملتا ہے، labels Gaussian نہیں، لہٰذا نہ کریں۔ یہ درست ہے اور کسی کو قائل نہیں کرتا، کیونکہ آپ sigmoid کے اوپر L=(py)2L = (p - y)^2 لکھ سکتے ہیں اور یہ train ہو جائے گا۔

جو دلیل اثر کرتی ہے وہ gradient کے بارے میں ہے۔ sigmoid کے اوپر squared error رکھیں تو chain rule دیتا ہے

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

وہ extra p(1p)p(1-p) وہی ہے جو پہلے cancel ہوا تھا۔ اب نہیں ہوتا، اور جب بھی model confident ہوتا ہے یہ zero کی طرف جاتا ہے — اس وقت بھی جب model confidence کے ساتھ غلط ہو۔ دونوں کو چند scores پر evaluate کریں، ایک ایسے example کے لیے جس کا true label 1 ہے:

score ssppcross-entropy L/s\partial L/\partial ssquared error L/s\partial L/\partial sratio
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 پر model اتنا غلط ہے جتنا ممکن ہے، اور squared error ایسا gradient دیتا ہے جو cross-entropy کے gradient سے 1,491 گنا چھوٹا ہے۔ غلطی جتنی worse ہو، model اس سے اتنا کم سیکھتا ہے۔ Cross-entropy کا gradient، اس کے برعکس، 1-1 پر saturate ہوتا ہے: maximally wrong ایک maximally large signal دیتا ہے، اور اس سے بڑا نہیں۔

Race چلائیں۔ دو ہزار balanced points، identical starting weights جو confidently wrong ہونے کے لیے چنے گئے ہیں (w=[6,6]\mathbf{w} = [-6, -6])، identical learning rate، فرق صرف loss کا ہے۔ دونوں runs کو cross-entropy سے score کیا گیا ہے تاکہ columns comparable ہوں۔

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 تک finish ہو چکی ہے۔ Squared error epoch 100 پر بھی 24 % accuracy پر ہے — اور epoch 10 کے 23 % سے move نہیں ہوا تھا — guessing سے بھی بدتر، کیونکہ اس نے confidently wrong start کیا اور جو gradient اسے rescue کرتا اسے 0.0007 سے multiply کر دیا گیا۔ یہ تقریباً epoch 500 پر escape کرتا ہے اور اسی جگہ پہنچتا ہے۔ لہٰذا ایماندار summary یہ ہے کہ sigmoid کے اوپر squared error incorrect نہیں؛ یہ بالکل وہاں slow ہے جہاں speed سب سے زیادہ معنی رکھتی ہے۔ دو-parameter model پر آپ 450 epochs کھو دیتے ہیں۔ سو layers والے network پر، جہاں کہیں نہ کہیں کوئی unit ہمیشہ confidently wrong ہوتا ہے، آپ training run کھو دیتے ہیں۔

Entropy، cross-entropy اور KL، ایک page میں

اس حصے کا لنک: Entropy، cross-entropy اور KL، ایک page میں

تین quantities، باب 8 میں perplexity کے لیے اور باب 11 میں اس penalty کے لیے جو fine-tuned policy کو اس کے reference کے قریب رکھتی ہے، ٹھیک طرح چاہیے ہوں گی۔ یہ اپنی reputation سے آسان ہیں۔2

Entropy bits کی average تعداد ہے جو آپ کو کسی distribution سے draw کو communicate کرنے کے لیے خرچ کرنا پڑتی ہے، اگر آپ اس کے لیے best possible code استعمال کریں:

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

Cross-entropy وہ خرچ ہے جب آپ qq کے لیے بنایا گیا code اس data پر استعمال کریں جو حقیقت میں pp سے آتا ہے:

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

KL divergence excess ہے — bits میں waste — جو qq پر یقین کرنے سے پیدا ہوتا ہے جب truth pp ہو:

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

Belt پر تینوں check کریں:

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

وہاں دو چیزیں نظر آتی ہیں۔ پہلی، ایک model جو صرف training base rate، 1.69 %، report کرتا ہے، 0.1330 bits کی cross-entropy حاصل کرتا ہے، تقریباً بالکل test labels کی entropy — جیسا کہ لازمی ہے، کیونکہ اس کے پاس درست distribution ہے اور کوئی دوسری information نہیں۔ Entropy وہ floor ہے جو فرد کے بارے میں ignorance آپ کو خرید کر دیتی ہے۔ دوسری، ایک model جو کندھے اچکا کر 0.5 کہتا ہے، ٹھیک 1 bit ادا کرتا ہے، اور دونوں کے بیچ gap، 0.8671 bits، بالکل KL divergence ہے۔ H+DKL=H(p,q)H + D_{\mathrm{KL}} = H(p,q) memorize کرنے کی identity نہیں؛ یہ ایک bill ہے جسے آپ add ہوتے دیکھ سکتے ہیں۔

اور training سے connection: جب label ایک single known class ہو، ”true“ distribution one-hot ہوتی ہے، اس کی entropy zero ہوتی ہے، اور cross-entropy برابر KL divergence ہوتی ہے۔ Cross-entropy کو minimise کرنا اور model کی distribution کو truth کی طرف کھینچنا ایک ہی عمل ہے۔

دو سے زیادہ answers: softmax، اور وہ shift جس کی کوئی قیمت نہیں

اس حصے کا لنک: دو سے زیادہ answers: softmax، اور وہ shift جس کی کوئی قیمت نہیں

Defective ایک چیز نہیں۔ moulding میں part short shot (material کافی نہیں)، flash (بہت زیادہ، mould سے باہر نچڑا ہوا)، یا burn بن کر نکل سکتا ہے۔ چار outcomes، لہٰذا چار logits، اور انہیں چار probabilities بننا ہے جن کا sum one ہو۔ یہ softmax ہے:

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

اس کی ایک property ہے جو accident جیسی لگتی ہے مگر دراصل پوری implementation ہے:

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

کسی بھی constant cc کے لیے، کیونکہ ezi+c=ecezie^{z_i + c} = e^{c} e^{z_i} اور ece^c اوپر اور نیچے cancel ہو جاتے ہیں۔ logits کے بیچ صرف differences معنی رکھتے ہیں۔ absolute level information نہیں ہے۔

خوش قسمتی ہے، کیونکہ absolute level ہی computer کو توڑتا ہے:

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 کو overflow کرتا ہے، sum infinity بن جاتا ہے، اور infinity divided by infinity nan ہے — نہ error، نہ crash، بس ایک silent hole جہاں تین probabilities ہوا کرتی تھیں۔ maximum logit کو subtract کرنا mathematically کچھ نہیں بدلتا اور numerically سب کچھ بدل دیتا ہے، کیونکہ largest exponent بالکل e0=1e^0 = 1 بن جاتا ہے۔ یہ باب 2 کا logsumexp trick ہے work clothes پہن کر، اور ہر serious implementation یہی کرتی ہے:

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 پھر وہی prediction minus truth ہے، اب YY one-hot کے ساتھ۔ binary case شروع سے ہی special case تھا۔

3,000 parts پر trained اور 1,000 پر tested، ہر ایک کے تین measurements (width، weight، melt temperature) کے ساتھ، یہ 94.00 % accuracy تک پہنچتا ہے۔ یہ ہے وہ چیز جو یہ number چھپا رہا ہے:

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

Model نصف سے کم short shots پکڑتا ہے۔ Accuracy یہ نہیں دیکھ سکتی، کیونکہ 86 % parts fine ہیں اور انہیں درست پکڑنا average کو اٹھانے کے لیے کافی ہے۔ Macro F1 — per-class F1 scores کا mean، جو rare class کو common class جتنا weight دیتا ہے — 0.7983 ہے، micro F1 کے 0.9400 کے مقابل، جو definition کے لحاظ سے accuracy کے identical ہے۔ جب بھی کوئی ایک F1 number report کرے، پوچھیں کون سا۔

Modelling یہاں ختم ہوئی۔ باقی chapter numbers کے بارے میں ہے۔

Trained binary model لیں اور ہر logit کو constant سے multiply کر کے دو variants بنائیں: hesitant version کے لیے 0.35، overconfident کے لیے 4۔ positive number سے multiply کرنے سے کوئی sign بدل نہیں سکتا، اس لیے تینوں models تمام 4,000 test parts کے لیے بالکل وہی label predict کرتے ہیں۔ Accuracy انہیں الگ نہیں بتا سکتی۔ Cross-entropy کو کوئی مشکل نہیں:

modelaccuracycross-entropymean loss when rightmean loss when wrongworst single loss
hesitant (logits × 0.35)0.98300.15490.13691.19902.80
as trained0.98300.05640.01472.46897.82
overconfident (logits × 4)0.98300.15630.00099.142727.63

Hesitant model ہر part پر چھوٹا tax دیتا ہے، ان ہزاروں پر بھی جنہیں یہ درست پکڑتا ہے۔ Overconfident model درست ہونے پر تقریباً free ہے اور غلط ہونے پر catastrophic — اس test set کا ایک part اکیلا اسے 27.63 nats خرچ کراتا ہے۔ دونوں مخالف routes سے تقریباً ایک ہی total پر آتے ہیں، اور trained model، جس کی probabilities data کے مطابق calibrated ہیں، دونوں سے تین گنا نیچے بیٹھتا ہے۔

یہ loss اور metric کے فرق کو بیان کرنے کا سب سے تیز طریقہ ہے۔ Loss وہ ہے جسے آپ optimise کرتے ہیں: اسے differentiable ہونا چاہیے، اور یہ model کی ہر بات دیکھتا ہے، یہ بھی کہ وہ کتنا sure تھا۔ Metric وہ ہے جس پر آپ کو judge کیا جاتا ہے: یہ step function، business rule، missed defects کی count ہو سکتا ہے۔ یہ ایک ہی object نہیں ہیں اور ہمیشہ agree نہیں کرتے — اسی لیے آپ شروع کرنے سے پہلے دونوں define کرتے ہیں، اور loss کو metric کی جگہ کبھی کھڑا نہیں ہونے دیتے صرف اس لیے کہ وہ screen پر موجود ہے۔

کسی بھی model سے پہلے requirement: سب سے lazy possible answer کیا score کرتا ہے؟ اس belt پر، ہمیشہ fine کہو:

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

98.15 %۔ اب trained logistic model، default threshold 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 %۔ اس نے baseline کو 0.15 percentage point سے beat کیا، اور جو report accuracy پر رک جائے گی وہ اسے win کہے گی۔ Confusion matrix بتاتا ہے کہ اصل میں کیا ہوا:

predicted finepredicted defective
actually fine3,9242
actually defective668

اس نے 74 میں سے 8 defective parts پکڑے اور 66 کو گزرنے دیا۔ تین numbers اس table کو پڑھنے کے تین طریقوں کے نام ہیں:

  • Precision =TP/(TP+FP)=8/10=0.800= \mathrm{TP}/(\mathrm{TP}+\mathrm{FP}) = 8/10 = 0.800۔ جن parts کو اس نے flag کیا، ان میں کتنے واقعی defective تھے۔ یہ wasted inspections کی cost ہے۔
  • Recall =TP/(TP+FN)=8/74=0.108= \mathrm{TP}/(\mathrm{TP}+\mathrm{FN}) = 8/74 = 0.108۔ defective parts میں سے اس نے کتنے پکڑے۔ یہ customer کو bad part ship کرنے کی cost ہے۔
  • F1 =2PR/(P+R)=0.190= 2PR/(P+R) = 0.190، ان دونوں کا harmonic mean، جو چھوٹے والے کے قریب رہتا ہے اور اس لیے ان میں سے صرف ایک سے flattering قبول نہیں کرتا۔

کون سا matter کرتا ہے، یہ factory پر depend کرتا ہے، mathematics پر نہیں: inspection چند seconds لیتی ہے اور shipped defect ایک recall notice بن سکتا ہے، اس لیے یہاں recall غالب ہے اور 0.108 failure ہے۔

لیکن model مسئلہ نہیں۔ Threshold مسئلہ ہے، اور threshold model کا حصہ نہیں — یہ probability کے بعد apply کیا گیا business decision ہے۔ اسے sweep کریں:

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 column کو نیچے پڑھیں۔ یہ پورے راستے گرتی ہے — 98.30 % سے 65.93 % تک — جبکہ model 8 defects پکڑنے سے 74 میں سے 71 پکڑنے تک جاتا ہے۔ یہ model جو بھی useful کام کر سکتا ہے، وہ اس کی accuracy کو worse بناتا ہے۔ headline number optimise کرنے والی team وہ version ship کرے گی جو کچھ نہیں ڈھونڈتا۔

تفصیلات دکھائیں

Class weighting signal create نہیں کرتی، یہ operating point move کرتی ہے۔ Imbalanced classes کے ساتھ معمول کا پہلا reflex rare class کو loss میں weight کرنا ہے۔ ایسا کرتے ہوئے، positives پر 1، 10 اور 60 کے weights کے ساتھ:

weight on positivesaccuracyprecisionrecallF1AUC
10.98300.8000.1080.1900.9363
100.96050.2530.5810.3520.9361
600.82900.0910.9190.1660.9361

Precision اور recall بہت دور move کرتے ہیں۔ AUC — یہ probability کہ model ایک random defective part کو random good part سے اوپر rank کرے، جو threshold کو مکمل طور پر ignore کرتی ہے — 0.0002 سے move ہوتی ہے، جو کچھ نہیں۔ Reweighting نے اسی model کو اسی trade-off curve پر slide کیا۔ اکثر یہی آپ چاہتے ہیں، اور یہ کبھی نئی information نہیں ہوتی: اگر ranking bad ہے تو کوئی weighting scheme اسے نہیں بچائے گی۔

تین splits، اور وہ leak جو آپ ڈھونڈنے والے ہیں

اس حصے کا لنک: تین splits، اور وہ leak جو آپ ڈھونڈنے والے ہیں

تین splits کیوں، دو کیوں نہیں؟ کیونکہ جس لمحے آپ examples کے کسی set کو کچھ بھی choose کرنے کے لیے استعمال کرتے ہیں — threshold، learning rate، چھ models میں سے کون ship کرنا ہے — وہ set fitting کے لیے استعمال ہو چکا ہے، اور اس کا score unbiased نہیں رہتا۔3 اس belt پر measured: validation set پر threshold sweep کرنے سے 0.196 چنا جاتا ہے، اور پھر model untouched test set پر F1 = 0.4122 score کرتا ہے۔ اگر sweep براہِ راست test set پر چلائی جاتی، تو وہاں best achievable 0.4186 تھا — ایک ایسا number جسے report کرنے کا کسی کو حق نہیں۔

Gap یہاں چھوٹا ہے، 0.006، کیونکہ یہ ایک hyperparameter تھا جو 4,000 validation examples کے مقابل ایک بار sweep ہوا۔ یہ ہر extra decision اور validation set کے ہر shrink کے ساتھ بڑھتا ہے۔ یہ بھی نوٹ کریں کہ single run میں direction guaranteed نہیں: chosen threshold نے validation پر 0.3902 اور test پر 0.4122 score کیا، لہٰذا validation نے اس بار اسے understate کیا۔ Bias کئی decisions پر systematic ہے، ایک میں visible نہیں۔4

اب exercise۔ Belt log ایک تیسرے column، station_seconds، کے ساتھ آتا ہے: ہر part نے inspection station پر کتنا وقت گزارا۔ اسے add کرنا preprocessing میں one-line change ہے۔ یہ جو کرتا ہے وہ یہ ہے:

modelaccuracyprecisionrecallF1cross-entropyAUC
width + weight0.98300.8000.1080.1900.05640.9363
+ station_seconds0.99200.7920.7700.7810.02360.9970

Recall 10.8 % سے 77.0 % پر چلا جاتا ہے۔ F1 چار گنا سے بھی زیادہ ہو جاتا ہے۔ اور دھیان دیں accuracy نے کیا کیا: 98.30 % → 99.20 %، point کے نو دسویں کا gain، ایسا number جو summary slide میں ”تقریباً 99 % دونوں طرح“ کہہ کر round ہو جاتا ہے۔ Accuracy پہلے failure دیکھنے میں fail ہوئی اور اب fraud دیکھنے میں fail ہوتی ہے۔

آگے پڑھنے سے پہلے: model cheat کر رہا ہے۔ معلوم کریں کیسے۔

Leak hunt کرنے کا طریقہ، اس order میں جو اسے سب سے تیزی سے ڈھونڈتا ہے۔

  1. Train اور test compare کریں۔ Overfitting large gap کے طور پر دکھتا ہے۔ یہاں: honest model 0.9838 train / 0.9830 test؛ leaky model 0.9936 train / 0.9920 test۔ دونوں gaps 0.2 points سے کم ہیں۔ Leak overfitting جیسا نہیں لگتا — leaky feature test time پر بھی اتنا ہی available ہے، لہٰذا model ایک ایسی دنیا میں خوب generalise کرتا ہے جو exists ہی نہیں کرتی۔

  2. ہر feature پر الگ، اکیلا model train کریں۔ جو بھی answer اٹھائے ہوئے ہو گا، خود announce کر دے گا:

    feature aloneaccuracyrecallF1AUC
    width0.98150.0140.0260.8691
    weight0.98150.0000.0000.7914
    station_seconds0.98500.4050.5000.9960

    ایک column، اکیلا، defects کو AUC 0.9960 پر rank کرتا ہے۔ caliper اور scale سے لیے گئے دو measurements 0.87 اور 0.79 manage کرتے ہیں۔ یہی asymmetry alarm ہے۔

  3. پوچھیں ہر number کب لکھا گیا تھا۔ Mean dwell time: pass ہونے والے parts کے لیے 2.23 seconds، fail ہونے والوں کے لیے 15.56 seconds۔ ظاہر ہے۔ Part station پر اس لیے dwell کرتا ہے کیونکہ inspector نے اسے belt سے اتار لیا — جو بعد میں ہوتا ہے، اور صرف اس وجہ سے کہ کسی نے فیصلہ کیا تھا یہ defective ہے۔ Column part کی measurement نہیں۔ یہ verdict کی measurement ہے۔

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

Highlighted line leak ہے: defective part کا dwell time مختلف distribution سے draw ہوتا ہے، کیونکہ human نے اسے belt سے اٹھایا۔ Applied machine learning میں یہ سب سے common serious bug ہے، اور اس کا نام ہے: target leakage — training features میں ایسی information جو prediction کے moment پر available نہیں ہوتی۔5 یہ کوئی exception نہیں پھینکتا۔ یہ بہتر number produce کرتا ہے۔ Project میں ہر incentive اسے keep کرنے کی طرف اشارہ کرتا ہے۔

Defence ایک سوال ہے، جو ہر column سے پوچھا جاتا ہے: جس instant مجھے یہ prediction چاہیے، کیا یہ value ابھی exist کرتی ہے؟ Live belt پر، station_seconds تب تک unknown ہے جب تک part inspect نہ ہو جائے — جو وہ چیز ہے جسے model replace کرنے والا تھا۔

فرض کریں آپ model کو 20 examples پر score کرتے ہیں اور یہ 17 درست کرتا ہے۔ آپ 85 % report کرتے ہیں۔

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 کی honest reading ہے کہیں 64 % اور 95 % کے بیچ۔ واقعی 65 % model یہ result 4.4 % وقت produce کرتا ہے — تئیس runs میں ایک — اور اگر آپ نے handful of prompts آزما کر best report کیا، تو آپ نے وہ run خود manufacture کیا۔ بیس میں سے سترہ ایک 85 % model کو 65 % model سے distinguish نہیں کر سکتے۔

Rate پر interval لگانے کے دو طریقے، اور دونوں آپ کے toolkit میں ہونے چاہئیں:

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)

Plain success rate کے لیے Wilson6 استعمال کریں؛ یہ کسی بھی nn پر well behaved رہتا ہے اور randomness نہیں مانگتا۔ اوپر note کریں کہ n=20n = 20 پر bootstrap کا upper end 1.0000 ہے — 20 points resample کرنا آسانی سے 20 correct ones draw کر سکتا ہے، اس لیے یہ اپنی granularity سے narrower interval represent نہیں کر سکتا۔ Bootstrap7 وہاں استعمال کریں جہاں کوئی formula نہیں، یعنی زیادہ تر interesting cases: F1، macro-averages، BLEU، pass@1، rubric-based judge کا score۔ اس belt پر، tuned model کے 0.4122 F1 کا bootstrap interval [0.3009, 0.5156] ہے — یہی number report میں آنا چاہیے، کیونکہ point estimate اکیلا ایسی comparison کی دعوت دیتا ہے جسے یہ support نہیں کر سکتا۔

ایک اور measurement، کیونکہ یہ بدل دیتی ہے کہ آپ دو models کیسے compare کریں۔ دو models انہی 500 examples پر scored:

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)

ان کے intervals overlap کرتے ہیں، اور folk rule — overlapping error bars کا مطلب significant difference نہیں — comparison کو inconclusive کہے گا۔ ایسا نہیں ہے۔ دونوں models انہی examples پر چلے، اس لیے صحیح quantity per-example difference ہے، جس کا interval [0.0260, 0.0680] ہے، آرام سے zero سے اوپر۔ وہ 500 items میں سے صرف 31 پر disagree کرتے ہیں، اور A ان disagreements میں سے 27 جیتتا ہے؛ shared examples، easy اور hard دونوں، noise add کرنے کے بجائے cancel ہو جاتے ہیں۔ Models کو paired compare کریں، اور آپ data کے ایک fraction سے وہی conclusion لے آتے ہیں۔

اب آپ کے پاس ایک model ہے جو calibrated probabilities output کرتا ہے، ایک loss جو convenience کے بجائے data کے بارے میں claim سے derived ہے، ایک gradient جو لفظی طور پر prediction minus truth ہے، اور — زیادہ اہم — یہ معلوم کرنے کی machinery کہ اس میں سے کچھ کام بھی کرتا ہے یا نہیں۔ اوپر والا ten-line Wilson interval verbatim reuse ہوتا ہے: یہ باب 15 میں prompt variants، باب 19 میں retrieval tables، اور باب 29 میں golden set کو carry کرتا ہے۔ Bootstrap وہ ہے جس کی طرف آپ اس وقت جاتے ہیں جب کوئی formula نہیں ہوتا۔

مگر model اب بھی ایک layer ہے۔ یہ ایک line draw کرتا ہے، اور باب 1 نے XOR کی چار rows سے prove کیا تھا کہ line کافی نہیں۔ Fix stack کرنا ہے: پہلی layer جو space کو bend کرتی ہے، دوسری جو bent space میں line draw کرتی ہے۔

یہی وہ جگہ ہے جہاں اس باب کا tidy gradient ختم ہوتا ہے۔ اوپر سب کچھ اس لیے کام کر گیا کہ L/s=py\partial L/\partial s = p - y input اور loss کے بیچ ایک layer والے model کے لیے ایک بار ہاتھ سے لکھا جا سکتا تھا۔ بیچ میں دوسری layer رکھیں تو سوال کی شکل بدل جاتی ہے: loss کی derivative اس weight کے respect میں کیا ہے جو output کو بالکل touch نہیں کرتا — ایک ایسا weight جس کا influence صرف دوسری layer کے through آتا ہے، ممکن ہے ایک ساتھ کئی paths سے؟

وہ derivative exist کرتی ہے۔ اسے hand سے compute کرنا toy سے بڑی کسی بھی چیز کے لیے hopeless ہے، اور اسے ایک وقت میں ایک parameter کے لیے compute کرنا ایک مختلف scale پر hopeless ہے۔ ضرورت ایک procedure کی ہے جو forward pass کے ابھی چل کر آنے والے اسی graph پر ایک single backward pass سے network کی ہر derivative نکال دے۔

یہ باب 5 ہے، اور یہی engine ہے جس پر باقی course چلتا ہے۔


اس باب کے ساتھ پڑھنے کے قابل مزید: Bishop, Pattern Recognition and Machine Learning §1.2, §1.5, §1.6 and §4.3، جو probability، decision theory، information theory اور linear classification کو اسی order میں cover کرتا ہے جسے یہ chapter follow کرتا ہے؛ Murphy, Probabilistic Machine Learning: An Introduction, chapters 6 and 10؛ Prince, Understanding Deep Learning §5.4–5.7؛ اور Saito and Rehmsmeier, The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets (PLOS ONE, 2015) — کیوں اوپر quoted AUC وہ واحد threshold-free number نہیں ہونا چاہیے جسے آپ دیکھیں جب 1.7 % parts defective ہوں۔

  1. Ma, T. and Ng, A. CS229 Lecture Notes, Stanford University, chapters 2 and 3. جہاں pyp - y پیدا کرنے والی cancellation luck لگنا بند کرتی ہے: اپنے output سے match کرنے والی exponential-family distribution چنیں، اس کا canonical link استعمال کریں، اور gradient ہمیشہ prediction minus truth ہوتا ہے۔

  2. Olah, C. Visual Information Theory (2015), colah.github.io/posts/2015-09-Visual-Information. Entropy، cross-entropy اور KL divergence کو formulas کے بجائے bits میں costs کے طور پر سمجھانے والی سب سے واضح available account۔

  3. Abu-Mostafa, Y. S., Magdon-Ismail, M. and Lin, H.-T. Learning From Data (AMLBook, 2012), Caltech course کے lectures 13 and 17۔ Lecture 13 validation ہے؛ lecture 17، three learning principles پر، وہ جگہ ہے جہاں data snooping کو نام دیا جاتا ہے۔ دونوں مل کر اس باب کے discipline کا source ہیں: data set پر ہر نظر fitting decision ہے، چاہے آپ نے optimiser چلایا ہو یا نہیں۔

  4. James, G., Witten, D., Hastie, T. and Tibshirani, R. An Introduction to Statistical Learning, 2nd edition (Springer, 2021), chapters 2 and 5، bias–variance decomposition اور resampling کے لیے۔ Companion volume وہ ہے جہاں selection trap صاف صاف بیان ہوتا ہے: Hastie, Tibshirani and Friedman, The Elements of Statistical Learning, 2nd edition, §7.10.2, The Wrong and Right Way to Do Cross-validation۔

  5. Kaufman, S., Rosset, S., Perlich, C. and Stitelman, O. Leakage in Data Mining: Formulation, Detection, and Avoidance. ACM Transactions on Knowledge Discovery from Data 6(4), 2012. اوپر demonstrate کی گئی failure کا formal treatment، ان competitions کے case studies کے ساتھ جو ایسے model نے جیتیں جس نے data assemble ہونے کے طریقے کا artefact سیکھ لیا تھا۔

  6. Wilson, E. B. Probable Inference, the Law of Succession, and Statistical Inference. Journal of the American Statistical Association 22(158), pp. 209–212 (1927). اوپر wilson() میں استعمال ہونے والا score interval، proportion کے لیے اب بھی درست default۔ Textbook interval p^±zp^(1p^)/n\hat{p} \pm z\sqrt{\hat{p}(1-\hat{p})/n} وہ ہے جس سے بچنا چاہیے: یہ 0 اور 1 کے قریب nonsense دیتا ہے، اور چھوٹے nn پر بری طرح undercovers کرتا ہے۔

  7. Efron, B. Bootstrap Methods: Another Look at the Jackknife. The Annals of Statistics 7(1), pp. 1–26 (1979). وہ idea جو آپ کو کسی بھی statistic پر interval لگانے دیتا ہے جسے آپ compute کر سکتے ہیں، ان پر بھی جن کی کوئی sampling theory نہیں۔

ماڈل چننے کا کام LIA کے سپرد کرنے کے لیے تیار ہیں؟

ہر AI ماڈل ایک ہی جگہ — آج ہی مفت شروع کریں۔