분류, cross-entropy, 그리고 스스로를 속이지 않는 법
2장의 loss와 3장의 descent로 logistic classifier를 만들고, 98% 정확도가 아무것도 찾지 못하는 모델일 수 있는 이유를 봅니다.
이 페이지에서
벨트에서 나오는 모든 부품에 대해 이 부품은 괜찮다고 답하는 모델은 98.15 %의 경우 맞습니다. 동시에 아무 쓸모도 없습니다. 테스트 세트의 불량 부품 74개 중 하나도 잡아내지 못하기 때문입니다.
두 문장은 같은 모델을 설명합니다. 그 둘 사이의 거리가 이 장입니다.
전반부는 classifier를 만듭니다. 새로 필요한 것은 거의 없습니다. 2장은 데이터가 어떻게 생성되는지에 대한 가정을 loss function으로 바꾸는 레시피를 주었고, 3장은 그 레시피가 건네주는 어떤 loss 위에서도 아래로 걸어 내려가는 기계를 주었습니다. 이 둘을 예/아니오 질문에 적용하면 logistic regression이 나오고, 여기에 새로운 아이디어 하나 — logit — 가 더해집니다. 이 logit은 17장에서 다시 비용을 청구하게 됩니다.
후반부가 더 어렵습니다. 이 지점 이후의 과정에서는 모든 것이 누군가 측정한 숫자로 평가됩니다. 진짜 개선과 측정 artefact를 구분하지 못한다면, 뒤따르는 모든 장은 장식에 불과합니다. 그래서 다룰 것은 confusion matrix, precision과 recall, 세 가지 split, leakage, 그리고 거의 아무도 솔직히 답하지 않는 질문입니다 — 실제로 테스트 예제는 몇 개나 필요할까?
여기서의 산술은 20,000개 행 위에서 돌아가므로 전체가 vectorised되어 있습니다. NumPy는 2장부터 계속 일을 해 왔고, 이제부터는 그것을 굳이 언급할 가치가 없어집니다.
더 희귀한 질문이 있는 벨트
섹션 링크: 더 희귀한 질문이 있는 벨트1장과 같은 공장, 더 어려운 질문입니다. 받을 것인가 거부할 것인가 대신 질문은 이 부품이 불량인가입니다. 그리고 불량은 드뭅니다. 이 점이 이 장의 측정 절반을 어렵게 만들고, 모델링 절반을 기만적으로 쉽게 만듭니다.
import numpy as np
rng = np.random.default_rng(4)
N = 20_000
width = rng.normal(22.0, 0.9, N) # millimetres
weight = rng.normal(57.0, 3.0, N) # grams
z_true = -5.90 + 1.90 * (width - 22.0) + 0.42 * (weight - 57.0)
y = (rng.random(N) < 1 / (1 + np.exp(-z_true))).astype(float)
perm = rng.permutation(N)
train, val, test = perm[:12_000], perm[12_000:16_000], perm[16_000:]N = 20000 defects = 337 base rate = 0.0169
defects per split = 203 60 74split은 두 개가 아니라 세 개입니다. 그 이유는 별도 절을 받을 만하고 아래에서 다룹니다. 지금은 첫 번째로 train하고, 두 번째로 tune하고, 세 번째는 보지 마세요.
features는 standardised됩니다 — 평균을 빼고 표준편차로 나눕니다 — 단 training statistics만 사용해서 입니다. 이유는 1장에서 perceptron의 convergence bound로 보였듯, 중심이 맞지 않은 데이터는 기하를 적대적으로 만들기 때문입니다. 그 평균을 어떤 행에서 계산할 수 있는지는 이 장 뒤쪽에서 살아 있는 질문이 됩니다.
판정에서 확률로
섹션 링크: 판정에서 확률로perceptron은 부호를 반환했습니다. 부호는 거부와 거부, 하지만 간신히를 구분할 수 없습니다. 그리고 바로 그 차이가 공장에서 사람이 어떤 부품을 먼저 재검사할지 결정하는 데 필요합니다.
그러니 2장의 레시피를 글자 그대로 따릅니다. label이 어떻게 생성된다고 주장하는지 적고, likelihood를 취하고, log를 취하고, 부호를 바꾸면 loss가 됩니다. 예/아니오 결과에 대한 주장은 Bernoulli 분포입니다. 부품이 불량일 확률이 이고,
이는 “이면 , 이면 ”라고 쓰는 간결한 방식일 뿐입니다. 여기에 log를 취하고 부호를 바꾸면, 한 예제의 loss는
이것이 binary cross-entropy입니다. 편리해서 선택한 것이 아닙니다. 동전 던지기가 가질 수 있는 유일한 분포의 negative log-likelihood입니다. 다른 선택지는 없었습니다.
아직 빠진 것은 가 어디서 오는가입니다. 모델은 weighted sum 을 계산합니다. 이는 실수이고 전체 직선을 범위로 갖지만, 확률은 안에 살아야 합니다. 둘 사이를 옮겨 주는 함수가 logistic sigmoid입니다.
logit -4.0 -> p = 0.0180 loss when y=1 and p=0.9 : 0.1054
logit -1.0 -> p = 0.2689 loss when y=1 and p=0.5 : 0.6931
logit 0.0 -> p = 0.5000 loss when y=1 and p=0.01 : 4.6052
logit 4.0 -> p = 0.9820오른쪽 열을 가격표처럼 읽으세요. 90 % 확신으로 맞으면 비용은 0.105입니다. 결정을 회피하면 0.693을 냅니다 — 이는 , 어깨를 으쓱하는 가격입니다. 자신 있게 틀리면 4.6, 44배 더 비싸고, 모델이 실수에 더 확신할수록 가격은 한없이 올라갑니다. cross-entropy는 단순히 오류를 세지 않습니다. 오만함에 요금을 매깁니다.
gradient는 prediction minus truth입니다
섹션 링크: gradient는 prediction minus truth입니다3장은 말했습니다. 무엇이든 train하려면 각 parameter에 대한 loss의 derivative를 구하라고요. 한 예제에 대해 해 봅시다. 및 일 때:
세부 정보 보기
지저분함을 상쇄시키는 두 줄. sigmoid에는 유난히 기분 좋은 derivative, 가 있습니다. 그리고 loss를 미분하면
chain rule로 둘을 곱하면 가 위와 아래에 한 번씩 나타납니다. 정확히 상쇄되고, 만 살아남습니다. 이 상쇄는 우연이 아닙니다. loss가 어떤 분포의 negative log-likelihood이고 output function이 그 분포가 자연스럽게 사용하는 함수일 때마다 일어나는 일입니다. 이 짝에는 이름이 있습니다 — generalised linear model — 그리고 깔끔한 gradient는 그 지문입니다.1
따라서 update는 prediction minus truth, times the input입니다. 그 이상은 없습니다. 아래가 전체 trainer입니다. 3장의 descent에서 한 줄만 바뀌었습니다.
def sigmoid(z):
return np.where(z >= 0, 1.0 / (1.0 + np.exp(-z)),
np.exp(np.minimum(z, 0)) / (1.0 + np.exp(np.minimum(z, 0))))
def fit_logistic(X, y, lr=0.5, epochs=4000):
w, b = np.zeros(X.shape[1]), 0.0
for _ in range(epochs):
p = sigmoid(X @ w + b)
g = p - y
w -= lr * (X.T @ g) / len(y)
b -= lr * g.sum() / len(y)
return w, bsigmoid 안의 np.where는 장식이 아닙니다. 를 직접 계산하면 큰 음수 에서 overflow가 납니다. branch는 지수부를 음수로 유지하는, 대수적으로 같은 형태를 고릅니다. 이것은 2장의 floating-point 상자가 첫 번째 빚을 회수하는 순간이고, 두 절 뒤에서 더 큰 빚을 회수할 것입니다.
왜 squared error가 아니며, 왜 답은 gradient에 관한 것인가
섹션 링크: 왜 squared error가 아니며, 왜 답은 gradient에 관한 것인가cross-entropy를 squared error보다 선호하는 표준 설명은 위의 likelihood argument입니다. squared error는 Gaussian noise를 가정할 때 나오는 것이고, labels는 Gaussian이 아니므로 쓰지 말라는 것입니다. 맞는 말이지만 아무도 설득하지 못합니다. sigmoid 위에 를 써도 train은 되기 때문입니다.
와닿는 논증은 gradient에 관한 것입니다. sigmoid 위에 squared error를 올리면 chain rule은
을 줍니다. 추가된 가 앞에서는 상쇄되었던 바로 그 항입니다. 이제는 상쇄되지 않고, 모델이 확신할 때마다 0으로 갑니다 — 모델이 자신 있게 틀렸을 때도 포함해서요. true label이 1인 예제에 대해 몇 가지 score에서 둘을 평가해 봅니다.
| score | cross-entropy | squared error | ratio | |
|---|---|---|---|---|
| 0.000335 | 1,491 | |||
| 0.017986 | 28.3 | |||
| 0.119203 | 4.8 | |||
| 0.500000 | 2.0 | |||
| 0.880797 | 4.8 |
에서 모델은 가능한 만큼 틀렸고, squared error는 cross-entropy의 gradient보다 1,491배 작은 gradient로 반응합니다. 실수가 나쁠수록 모델은 그 실수에서 덜 배웁니다. 반면 cross-entropy의 gradient는 에서 saturate됩니다. 최대한 틀리면 최대한 큰 signal이 나오며, 그보다 커지지는 않습니다.
경주를 돌려 봅니다. balanced points 2,000개, 자신 있게 틀리도록 선택한 동일한 시작 weights(), 동일한 learning rate, 다른 것은 loss뿐입니다. 두 run 모두 cross-entropy로 점수를 매겨 열을 비교할 수 있게 했습니다.
| epoch | cross-entropy loss | accuracy | squared-error loss | accuracy |
|---|---|---|---|---|
| 1 | 5.4865 | 0.2300 | 5.9499 | 0.2290 |
| 10 | 1.5525 | 0.2460 | 5.9042 | 0.2290 |
| 50 | 0.4642 | 0.7780 | 5.6913 | 0.2320 |
| 100 | 0.4639 | 0.7770 | 5.3955 | 0.2410 |
| 200 | 0.4639 | 0.7770 | 4.6311 | 0.2745 |
| 500 | 0.4639 | 0.7770 | 0.5291 | 0.7660 |
| 1,000 | 0.4639 | 0.7770 | 0.4640 | 0.7765 |
cross-entropy는 epoch 50에서 끝납니다. squared error는 epoch 100에서도 accuracy 24 %입니다 — epoch 10의 23 %에서 움직이지도 않았습니다 — — guessing보다 나쁩니다. 자신 있게 틀린 상태에서 시작했고, 구해 줄 gradient가 0.0007로 곱해졌기 때문입니다. epoch 500쯤 탈출해서 같은 지점에 도착합니다. 그러므로 정직한 요약은 sigmoid 위의 squared error가 틀린 것은 아니라는 것입니다. 다만 속도가 가장 중요한 곳에서 정확히 느립니다. 두 parameter 모델에서는 450 epoch를 잃습니다. 어디선가 어떤 unit은 항상 자신 있게 틀려 있는 100층 network에서는 training run을 잃습니다.
Entropy, cross-entropy, KL을 한 페이지로
섹션 링크: Entropy, cross-entropy, KL을 한 페이지로세 가지 양입니다. 8장의 perplexity와 11장의 fine-tuned policy를 reference 근처에 붙들어 두는 penalty에서 제대로 필요합니다. 평판보다 쉽습니다.2
Entropy는 어떤 분포에서 뽑힌 값을 전달하기 위해 써야 하는 평균 bit 수입니다. 그 분포에 가능한 최선의 code를 쓸 때입니다.
Cross-entropy는 실제로는 에서 오는 데이터에 대해 용으로 만든 code를 사용할 때 지불하는 비용입니다.
KL divergence는 초과분입니다 — 진실이 인데 라고 믿어서 생기는 bit 단위의 낭비입니다.
벨트에서 셋을 확인해 봅니다.
test defect rate = 0.0185
entropy of that coin = 0.1329 bits
cross-entropy of the constant predictor on test = 0.1330 bits
KL(test coin || fair coin) = 0.8671 bits
H + KL = 1.0000 bits
cross-entropy of the p=0.5 predictor on test = 1.0000 bits두 가지가 보입니다. 첫째, training base rate인 1.69 %만 보고하는 모델은 cross-entropy 0.1330 bits를 달성합니다. 테스트 labels의 entropy와 거의 정확히 같습니다. 그래야만 합니다. 올바른 분포를 갖고 있지만 다른 정보는 없기 때문입니다. Entropy는 개인에 대해 무지할 때 얻게 되는 바닥입니다. 둘째, 어깨를 으쓱하며 0.5라고 말하는 모델은 정확히 1 bit를 냅니다. 그리고 둘 사이의 차이인 0.8671 bits가 바로 KL divergence입니다. 는 외울 항등식이 아닙니다. 더해지는 청구서를 직접 볼 수 있는 것입니다.
그리고 training으로 돌아가는 연결은 이렇습니다. label이 하나의 알려진 class일 때, “true” distribution은 one-hot이고 entropy는 0이며 cross-entropy는 KL divergence와 같습니다. cross-entropy를 최소화하는 것과 모델의 distribution을 진실 쪽으로 끌어당기는 것은 같은 행위입니다.
답이 둘보다 많을 때: softmax, 그리고 아무 비용 없는 shift
섹션 링크: 답이 둘보다 많을 때: softmax, 그리고 아무 비용 없는 shiftDefective는 하나가 아닙니다. molding에서 부품은 short shot(재료 부족), flash(너무 많아 금형 밖으로 밀려나옴), 또는 burn으로 나올 수 있습니다. 결과는 네 가지이므로 logits도 네 개이고, 합이 1인 네 probability가 되어야 합니다. 그것이 softmax입니다.
우연처럼 보이지만 사실 구현 전체인 성질이 있습니다.
어떤 상수 에 대해서도 그렇습니다. 이고 가 위아래에서 상쇄되기 때문입니다. logits 사이의 차이만 의미가 있습니다. 절대 수준은 정보가 아닙니다.
다행입니다. 컴퓨터를 망가뜨리는 것이 바로 절대 수준이기 때문입니다.
logits = [800. 801. 799.]
naive softmax = [nan nan nan]
shifted by -max = [0.2447 0.6652 0.09 ]
same softmax after adding 1000 to every logit: True는 64-bit float에서 overflow되고, 합은 infinity가 되며, infinity를 infinity로 나누면 nan이 됩니다 — error도 아니고 crash도 아니며, 세 probability가 있던 자리에 생기는 조용한 구멍입니다. 최대 logit을 빼는 것은 수학적으로는 아무것도 바꾸지 않지만 수치적으로는 모든 것을 바꿉니다. 가장 큰 exponent가 정확히 이 되기 때문입니다. 이것은 2장의 logsumexp trick이 작업복을 입은 모습이고, 모든 진지한 구현이 그렇게 합니다.
def softmax(Z):
Z = Z - Z.max(axis=1, keepdims=True)
E = np.exp(Z)
return E / E.sum(axis=1, keepdims=True)
def fit_softmax(X, Y, lr=1.0, epochs=6000):
W, b = np.zeros((X.shape[1], Y.shape[1])), np.zeros(Y.shape[1])
for _ in range(epochs):
G = (softmax(X @ W + b) - Y) / len(X)
W -= lr * (X.T @ G)
b -= lr * G.sum(0)
return W, bgradient는 다시 prediction minus truth입니다. 이제 는 one-hot입니다. binary case는 처음부터 special case였을 뿐입니다.
부품 3,000개로 train하고 1,000개로 test했으며, 각 부품에는 측정값 세 개(width, weight, melt temperature)가 있습니다. 94.00 % accuracy에 도달합니다. 그 숫자가 숨기는 것은 다음과 같습니다.
| truth ↓ / predicted → | ok | short shot | flash | burn | recall |
|---|---|---|---|---|---|
| ok | 850 | 5 | 9 | 0 | 0.984 |
| short shot | 22 | 21 | 0 | 0 | 0.488 |
| flash | 20 | 0 | 30 | 1 | 0.588 |
| burn | 3 | 0 | 0 | 39 | 0.929 |
| precision | 0.950 | 0.808 | 0.769 | 0.975 |
모델은 short shot의 절반도 찾지 못합니다. accuracy는 이것을 볼 수 없습니다. 부품의 86 %가 정상이고, 그것들을 맞히는 것만으로 평균을 끌고 갈 수 있기 때문입니다. Macro F1 — class별 F1 score의 평균으로, rare class와 common class를 같은 무게로 둡니다 — 은 0.7983입니다. micro F1은 0.9400이고, 정의상 accuracy와 같습니다. 누군가 F1 숫자 하나를 보고하면 어떤 F1인지 물어보세요.
모델링은 여기까지입니다. 이 장의 나머지는 숫자에 관한 것입니다.
세 모델, 하나의 accuracy
섹션 링크: 세 모델, 하나의 accuracytrain된 binary model을 가져와 모든 logit에 상수를 곱해 두 variant를 만듭니다. 주저하는 버전에는 0.35, 과신하는 버전에는 4입니다. 양수를 곱해도 어떤 부호도 바뀌지 않으므로 세 모델은 4,000개 테스트 부품 모두에 대해 정확히 같은 label을 예측합니다. accuracy는 구분할 수 없습니다. cross-entropy는 전혀 어려워하지 않습니다.
| model | accuracy | cross-entropy | mean loss when right | mean loss when wrong | worst single loss |
|---|---|---|---|---|---|
| hesitant (logits × 0.35) | 0.9830 | 0.1549 | 0.1369 | 1.1990 | 2.80 |
| as trained | 0.9830 | 0.0564 | 0.0147 | 2.4689 | 7.82 |
| overconfident (logits × 4) | 0.9830 | 0.1563 | 0.0009 | 9.1427 | 27.63 |
주저하는 모델은 모든 부품에 작은 세금을 냅니다. 맞힌 수천 개에도 마찬가지입니다. 과신하는 모델은 맞을 때는 거의 공짜지만 틀릴 때는 재앙입니다. 그 test set의 부품 하나만으로도 27.63 nats를 냅니다. 둘은 정반대 경로로 거의 같은 총액에 도착하고, probability가 데이터에 calibrated된 train된 모델은 둘보다 세 배 아래에 있습니다.
이것이 loss와 metric의 차이를 가장 날카롭게 말하는 방식입니다. loss는 optimise하는 것입니다. differentiable해야 하고, 모델이 말한 모든 것, including 얼마나 확신했는지를 봅니다. metric은 평가받는 것입니다. step function일 수도 있고, business rule일 수도 있고, 놓친 불량의 count일 수도 있습니다. 둘은 같은 객체가 아니며 항상 동의하지도 않습니다. 그래서 시작 전에 둘 다 정의해야 하고, 화면에 보인다는 이유로 loss가 metric을 대신하게 두면 안 됩니다.
멍청한 baseline이 먼저입니다
섹션 링크: 멍청한 baseline이 먼저입니다어떤 모델보다 먼저 필요한 것은 이것입니다. 가장 게으른 답은 몇 점인가? 이 벨트에서는 항상 정상이라고 말하기입니다.
always-say-fine baseline: accuracy = 0.9815
confusion (tn, fp, fn, tp) = (3926, 0, 74, 0)98.15 %. 이제 train된 logistic model을 기본 threshold 0.5에서 봅니다.
logistic @0.5: accuracy=0.9830 precision=0.8000 recall=0.1081 F1=0.1905
confusion (tn, fp, fn, tp) = (3924, 2, 66, 8)98.30 %. baseline을 0.15 percentage point 이겼고, accuracy에서 멈추는 보고서는 이것을 승리라고 부를 것입니다. confusion matrix는 실제로 무슨 일이 일어났는지 말합니다.
| predicted fine | predicted defective | |
|---|---|---|
| actually fine | 3,924 | 2 |
| actually defective | 66 | 8 |
그 모델은 불량 부품 74개 중 8개를 찾았고 66개를 통과시켰습니다. 세 숫자가 이 표를 읽는 세 가지 방식을 이름 붙입니다.
- Precision . 모델이 표시한 부품 중 실제로 불량인 것은 몇 개인가. 이것은 낭비된 검사 비용입니다.
- Recall . 불량 부품 중 몇 개를 잡았는가. 이것은 나쁜 부품을 고객에게 보내는 비용입니다.
- F1 , 둘의 harmonic mean으로, 더 작은 쪽 근처에 머물러 둘 중 하나만으로 치켜세워지는 것을 거부합니다.
무엇이 중요한지는 수학이 아니라 공장에 달려 있습니다. 검사는 몇 초가 들고, 출하된 불량은 리콜 통지를 부릅니다. 그래서 여기서는 recall이 지배적이며 0.108은 실패입니다.
하지만 모델이 문제가 아닙니다. threshold가 문제입니다. 그리고 threshold는 모델의 일부가 아닙니다. probability에 사후 적용되는 business decision입니다. sweep해 봅니다.
| threshold | TP | FP | FN | accuracy | precision | recall | F1 |
|---|---|---|---|---|---|---|---|
| 0.500 | 8 | 2 | 66 | 0.9830 | 0.800 | 0.108 | 0.190 |
| 0.200 | 27 | 28 | 47 | 0.9812 | 0.491 | 0.365 | 0.419 |
| 0.100 | 42 | 118 | 32 | 0.9625 | 0.263 | 0.568 | 0.359 |
| 0.050 | 54 | 236 | 20 | 0.9360 | 0.186 | 0.730 | 0.297 |
| 0.020 | 67 | 570 | 7 | 0.8558 | 0.105 | 0.905 | 0.188 |
| 0.005 | 71 | 1,360 | 3 | 0.6593 | 0.050 | 0.959 | 0.094 |
accuracy 열을 아래로 읽어 보세요. 98.30 %에서 65.93 %까지 계속 떨어집니다. 그동안 모델은 불량 8개를 잡는 데서 74개 중 71개를 잡는 데로 갑니다. 이 모델이 할 수 있는 모든 유용한 일은 accuracy를 더 나쁘게 만듭니다. headline number를 optimise하는 팀은 아무것도 찾지 못하는 버전을 출하할 것입니다.
세부 정보 보기
Class weighting은 signal을 만들지 않습니다. operating point를 옮깁니다. imbalanced classes에서 보통 첫 반응은 rare class에 loss weight를 주는 것입니다. positives에 1, 10, 60의 weight를 주면 다음과 같습니다.
| weight on positives | accuracy | precision | recall | F1 | AUC |
|---|---|---|---|---|---|
| 1 | 0.9830 | 0.800 | 0.108 | 0.190 | 0.9363 |
| 10 | 0.9605 | 0.253 | 0.581 | 0.352 | 0.9361 |
| 60 | 0.8290 | 0.091 | 0.919 | 0.166 | 0.9361 |
precision과 recall은 크게 움직입니다. AUC — 모델이 random defective part를 random good one보다 위에 rank할 probability로, threshold를 완전히 무시합니다 — 는 0.0002 움직입니다. 아무것도 아닙니다. Reweighting은 같은 모델을 같은 trade-off curve 위에서 미끄러뜨렸습니다. 그것이 원하는 일인 경우가 많고, 그것은 결코 새 정보가 아닙니다. ranking이 나쁘다면 어떤 weighting scheme도 구하지 못합니다.
세 split, 그리고 곧 찾게 될 leak
섹션 링크: 세 split, 그리고 곧 찾게 될 leak왜 split이 두 개가 아니라 세 개인가요? 어떤 예제 세트를 사용해 무엇이든 선택하는 순간 — threshold, learning rate, 여섯 모델 중 출하할 것 — 그 세트는 fitting에 사용된 것이고, 그 score는 unbiased가 아니게 됩니다.3 이 벨트에서 측정하면, validation set에서 threshold를 sweep해 0.196을 고르고, 모델은 untouched test set에서 F1 = 0.4122를 기록합니다. sweep을 test set에서 직접 돌렸다면 거기서 가능한 최고값은 0.4186이었습니다 — 누구도 보고할 자격이 없는 숫자입니다.
여기서는 gap이 0.006으로 작습니다. hyperparameter 하나를 validation examples 4,000개에 대해 한 번 sweep했기 때문입니다. 결정이 하나씩 늘고 validation set이 작아질수록 gap은 커집니다. 또한 단일 run에서 방향이 보장되지 않는다는 점도 주의하세요. 선택된 threshold는 validation에서 0.3902, test에서 0.4122를 기록했으므로 이번에는 validation이 과소평가했습니다. bias는 많은 결정 전체에서 systematic한 것이지, 한 번에 보이는 것이 아닙니다.4
이제 연습입니다. 벨트 log에는 세 번째 column station_seconds가 있습니다. 각 부품이 inspection station에 머문 시간입니다. 이것을 추가하는 것은 preprocessing의 한 줄 변경입니다. 결과는 다음과 같습니다.
| model | accuracy | precision | recall | F1 | cross-entropy | AUC |
|---|---|---|---|---|---|---|
| width + weight | 0.9830 | 0.800 | 0.108 | 0.190 | 0.0564 | 0.9363 |
| + station_seconds | 0.9920 | 0.792 | 0.770 | 0.781 | 0.0236 | 0.9970 |
recall이 10.8 %에서 77.0 %로 갑니다. F1은 네 배 이상이 됩니다. 그리고 accuracy가 한 일을 보세요. 98.30 % → 99.20 %, 0.9 point gain입니다. summary slide에서는 “어느 쪽이든 약 99 %”로 반올림될 만한 숫자입니다. accuracy는 앞서 실패를 보지 못했고, 이제는 사기도 보지 못합니다.
계속 읽기 전에: 모델은 부정행위를 하고 있습니다. 어떻게인지 찾아보세요.
leak를 찾는 법, 가장 빨리 찾는 순서.
-
Train과 test를 비교합니다. Overfitting은 큰 gap으로 나타납니다. 여기서는 honest model이 0.9838 train / 0.9830 test, leaky model이 0.9936 train / 0.9920 test입니다. 두 gap 모두 0.2 point 미만입니다. leak는 overfitting처럼 보이지 않습니다 — leaky feature가 test time에도 똑같이 available하기 때문에, 모델은 존재하지 않는 세계에 아름답게 generalise합니다.
-
feature 하나당 모델 하나를, 단독으로 train합니다. 답을 담고 있는 것은 스스로를 드러냅니다.
feature alone accuracy recall F1 AUC width 0.9815 0.014 0.026 0.8691 weight 0.9815 0.000 0.000 0.7914 station_seconds0.9850 0.405 0.500 0.9960 column 하나가 단독으로 defects를 AUC 0.9960으로 rank합니다. caliper와 scale로 잰 두 measurements는 0.87과 0.79입니다. 이 비대칭이 경보입니다.
-
각 숫자가 언제 기록되었는지 묻습니다. mean dwell time은 passed parts에서 2.23 seconds, failed parts에서 15.56 seconds입니다. 당연합니다. 부품은 inspector가 벨트에서 빼냈기 때문에 station에 머뭅니다. 이는 누군가 그것을 defective라고 결정한 뒤에, 그리고 오직 그 이유 때문에 일어납니다. 이 column은 부품의 measurement가 아닙니다. verdict의 measurement입니다.
station = 1.8 + rng.exponential(0.35, N) # a part just passing through
audited = rng.random(N) < 0.006 # random spot checks
station[audited] += rng.uniform(6.0, 26.0, audited.sum())
station[y == 1] = 9.0 + rng.exponential(7.0, (y == 1).sum()) highlight된 줄이 leak입니다. defective part의 dwell time은 다른 distribution에서 뽑힙니다. 사람이 그것을 벨트에서 빼냈기 때문입니다. 이것은 applied machine learning에서 가장 흔한 심각한 bug이고, 이름이 있습니다. target leakage — prediction이 이루어져야 하는 순간에는 available하지 않을 정보가 training features 안에 있는 것입니다.5 exception을 던지지 않습니다. 더 좋은 숫자를 만들어 냅니다. 프로젝트의 모든 incentive는 그것을 유지하는 쪽을 가리킵니다.
방어책은 모든 column에 던지는 하나의 질문입니다. 이 prediction이 필요한 바로 그 순간, 이 값은 이미 존재하는가? live belt에서는 station_seconds를 부품 검사 이후에야 알 수 있습니다. 그런데 그것이 모델이 대체해야 할 일이었습니다.
테스트 예제는 몇 개나 필요할까?
섹션 링크: 테스트 예제는 몇 개나 필요할까?모델을 20개 예제에서 평가했고 17개를 맞혔다고 합시다. 85 %라고 보고합니다.
17 correct out of 20 -> accuracy 0.8500
Wilson 95% CI : [0.6396, 0.9476]
bootstrap 95% CI : [0.7000, 1.0000]
P(a 65% model scores 17 or more out of 20) = 0.0444
P(an 85% model scores 17 or more out of 20) = 0.647717/20의 정직한 해석은 64 %와 95 % 사이 어딘가입니다. 진짜 65 % 모델도 이 결과를 4.4 % 확률로 냅니다 — 23번에 한 번 — 그리고 prompt 몇 개를 시험해 본 뒤 최고를 보고했다면 그 run을 직접 제조한 것입니다. 20개 중 17개는 85 % 모델과 65 % 모델을 구분할 수 없습니다.
rate에 interval을 붙이는 두 가지 방법이 있으며, 둘 다 toolkit에 있어야 합니다.
def wilson(k, n, z=1.959963985):
"""95% interval for k successes in n trials. Correct at small n; no simulation."""
ph, d = k / n, 1 + z * z / n
centre = (ph + z * z / (2 * n)) / d
half = z * (ph * (1 - ph) / n + z * z / (4 * n * n)) ** 0.5 / d
return centre - half, centre + half
def bootstrap_ci(correct, n_resamples=10_000, alpha=0.05, seed=0):
"""95% interval for the mean of any per-example score array. Works on F1 too."""
rng = np.random.default_rng(seed)
correct = np.asarray(correct, dtype=float)
draws = correct[rng.integers(0, len(correct), size=(n_resamples, len(correct)))]
lo, hi = np.quantile(draws.mean(axis=1), [alpha / 2, 1 - alpha / 2])
return float(correct.mean()), float(lo), float(hi)평범한 success rate에는 Wilson6을 쓰세요. 어떤 에서도 잘 behaved되고 randomness가 필요 없습니다. 위에서 일 때 bootstrap의 upper end가 1.0000임을 보세요. 20개 point를 resampling하면 20개 correct를 쉽게 뽑을 수 있으므로, 자기 granularity보다 좁은 interval을 표현할 수 없습니다. 공식이 없는 곳에는 bootstrap7을 쓰세요. 대부분의 흥미로운 case가 그렇습니다. F1, macro-averages, BLEU, pass@1, rubric-based judge의 score입니다. 이 벨트에서 tuned model의 F1 0.4122는 **[0.3009, 0.5156]**의 bootstrap interval을 가집니다. 보고서에는 이 숫자가 들어가야 합니다. point estimate만 있으면 support할 수 없는 비교를 부르기 때문입니다.
마지막 measurement 하나를 더 봅니다. 두 모델을 비교하는 방식이 바뀌기 때문입니다. 같은 500 examples에서 scored된 두 모델입니다.
model A: 0.8580 95% CI [0.8260, 0.8880]
model B: 0.8120 95% CI [0.7780, 0.8460]
the two intervals overlap: True
paired difference A-B: 0.0460 95% CI [0.0260, 0.0680]
they disagree on 31 of 500 examples (A right 27, B right 4)interval은 겹칩니다. 그리고 folk rule — error bar가 겹치면 significant difference가 없다 — 은 이 비교를 inconclusive하다고 부를 것입니다. 그렇지 않습니다. 두 모델은 같은 examples에서 run했으므로, 올바른 quantity는 per-example difference이고, 그 interval은 [0.0260, 0.0680]이며 0보다 넉넉히 위입니다. 두 모델은 500 items 중 31개에서만 의견이 다르고, A는 그 disagreement 중 27개에서 이깁니다. 쉬운 것과 어려운 것을 포함한 shared examples가 noise를 더하는 대신 상쇄됩니다. 모델을 paired로 비교하면 훨씬 적은 데이터로 같은 결론에 도달합니다.
다음은 어디로 가는가
섹션 링크: 다음은 어디로 가는가이제 당신에게는 calibrated probabilities를 출력하는 모델, 편의를 위해 고른 것이 아니라 데이터에 대한 claim에서 derived된 loss, 말 그대로 prediction minus truth인 gradient, 그리고 — 더 중요하게 — 그중 어떤 것이 작동하는지 알아내는 machinery가 있습니다. 위의 10줄짜리 Wilson interval은 그대로 재사용됩니다. 15장의 prompt variants, 19장의 retrieval tables, 29장의 golden set을 지탱합니다. 공식이 없을 때 손을 뻗는 곳이 bootstrap입니다.
하지만 모델은 여전히 한 layer입니다. 선을 긋고, 1장은 XOR 네 행으로 선 하나로는 충분하지 않다는 것을 증명했습니다. 해결책은 쌓는 것입니다. 첫 layer가 공간을 휘게 하고, second layer가 휘어진 공간에 선을 긋습니다.
이 지점에서 이 장의 tidy gradient는 끝납니다. 위의 모든 것은 를 손으로 한 번 써 내려갈 수 있었기 때문에 작동했습니다. input과 loss 사이에 layer 하나가 있는 모델이었기 때문입니다. 중간에 second layer를 넣으면 질문의 모양이 바뀝니다. output을 전혀 건드리지 않는 weight — 그 영향이 다른 layer를 통해서만, 어쩌면 여러 path를 동시에 통해서 도착하는 weight — 에 대한 loss의 derivative는 무엇일까요?
그 derivative는 존재합니다. toy보다 큰 것에서 손으로 계산하는 것은 가망이 없고, parameter 하나씩 계산하는 것도 다른 scale에서 가망이 없습니다. 필요한 것은 forward pass가 방금 걸어간 같은 graph 위에서 single backward pass로 network의 모든 derivative를 얻는 절차입니다.
그것이 5장이고, 이 과정의 나머지가 달리는 engine입니다.
Sources and method
섹션 링크: Sources and method이 장과 함께 읽을 만한 것들: Bishop, Pattern Recognition and Machine Learning §1.2, §1.5, §1.6 and §4.3. 이 장이 따르는 순서대로 probability, decision theory, information theory, linear classification을 다룹니다. Murphy, Probabilistic Machine Learning: An Introduction, chapters 6 and 10; Prince, Understanding Deep Learning §5.4–5.7; 그리고 Saito and Rehmsmeier, The Precision-Recall Plot Is More Informative than the ROC Plot When Evaluating Binary Classifiers on Imbalanced Datasets (PLOS ONE, 2015) — 부품의 1.7 %가 defective일 때 위에서 인용한 AUC가 당신이 봐야 할 유일한 threshold-free number가 아니어야 하는 이유입니다.
-
Ma, T. and Ng, A. CS229 Lecture Notes, Stanford University, chapters 2 and 3. 를 만들어 내는 상쇄가 운처럼 보이지 않게 되는 지점입니다. output에 맞는 exponential-family distribution을 선택하고, 그 canonical link를 사용하면 gradient는 항상 prediction minus truth입니다. ↩
-
Olah, C. Visual Information Theory (2015),
colah.github.io/posts/2015-09-Visual-Information. entropy, cross-entropy, KL divergence를 공식이 아니라 bits 단위의 비용으로 설명한 가장 명확한 글입니다. ↩ -
Abu-Mostafa, Y. S., Magdon-Ismail, M. and Lin, H.-T. Learning From Data (AMLBook, 2012), Caltech course의 lectures 13 and 17. Lecture 13은 validation이고, 세 가지 learning principles를 다루는 lecture 17에서는 data snooping에 이름을 붙입니다. 둘을 합치면 이 장의 규율이 나옵니다. optimiser를 돌렸는지 여부와 무관하게, data set을 한 번 들여다볼 때마다 그것은 fitting decision입니다. ↩
-
James, G., Witten, D., Hastie, T. and Tibshirani, R. An Introduction to Statistical Learning, 2nd edition (Springer, 2021), chapters 2 and 5. bias–variance decomposition과 resampling에 관한 내용입니다. companion volume은 selection trap을 명시적으로 말하는 곳입니다. Hastie, Tibshirani and Friedman, The Elements of Statistical Learning, 2nd edition, §7.10.2, The Wrong and Right Way to Do Cross-validation. ↩
-
Kaufman, S., Rosset, S., Perlich, C. and Stitelman, O. Leakage in Data Mining: Formulation, Detection, and Avoidance. ACM Transactions on Knowledge Discovery from Data 6(4), 2012. 위에서 시연한 실패를 formal하게 다룬 글이며, 데이터가 조립된 방식의 artefact를 학습한 모델이 이긴 competitions의 case studies를 포함합니다. ↩
-
Wilson, E. B. Probable Inference, the Law of Succession, and Statistical Inference. Journal of the American Statistical Association 22(158), pp. 209–212 (1927). 위의
wilson()에서 사용한 score interval이며, proportion에 대한 올바른 default로 여전히 유효합니다. textbook interval 는 피해야 할 것입니다. 0과 1 근처에서 nonsense를 내고, 작은 에서 badly undercovers합니다. ↩ -
Efron, B. Bootstrap Methods: Another Look at the Jackknife. The Annals of Statistics 7(1), pp. 1–26 (1979). sampling theory가 없는 것들을 포함해, 계산할 수 있는 어떤 statistic에도 interval을 붙일 수 있게 해 주는 아이디어입니다. ↩