Lewati ke konten
2/30Bab 2 dari 30

Dari Mana Loss Function Berasal: Likelihood, Bukan Konvensi

Tiga garis pada 20 pengukuran yang sama, tiga aturan skor, tiga pemenang. Squared error adalah pilihan tentang noise.

Di halaman ini

Mata pisau yang memotong komponen itu aus. Selama shift sepuluh jam, ketajamannya cukup berkurang sehingga komponen yang keluar dari ban berjalan menjadi sepersekian milimeter lebih lebar daripada saat mulai, dan begitu melewati 23,5 milimeter, inspeksi menolaknya. Tidak ada seorang pun di pabrik yang tahu kapan itu terjadi. Yang mereka punya adalah jangka sorong, buku catatan, dan dua puluh pembacaan dari Selasa lalu: jumlah jam sejak mata pisau diganti, dan lebar komponen yang diukur pada saat itu.

Seseorang menggambar garis melalui titik-titiknya. Orang lain menggambar garis yang sedikit berbeda. Orang ketiga menggambar garis ketiga. Ketiganya terlihat masuk akal di kertas, dan ketiganya berbeda pendapat tentang kapan mata pisau harus diganti hingga beberapa jam — di pabrik ini, selisih antara minggu yang tenang dan satu batch yang harus dibuang.

Garis mana yang lebih baik?

Seperti dinyatakan, pertanyaan itu tidak punya jawaban. Bukan jawaban yang sulit — benar-benar tidak ada jawaban. “Lebih baik” bukan sifat sebuah garis seperti kemiringannya; itu adalah sifat sebuah garis bersama aturan untuk memberi skor pada garis, dan sampai seseorang menuliskan aturannya, tidak ada yang bisa dihitung. Bab ini menganggap kalimat itu serius, dan berakhir dengan penemuan bahwa aturan paling umum dalam machine learning bukanlah konvensi, melainkan konsekuensi dari klaim tentang dunia — klaim yang bisa kamu uji, dan yang kadang salah.

Satu pengakuan sebelum baris kode pertama. Dua puluh pembacaan ini bukan dari pabrik sungguhan: saya membuatnya dari garis yang saya pilih, width=20.00+0.30h\text{width} = 20.00 + 0.30 \cdot h, ditambah noise acak dengan sebaran sekitar sepersepuluh milimeter. Itu penting, karena semua yang di bawah ini membahas apakah sebuah metode memulihkan kebenaran, dan satu-satunya cara memeriksanya adalah mengetahui kebenaran lebih dulu. Jadi: 0,30 milimeter per jam adalah jawaban di bagian belakang buku. Kamu tidak boleh memakainya, hanya boleh memeriksanya.

Berikut pembacaannya dan tiga garisnya, diberi skor dengan tiga cara: squared error, yang semua orang langsung ambil; absolute error, yang mungkin dipilih seorang statistikawan; dan worst error, yang akan dipilih teknisi mesin, karena inspektur tidak peduli dengan rata-ratamu — ia menolak satu komponen yang keluar dari toleransi.

NumPy masuk di sini, satu bab setelah perceptron Python murni, karena satu alasan: pada akhir bab ini kita mengevaluasi empat ratus ribu garis kandidat terhadap masing-masing dua puluh pembacaan, dan loop Python adalah alat yang keliru untuk itu. Ini juga notasi yang dipakai setiap sumber yang dikutip di bawah.

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}")               

Besaran pada baris yang disorot adalah residual: apa yang dikatakan garis dikurangi apa yang dikatakan jangka sorong, satu angka per pembacaan. Setiap aturan skor dalam bab ini, dan setiap loss function dalam dua puluh delapan bab setelahnya, adalah suatu cara untuk memampatkan daftar residual menjadi satu angka. Bedanya hanya pada cara memampatkannya.

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

Baca kolomnya, bukan barisnya. Squared error memilih B, absolute error memilih A, worst error memilih C: tiga aturan, tiga pemenang, pada dua puluh titik yang sama.

Saya memilih tiga garis ini agar mereka tidak sepakat, dan saya harus mengatakannya dengan jelas. Poinnya adalah betapa mudahnya itu — beberapa menit mencari di antara intercept dan slope yang tampak masuk akal menghasilkan ratusan tripel seperti ini. Peringkat adalah sifat aturan yang kamu pilih, bukan fakta tentang garis-garisnya, jadi aturan itu bukan detail implementasi: aturan itu adalah definisi masalahnya. Maka muncullah pertanyaan yang menjadi alasan bab ini ada: atas dasar apa kamu memilihnya?

Pertama hal yang lebih kecil, karena garisnya bukan tiga, melainkan tak terhingga banyaknya. Ambil squared error dulu, karena itulah yang diambil semua orang, dan perkecil masalahnya menjadi satu angka menggunakan trik yang menyelamatkan perceptron dari sebelas ribu epoch di Bab 1: kurangi rata-rata dari kedua kolom. Setelah awan titik dipusatkan pada origin, garis terbaik di bawah squared error melewati origin persis — jadi intercept sudah ditetapkan dan hanya slope yang tersisa untuk dipilih.

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

Enam ratus satu slope kandidat, satu pemenang: 0,293 milimeter per jam melawan kebenaran 0,300. Dua puluh pembacaan ber-noise dan sebuah for-loop berhasil mendekati dalam seperseratus milimeter per jam — dua koma sepertiga persen.

Bagian menariknya bukan pemenangnya, melainkan bentuk pencariannya. Cetak seluruh kurva, diputar sehingga loss berjalan dari kiri ke kanan:

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

Itu adalah lembah, dilihat dari samping. Ia punya satu dasar, dindingnya naik mulus di kedua sisi, dan — inilah bagian yang tidak bisa ditawarkan tangga Bab 1 — di setiap titik tunggal di atasnya ada arah “menurun” yang terdefinisi jelas. Ingat bentuk itu. Bab 3 sepenuhnya tentang berjalan menurun tanpa mengunjungi keenam ratus satu titik, dan tentang apa yang berubah ketika sebuah lembah punya lebih dari satu dasar.

Kita punya lembah karena kita menguadratkan. Absolute error akan memberinya tekukan di dasar; worst error akan memberinya bentangan datar di mana menggeser garis tidak mengubah apa pun. Menguadratkan jelas nyaman — dan kenyamanan kira-kira menjadi alasan yang diberikan kebanyakan kursus, dihias dalam empat bentuk: ia membuat error positif (absolute value juga begitu); ia menghukum error besar lebih berat (mengapa harus begitu?); ia differentiable (pangkat empat juga); ia dipakai semua orang (memang, dan itu bukan argumen).

Inilah posisi yang jujur. Squared error memilih garis B dan absolute error memilih garis A. Salah satunya benar untuk pabrik ini dan yang lain salah, dan belum ada apa pun sejauh ini yang bisa memberi tahu kamu yang mana. Untuk memilih aturan, kamu perlu mengetahui sesuatu tentang bagaimana pembacaan bisa berbeda dari garis, dan itu adalah pertanyaan tentang dunia, bukan tentang matematika. Menjawabnya membutuhkan satu perangkat kecil.

Inilah klaim yang mengubah “garis mana yang lebih baik” menjadi pertanyaan dengan jawaban.

Anggap lebar sebuah komponen adalah garis ditambah error acak, dan anggap error itu diambil dari Gaussian — kurva lonceng — dengan mean nol dan 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)

Density Gaussian adalah

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

Sekarang lakukan sesuatu yang tidak bisa dilakukan perceptron. Untuk slope kandidat tertentu θ\theta, setiap pembacaan memiliki residual, dan rumus di atas mengubah residual itu menjadi angka: seberapa masuk akal error sebesar itu persisnya, jika slope ini adalah kebenaran? Pembacaan yang berada di garis mendapat angka besar, pembacaan yang meleset setengah milimeter mendapat angka kecil.

Pembacaannya independen — jangka sorong tidak mengingat komponen terakhir — jadi product rule mengatakan bahwa plausibilitas seluruh buku catatan adalah hasil kali density individual. Hasil kali itu adalah likelihood dari θ\theta.1 Perhatikan arahnya, karena arah inilah yang dibahas Bayes’ rule: datanya tetap dan diketahui, dan parameternyalah yang berubah. Ini bukan “probabilitas slope”. Ini adalah probabilitas yang diberikan model pada data yang benar-benar kamu dapatkan, dibaca sebagai fungsi dari slope.

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

Slope 0,293 membuat buku catatan ini empat puluh enam ribu kali lebih masuk akal daripada 0,25, dan seratus dua puluh tujuh juta kali lebih masuk akal daripada 0,35. Maximum likelihood adalah prinsip bahwa kamu memilih parameter yang membuat apa yang benar-benar kamu amati menjadi sesedikit mungkin mengejutkan. Itu bukan teorema, melainkan usulan tentang apa arti “terbaik” semestinya — usulan yang punya isi, karena ia memaksamu menyatakan asumsi tentang noise sebelum kamu boleh memberi skor apa pun.

Jalankan tiga baris kode yang sama pada satu bulan shift, bukan satu shift, dan metodenya tumbang.

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

Dua ribu perkalian dan jawabannya adalah inf. Ubah satu konstanta — jangka sorong yang lebih ceroboh, sehingga density keluar lebih kecil dari 1 alih-alih lebih besar — dan kode yang sama mengembalikan 0.0. Keduanya salah, dalam arah berlawanan, tidak ada exception yang bisa kamu tangkap, dan yang kedua bahkan tidak mencetak peringatan.

Tidak ada yang salah dengan matematikanya. Likelihood pada pengaturan itu adalah angka hingga yang terdefinisi sempurna: logaritma naturalnya 1400,91, jadi angkanya sendiri sekitar 1060810^{608}. Masalahnya komputer kamu tidak memiliki angka itu, dan memahami persis angka mana yang ia miliki layak dilakukan, karena ini bukan terakhir kalinya ia akan menentukan hasil.

Perbaikan untuk hasil kali yang meledak adalah yang biasa: ambil logaritma. Logaritma mengubah hasil kali menjadi jumlah, ia strictly increasing sehingga tidak bisa menggeser lokasi maksimum, dan jumlah dua ribu angka sedang adalah sesuatu yang ditangani float64 tanpa keluhan. Secara konvensi kita mengambil negative log-likelihood, sehingga lebih baik berarti lebih kecil. Sekarang substitusikan density Gaussian dan lihat apa yang terjadi.

  1. Mulai dari hasil kali. Likelihood adalah L(θ)=i=1Np(yiθxi)\mathcal{L}(\theta) = \prod_{i=1}^{N} p(y_i - \theta x_i), dengan pp density Gaussian di atas.

  2. Ambil minus log. Hasil kali menjadi jumlah, dan eksponensial dalam density langsung saling meniadakan dengan logaritma:

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. Buang semua yang tidak mengandung θ\theta. Term pertama adalah konstanta. 1/2σ21/2\sigma^2 di depan jumlah adalah konstanta positif, dan menskalakan fungsi dengan konstanta positif tidak bisa menggeser lokasi minimumnya. Yang tersisa adalah
i=1N(yiθxi)2\sum_{i=1}^{N}\left(y_i - \theta x_i\right)^2

yaitu jumlah residual kuadrat — hal yang kita pakai untuk memulai bab ini karena itulah hal pertama yang terpikir oleh siapa pun.

Itulah hasil yang menjadi alasan bab ini ada, dan ia layak dinyatakan tanpa pagar: squared error bukan konvensi. Ia adalah negative log-likelihood dari Gaussian, setelah konstanta dibuang. Meminimalkan squared error adalah tindakan yang persis sama dengan menegaskan bahwa error kamu Gaussian dan bertanya parameter mana yang membuat datamu paling tidak mengejutkan. Kamu sudah membuat penegasan itu sejak awal; hanya saja tidak ada yang memberitahumu.

Ekuivalensinya bisa diperiksa, jadi periksalah: pindai enam ratus satu slope yang sama dengan negative log-likelihood lengkap, konstanta dan semuanya, dan dengan squared error biasa.

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

Angka berbeda pada sumbu vertikal, dan salah satunya negatif, sesuatu yang tidak pernah terjadi pada jumlah kuadrat: negative log-likelihood bisa turun di bawah nol, karena density bisa melebihi 1. Dasar yang sama dari lembah yang sama, hingga titik grid terakhir.

Tampilkan derivasi lengkap

Pembuangan mana yang aman, tepatnya? Manuver yang sama muncul di setiap bab yang menurunkan loss, dan tidak selalu tidak berbahaya.

Membuang konstanta aditif aman kapan pun ia tidak bergantung pada parameter yang kamu optimalkan, dan membuang konstanta multiplikatif positif aman karena argminθcf(θ)=argminθf(θ)\arg\min_\theta c\,f(\theta) = \arg\min_\theta f(\theta) untuk c>0c > 0 apa pun. Keduanya gagal begitu σ\sigma juga sedang di-fit: saat itu N2log(2πσ2)\frac{N}{2}\log(2\pi\sigma^2) sama sekali bukan konstanta, melainkan term yang mencegah model mengklaim σ=0\sigma = 0 dan plausibilitas tak hingga. Itulah tepatnya bagian berikutnya.

Keduanya gagal dengan cara berbeda lagi di Bab 3: konstanta multiplikatif tidak menggeser minimum, tetapi ia menskalakan gradient, dan gradient dikalikan dengan learning rate. Membagi dengan NN untuk mendapatkan mean squared error alih-alih sum tidak terlihat pada jawabannya dan sangat terlihat pada training run — dengan sum, menggandakan ukuran batch menggandakan setiap langkah yang kamu ambil.

Kita menetapkan σ\sigma pada 0,12 secara sewenang-wenang, dan tidak ada seorang pun di pabrik yang tahu sebaran error jangka sorong mereka. Perlakukan ia sebagai unknown kedua dan biarkan maximum likelihood menentukannya juga. Di sini term konstanta yang baru saja kita buang kembali, karena hanya term itu yang berdiri di antara model dan klaim presisi sempurna.

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

Keduanya sepakat hingga empat desimal, dan bukan kebetulan: menurunkan ekspresi itu dan menyetelnya ke nol memberi σ^2=1Nri2\hat{\sigma}^2 = \frac{1}{N}\sum r_i^2 persis. Jadi mean squared error bukan sekadar mirip variance. Di bawah model ini, ia adalah estimasi maximum-likelihood dari variance noise — angka yang selama ini kamu minimalkan adalah estimasi seberapa berisik sensormu.

Satu kerutan, murah untuk dinyatakan dan mahal untuk ditemukan kembali nanti: estimasi itu bias ke bawah, karena residual diukur terhadap fit yang dirinya sendiri dipilih untuk membuat residual kecil. Simulasikan — dua ratus ribu buku catatan, masing-masing dua puluh pembacaan, diambil dari distribution yang true variance-nya tepat 1, dengan satu parameter fit diestimasi dari pembacaan itu sendiri. Membagi jumlah kuadrat dengan NN memberi rata-rata 0,9501; membagi dengan N1N-1 memberi 1,0001; dan (N1)/N(N-1)/N adalah 0,95 tepat. Setiap parameter yang kamu fit menghabiskan satu degree of freedom, dan ini adalah contoh terkecil yang terlihat dari masalah yang jauh lebih besar: model selalu tampak lebih baik pada data yang dipakai untuk fit. Bab 4 mengubahnya menjadi disiplin menahan sebagian data, dan Bab 6 memberi nama pada efeknya.

Jika squared error menegaskan bahwa noise adalah Gaussian, pertanyaan berikutnya adalah apa yang terjadi ketika penegasan itu salah. Bukan sedikit salah — salah seperti pengukuran nyata itu salah.

Di lantai produksi, sebagian besar pembacaan jangka sorong akurat hingga sepersepuluh milimeter, dan sekali atau dua kali per shift serpihan geram masuk ke bawah rahang sehingga pembacaannya meleset beberapa milimeter. Error seperti itu heavy-tailed: kecil hampir sepanjang waktu, sesekali sangat besar, dan sangat besar jauh lebih sering daripada yang diizinkan kurva lonceng. Distribution Cauchy adalah model bersih standar untuk perilaku itu, dan density-nya sesederhana Gaussian:

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

Bedanya ada di tail: Gaussian turun seperti eε2e^{-\varepsilon^2}, sangat cepat, dan Cauchy seperti 1/ε21/\varepsilon^2, hampir tidak turun sama sekali. Konsekuensinya lebih mudah dilihat daripada dikatakan:

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

Sample variance Gaussian menetap pada 0,0144, yaitu 0.1220.12^2, dan tetap di sana. Cauchy naik, dan terus naik selama kamu mengambil sampel, karena tidak ada apa pun yang menjadi tujuan convergence: distribution Cauchy tidak punya variance, dan tidak punya mean juga. Squared error, yang seluruh urusannya adalah meminimalkan rata-rata kuadrat, sedang diminta mencari besaran yang tidak ada.

Jadi inilah satu shift ketika jangka sorong tertipu. Dua puluh jam yang sama, mata pisau yang sama, drift 0,30 milimeter per jam yang sama — hanya noise-nya sekarang Cauchy. Fit dua kali: sekali dengan meminimalkan residual kuadrat, sekali dengan meminimalkan negative log-likelihood dari noise yang benar-benar menghasilkan data. Trik centring tidak membantu di sini — ia hanya mengunci intercept untuk squared error — jadi kedua fit dilakukan dengan brute force di atas grid intercept dan slope, karena kita masih tidak punya cara untuk menemukan dasar lembah kecuali dengan mengunjunginya.

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

Dua baris yang disorot adalah seluruh perbedaan antara fit. Ambil log dari density Cauchy, buang konstanta persis seperti sebelumnya, dan log(1+(r/s)2)\sum \log\left(1 + (r/s)^2\right) adalah yang tersisa. Resep yang sama, klaim berbeda tentang noise.

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 melaporkan drift 0,108 milimeter per jam, kira-kira sepertiga dari laju sebenarnya, dan menyimpulkan bahwa mata pisau masih baik sampai jam 19,6. Jawaban sebenarnya adalah jam 11,7. Jika bertindak berdasarkan fit itu, pabrik menjalankan press delapan jam ekstra membuat komponen yang keluar dari toleransi, atas otoritas loss function paling standar di bidang ini. Fit Cauchy, memakai dua puluh pembacaan yang sama, grid yang sama, dan perbedaan satu baris kode, mendarat pada jam 11,8.

Dua keberatan layak dijawab, karena keduanya adalah hal pertama yang dikatakan engineer yang baik.

Outlier-nya jelas — hapus saja. Kamu bisa, dan itu membantu, dan itu belum cukup. Menghapus satu pembacaan terburuk menggeser slope least-squares dari 0,108 ke 0,239, yang masih menempatkan penggantian mata pisau pada jam 13,1, terlambat satu setengah jam; menghapus yang terburuk, melakukan refit, lalu menghapus apa pun yang terburuk sekarang membawamu ke 0,286 — dan perhatikan bahwa ini sudah merupakan prosedur, bukan observasi: hapus dua residual terbesar dari fit awal sebagai gantinya dan kamu mendarat pada 0,223. Namun kini kamu telah membuat judgement call yang tidak bisa kamu tulis atau pertahankan, dan mengotomatiskan aturan itu tidak menyelamatkannya: drop-the-largest-residual-then-refit, dijalankan pada seribu shift simulasi, memiliki median error slope 0,0177 melawan 0,0100 dari likelihood fit, dan meleset lebih dari 0,05 pada 14,7% shift melawan 1,3%. Penghapusan adalah tambalan di atas asumsi yang salah. Likelihood tidak membutuhkan tambalan, karena ia tidak pernah mengasumsikan outlier itu mustahil.

Kamu memilih dataset yang beruntung. Keberatan itu tepat sekali, karena itulah eksperimen terakhir mensimulasikan seribu shift independen dan melakukan refit dua cara pada masing-masing.

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, bukan mean, karena alasan yang sama seperti semua hal lain di bagian ini: error least-squares didorong oleh Cauchy, jadi rata-ratanya bukan sesuatu yang stabil untuk dilaporkan. Least squares sangat salah dua shift dari lima; likelihood fit sangat salah satu shift dari tujuh puluh tujuh, dan kegagalan terburuknya di seribu shift kurang dari seperlima kegagalan terburuk least squares.

Semua ini tidak membuat squared error buruk. Ini membuatnya spesifik, dan aritmetika menjelaskan persis alasannya. Ambil residual 0,1 mm dan residual 7 mm. Setelah dikuadratkan, pembacaan buruk berkontribusi 4.900 kali lebih besar ke total daripada pembacaan baik, sehingga garis diseret utuh ke arahnya; di bawah Cauchy log-likelihood, dua residual yang sama berkontribusi 0,527 dan 8,133, rasio 15,4. Pembacaan buruk tetap dihitung, ia hanya tidak berhak memutuskan. Ini awal dari robust statistics, tempat Huber’s 1964 loss membagi selisih dengan berperilaku kuadratik untuk residual kecil dan linear untuk residual besar,7 dan tempat Tukey sudah menunjukkan betapa sedikit kontaminasi yang dibutuhkan untuk membuat sample variance menjadi alat yang lebih buruk daripada mean absolute deviation.8

Satu catatan historis, terlalu bagus untuk ditinggalkan. Least squares pertama kali diterbitkan oleh Legendre pada 1805, sebagai perangkat aljabar yang nyaman tanpa pembenaran selain bahwa ia bekerja.9 Empat tahun kemudian Gauss menjalankan argumen itu mundur: ia menganggap sudah benar bahwa arithmetic mean adalah cara tepat untuk menggabungkan pengukuran berulang, bertanya error distribution mana yang membuat mean menjadi nilai paling mungkin, dan menunjukkan bahwa pada dasarnya hanya satu yang bisa — yang kini dinamai menurut dirinya.10 Turunan dalam bab ini adalah miliknya, berusia lebih dari dua abad, dan masih menjadi bagian yang ditinggalkan kebanyakan kursus.

What you can now say, and what you still cannot do

Tautan ke bagian: What you can now say, and what you still cannot do

Earned. Loss function adalah aturan skor, dan peringkat yang dihasilkannya adalah sifat aturan itu, bukan sifat kandidat. Setiap loss dalam kursus ini adalah negative log-likelihood dari suatu asumsi tentang noise, setelah konstanta dibuang — Gaussian memberi squared error di sini, Bernoulli memberi cross-entropy di Bab 4, dan categorical distribution atas vocabulary memberi next-token loss di Bab 8. Resepnya tidak pernah berubah: nyatakan noise, tulis likelihood, ambil minus log. Dan ketika asumsinya salah, model bukan sekadar tidak presisi, ia salah dalam arah yang bisa kamu prediksi.

Still missing. Kita menemukan dasar lembah dengan mengunjungi setiap titik di dalamnya. Itu berhasil untuk satu parameter dan enam ratus kandidat, dan bertahan untuk dua parameter pada 401.301 kandidat dalam seperlima detik. Tiga parameter pada resolusi yang sama adalah 201.051.801 kandidat dan tidak lagi muat dalam satu array; network kecil di Bab 5 punya ribuan parameter, dan model yang diberi harga oleh Bab 10 punya miliaran. Brute force di sini bukan lambat, melainkan mustahil secara aritmetika, dan tidak ada apa pun dalam bab ini yang menyarankan alternatif.

Namun lihat kembali lembahnya. Berdiri di θ=0.20\theta = 0.20 dengan loss 0,0822, arah “menurun” bukan misteri — kamu bisa melihatnya di halaman, kurvanya menurun ke kanan. Jika kamu bisa bertanya kepada loss function ke arah mana ia miring di titik tempat kamu berdiri, tanpa mengevaluasinya di tempat lain, kamu bisa melangkah ke arah itu, bertanya lagi, dan mengulanginya sampai tanahnya datar.

Pertanyaan itu punya nama. Kemiringan fungsi pada sebuah titik adalah derivative-nya, dan untuk fungsi dengan banyak parameter, kumpulan kemiringan di semua arah sekaligus adalah gradient. Bab 1 tidak bisa memakai gradient, karena error perceptron berupa tangga tanpa kemiringan untuk ditanyakan. Bab ini telah membangun sesuatu yang lebih baik: loss yang mulus di mana-mana dan berasal dari asumsi yang dinyatakan, bukan dari preferensi.

Jadi pertanyaan untuk Bab 3 bukan lagi apakah slope ada. Pertanyaannya adalah bagaimana menghitungnya, mengapa bergerak melawannya turun bukannya naik — tanda yang hampir setiap kursus memintamu terima begitu saja — dan seberapa jauh melangkah sebelum bertanya lagi, yang ternyata menjadi satu angka yang menentukan apakah training run converges, berosilasi di sekitar jawaban selamanya, atau lari menuju infinity.


Juga layak dibaca bersama bab ini: Prince, Understanding Deep Learning §5.1–5.2 dan Appendix C, yang membangun setiap loss dalam buku dari maximum likelihood dengan urutan yang dipakai di sini; Goodfellow, Bengio, dan Courville, Deep Learning §3.1–3.11 dan §5.5, yang bagian maximum-likelihood-nya juga menurunkan KL divergence yang dibutuhkan Bab 4; Murphy, Probabilistic Machine Learning: An Introduction bab 2 dan §4.2, tentang apa yang dijamin dan tidak dijamin maximum likelihood; Deisenroth, Faisal, dan Ong, Mathematics for Machine Learning §6.1–6.4 untuk sum rule, product rule, dan Bayes’ rule yang dilakukan dengan benar; catatan singkat CMU dari Tom Mitchell Estimating Probabilities: MLE and MAP (2016); serta §22.7 dari Dive into Deep Learning, yang mencapai hasil yang sama dalam kode yang bisa dijalankan.

  1. Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, hlm. 309–368 (1922). Tempat likelihood dijabarkan sebagai metode umum, bersama “parameter”, “statistic”, sufficiency, dan efficiency. Penamaannya sendiri, dan pemisahannya dari probability, muncul setahun lebih awal: Fisher, R. A., On the “probable error” of a coefficient of correlation deduced from a small sample, Metron 1, hlm. 3–32 (1921), hlm. 24–25.

  2. IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Mendefinisikan binary32 dan binary16, serta aturan pembulatan yang membuat eksperimen penjumlahan keluar seperti itu.

  3. Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Parameter formatnya, dan alasan menukar bit mantissa dengan bit exponent.

  4. Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling, dan besaran gradient terukur yang membuatnya perlu di float16.

  5. Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), hlm. 5–48 (1991). Masih menjadi penjelasan tunggal terbaik tentang mengapa dua urutan penjumlahan tidak sepakat.

  6. Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), hlm. 40 (1965). Compensated summation dalam setengah halaman.

  7. Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), hlm. 73–101 (1964). Loss yang kuadratik dekat nol dan linear di tail, diturunkan alih-alih ditambal.

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

  9. Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paris, 1805), lampiran Sur la méthode des moindres quarrés. Publikasi pertama least squares, sebagai perangkat komputasi.

  10. Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Buku II, §§175–179. Argumen dari arithmetic mean ke normal error law, dan dari sana ke least squares.


Dibuat oleh

David Vicente Campos

Pendiri NeuraLIA Labs & salah satu pendiri MyRealFood

Saya seorang insinyur komputer lulusan Universitas León. Saya ikut mendirikan MyRealFood, tempat saya sebagai CTO membangun aplikasi yang telah digunakan jutaan orang untuk makan lebih sehat, dan saya mendirikan NeuraLIA Labs, tempat saya membangun produk AI. Di sini saya menulis tentang hal-hal yang harus saya pahami sepanjang perjalanan, sebagaimana dulu saya berharap ada yang menjelaskannya kepada saya.

Selengkapnya tentang penulis

Diterbitkan oleh NeuraLIA Labs.

Dapatkan postingan baru di inbox kamu

Berita AI, panduan, dan update produk — email singkat saat kami menerbitkan sesuatu yang layak kamu baca.

Indeks kursus

Abstract software decision engine with branching paths, probability nodes, and glowing gates.
jev11 menit baca

Model AI Jev dibuat untuk keputusan, bukan prosa

Jev dari TypeSafe AI menarik perhatian karena memperlakukan kecerdasan software sebagai persoalan probabilitas: pilih cabang yang tepat, sertakan keyakinan, dan hindari membayar LLM untuk menulis teks saat kode membutuhkan keputusan.

Abstract agent runtime sorting documents, memory blocks and pointer nodes inside a bounded context frame.
context-engineering11 menit baca

Rekayasa konteks untuk agen AI jangka panjang

Agen yang berjalan lama tidak gagal hanya karena window-nya kecil. Mereka gagal ketika file, output tool, dan riwayat lama menggeser tugas yang seharusnya diselesaikan agen.

Siap membiarkan LIA yang memilih?

Berkarya dengan semua model AI dalam satu tempat — mulai gratis hari ini.