Hàm mất mát đến từ đâu: likelihood, không phải quy ước
Ba đường kẻ tay trên cùng 20 phép đo, ba quy tắc chấm điểm chọn ba người thắng khác nhau. Squared error là một lựa chọn.
Trên trang này
Lưỡi dao cắt chi tiết đang mòn dần. Trong một ca mười giờ, nó mất đủ độ sắc để các chi tiết rời băng chuyền rộng hơn ban đầu một phần nhỏ của milimét, và một khi chúng vượt quá 23,5 milimét, bộ phận kiểm tra sẽ loại. Không ai trong nhà máy biết chuyện đó xảy ra lúc nào. Thứ họ có là một thước cặp, một cuốn sổ, và hai mươi số đọc từ thứ Ba tuần trước: số giờ kể từ khi thay lưỡi dao, và bề rộng của chi tiết được đo tại thời điểm đó.
Có người vẽ một đường qua các điểm. Người khác vẽ một đường hơi khác. Người thứ ba vẽ đường thứ ba. Cả ba đều trông hợp lý trên giấy, và chúng bất đồng với nhau vài giờ về thời điểm cần thay lưỡi dao — ở nhà máy này, đó là khác biệt giữa một tuần yên ổn và một lô hàng bị loại.
Đường nào tốt hơn?
Như đã nêu, câu hỏi đó không có câu trả lời. Không phải một câu trả lời khó — mà là không có câu trả lời nào cả. "Tốt hơn" không phải là một thuộc tính của một đường giống như độ dốc của nó; nó là thuộc tính của một đường cùng với một quy tắc để chấm điểm các đường, và cho đến khi có ai đó viết quy tắc đó ra thì chẳng có gì để tính. Chương này xem câu ấy là nghiêm túc, và kết thúc bằng phát hiện rằng quy tắc phổ biến nhất trong machine learning không phải là một quy ước mà là hệ quả của một tuyên bố về thế giới — một tuyên bố bạn có thể kiểm tra, và đôi khi là sai.
Một lời thú nhận trước dòng code đầu tiên. Hai mươi số đọc này không đến từ một nhà máy thật: tôi tạo chúng từ một đường do tôi chọn, , cộng với nhiễu ngẫu nhiên có độ phân tán khoảng một phần mười milimét. Điều đó quan trọng, vì mọi thứ bên dưới đều nói về việc liệu một phương pháp có khôi phục được sự thật hay không, và cách duy nhất để kiểm tra điều đó là biết trước sự thật. Vậy nên: 0,30 milimét mỗi giờ là đáp án ở cuối sách. Bạn không được phép dùng nó, chỉ được kiểm tra đối chiếu với nó.
Three rules, three winners
Liên kết đến mục: Three rules, three winnersĐây là các số đọc và ba đường, được chấm theo ba cách: squared error, thứ ai cũng nghĩ đến; absolute error, thứ một nhà thống kê có thể chọn; và worst error, thứ người thợ máy sẽ chọn, vì người kiểm tra không quan tâm đến trung bình của bạn — anh ta loại đúng chi tiết đơn lẻ vượt dung sai.
NumPy xuất hiện ở đây, một chương sau perceptron thuần Python, vì một lý do: đến cuối chương này, chúng ta đánh giá bốn trăm nghìn đường ứng viên trên hai mươi số đọc mỗi đường, và vòng lặp Python là công cụ sai cho việc đó. Nó cũng là ký pháp mà mọi nguồn được trích dẫn bên dưới sử dụng.
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}") Đại lượng trong các dòng được tô sáng là phần dư: điều đường dự đoán trừ đi điều thước cặp đo được, một số cho mỗi số đọc. Mọi quy tắc chấm điểm trong chương này, và mọi loss function trong hai mươi tám chương sau nó, đều là một cách nào đó để ép một danh sách phần dư xuống thành một con số duy nhất. Chúng chỉ khác nhau ở cách ép.
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.320Hãy đọc các cột, không phải các hàng. Squared error nói B, absolute error nói A, worst error nói C: ba quy tắc, ba người thắng, trên cùng hai mươi điểm.
Tôi chọn ba đường này sao cho chúng bất đồng, và cần nói rõ như vậy. Điểm đáng chú ý là việc đó dễ đến mức nào — chỉ vài phút tìm kiếm trên các hệ số chặn và độ dốc trông hợp lý đã lộ ra hàng trăm bộ ba như thế. Thứ hạng là thuộc tính của quy tắc bạn chọn, không phải một sự thật về các đường, nên quy tắc không phải chi tiết triển khai: nó chính là định nghĩa của bài toán. Điều đó đặt ra câu hỏi mà chương này tồn tại để trả lời: bạn chọn nó dựa trên cơ sở nào?
One parameter, and a valley
Liên kết đến mục: One parameter, and a valleyTrước hết là một chuyện nhỏ hơn, vì không chỉ có ba đường mà có vô hạn đường. Tạm lấy squared error, vì đó là thứ ai cũng lấy, và thu nhỏ bài toán còn một con số bằng mẹo đã cứu perceptron khỏi mười một nghìn epoch trong Chapter 1: trừ trung bình khỏi cả hai cột. Một khi đám mây điểm được đưa về tâm ở gốc tọa độ, đường tốt nhất theo squared error đi chính xác qua gốc — vậy hệ số chặn đã được quyết định và chỉ còn độ dốc cần chọn.
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}")601 candidates -> theta=0.293 mse=0.010115Sáu trăm lẻ một độ dốc ứng viên, một người thắng: 0,293 milimét mỗi giờ so với sự thật 0,300. Hai mươi số đọc nhiễu và một vòng for đã đến trong phạm vi một phần trăm milimét mỗi giờ — hai phẩy ba phần trăm.
Phần thú vị không phải là người thắng mà là hình dạng của phép tìm kiếm. In toàn bộ đường cong, xoay lại để loss chạy từ trái sang phải:
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}")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Đó là một thung lũng, nhìn từ bên cạnh. Nó có một đáy, các vách tăng mượt mà ở cả hai phía, và — đây là phần mà chiếc cầu thang của Chapter 1 không thể cho — tại mọi điểm đơn lẻ trên nó đều có một hướng "xuống dốc" được xác định rõ. Hãy nhớ hình dạng đó. Chapter 3 hoàn toàn nói về việc đi xuống nó mà không ghé qua cả sáu trăm lẻ một điểm, và về điều gì thay đổi khi một thung lũng có nhiều hơn một đáy.
So why squared?
Liên kết đến mục: So why squared?Chúng ta có một thung lũng vì đã bình phương. Absolute error sẽ tạo ra một góc gãy ở đáy; worst error sẽ tạo ra những đoạn phẳng nơi dịch chuyển đường không làm thay đổi gì cả. Bình phương rõ ràng là tiện — và sự tiện lợi đại khái là lý do hầu hết khóa học đưa ra, được mặc bốn bộ áo: nó làm lỗi thành dương (giá trị tuyệt đối cũng vậy); nó phạt lỗi lớn nặng hơn (tại sao nên vậy?); nó khả vi (lũy thừa bậc bốn cũng vậy); nó là thứ mọi người dùng (đúng, và đó không phải một lập luận).
Đây là lập trường trung thực. Squared error chọn đường B và absolute error chọn đường A. Một trong hai đúng cho nhà máy này và cái còn lại sai, và không điều gì đã nói đến giờ có thể cho bạn biết cái nào. Để chọn quy tắc, bạn cần biết điều gì đó về cách các số đọc trở nên khác với đường, và đó là một câu hỏi về thế giới, không phải về toán học. Trả lời nó cần một mảnh máy móc nhỏ.
The likelihood of a line
Liên kết đến mục: The likelihood of a lineĐây là tuyên bố biến "đường nào tốt hơn" thành một câu hỏi có câu trả lời.
Giả sử bề rộng của một chi tiết là đường cộng với một lỗi ngẫu nhiên, và giả sử lỗi đó được rút từ một Gaussian — đường cong hình chuông — có trung bình bằng không và độ lệch chuẩn :
Mật độ của Gaussian là
Bây giờ làm một việc mà perceptron không thể. Với một độ dốc ứng viên cho trước , mỗi số đọc có một phần dư, và công thức trên biến phần dư đó thành một con số: nếu độ dốc này là sự thật, thì một lỗi đúng bằng kích thước đó hợp lý đến mức nào? Một số đọc nằm trên đường nhận số lớn, một số đọc lệch nửa milimét nhận số nhỏ.
Các số đọc độc lập — thước cặp không nhớ chi tiết trước đó — nên quy tắc tích nói rằng độ hợp lý của toàn bộ cuốn sổ là tích của các mật độ riêng lẻ. Tích đó là likelihood của .1 Hãy chú ý chiều, vì đó là chiều mà quy tắc Bayes nói tới: dữ liệu là cố định và đã biết, còn tham số là thứ thay đổi. Đây không phải "xác suất của độ dốc". Nó là xác suất mà model gán cho dữ liệu bạn thật sự nhận được, đọc như một hàm của độ dốc.
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}")theta=0.25 likelihood = 521.952
theta=0.293 likelihood = 2.42028e+07
theta=0.35 likelihood = 0.190312Độ dốc 0,293 khiến cuốn sổ này hợp lý hơn 0,25 bốn mươi sáu nghìn lần, và hợp lý hơn 0,35 một trăm hai mươi bảy triệu lần. Maximum likelihood là nguyên tắc rằng bạn chọn tham số khiến điều bạn thực sự quan sát được trở nên ít đáng ngạc nhiên nhất có thể. Nó không phải một định lý mà là một đề xuất về việc "tốt nhất" nên nghĩa là gì — một đề xuất có nội dung, vì nó buộc bạn phải nêu giả định của mình về nhiễu trước khi được phép chấm điểm bất cứ thứ gì.
The product breaks
Liên kết đến mục: The product breaksChạy cùng ba dòng code trên một tháng ca làm thay vì một ca, và phương pháp sụp đổ.
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)RuntimeWarning: overflow encountered in reduce
2000 readings, sigma = 0.12 mm : inf
2000 readings, sigma = 2.00 mm : 0.0
largest float64 : 1.7976931348623157e+308Hai nghìn phép nhân và đáp án là inf. Đổi một hằng số — một thước cặp cẩu thả hơn, nên các mật độ nhỏ hơn 1 thay vì lớn hơn — và cùng đoạn code trả về 0.0. Cả hai đáp án đều sai, theo hai hướng ngược nhau, không cái nào ném exception để bạn bắt, và cái thứ hai thậm chí không in cảnh báo.
Toán học không có gì sai. Likelihood ở các thiết lập đó là một số hữu hạn được xác định hoàn toàn: logarithm tự nhiên của nó là 1400,91, nên bản thân con số khoảng . Vấn đề là máy tính của bạn không có con số đó, và rất đáng hiểu chính xác nó có những con số nào, vì đây không phải lần cuối nó quyết định kết quả.
Where the square comes from
Liên kết đến mục: Where the square comes fromCách sửa tích nổ tung là cách quen thuộc: lấy logarithm. Logarithm biến tích thành tổng, nó tăng nghiêm ngặt nên không thể dịch chuyển vị trí của cực đại, và một tổng của hai nghìn số vừa phải là thứ float64 xử lý không phàn nàn. Theo quy ước, ta lấy negative log-likelihood, để tốt hơn nghĩa là nhỏ hơn. Bây giờ thay mật độ Gaussian vào và xem chuyện gì xảy ra.
-
Bắt đầu từ tích. Likelihood là , với là mật độ Gaussian ở trên.
-
Lấy trừ log. Tích trở thành tổng, và hàm mũ trong mật độ triệt tiêu thẳng với logarithm:
- Vứt bỏ mọi thứ không chứa . Hạng đầu là một hằng số. trước tổng là một hằng số dương, và nhân một hàm với hằng số dương không thể dịch chuyển nơi cực tiểu của nó. Thứ còn lại là
chính là tổng các phần dư bình phương — thứ chúng ta bắt đầu chương này cùng với nó vì đó là thứ đầu tiên ai cũng nghĩ đến.
Đó là kết quả mà chương này tồn tại để đưa ra, và nó đáng được phát biểu không rào đón: squared error không phải một quy ước. Nó là negative log-likelihood của một Gaussian, sau khi bỏ các hằng số. Tối thiểu hóa squared error chính xác là cùng một hành động với việc khẳng định lỗi của bạn là Gaussian và hỏi tham số nào khiến dữ liệu của bạn ít đáng ngạc nhiên nhất. Bạn đã luôn khẳng định điều đó; chỉ là không ai nói với bạn.
Tương đương này có thể kiểm tra được, vậy hãy kiểm tra: quét cùng sáu trăm lẻ một độ dốc với negative log-likelihood đầy đủ, gồm cả hằng số, và với squared error thuần.
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())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: TrueCác con số khác nhau trên trục dọc, và một trong chúng là âm, điều mà một tổng bình phương không bao giờ có: negative log-likelihood có thể xuống dưới không, vì mật độ có thể vượt quá 1. Cùng đáy của cùng thung lũng, đến đúng điểm lưới cuối cùng.
Hiện toàn bộ phần suy diễn
Chính xác thì những phần bỏ đi nào là an toàn? Cùng thao tác này xuất hiện trong mọi chương suy ra một loss, và không phải lúc nào nó cũng vô hại.
Bỏ một hằng số cộng là an toàn bất cứ khi nào nó không phụ thuộc vào tham số bạn đang tối ưu, và bỏ một hằng số nhân dương là an toàn vì với mọi . Cả hai đều thất bại ngay khi cũng đang được fit: khi đó hoàn toàn không phải hằng số, nó là hạng ngăn model tuyên bố và likelihood vô hạn. Đó chính xác là phần tiếp theo.
Chúng lại thất bại theo cách khác ở Chapter 3: một hằng số nhân không dịch chuyển cực tiểu, nhưng nó scale gradient, và gradient bị nhân với learning rate. Chia cho để có mean squared error thay vì sum là vô hình với đáp án và cực kỳ hữu hình với lần huấn luyện — với tổng, tăng gấp đôi batch size làm gấp đôi mọi bước bạn đi.
Sigma is not free either
Liên kết đến mục: Sigma is not free eitherChúng ta cố định ở 0,12 bằng mệnh lệnh, và không ai ở nhà máy biết độ phân tán lỗi của thước cặp. Hãy xem nó như ẩn số thứ hai và để maximum likelihood quyết định cả nó. Ở đây hạng hằng số vừa bị bỏ quay trở lại, vì nó là thứ duy nhất đứng giữa model và tuyên bố về độ chính xác hoàn hảo.
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))best sigma on the grid : 0.1006
sqrt(mean squared residual) : 0.1006Hai kết quả khớp đến bốn chữ số thập phân, và không phải tình cờ: lấy đạo hàm biểu thức đó và đặt bằng không cho chính xác. Vậy mean squared error không chỉ giống một phương sai. Theo model này, nó chính là ước lượng maximum-likelihood của phương sai của nhiễu — con số bạn đã tối thiểu hóa bấy lâu là một ước lượng về mức nhiễu của cảm biến.
Một nếp gấp, nói thì rẻ mà về sau tự khám phá lại thì đắt: ước lượng đó bị chệch thấp, vì các phần dư được đo so với một fit vốn được chọn để làm chúng nhỏ. Hãy mô phỏng — hai trăm nghìn cuốn sổ, mỗi cuốn hai mươi số đọc, rút từ một phân phối có phương sai thật đúng bằng 1, với một tham số của fit được ước lượng từ chính các số đọc. Chia tổng bình phương cho cho trung bình 0,9501; chia cho cho 1,0001; và đúng bằng 0,95. Mỗi tham số bạn fit tiêu tốn một bậc tự do, và đây là trường hợp nhỏ nhất có thể thấy của một vấn đề lớn hơn nhiều: một model luôn trông tốt hơn trên dữ liệu mà nó được fit. Chapter 4 biến điều đó thành kỷ luật giữ lại dữ liệu, và Chapter 6 đặt tên cho hiệu ứng ấy.
A loss is a claim about the noise
Liên kết đến mục: A loss is a claim about the noiseNếu squared error khẳng định rằng nhiễu là Gaussian, câu hỏi tiếp theo là điều gì xảy ra khi khẳng định đó sai. Không phải hơi sai — mà sai theo cách các phép đo thật thường sai.
Trên sàn xưởng, hầu hết số đọc thước cặp chính xác đến một phần mười milimét, và một hoặc hai lần mỗi ca, một mảnh phoi lọt dưới mỏ kẹp khiến số đọc lệch vài milimét. Những lỗi như vậy là đuôi nặng: hầu hết thời gian thì nhỏ, thỉnh thoảng khổng lồ, và khổng lồ thường xuyên hơn nhiều so với điều đường cong chuông cho phép. Phân phối Cauchy là model sạch tiêu chuẩn cho hành vi đó, và mật độ của nó đơn giản như của Gaussian:
Khác biệt nằm ở phần đuôi: Gaussian giảm như , nhanh tàn nhẫn, còn Cauchy như , gần như không giảm. Hệ quả dễ thấy hơn dễ nói:
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}") 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.10Phương sai mẫu của Gaussian ổn định ở 0,0144, tức , và ở đó. Cauchy thì tăng, và tiếp tục tăng chừng nào bạn còn lấy mẫu, vì không có gì để nó hội tụ tới: phân phối Cauchy không có phương sai, và cũng không có trung bình. Squared error, thứ toàn bộ công việc là tối thiểu hóa trung bình các bình phương, đang bị yêu cầu một đại lượng không tồn tại.
Vậy đây là một ca mà thước cặp bị đánh lừa. Cùng hai mươi giờ, cùng lưỡi dao, cùng độ trôi 0,30 milimét mỗi giờ — chỉ có nhiễu giờ là Cauchy. Fit nó hai lần: một lần bằng cách tối thiểu hóa phần dư bình phương, một lần bằng cách tối thiểu hóa negative log-likelihood của nhiễu thật sự đã sinh dữ liệu. Mẹo đưa về tâm không giúp gì ở đây — nó chỉ ghim hệ số chặn cho squared error — nên cả hai fit đều dùng brute force trên một lưới hệ số chặn và độ dốc, vì chúng ta vẫn chưa có cách tìm đáy thung lũng ngoài việc ghé thăm nó.
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")Hai dòng được tô sáng là toàn bộ khác biệt giữa các fit. Lấy log của mật độ Cauchy, bỏ các hằng số đúng như trước, và là thứ còn lại. Cùng công thức, tuyên bố khác về nhiễu.
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 evaluatedLeast squares báo độ trôi 0,108 milimét một giờ, khoảng một phần ba tốc độ thật, và kết luận rằng lưỡi dao còn dùng tốt đến giờ 19,6. Đáp án thật là giờ 11,7. Nếu hành động theo fit đó, nhà máy chạy máy ép thêm tám giờ để tạo ra các chi tiết vượt dung sai, dựa trên thẩm quyền của loss function tiêu chuẩn nhất trong lĩnh vực. Cauchy fit, dùng cùng hai mươi số đọc, cùng lưới, và chỉ khác một dòng code, hạ cánh ở giờ 11,8.
Hai phản đối đáng được trả lời, vì cả hai là điều đầu tiên một kỹ sư giỏi sẽ nói.
Điểm ngoại lai quá rõ — cứ xóa nó đi. Bạn có thể, nó giúp, và vẫn chưa đủ. Xóa số đọc tệ nhất duy nhất đưa độ dốc least-squares từ 0,108 lên 0,239, vẫn đặt thời điểm thay lưỡi dao ở giờ 13,1, muộn một tiếng rưỡi; xóa điểm tệ nhất, fit lại, rồi xóa bất kỳ điểm nào tệ nhất bây giờ đưa bạn tới 0,286 — và hãy chú ý rằng đây đã là một thủ tục, không phải một quan sát: nếu thay vào đó xóa hai phần dư lớn nhất của fit ban đầu, bạn hạ cánh ở 0,223. Nhưng giờ bạn đã đưa ra các phán đoán không thể viết xuống hoặc bảo vệ, và tự động hóa quy tắc cũng không cứu nó: drop-the-largest-residual-then-refit, chạy trên một nghìn ca mô phỏng, có sai số độ dốc trung vị 0,0177 so với 0,0100 của likelihood fit, và lệch hơn 0,05 trong 14,7% số ca so với 1,3%. Xóa là một miếng vá chồng lên một giả định sai. Likelihood không cần miếng vá, vì nó chưa bao giờ giả định điểm ngoại lai là bất khả.
Bạn đã chọn một bộ dữ liệu may mắn. Phản đối đó hoàn toàn đúng, và đó là lý do thí nghiệm cuối mô phỏng một nghìn ca độc lập rồi refit theo cả hai cách trên mỗi ca.
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") 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 shiftsTrung vị, không phải trung bình, vì cùng lý do như mọi thứ khác trong phần này: các lỗi least-squares bị một Cauchy chi phối, nên trung bình của chúng không phải thứ ổn định để báo cáo. Least squares sai nặng trong hai ca trên năm; likelihood fit sai nặng trong một ca trên bảy mươi bảy, và thất bại tệ nhất của nó trên một nghìn ca nhỏ hơn một phần năm thất bại tệ nhất của least squares.
Không điều nào trong đây làm squared error trở nên xấu. Nó làm squared error trở nên cụ thể, và số học nói chính xác vì sao. Lấy một phần dư 0,1 mm và một phần dư 7 mm. Sau khi bình phương, số đọc xấu đóng góp vào tổng nhiều gấp 4.900 lần số đọc tốt, nên đường bị kéo nguyên khối về phía nó; dưới Cauchy log-likelihood, hai phần dư đó đóng góp 0,527 và 8,133, tỷ lệ 15,4. Số đọc xấu vẫn được tính, nó chỉ không được quyền quyết định. Đây là khởi đầu của thống kê robust, nơi loss năm 1964 của Huber chia đôi khác biệt bằng cách hành xử bậc hai với phần dư nhỏ và tuyến tính với phần dư lớn,7 và nơi Tukey trước đó đã cho thấy chỉ cần rất ít nhiễm bẩn đã đủ làm phương sai mẫu thành công cụ tệ hơn mean absolute deviation.8
Một ghi chú lịch sử, hay đến mức không nên bỏ qua. Least squares được công bố trước, bởi Legendre năm 1805, như một thiết bị đại số tiện lợi không có biện minh nào ngoài việc nó hiệu quả.9 Bốn năm sau, Gauss chạy lập luận ngược lại: ông xem như đã biết rằng trung bình cộng là cách đúng để kết hợp các phép đo lặp lại, hỏi phân phối lỗi nào khiến trung bình là giá trị có xác suất cao nhất, và chỉ ra rằng về cơ bản chỉ có một phân phối làm được — phân phối nay mang tên ông.10 Suy luận trong chương này là của ông, đã hơn hai thế kỷ tuổi, và vẫn là phần mà hầu hết khóa học bỏ qua.
What you can now say, and what you still cannot do
Liên kết đến mục: What you can now say, and what you still cannot doĐã đạt được. Một loss function là một quy tắc chấm điểm, và thứ hạng nó tạo ra là thuộc tính của quy tắc, không phải của các ứng viên. Mọi loss trong khóa học này là negative log-likelihood của một giả định nào đó về nhiễu, sau khi bỏ các hằng số — Gaussian cho squared error ở đây, Bernoulli cho cross-entropy ở Chapter 4, và một phân phối categorical trên một vocabulary cho next-token loss ở Chapter 8. Công thức không bao giờ đổi: nêu nhiễu, viết likelihood, lấy trừ log. Và khi giả định sai, model không chỉ thiếu chính xác, nó sai theo một hướng bạn có thể dự đoán.
Vẫn còn thiếu. Chúng ta tìm đáy thung lũng bằng cách ghé thăm mọi điểm trong đó. Cách đó hiệu quả với một tham số và sáu trăm ứng viên, và sống sót qua hai tham số ở 401.301 ứng viên trong một phần năm giây. Ba tham số ở cùng độ phân giải là 201.051.801 ứng viên và không còn vừa trong một array; một network nhỏ trong Chapter 5 có hàng nghìn tham số, và các model mà Chapter 10 đặt giá có hàng tỷ. Brute force ở đây không phải chậm, nó bất khả về số học, và không điều gì trong chương này gợi ý một lựa chọn thay thế.
Dù vậy, hãy nhìn lại thung lũng. Đứng tại với loss 0,0822, hướng "xuống dốc" không phải bí ẩn — bạn có thể thấy nó trên trang, đường cong dốc xuống về bên phải. Nếu bạn có thể hỏi loss function rằng nó dốc theo hướng nào tại điểm bạn đang đứng, mà không cần đánh giá nó ở nơi nào khác, bạn có thể bước theo hướng đó, hỏi lại, và lặp lại cho đến khi mặt đất phẳng.
Câu hỏi đó có một cái tên. Độ dốc của một hàm tại một điểm là đạo hàm của nó, và với một hàm nhiều tham số, tập hợp các độ dốc theo mọi hướng cùng lúc là gradient. Chapter 1 không thể dùng gradient, vì lỗi của perceptron là một cầu thang không có độ dốc để hỏi. Chương này đã xây được thứ tốt hơn: một loss trơn ở mọi nơi và đến từ một giả định đã nêu chứ không phải một sở thích.
Vậy câu hỏi cho Chapter 3 không còn là liệu một độ dốc có tồn tại hay không. Nó là cách tính nó, vì sao đi ngược nó lại xuống dốc thay vì lên dốc — một dấu mà hầu như mọi khóa học yêu cầu bạn tin — và bước bao xa trước khi hỏi lại, điều hóa ra là con số duy nhất quyết định một lần huấn luyện hội tụ, dao động quanh đáp án mãi mãi, hay chạy vọt ra vô cực.
Sources and method
Liên kết đến mục: Sources and methodCũng đáng đọc song song với chương này: Prince, Understanding Deep Learning §5.1–5.2 và Appendix C, xây dựng mọi loss trong sách từ maximum likelihood theo thứ tự dùng ở đây; Goodfellow, Bengio và Courville, Deep Learning §3.1–3.11 và §5.5, phần maximum-likelihood cũng suy ra KL divergence mà Chapter 4 cần; Murphy, Probabilistic Machine Learning: An Introduction chapter 2 và §4.2, về những gì maximum likelihood có và không bảo đảm; Deisenroth, Faisal và Ong, Mathematics for Machine Learning §6.1–6.4 cho sum rule, product rule và Bayes' rule được làm đúng; ghi chú ngắn của Tom Mitchell ở CMU Estimating Probabilities: MLE and MAP (2016); và §22.7 của Dive into Deep Learning, đạt cùng kết quả bằng code có thể chạy.
Tài liệu tham khảo
Liên kết đến mục: Tài liệu tham khảo-
Fisher, R. A. On the mathematical foundations of theoretical statistics. Philosophical Transactions of the Royal Society A 222, pp. 309–368 (1922). Nơi likelihood được trình bày như một phương pháp tổng quát, cùng với "parameter", "statistic", tính đủ và hiệu quả. Bản thân cách gọi tên, và sự tách biệt khỏi xác suất, đến sớm hơn một năm: 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. ↩
-
IEEE Standard for Floating-Point Arithmetic, IEEE 754-2019. Định nghĩa binary32 và binary16, cùng các quy tắc làm tròn khiến thí nghiệm cộng cho ra đúng như vậy. ↩
-
Kalamkar, D. et al. A Study of BFLOAT16 for Deep Learning Training. arXiv:1905.12322 (2019). Các tham số của định dạng, và lập luận cho việc đổi bit mantissa lấy bit exponent. ↩
-
Micikevicius, P. et al. Mixed Precision Training. ICLR 2018, arXiv:1710.03740. Loss scaling, và các độ lớn gradient đo được khiến nó cần thiết trong float16. ↩
-
Goldberg, D. What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys 23(1), pp. 5–48 (1991). Vẫn là lời giải thích đơn lẻ tốt nhất về vì sao hai thứ tự cộng bất đồng. ↩
-
Kahan, W. Pracniques: further remarks on reducing truncation errors. Communications of the ACM 8(1), p. 40 (1965). Phép cộng bù trong nửa trang. ↩
-
Huber, P. J. Robust estimation of a location parameter. The Annals of Mathematical Statistics 35(1), pp. 73–101 (1964). Loss có dạng bậc hai gần zero và tuyến tính ở đuôi, được suy ra chứ không phải vá lại. ↩
-
Tukey, J. W. A survey of sampling from contaminated distributions, in Contributions to Probability and Statistics (Stanford University Press, 1960), pp. 448–485. ↩
-
Legendre, A. M. Nouvelles méthodes pour la détermination des orbites des comètes (Paris, 1805), phụ lục Sur la méthode des moindres quarrés. Công bố đầu tiên về least squares, như một thiết bị tính toán. ↩
-
Gauss, C. F. Theoria Motus Corporum Coelestium (Hamburg, 1809), Book II, §§175–179. Lập luận từ trung bình cộng đến luật lỗi chuẩn, và từ đó đến least squares. ↩