सामग्री पर जाएँ
2/30अध्याय 2 / 30

Loss Function कहाँ से आती है: Likelihood, Convention नहीं

एक ही 20 मापों पर तीन रेखाएँ और तीन scoring rules तीन विजेता चुनते हैं। Squared error एक चुनाव है।

इस पेज पर

भागों को काटने वाली blade घिसती जाती है। दस घंटे की shift में उसकी धार इतनी कम हो जाती है कि belt से उतरते parts शुरुआत की तुलना में मिलीमीटर के एक अंश जितने चौड़े हो जाते हैं, और जैसे ही वे 23.5 मिलीमीटर पार करते हैं, inspection उन्हें reject कर देता है। Plant में किसी को नहीं पता कि यह कब होता है। उनके पास बस एक caliper, एक notebook, और पिछले मंगलवार की बीस readings हैं: blade बदले जाने के बाद बीते घंटे, और उस पल पर मापी गई part की चौड़ाई।

कोई points के बीच से एक line खींचता है। कोई और थोड़ी अलग line खींचता है। तीसरा व्यक्ति तीसरी line खींचता है। कागज़ पर तीनों ठीक लगती हैं, और वे blade कब बदलनी है इस पर कई घंटों का फर्क देती हैं — इस plant में, एक शांत हफ्ते और scrapped batch के बीच का फर्क।

कौन-सी line बेहतर है?

जैसा सवाल रखा गया है, उसका कोई जवाब नहीं है। मुश्किल जवाब नहीं — कोई जवाब ही नहीं। “बेहतर” किसी line की वैसी property नहीं है जैसी उसकी slope है; यह line की property है साथ में lines को score करने के rule के, और जब तक कोई rule लिख नहीं देता, compute करने के लिए कुछ नहीं है। यह chapter इस वाक्य को गंभीरता से लेता है, और इस discovery पर खत्म होता है कि machine learning का सबसे common rule कोई convention नहीं बल्कि दुनिया के बारे में एक claim का परिणाम है — ऐसा claim जिसे आप test कर सकते हैं, और जो कभी-कभी false होता है।

Code की पहली line से पहले एक confession। ये बीस readings किसी real factory से नहीं हैं: मैंने इन्हें अपनी चुनी हुई line, width=20.00+0.30h\text{width} = 20.00 + 0.30 \cdot h, plus लगभग मिलीमीटर के दसवें हिस्से जितने spread वाले random noise से generate किया है। यह matter करता है, क्योंकि नीचे सब कुछ इस बारे में है कि कोई method किसी truth को recover करता है या नहीं, और इसे check करने का इकलौता तरीका है truth को पहले से जानना। तो: 0.30 मिलीमीटर प्रति घंटा book के पीछे का answer है। आपको इसे use करने की अनुमति नहीं है, केवल इसके against check करने की।

यहाँ readings और तीन lines हैं, जिन्हें तीन तरीकों से score किया गया है: squared error, जिसे हर कोई पहले उठाता है; absolute error, जिसे कोई statistician चुन सकता है; और worst error, जिसे machinist चुनेगा, क्योंकि inspector आपके average की परवाह नहीं करता — वह tolerance से बाहर single part को reject करता है।

NumPy यहाँ, pure-Python perceptron के एक chapter बाद, एक वजह से आता है: इस chapter के अंत तक हम चार लाख candidate lines को बीस-बीस readings के against evaluate करते हैं, और Python loop इसके लिए गलत tool है। यह वही notation भी है जिसमें नीचे cite किए गए हर 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 बनाने का तरीका है। वे केवल इस बात में अलग हैं कि वे कैसे दबाते हैं।

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

Rows नहीं, columns पढ़िए। Squared error कहता है B, absolute error कहता है A, worst error कहता है C: तीन rules, तीन winners, उन्हीं बीस points पर।

मैंने ये तीन lines इसलिए चुनीं कि वे disagree करें, और यह साफ़ कहना चाहिए। Point यह है कि यह कितना आसान था — sensible-looking intercepts और slopes पर कुछ मिनट खोजने से ऐसे hundreds triples मिल जाते हैं। Ranking आपके चुने हुए rule की property है, lines के बारे में कोई fact नहीं, इसलिए rule implementation detail नहीं है: वही problem की definition है। इससे वह सवाल उठता है जिसका जवाब देने के लिए यह chapter है: आप इसे किस आधार पर चुनते हैं?

पहले एक छोटी बात, क्योंकि तीन lines नहीं बल्कि infinitely many हैं। अभी squared error लें, क्योंकि हर कोई वही लेता है, और problem को एक single number तक shrink करें उस trick से जिसने Chapter 1 में perceptron के ग्यारह हजार epochs बचाए थे: दोनों columns से mean घटा दें। जब points का cloud origin पर centred हो जाता है, squared error के तहत best line ठीक origin से गुजरती है — इसलिए intercept तय हो जाता है और चुनने के लिए केवल 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: truth 0.300 के against 0.293 मिलीमीटर प्रति घंटा। बीस 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

यह side से देखी गई valley है। इसका एक bottom है, walls दोनों तरफ smoothly ऊपर उठती हैं, और — यह वह हिस्सा है जो Chapter 1 की staircase नहीं दे सकती थी — इस पर हर single point पर “downhill” की well-defined direction है। उस shape को याद रखें। Chapter 3 पूरी तरह इस बारे में है कि सभी छह सौ एक points visit किए बिना इसमें नीचे कैसे चलें, और जब valley के एक से ज्यादा bottoms हों तो क्या बदलता है।

हमारे पास valley इसलिए है क्योंकि हमने square किया। Absolute error bottom पर kink देता; worst error flat stretches देता जहाँ line को हिलाने से कुछ भी नहीं बदलता। Squaring निर्विवाद रूप से convenient है — और convenience ही लगभग वह reason है जो most courses देते हैं, चार तरह से सजाकर: यह errors को positive बनाता है (absolute value भी बनाती है); यह big errors को ज्यादा punish करता है (क्यों करना चाहिए?); यह differentiable है (fourth power भी है); हर कोई यही use करता है (करता है, और यह argument नहीं है)।

ईमानदार position यह है। Squared error ने line B चुनी और absolute error ने line A। इनमें से एक इस factory के लिए सही है और दूसरी गलत, और अब तक कही गई कोई बात आपको नहीं बता सकती कि कौन-सी। Rule चुनने के लिए आपको readings line से अलग कैसे हुईं इसके बारे में कुछ जानना होगा, और यह mathematics के बारे में नहीं, दुनिया के बारे में सवाल है। इसका जवाब देने के लिए machinery का एक छोटा piece चाहिए।

यह वह claim है जो “कौन-सी line बेहतर है” को answer वाले question में बदलता है।

Assume करें कि part की width line plus random error है, और assume करें कि error Gaussian — bell curve — से drawn है, 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 मिलता है, आधा मिलीमीटर दूर reading को छोटा।

Readings independent हैं — caliper पिछले part को remember नहीं करता — इसलिए product rule कहता है कि पूरी 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 के रूप में पढ़ी गई।

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 से छियालीस हजार गुना, और 0.35 से एक सौ सत्ताईस million गुना ज्यादा plausible बनाती है। Maximum likelihood वह principle है कि आप वह parameter चुनते हैं जो आपने actually observe किया उसे जितना संभव हो unsurprising बनाता है। यह theorem नहीं बल्कि proposal है कि “best” का meaning क्या होना चाहिए — content वाला proposal, क्योंकि यह आपको किसी भी चीज़ को score करने से पहले noise के बारे में अपनी assumption state करने पर मजबूर करता है।

वही तीन lines of code एक shift के बजाय एक महीने की shifts पर चलाएँ, और 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 से बड़ी नहीं बल्कि छोटी आएँ — और वही code 0.0 return करता है। दोनों answers गलत हैं, opposite directions में, कोई भी ऐसा exception नहीं उठाता जिसे आप catch कर सकें, और दूसरा तो warning भी print नहीं करता।

Mathematics में कुछ गलत नहीं है। उन settings पर likelihood पूरी तरह well-defined finite number है: उसका natural logarithm 1400.91 है, इसलिए number खुद लगभग 1060810^{608} है। Problem यह है कि आपके computer के पास वह number नहीं है, और यह समझना worth है कि उसके पास exactly कौन से numbers हैं, क्योंकि यह आखिरी बार नहीं होगा जब वह outcome decide करेगा।

Exploding product का fix usual है: logarithms लें। Logarithm products को sums में बदलता है, यह strictly increasing है इसलिए 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 की location नहीं बदल सकता। जो बचता है वह है
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 हटाने के बाद। Squared error minimise करना exactly वही act है जैसा यह assert करना कि आपकी errors Gaussian हैं और पूछना कि कौन-सा parameter आपके data को least surprising बनाता है। आप यह assertion all along कर रहे थे; बस आपको बताया नहीं जा रहा था।

Equivalence checkable है, तो check करें: वही छह सौ एक slopes full negative log-likelihood, constants समेत, और plain squared error के साथ scan करें।

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 पर अलग 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 करने से रोकता है। Exactly यही अगला section है।

वे Chapter 3 में फिर अलग तरह से fail करते हैं: multiplicative constant minimum को move नहीं करता, लेकिन यह gradient को scale करता है, और gradient learning rate से multiply होता है। NN से divide करके sum के बजाय mean squared error पाना answer के लिए invisible है और training run के लिए बहुत 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 करते हैं, और accident से नहीं: उस expression को differentiate करके zero पर set करने से exactly σ^2=1Nri2\hat{\sigma}^2 = \frac{1}{N}\sum r_i^2 मिलता है। इसलिए mean squared error केवल variance जैसा नहीं है। इस model के तहत यह noise के variance का maximum-likelihood estimate है — जिस number को आप all along minimise कर रहे थे, वह आपके sensor के noise का estimate था।

एक wrinkle, जिसे state करना सस्ता और बाद में rediscover करना महँगा है: वह estimate biased low है, क्योंकि residuals उस fit के against measured थे जिसे खुद उन्हें small बनाने के लिए चुना गया था। 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 बिल्कुल 0.95 है। आप जो हर parameter fit करते हैं वह एक degree of freedom cost करता है, और यह बहुत बड़े problem का सबसे छोटा visible instance है: model हमेशा उस data पर बेहतर दिखता है जिस पर उसे fit किया गया था। Chapter 4 इसे data hold back करने के discipline में बदलता है, और Chapter 6 effect को उसका नाम देता है।

अगर squared error assert करता है कि noise Gaussian है, तो अगला सवाल है कि assertion false होने पर क्या होता है। Slightly false नहीं — उस तरह false जैसे real measurements false होते हैं।

Shop floor पर, ज्यादातर caliper readings मिलीमीटर के दसवें हिस्से तक good होती हैं, और shift में एक-दो बार swarf की chip jaw के नीचे आ जाती है और reading कई मिलीमीटर off हो जाती है। ऐसी errors heavy-tailed होती हैं: ज्यादातर small, कभी-कभार enormous, और bell curve जितनी allow करती है उससे कहीं ज्यादा often enormous। 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)}

Difference tail है: Gaussian eε2e^{-\varepsilon^2} की तरह गिरता है, 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, जिसका पूरा काम squares के average को minimise करना है, ऐसी quantity माँग रहा है जो exist नहीं करती।

तो यहाँ एक shift है जहाँ caliper fooled हो गया। वही बीस hours, वही blade, वही 0.30 मिलीमीटर प्रति घंटे का drift — बस noise अब Cauchy है। इसे दो बार fit करें: एक बार squared residuals minimise करके, एक बार उस noise की negative log-likelihood minimise करके जिसने actually data generate किया। Centering trick यहाँ मदद नहीं करती — यह intercept को केवल squared error के लिए pin करती है — इसलिए दोनों 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 के बीच पूरा 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 पर act करते हुए, plant field की सबसे standard loss function के authority पर press को आठ extra hours तक चलाता है और out-of-tolerance parts बनाता है। Cauchy fit, वही बीस readings, वही grid, और code में एक line के difference का use करके, hour 11.8 पर land करता है।

दो objections answers deserve करते हैं, क्योंकि दोनों पहली चीज़ हैं जो कोई good engineer कहता है।

Outlier obvious है — बस उसे delete कर दें। आप कर सकते हैं, और मदद मिलती है, और यह 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 के two largest residuals delete करें तो आप 0.223 पर land करते हैं। लेकिन अब आपने judgement calls कर दिए हैं जिन्हें आप लिख या defend नहीं कर सकते, और rule automate करने से वह rescue नहीं होता: drop-the-largest-residual-then-refit, हजार simulated shifts पर run करने पर, likelihood fit के 0.0100 के against 0.0177 median slope error देता है, और 1.3% के against 14.7% shifts में 0.05 से ज्यादा off होता है। Deletion wrong assumption के ऊपर patch है। Likelihood को patch नहीं चाहिए, क्योंकि उसने कभी assume नहीं किया कि outlier impossible था।

आपने lucky dataset चुना। यह objection exactly सही है, इसलिए last experiment हजार independent shifts simulate करता है और हर एक पर दोनों तरीकों से 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 हैं, इसलिए उनका 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 करती है, इसलिए line bodily उसकी तरफ dragged होती है; Cauchy log-likelihood के तहत वही दो residuals 0.527 और 8.133 contribute करते हैं, ratio 15.4। Bad reading अब भी count होती है, बस वह decide नहीं करती। यही robust statistics की शुरुआत है, जहाँ Huber की 1964 loss small residuals के लिए quadratically और large ones के लिए linearly behave करके difference split करती है,7 और जहाँ Tukey पहले ही दिखा चुका था कि sample variance को mean absolute deviation से worse tool बनाने के लिए कितनी कम contamination चाहिए।8

एक historical note, छोड़ने के लिए बहुत अच्छा। Least squares पहले Legendre ने 1805 में publish किया, एक convenient algebraic device के रूप में जिसका worked करने के अलावा कोई justification नहीं था।9 चार साल बाद Gauss ने argument backwards चलाया: उसने given माना कि repeated measurements combine करने का सही तरीका arithmetic mean है, पूछा कि कौन-सी error distribution mean को most probable value बनाती है, और दिखाया कि essentially केवल एक बनाती है — वही जो अब उसके नाम पर है।10 इस chapter की derivation उसकी है, दो centuries से ज्यादा पुरानी है, और फिर भी यही हिस्सा most courses छोड़ देते हैं।

Earned. Loss function एक scoring rule है, और जो ranking यह produce करती है वह rule की property है, candidates की नहीं। इस course की हर loss किसी noise assumption की negative log-likelihood है, constants हटाकर — 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 करके found किया। यह एक parameter और छह सौ candidates के लिए worked किया, और दो parameters पर 401,301 candidates को second के पाँचवें हिस्से में survive कर गया। Same resolution पर तीन parameters 201,051,801 candidates हैं और अब एक array में fit नहीं होते; Chapter 5 का small network हजारों parameters रखता है, और जिन models पर Chapter 10 price लगाता है उनमें billions हैं। यहाँ brute force slow नहीं है, arithmetically impossible है, और इस chapter में कुछ भी alternative suggest नहीं करता।

Valley को फिर देखें। θ=0.20\theta = 0.20 पर खड़े होकर, loss 0.0822 के साथ, “downhill” की direction mystery नहीं है — आप page पर देख सकते हैं, curve right की तरफ down slope करती है। अगर आप loss function से पूछ सकते कि आप जिस point पर खड़े हैं वहाँ यह किस direction में slopes करती है, बिना इसे कहीं और evaluate किए, तो आप उस direction में step ले सकते, फिर पूछ सकते, और repeat कर सकते जब तक जमीन flat न हो जाए।

इस question का नाम है। किसी 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 के लिए question अब यह नहीं है कि slope exists करती है या नहीं। यह है कि इसे compute कैसे करें, इसके against move करने से uphill के बजाय downhill क्यों जाता है — एक sign जिसे लगभग हर course आपसे faith पर लेने को कहता है — और फिर पूछने से पहले कितना far step लें, जो वह एक number निकलता है जो decide करता है कि training run converge करेगा, answer के around forever oscillate करेगा, या infinity की तरफ भाग जाएगा।


इस chapter के साथ पढ़ने लायक भी: Prince, Understanding Deep Learning §5.1–5.2 and Appendix C, जो book की हर loss को maximum likelihood से उसी order में build करता है जो यहाँ use हुआ है; Goodfellow, Bengio and Courville, Deep Learning §3.1–3.11 and §5.5, whose maximum-likelihood section also derives the KL divergence that Chapter 4 needs; Murphy, Probabilistic Machine Learning: An Introduction chapter 2 and §4.2, on what maximum likelihood does and does not 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's short CMU note Estimating Probabilities: MLE and MAP (2016); and §22.7 of Dive into Deep Learning, which reaches the same result in runnable code.

  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 define करता है, और rounding rules भी जो summation experiment को वैसा बनाते हैं जैसा वह आता है।

  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 के पास 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 का first publication, computational device के रूप में।

  10. Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Book II, §§175–179. Arithmetic mean से normal error law तक argument, और वहाँ से least squares तक।


निर्माता

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.
jev13 मिनट पढ़ें

Jev AI मॉडल गद्य के लिए नहीं, निर्णयों के लिए बना है

TypeSafe AI का Jev ध्यान खींच रहा है क्योंकि यह सॉफ्टवेयर इंटेलिजेंस को संभावना की समस्या मानता है: सही शाखा चुनें, भरोसे का स्तर जोड़ें, और जब कोड को निर्णय चाहिए तो LLM से टेक्स्ट लिखवाने पर खर्च न करें।

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering14 मिनट पढ़ें

लॉन्ग-होराइजन AI एजेंट्स के लिए कॉन्टेक्स्ट इंजीनियरिंग

लंबे समय तक चलने वाले एजेंट सिर्फ इसलिए असफल नहीं होते कि विंडो छोटी है। वे तब असफल होते हैं जब फ़ाइलें, टूल आउटपुट और पुराना इतिहास उस काम को ही पीछे धकेल देते हैं जिसे एजेंट को पूरा करना था।

मॉडल चुनने का काम LIA पर छोड़ने के लिए तैयार हैं?

हर AI मॉडल एक ही जगह — आज ही मुफ़्त शुरू करें।