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

Loss Function کہاں سے آتا ہے: Likelihood، روایت نہیں

ایک ہی 20 پیمائشوں پر تین لکیریں اور تین scoring rules؛ ہر rule الگ فاتح چنتا ہے۔ squared error ایک مفروضہ ہے۔

اس صفحے پر

جو blade پرزے کاٹتا ہے وہ گھس جاتا ہے۔ دس گھنٹے کی shift میں اس کی دھار اتنی کم ہو جاتی ہے کہ belt سے اترنے والے پرزے شروع کے مقابلے میں ملی میٹر کے ایک چھوٹے حصے جتنے چوڑے ہو جاتے ہیں، اور جب وہ 23.5 ملی میٹر سے گزر جائیں تو inspection انہیں reject کر دیتی ہے۔ plant میں کسی کو معلوم نہیں کہ یہ کب ہوتا ہے۔ ان کے پاس ایک caliper، ایک notebook، اور پچھلے منگل کی بیس readings ہیں: blade بدلنے کے بعد گزرے ہوئے گھنٹے، اور اسی لمحے measured part کی width۔

کوئی points کے بیچ ایک line کھینچتا ہے۔ کوئی اور ذرا مختلف line کھینچتا ہے۔ تیسرا شخص تیسری line بناتا ہے۔ کاغذ پر تینوں معقول لگتی ہیں، اور blade کب بدلنا ہے اس بارے میں کئی گھنٹوں کا فرق بتاتی ہیں — اس plant میں یہی فرق ایک پرسکون ہفتے اور scrap ہو جانے والے batch کے درمیان ہے۔

کون سی line بہتر ہے؟

جیسا کہ سوال رکھا گیا ہے، اس کا کوئی جواب نہیں۔ مشکل جواب نہیں — بالکل کوئی جواب نہیں۔ "بہتر" line کی ویسی خاصیت نہیں جیسے اس کا slope؛ یہ line کی خاصیت ہے ایک ایسے rule کے ساتھ جو lines کو score کرے، اور جب تک کوئی وہ rule لکھ نہ دے compute کرنے کو کچھ نہیں۔ یہ chapter اس جملے کو سنجیدگی سے لیتا ہے، اور آخر میں یہ دریافت کرتا ہے کہ machine learning کا سب سے عام rule کوئی convention نہیں بلکہ دنیا کے بارے میں ایک دعوے کا نتیجہ ہے — ایک ایسا دعویٰ جسے آپ test کر سکتے ہیں، اور جو کبھی کبھی false ہوتا ہے۔

code کی پہلی line سے پہلے ایک اعتراف۔ یہ بیس readings کسی حقیقی factory سے نہیں ہیں: میں نے انہیں اپنی chosen line، width=20.00+0.30h\text{width} = 20.00 + 0.30 \cdot h، plus random noise سے generate کیا ہے جس کا spread تقریباً ایک دسویں ملی میٹر ہے۔ یہ اہم ہے، کیونکہ نیچے سب کچھ اس بارے میں ہے کہ آیا کوئی method سچ recover کرتا ہے، اور اسے check کرنے کا واحد طریقہ یہ ہے کہ سچ پہلے سے معلوم ہو۔ لہٰذا: 0.30 ملی میٹر per hour کتاب کے آخر والا جواب ہے۔ آپ اسے استعمال نہیں کر سکتے، صرف اس کے against check کر سکتے ہیں۔

یہ readings اور تین lines ہیں، تین طریقوں سے scored: squared error، جس کی طرف سب پہلے جاتے ہیں؛ absolute error، جسے شاید statistician چنے؛ اور worst error، جسے machinist چنے گا، کیونکہ inspector کو آپ کے average سے غرض نہیں — وہ tolerance سے باہر واحد part کو reject کرتا ہے۔

NumPy یہاں pure-Python perceptron کے ایک chapter بعد ایک وجہ سے آتا ہے: اس chapter کے آخر تک ہم چار لاکھ candidate lines کو، ہر ایک کو بیس readings کے against، evaluate کرتے ہیں، اور Python loop اس کے لیے غلط tool ہے۔ یہ وہ notation بھی ہے جس میں نیچے cited ہر source لکھی گئی ہے۔

loss.pyPYTHON
import numpy as np

# Hours since the blade was changed, and the width of the part measured then.
SHIFT = np.array([
    (0.5, 20.17), (1.0, 20.28), (1.5, 20.53), (2.0, 20.61), (2.5, 20.69),
    (3.0, 20.94), (3.5, 21.21), (4.0, 21.31), (4.5, 21.27), (5.0, 21.35),
    (5.5, 21.58), (6.0, 21.80), (6.5, 21.67), (7.0, 22.07), (7.5, 22.10),
    (8.0, 22.31), (8.5, 22.48), (9.0, 22.66), (9.5, 22.90), (10.0, 23.13),
])
h, y = SHIFT[:, 0], SHIFT[:, 1]

LINES = {"A": (20.10, 0.26), "B": (20.20, 0.28), "C": (20.30, 0.26)}

for name, (a, b) in LINES.items():
    r = y - (a + b * h)                                      
    print(f"{name}   mean square {np.mean(r**2):.5f}"
          f"   mean absolute {np.mean(np.abs(r)):.5f}"
          f"   worst {np.max(np.abs(r)):.3f}")               

highlighted lines میں quantity residual ہے: line نے کیا کہا minus caliper نے کیا کہا، ہر reading کے لیے ایک number۔ اس chapter کا ہر scoring rule، اور اس کے بعد آنے والے اٹھائیس chapters کا ہر loss function، residuals کی list کو ایک single number میں squash کرنے کا کوئی طریقہ ہے۔ فرق صرف یہ ہے کہ وہ squash کیسے کرتے ہیں۔

TEXT
A   mean square 0.02699   mean absolute 0.12600   worst 0.430
B   mean square 0.02524   mean absolute 0.13700   worst 0.350
C   mean square 0.03179   mean absolute 0.15000   worst 0.320

columns پڑھیں، rows نہیں۔ squared error کہتا ہے B، absolute error کہتا ہے A، worst error کہتا ہے C: ایک ہی بیس points پر تین rules، تین winners۔

میں نے یہ تین lines اس طرح چنی تھیں کہ وہ disagree کریں، اور مجھے یہ صاف کہنا چاہیے۔ point یہ ہے کہ یہ کتنا آسان تھا — sensible-looking intercepts اور slopes پر چند منٹ کی search ایسے سینکڑوں triples نکال دیتی ہے۔ ranking آپ کے chosen rule کی خاصیت ہے، lines کے بارے میں fact نہیں، لہٰذا rule implementation detail نہیں: وہ problem کی definition ہے۔ جس سے وہ سوال اٹھتا ہے جس کا جواب دینے کے لیے یہ chapter ہے: آپ اسے کن بنیادوں پر choose کرتے ہیں؟

پہلے ایک چھوٹی بات، کیونکہ lines تین نہیں بلکہ infinitely many ہیں۔ فی الحال squared error لیں، چونکہ سب یہی لیتے ہیں، اور اس trick سے problem کو ایک single number تک shrink کریں جس نے Chapter 1 میں perceptron کو گیارہ ہزار epochs بچائے تھے: دونوں columns سے mean subtract کریں۔ جب points کا cloud origin پر centred ہو جائے تو squared error کے تحت best line عین origin سے گزرتی ہے — so intercept settle ہو گیا اور choose کرنے کو صرف slope رہ گیا۔

loss.py (continued)PYTHON
u, v = h - h.mean(), y - y.mean()        # 5.25 hours, 21.553 mm

def mse(theta):
    return np.mean((v - theta * u) ** 2)

grid = np.arange(0.0, 0.6001, 0.001)
curve = np.array([mse(t) for t in grid])
print(grid.size, "candidates ->", f"theta={grid[curve.argmin()]:.3f}", f"mse={curve.min():.6f}")
TEXT
601 candidates -> theta=0.293 mse=0.010115

چھ سو ایک candidate slopes، ایک winner: 0.293 ملی میٹر per hour، truth 0.300 کے مقابلے میں۔ بیس noisy readings اور ایک for-loop ایک ملی میٹر فی گھنٹہ کے سوویں حصے تک پہنچ گئے — دو اور ایک تہائی percent۔

دلچسپ چیز winner نہیں بلکہ search کی shape ہے۔ پوری curve print کریں، rotate کر کے تاکہ loss left to right چلے:

loss.py (continued)PYTHON
ts = np.arange(0.0, 0.6001, 0.04)
ls = np.array([mse(t) for t in ts])
for t, l in zip(ts, ls):
    col = round(l / ls.max() * 50)
    print(f"theta={t:.2f} |{' ' * col}*{' ' * (50 - col)}| mse={l:7.4f}")
TEXT
theta=0.00 |                                              *    | mse= 0.7244
theta=0.04 |                                  *                | mse= 0.5428
theta=0.08 |                        *                          | mse= 0.3878
theta=0.12 |                *                                  | mse= 0.2593
theta=0.16 |          *                                        | mse= 0.1575
theta=0.20 |     *                                             | mse= 0.0822
theta=0.24 |  *                                                | mse= 0.0336
theta=0.28 | *                                                 | mse= 0.0116
theta=0.32 | *                                                 | mse= 0.0161
theta=0.36 |   *                                               | mse= 0.0473
theta=0.40 |       *                                           | mse= 0.1050
theta=0.44 |            *                                      | mse= 0.1894
theta=0.48 |                   *                               | mse= 0.3004
theta=0.52 |                            *                      | mse= 0.4379
theta=0.56 |                                      *            | mse= 0.6021
theta=0.60 |                                                  *| mse= 0.7928

یہ ایک valley ہے، side سے دیکھی ہوئی۔ اس کا ایک bottom ہے، walls دونوں طرف smoothly اوپر جاتے ہیں، اور — یہ وہ حصہ ہے جو Chapter 1 کی staircase نہیں دے سکتی تھی — اس پر ہر single point پر "downhill" کی well-defined direction موجود ہے۔ اس shape کو یاد رکھیں۔ Chapter 3 پورا اس بات پر ہے کہ تمام چھ سو ایک points visit کیے بغیر اس کے نیچے کیسے walk کیا جائے، اور جب valley کے ایک سے زیادہ bottom ہوں تو کیا بدلتا ہے۔

ہمare پاس valley اس لیے ہے کہ ہم نے square کیا۔ absolute error bottom پر kink دیتا؛ worst error flat stretches دیتا جہاں line کو move کرنے سے کچھ بھی نہیں بدلتا۔ Squaring بے شک convenient ہے — اور convenience ہی تقریباً وہ وجہ ہے جو زیادہ تر courses چار انداز میں سجا کر دیتے ہیں: یہ errors کو positive بنا دیتا ہے (absolute value بھی بناتی ہے)؛ یہ بڑے errors کو زیادہ punish کرتا ہے (کیوں کرنا چاہیے؟)؛ یہ differentiable ہے (fourth power بھی ہے)؛ یہ وہی ہے جو سب use کرتے ہیں (ہے، اور یہ argument نہیں)۔

ایمان دار position یہ ہے۔ squared error نے line B select کی اور absolute error نے line A۔ ان میں سے ایک اس factory کے لیے right ہے اور دوسری wrong، اور اب تک کہی گئی کوئی بات نہیں بتا سکتی کہ کون سی۔ rule choose کرنے کے لیے آپ کو کچھ جاننا ہو گا کہ readings line سے different کیسے ہوئیں، اور یہ mathematics کے بارے میں نہیں بلکہ world کے بارے میں سوال ہے۔ اس کا جواب دینے کے لیے machinery کا ایک چھوٹا ٹکڑا چاہیے۔

یہ وہ claim ہے جو "کون سی line بہتر ہے" کو ایک answer والے سوال میں بدلتا ہے۔

Assume کریں part کی width line plus random error ہے، اور assume کریں کہ error Gaussian — bell curve — سے draw ہوئی ہے، mean zero اور standard deviation σ\sigma کے ساتھ:

yi=θxi+εi,εiN(0,σ2)y_i = \theta x_i + \varepsilon_i, \qquad \varepsilon_i \sim \mathcal{N}(0, \sigma^2)

Gaussian کی density ہے

p(ε)=1σ2πexp ⁣(ε22σ2)p(\varepsilon) = \frac{1}{\sigma\sqrt{2\pi}} \exp\!\left(-\frac{\varepsilon^2}{2\sigma^2}\right)

اب وہ کریں جو perceptron نہیں کر سکتا تھا۔ ایک given candidate slope θ\theta کے لیے ہر reading کا residual ہے، اور اوپر کی formula اس residual کو ایک number میں بدلتی ہے: اگر یہ slope truth ہے تو exactly اس size کی error کتنی plausible ہے؟ line پر پڑی reading کو بڑا number ملتا ہے، آدھا millimetre دور reading کو چھوٹا۔

readings independent ہیں — caliper پچھلے part کو remember نہیں کرتا — so product rule کہتا ہے کہ whole notebook کی plausibility individual densities کا product ہے۔ یہی product θ\theta کی likelihood ہے۔1 direction note کریں، کیونکہ Bayes' rule اسی direction کے بارے میں ہے: data fixed اور known ہے، اور parameter vary کرتا ہے۔ یہ "slope کی probability" نہیں۔ یہ وہ probability ہے جو model آپ کو actually ملے data کو assign کرتا ہے، slope کے function کے طور پر read کی ہوئی۔

likelihood.pyPYTHON
SIGMA = 0.12

def gaussian(r, sigma):
    return np.exp(-r ** 2 / (2 * sigma ** 2)) / (sigma * np.sqrt(2 * np.pi))

def likelihood(theta):
    return np.prod(gaussian(v - theta * u, SIGMA))          

for t in (0.25, 0.293, 0.35):
    print(f"theta={t}   likelihood = {likelihood(t):.6g}")
TEXT
theta=0.25   likelihood = 521.952
theta=0.293   likelihood = 2.42028e+07
theta=0.35   likelihood = 0.190312

0.293 کا slope اس notebook کو 0.25 کے مقابلے میں چھیالیس ہزار times زیادہ plausible بناتا ہے، اور 0.35 کے مقابلے میں ایک سو ستائیس million times زیادہ plausible۔ Maximum likelihood وہ principle ہے کہ آپ وہ parameter pick کرتے ہیں جو آپ نے actually observe کیا اسے as unsurprising as possible بنائے۔ یہ theorem نہیں بلکہ proposal ہے کہ "best" کا مطلب کیا ہونا چاہیے — content والا proposal، کیونکہ یہ آپ کو noise کے بارے میں اپنا assumption state کرنے پر مجبور کرتا ہے، اس سے پہلے کہ آپ کچھ score کر سکیں۔

ایک shift کے بجائے پورے مہینے کی shifts پر وہی تین lines of code چلائیں، اور method گر پڑتا ہے۔

likelihood.py (continued)PYTHON
rng = np.random.default_rng(7)
u_big = rng.uniform(-5.25, 5.25, 2000)                     # 2000 readings, not 20
v_big = 0.30 * u_big + 0.12 * rng.standard_normal(2000)

print("2000 readings, sigma = 0.12 mm :", np.prod(gaussian(v_big - 0.30 * u_big, 0.12)))
noisy = 0.30 * u_big + 2.0 * rng.standard_normal(2000)
print("2000 readings, sigma = 2.00 mm :", np.prod(gaussian(noisy - 0.30 * u_big, 2.0)))
print("largest float64 :", np.finfo(np.float64).max)
TEXT
RuntimeWarning: overflow encountered in reduce
2000 readings, sigma = 0.12 mm : inf
2000 readings, sigma = 2.00 mm : 0.0
largest float64 : 1.7976931348623157e+308

دو ہزار multiplications اور answer inf ہے۔ ایک constant بدلیں — sloppier caliper، تاکہ densities 1 سے large کے بجائے smaller نکلیں — اور وہی code 0.0 return کرتا ہے۔ دونوں answers غلط ہیں، opposite directions میں، neither کوئی exception raise کرتا ہے جسے آپ catch کر سکیں، اور دوسرا تو warning بھی print نہیں کرتا۔

mathematics میں کچھ غلط نہیں۔ ان settings پر likelihood ایک perfectly well-defined finite number ہے: اس کا natural logarithm 1400.91 ہے، so number خود تقریباً 1060810^{608} ہے۔ problem یہ ہے کہ آپ کے computer کے پاس وہ number نہیں، اور یہ سمجھنا worth ہے کہ اس کے پاس exactly کون سے numbers ہیں، کیونکہ یہ آخری بار نہیں جب یہ outcome decide کرے گا۔

exploding product کا fix معمول والا ہے: logarithms لیں۔ logarithm products کو sums میں بدلتا ہے، یہ strictly increasing ہے so maximum کی location نہیں بدل سکتا، اور دو ہزار moderate numbers کا sum ایسی چیز ہے جسے float64 بغیر شکایت handle کر لیتا ہے۔ convention سے ہم negative log-likelihood لیتے ہیں، تاکہ better کا مطلب smaller ہو۔ اب Gaussian density substitute کریں اور دیکھیں کیا ہوتا ہے۔

  1. product سے start کریں۔ likelihood L(θ)=i=1Np(yiθxi)\mathcal{L}(\theta) = \prod_{i=1}^{N} p(y_i - \theta x_i) ہے، جہاں pp اوپر والی Gaussian density ہے۔

  2. minus log لیں۔ product sum بن جاتا ہے، اور density میں exponential logarithm کے against outright cancel ہو جاتا ہے:

logL(θ)=N2log ⁣(2πσ2)+12σ2i=1N(yiθxi)2-\log \mathcal{L}(\theta) = \frac{N}{2}\log\!\left(2\pi\sigma^2\right) + \frac{1}{2\sigma^2}\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2
  1. ہر وہ چیز پھینک دیں جس میں θ\theta نہیں۔ پہلا term constant ہے۔ sum کے سامنے 1/2σ21/2\sigma^2 positive constant ہے، اور کسی function کو positive constant سے scale کرنے سے اس کا minimum کہاں ہے نہیں بدل سکتا۔ جو باقی بچتا ہے وہ ہے
i=1N(yiθxi)2\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2

جو squared residuals کا sum ہے — وہی چیز جس سے ہم نے chapter شروع کیا تھا کیونکہ یہی پہلی چیز ہے جو کسی کے ذہن میں آتی ہے۔

یہ وہ result ہے جس کے لیے یہ chapter موجود ہے، اور اسے بغیر hedging کے state کرنا چاہیے: squared error کوئی convention نہیں۔ یہ Gaussian کی negative log-likelihood ہے، constants removed کے ساتھ۔ squared error minimise کرنا عین وہی act ہے جیسے assert کرنا کہ آپ کی errors Gaussian ہیں اور پوچھنا کہ کون سا parameter آپ کے data کو least surprising بناتا ہے۔ آپ یہ assertion شروع سے کر رہے تھے؛ بس آپ کو بتایا نہیں جا رہا تھا۔

equivalence checkable ہے، so check کریں: وہی چھ سو ایک slopes full negative log-likelihood، constants and all، کے ساتھ scan کریں، اور plain squared error کے ساتھ بھی۔

likelihood.py (continued)PYTHON
N = v.size

def nll(theta):
    r = v - theta * u
    return N * np.log(SIGMA * np.sqrt(2 * np.pi)) + np.sum(r ** 2) / (2 * SIGMA ** 2)

nlls = np.array([nll(t) for t in grid])
mses = np.array([mse(t) for t in grid])
print(f"argmin of the negative log-likelihood : theta={grid[nlls.argmin()]:.3f}  nll={nlls.min():.6f}")
print(f"argmin of the mean squared error      : theta={grid[mses.argmin()]:.3f}  mse={mses.min():.6f}")
print("same index:", nlls.argmin() == mses.argmin())
TEXT
argmin of the negative log-likelihood : theta=0.293  nll=-17.001977
argmin of the mean squared error      : theta=0.293  mse=0.010115
same index: True

vertical axis پر different numbers، اور ان میں سے ایک negative ہے، جو sum of squares کبھی نہیں ہوتا: negative log-likelihood zero سے نیچے جا سکتی ہے، کیونکہ density 1 سے exceed کر سکتی ہے۔ same valley کا same bottom، last grid point تک۔

مکمل اخذ دکھائیں

کون سے discards exactly safe ہیں؟ یہی manoeuvre ہر chapter میں آتا ہے جو loss derive کرتا ہے، اور یہ ہمیشہ innocent نہیں ہوتا۔

additive constant drop کرنا safe ہے جب بھی وہ اس parameter پر depend نہ کرے جسے آپ optimise کر رہے ہیں، اور positive multiplicative constant drop کرنا safe ہے کیونکہ کسی بھی c>0c > 0 کے لیے argminθcf(θ)=argminθf(θ)\arg\min_\theta c\,f(\theta) = \arg\min_\theta f(\theta)۔ دونوں اسی لمحے fail ہوتے ہیں جب σ\sigma بھی fit کیا جا رہا ہو: پھر N2log(2πσ2)\frac{N}{2}\log(2\pi\sigma^2) constant بالکل نہیں، یہی term ہے جو model کو σ=0\sigma = 0 اور infinite plausibility claim کرنے سے روکتا ہے۔ یہی اگلا section ہے۔

Chapter 3 میں وہ پھر differently fail ہوتے ہیں: multiplicative constant minimum کو move نہیں کرتا، مگر یہ gradient کو scale کرتا ہے، اور gradient learning rate سے multiplied ہوتا ہے۔ NN سے divide کر کے mean squared error حاصل کرنا، sum کے بجائے، answer کے لیے invisible اور training run کے لیے highly visible ہے — sum کے ساتھ، batch size double کرنے سے آپ کا ہر step double ہو جاتا ہے۔

ہم نے σ\sigma کو fiat سے 0.12 پر fix کیا، اور plant میں کسی کو اپنے caliper کی error کا spread معلوم نہیں۔ اسے second unknown سمجھیں اور maximum likelihood کو اسے بھی decide کرنے دیں۔ یہاں constant term جسے ہم ابھی discard کر رہے تھے واپس آتا ہے، کیونکہ یہی واحد چیز ہے جو model اور perfect precision کے claim کے بیچ کھڑی ہے۔

likelihood.py (continued)PYTHON
r = v - 0.293 * u
sigmas = np.arange(0.01, 1.0001, 0.0001)
nll_sigma = N * np.log(sigmas * np.sqrt(2 * np.pi)) + np.sum(r ** 2) / (2 * sigmas ** 2)

print("best sigma on the grid       :", round(float(sigmas[nll_sigma.argmin()]), 4))
print("sqrt(mean squared residual)  :", round(float(np.sqrt(np.mean(r ** 2))), 4))
TEXT
best sigma on the grid       : 0.1006
sqrt(mean squared residual)  : 0.1006

دونوں four decimals تک agree کرتے ہیں، اور accidentally نہیں: اس expression کو differentiate کر کے zero پر set کرنے سے exactly σ^2=1Nri2\hat{\sigma}^2 = \frac{1}{N}\sum r_i^2 ملتا ہے۔ so mean squared error محض variance جیسا نہیں۔ اس model کے تحت یہ noise کی variance کا maximum-likelihood estimate ہے — جس number کو آپ شروع سے minimise کر رہے تھے وہ اصل میں یہ estimate تھا کہ آپ کا sensor کتنا noisy ہے۔

ایک wrinkle، کہنا cheap اور بعد میں rediscover کرنا expensive: یہ estimate low biased ہے، کیونکہ residuals ایک ایسے fit کے against measure ہوئے جو خود انہیں small بنانے کے لیے chosen تھا۔ اسے simulate کریں — بیس readings کی دو لاکھ notebooks، ایسی distribution سے drawn جس کی true variance exactly 1 ہے، fit کا ایک parameter خود readings سے estimated۔ sum of squares کو NN سے divide کرنے سے average 0.9501 آتا ہے؛ N1N-1 سے divide کرنے سے 1.0001؛ اور (N1)/N(N-1)/N exact 0.95 ہے۔ ہر parameter جو آپ fit کرتے ہیں ایک degree of freedom cost کرتا ہے، اور یہ بہت بڑے problem کی smallest visible instance ہے: model ہمیشہ اس data پر بہتر دکھتا ہے جس پر اسے fit کیا گیا۔ Chapter 4 اسے data hold back کرنے کی discipline میں بدلتا ہے، اور Chapter 6 effect کو اس کا نام دیتا ہے۔

اگر squared error assert کرتا ہے کہ noise Gaussian ہے، اگلا سوال یہ ہے کہ جب assertion false ہو تو کیا ہوتا ہے۔ تھوڑا false نہیں — اس طرح false جیسے real measurements false ہوتی ہیں۔

shop floor پر زیادہ تر caliper readings ایک tenth of a millimetre تک اچھی ہوتی ہیں، اور shift میں ایک دو بار swarf کا chip jaw کے نیچے آ جاتا ہے اور reading کئی millimetres off ہو جاتی ہے۔ ایسی errors heavy-tailed ہیں: زیادہ تر small، کبھی کبھار enormous، اور enormous اتنی بار جتنی bell curve allow نہیں کرتی۔ Cauchy distribution اس behaviour کا standard clean model ہے، اور اس کی density Gaussian کی طرح simple ہے:

p(ε)=1πs(1+(ε/s)2)p(\varepsilon) = \frac{1}{\pi s \left(1 + (\varepsilon/s)^2\right)}

فرق tail ہے: Gaussian eε2e^{-\varepsilon^2} کی طرح fall off کرتا ہے، brutally fast، اور Cauchy 1/ε21/\varepsilon^2 کی طرح، بمشکل ہی۔ consequence کہنا آسان نہیں مگر دیکھنا آسان ہے:

PYTHON
rng = np.random.default_rng(3)
g = 0.12 * rng.standard_normal(10 ** 6)          # Gaussian noise
c = 0.12 * rng.standard_cauchy(10 ** 6)          # Cauchy noise, same scale
for k in (10 ** 2, 10 ** 3, 10 ** 4, 10 ** 5, 10 ** 6):
    print(f"{k:>9,} samples   gaussian var {g[:k].var():.4f}   cauchy var {c[:k].var():10.2f}")
TEXT
      100 samples   gaussian var 0.0164   cauchy var       0.26
    1,000 samples   gaussian var 0.0146   cauchy var      59.88
   10,000 samples   gaussian var 0.0145   cauchy var     358.17
  100,000 samples   gaussian var 0.0144   cauchy var    3097.98
1,000,000 samples   gaussian var 0.0144   cauchy var   32886.10

Gaussian کا sample variance 0.0144 پر settle ہوتا ہے، جو 0.1220.12^2 ہے، اور وہیں رہتا ہے۔ Cauchy کا چڑھتا ہے، اور sample کرتے رہنے تک چڑھتا رہتا ہے، کیونکہ converge کرنے کو کچھ ہے ہی نہیں: Cauchy distribution کی variance نہیں، اور mean بھی نہیں۔ squared error، جس کا whole business squares کے average کو minimise کرنا ہے، ایسی quantity مانگ رہا ہے جو exist نہیں کرتی۔

تو یہ ایک shift ہے جہاں caliper fool ہوا۔ وہی بیس hours، وہی blade، وہی 0.30 ملی میٹر per hour کا drift — صرف noise اب Cauchy ہے۔ اسے دو بار fit کریں: ایک بار squared residuals minimise کر کے، ایک بار اس noise کی negative log-likelihood minimise کر کے جس نے actually data generate کیا۔ centring trick یہاں help نہیں — یہ intercept کو صرف squared error کے لیے pin کرتی ہے — so دونوں fits intercepts اور slopes کے grid پر brute force سے جاتے ہیں، کیونکہ ہمارے پاس اب بھی valley کا bottom ڈھونڈنے کا کوئی طریقہ نہیں سوائے اسے visit کرنے کے۔

swarf.pyPYTHON
SWARF = np.array([
    (0.5, 20.08), (1.0, 21.95), (1.5, 20.86), (2.0, 27.51), (2.5, 20.64),
    (3.0, 20.75), (3.5, 21.01), (4.0, 21.03), (4.5, 21.37), (5.0, 20.60),
    (5.5, 22.03), (6.0, 21.95), (6.5, 21.98), (7.0, 22.01), (7.5, 21.73),
    (8.0, 22.97), (8.5, 22.60), (9.0, 22.66), (9.5, 22.44), (10.0, 22.78),
])
hs, ys = SWARF[:, 0], SWARF[:, 1]

A = np.arange(18.0, 22.001, 0.005)      # 801 intercepts
B = np.arange(-0.20, 0.8001, 0.002)     # 501 slopes
R = ys - (A[:, None, None] + B[None, :, None] * hs)      # every line against every point

SCALE = 0.12
square = np.sum(R ** 2, axis=2)                          # least squares          
cauchy = np.sum(np.log(1 + (R / SCALE) ** 2), axis=2)    # Cauchy likelihood      

for name, surface in (("least squares", square), ("Cauchy likelihood", cauchy)):
    i, j = np.unravel_index(surface.argmin(), surface.shape)
    print(f"{name:>18}:  width = {A[i]:.3f} + {B[j]:.4f} * hours"
          f"   -> 23.5 mm at hour {(23.5 - A[i]) / B[j]:.2f}")
print(f"{'the truth':>18}:  width = 20.000 + 0.3000 * hours"
      f"   -> 23.5 mm at hour {(23.5 - 20.0) / 0.30:.2f}")
print(f"{A.size * B.size:,} candidate lines evaluated")

دو highlighted lines ہی fits کے درمیان entire difference ہیں۔ Cauchy density کا log لیں، constants پہلے کی طرح exactly drop کریں، اور log(1+(r/s)2)\sum \log\left(1 + (r/s)^2\right) باقی بچتا ہے۔ same recipe، noise کے بارے میں different claim۔

TEXT
     least squares:  width = 21.380 + 0.1080 * hours   -> 23.5 mm at hour 19.63
 Cauchy likelihood:  width = 19.935 + 0.3020 * hours   -> 23.5 mm at hour 11.80
         the truth:  width = 20.000 + 0.3000 * hours   -> 23.5 mm at hour 11.67
401,301 candidate lines evaluated

Least squares 0.108 ملی میٹر فی گھنٹہ کا drift report کرتا ہے، real rate کے تقریباً ایک تہائی، اور conclude کرتا ہے کہ blade hour 19.6 تک good ہے۔ true answer hour 11.7 ہے۔ اس fit پر عمل کرتے ہوئے plant press کو آٹھ extra hours چلاتا ہے اور field کے سب سے standard loss function کے authority پر tolerance سے باہر parts بناتا رہتا ہے۔ Cauchy fit، وہی بیس readings، وہی grid، اور code میں ایک line کے فرق سے، hour 11.8 پر land کرتا ہے۔

دو objections answers deserve کرتے ہیں، کیونکہ دونوں وہ پہلی بات ہیں جو اچھا engineer کہتا ہے۔

outlier obvious ہے — بس اسے delete کر دیں۔ آپ کر سکتے ہیں، اور اس سے help ہوتی ہے، مگر یہ enough نہیں۔ single worst reading delete کرنے سے least-squares slope 0.108 سے 0.239 ہو جاتا ہے، جو پھر بھی blade change کو hour 13.1 پر رکھتا ہے، ڈیڑھ گھنٹہ late؛ worst کو delete کر کے، refit کر کے، اور جو اب worst ہے اسے delete کرنے سے آپ 0.286 تک پہنچتے ہیں — اور note کریں کہ یہ پہلے ہی ایک procedure ہے، observation نہیں: original fit کے دو largest residuals delete کریں تو آپ 0.223 پر land کرتے ہیں۔ مگر اب آپ نے judgement calls کر لی ہیں جنہیں آپ write down یا defend نہیں کر سکتے، اور rule automate کرنا اسے rescue نہیں کرتا: drop-the-largest-residual-then-refit، ایک ہزار simulated shifts پر run کیا گیا، likelihood fit کے 0.0100 کے مقابلے میں 0.0177 کا median slope error رکھتا ہے، اور shifts کے 14.7% میں 0.05 سے زیادہ off ہے، 1.3% کے مقابلے میں۔ deletion wrong assumption کے اوپر patch ہے۔ likelihood کو patch نہیں چاہیے، کیونکہ اس نے کبھی assume نہیں کیا کہ outlier impossible ہے۔

آپ نے lucky dataset pick کیا۔ یہ objection بالکل right ہے، اسی لیے last experiment ایک ہزار independent shifts simulate کرتا ہے اور ہر ایک پر دونوں ways refit کرتا ہے۔

swarf.py (continued)PYTHON
A = np.arange(18.0, 22.001, 0.02)        # a coarser grid: a thousand fits to do
B = np.arange(-0.20, 0.8001, 0.005)
lines = A[:, None, None] + B[None, :, None] * hs
rng = np.random.default_rng(2026)
err_sq, err_ca = [], []

for _ in range(1000):                                        # 1000 independent shifts
    ys = 20.00 + 0.30 * hs + SCALE * rng.standard_cauchy(hs.size)
    R = ys - lines
    _, j = np.unravel_index(np.sum(R ** 2, axis=2).argmin(), (A.size, B.size))
    _, q = np.unravel_index(np.sum(np.log1p((R / SCALE) ** 2), axis=2).argmin(), (A.size, B.size))
    err_sq.append(abs(B[j] - 0.30))
    err_ca.append(abs(B[q] - 0.30))

err_sq, err_ca = np.array(err_sq), np.array(err_ca)
for name, e in (("least squares", err_sq), ("Cauchy likelihood", err_ca)):
    print(f"{name:>18}: median slope error {np.median(e):.4f} mm/h"
          f"   off by more than 0.05 in {100 * np.mean(e > 0.05):4.1f}% of shifts"
          f"   worst {e.max():.3f}")
print(f"the likelihood fit is the closer of the two in {100 * np.mean(err_ca < err_sq):.1f}% of shifts")
TEXT
     least squares: median slope error 0.0350 mm/h   off by more than 0.05 in 40.4% of shifts   worst 0.500
 Cauchy likelihood: median slope error 0.0100 mm/h   off by more than 0.05 in  1.3% of shifts   worst 0.090
the likelihood fit is the closer of the two in 75.6% of shifts

Median، mean نہیں، اسی وجہ سے جس وجہ سے اس section میں ہر چیز ہے: least-squares errors Cauchy سے driven ہیں، so ان کا average report کرنے کے لیے stable چیز نہیں۔ Least squares پانچ میں سے دو shifts میں badly wrong ہے؛ likelihood fit ستتر میں سے ایک shift میں badly wrong ہے، اور ایک ہزار shifts میں اس کی worst failure least squares کی worst کا پانچواں حصہ بھی نہیں۔

اس میں سے کچھ بھی squared error کو bad نہیں بناتا۔ یہ اسے specific بناتا ہے، اور arithmetic exactly بتاتی ہے کیوں۔ 0.1 mm کا residual اور 7 mm کا residual لیں۔ Squared، bad reading total میں good reading کے مقابلے میں 4,900 times زیادہ contribute کرتی ہے، so line bodily اس کی طرف dragged ہو جاتی ہے؛ Cauchy log-likelihood کے تحت وہی دو residuals 0.527 اور 8.133 contribute کرتے ہیں، ratio 15.4۔ bad reading اب بھی count کرتی ہے، بس decide کرنے نہیں پاتی۔ یہی robust statistics کی beginning ہے، جہاں Huber کا 1964 loss small residuals کے لیے quadratically اور large ones کے لیے linearly behave کر کے فرق split کرتا ہے،7 اور جہاں Tukey پہلے ہی دکھا چکا تھا کہ sample variance کو mean absolute deviation سے worse tool بنانے کے لیے کتنی کم contamination کافی ہے۔8

ایک historical note بھی، اتنا اچھا کہ چھوڑا نہیں جا سکتا۔ Least squares پہلے Legendre نے 1805 میں publish کیا، ایک convenient algebraic device کے طور پر جس کی justification بس یہ تھی کہ یہ کام کرتا تھا۔9 چار سال بعد Gauss نے argument کو الٹا چلایا: اس نے given لیا کہ repeated measurements combine کرنے کا right way arithmetic mean ہے، پوچھا کہ کون سی error distribution mean کو most probable value بناتی ہے، اور دکھایا کہ essentially صرف ایک کرتی ہے — وہ جو اب اس کے نام سے ہے۔10 اس chapter کی derivation اسی کی ہے، دو centuries سے زیادہ پرانی ہے، اور پھر بھی وہی part ہے جو زیادہ تر courses چھوڑ دیتے ہیں۔

اب آپ کیا کہہ سکتے ہیں، اور ابھی کیا نہیں کر سکتے

اس حصے کا لنک: اب آپ کیا کہہ سکتے ہیں، اور ابھی کیا نہیں کر سکتے

Earned۔ loss function ایک scoring rule ہے، اور جو ranking یہ produce کرتا ہے وہ rule کی property ہے، candidates کی نہیں۔ اس course کا ہر loss noise کے بارے میں کسی assumption کی negative log-likelihood ہے، constants thrown away کے ساتھ — Gaussian یہاں squared error دیتا ہے، Bernoulli Chapter 4 میں cross-entropy دیتا ہے، اور vocabulary پر categorical distribution Chapter 8 میں next-token loss دیتا ہے۔ recipe کبھی نہیں بدلتی: noise state کریں، likelihood لکھیں، minus log لیں۔ اور جب assumption wrong ہو تو model محض imprecise نہیں، وہ ایسی direction میں wrong ہے جسے آپ predict کر سکتے ہیں۔

Still missing۔ ہم نے valley کا bottom اس میں موجود ہر point visit کر کے پایا۔ یہ one parameter اور six hundred candidates کے لیے کام کر گیا، اور two parameters پر 401,301 candidates کے ساتھ ایک second کے پانچویں حصے میں survive کر گیا۔ same resolution پر three parameters 201,051,801 candidates ہیں اور ایک array میں fit نہیں ہوتے؛ Chapter 5 کا small network thousands of parameters رکھتا ہے، اور Chapter 10 جن models کی قیمت لگاتا ہے ان کے billions ہیں۔ brute force یہاں slow نہیں، arithmetically impossible ہے، اور اس chapter میں کچھ بھی alternative suggest نہیں کرتا۔

مگر valley کو دوبارہ دیکھیں۔ θ=0.20\theta = 0.20 پر 0.0822 loss کے ساتھ کھڑے ہوں تو "downhill" کی direction mystery نہیں — آپ page پر دیکھ سکتے ہیں، curve right کی طرف down slope کرتی ہے۔ اگر آپ loss function سے پوچھ سکیں کہ وہ اس point پر جہاں آپ کھڑے ہیں کس طرف slope کرتی ہے، کہیں اور evaluate کیے بغیر، تو آپ اسی طرف step لے سکتے ہیں، دوبارہ پوچھ سکتے ہیں، اور repeat کر سکتے ہیں جب تک زمین flat نہ ہو جائے۔

اس سوال کا ایک نام ہے۔ کسی point پر function کا slope اس کا derivative ہے، اور many parameters کے function کے لیے ہر direction میں slopes کا collection gradient ہے۔ Chapter 1 اسے use نہیں کر سکتا تھا، کیونکہ perceptron کی error ایسی staircase تھی جس سے slope پوچھا ہی نہیں جا سکتا تھا۔ اس chapter نے کچھ بہتر بنایا ہے: ایک loss جو ہر جگہ smooth ہے اور جو preference کے بجائے stated assumption سے آیا ہے۔

لہٰذا Chapter 3 کا سوال اب یہ نہیں کہ slope exists ہے یا نہیں۔ سوال یہ ہے کہ اسے compute کیسے کیا جائے، اس کے against move کرنا uphill کے بجائے downhill کیوں جاتا ہے — ایک sign جسے تقریباً ہر course آپ سے faith پر لینے کو کہتا ہے — اور دوبارہ پوچھنے سے پہلے کتنا step لیا جائے، جو نکلتا ہے وہی ایک number ہے جو decide کرتا ہے کہ training run converge کرے گا، answer کے around ہمیشہ oscillate کرے گا، یا infinity کی طرف بھاگ جائے گا۔


اس chapter کے ساتھ یہ بھی پڑھنے کے قابل ہیں: Prince, Understanding Deep Learning §5.1–5.2 and Appendix C، جو یہاں used order میں book کا ہر loss maximum likelihood سے build کرتا ہے؛ Goodfellow, Bengio and Courville, Deep Learning §3.1–3.11 and §5.5، whose maximum-likelihood section وہ KL divergence بھی derive کرتا ہے جو Chapter 4 کو چاہیے؛ Murphy, Probabilistic Machine Learning: An Introduction chapter 2 and §4.2، اس پر کہ maximum likelihood کیا guarantee کرتا ہے اور کیا نہیں؛ Deisenroth, Faisal and Ong, Mathematics for Machine Learning §6.1–6.4 for the sum rule, product rule and Bayes' rule done properly؛ Tom Mitchell کا short CMU note Estimating Probabilities: MLE and MAP (2016)؛ اور Dive into Deep Learning کا §22.7، جو runnable code میں same result تک پہنچتا ہے۔

  1. Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, pp. 309–368 (1922). جہاں likelihood کو general method کے طور پر set out کیا گیا، ساتھ میں "parameter"، "statistic"، sufficiency اور efficiency۔ naming خود، اور probability سے separation، ایک سال پہلے ہے: Fisher, R. A., On the “probable error” of a coefficient of correlation deduced from a small sample, Metron 1, pp. 3–32 (1921), pp. 24–25.

  2. IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. binary32 اور binary16، اور rounding rules define کرتا ہے جو summation experiment کو ویسا outcome دیتے ہیں۔

  3. Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). format کے parameters، اور mantissa bits کو exponent bits کے لیے trade کرنے کا case۔

  4. Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling، اور measured gradient magnitudes جو float16 میں اسے necessary بناتے ہیں۔

  5. Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), pp. 5–48 (1991). اب بھی best single explanation کہ summation کے دو orders disagree کیوں کرتے ہیں۔

  6. Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), p. 40 (1965). آدھے page میں compensated summation۔

  7. Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), pp. 73–101 (1964). وہ loss جو zero کے near quadratic اور tails میں linear ہے، patched together کے بجائے derived۔

  8. Tukey, J. W. A survey of sampling from contaminated distributions, in Contributions to Probability and Statistics (Stanford University Press, 1960), pp. 448–485.

  9. Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paris, 1805), appendix Sur la méthode des moindres quarrés. least squares کی پہلی publication، computational device کے طور پر۔

  10. Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Book II, §§175–179. arithmetic mean سے normal error law تک، اور وہاں سے least squares تک argument۔


تیار کردہ

David Vicente Campos

NeuraLIA Labs کے بانی اور MyRealFood کے شریک بانی

میں یونیورسٹی آف لیون سے کمپیوٹر انجینئر ہوں۔ میں نے MyRealFood کی مشترکہ بنیاد رکھی، جہاں بطور CTO میں نے وہ ایپ بنائی جسے لاکھوں لوگ بہتر غذا کے لیے استعمال کر چکے ہیں، اور میں نے NeuraLIA Labs قائم کیا، جہاں میں AI مصنوعات بناتا ہوں۔ یہاں میں ان باتوں کے بارے میں لکھتا ہوں جو اس سفر میں مجھے سمجھنی پڑیں، اس طرح جس طرح کاش کسی نے مجھے سمجھائی ہوتیں۔

مصنف کے بارے میں مزید

NeuraLIA Labs کی جانب سے شائع کردہ۔

نئی پوسٹس اپنے ان باکس میں پائیں

AI کی خبریں، گائیڈز اور پروڈکٹ اپ ڈیٹس — جب ہم آپ کے وقت کے قابل کچھ شائع کریں تو ایک مختصر ای میل۔

کورس انڈیکس

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev14 منٹ مطالعہ

Jev AI ماڈل فیصلوں کے لیے بنایا گیا ہے، نثر کے لیے نہیں

TypeSafe AI کا Jev اس لیے توجہ کھینچ رہا ہے کہ یہ software intelligence کو احتمال کے مسئلے کے طور پر دیکھتا ہے: درست branch چنیں، confidence منسلک کریں، اور جب code کو فیصلہ چاہیے ہو تو text لکھوانے کے لیے LLM کو ادائیگی سے بچیں۔

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering14 منٹ مطالعہ

طویل مدتی AI ایجنٹس کے لیے کانٹیکسٹ انجینئرنگ

طویل عرصے تک چلنے والے ایجنٹس صرف اس لیے ناکام نہیں ہوتے کہ ونڈو چھوٹی ہے۔ وہ اس وقت ناکام ہوتے ہیں جب فائلیں، ٹول آؤٹ پٹس اور پرانی ہسٹری اس کام کو باہر دھکیل دیتی ہیں جسے ایجنٹ نے مکمل کرنا تھا۔

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

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