분포 이동과 OOD
먼저 읽을 장 21.1 불확실성 정량화15.4 데이터 분할과 누수 방지
모든 평가 지표는 "시험 데이터가 운영 데이터를 대표한다"는 가정 위에 서 있다. 과학 연구에서 이 가정은 거의 언제나 조금씩 깨진다. 새 장비로 측정하고, 더 높은 온도에서 실험하고, 다른 병원의 환자를 보고, 아직 합성하지 않은 분자를 예측한다. 학습할 때와 쓸 때의 데이터 분포가 다른 것을 분포 이동(distribution shift)이라 한다. 15.4장에서 주장에 맞는 분할로 일반화를 정직하게 평가하는 법을 보았다. 이 장은 한 걸음 더 나아가, 이동의 종류를 구분하고, 이동을 탐지하고, 이동에 대응하는 방법을 다룬다.
이 장의 중심 메시지는 단순하다. "일반화한다"는 말에는 언제나 무엇에 대해서가 붙어야 한다. 새 셀, 새 온도, 새 장비, 새 시점은 서로 다른 일반화이고, 하나를 검증했다고 다른 것이 따라오지 않는다.
학습 목표
- 분포 이동의 유형을 구분한다
- OOD 탐지와 일반화를 평가한다
- 운영 중 drift에 대응한다
분포 이동의 유형
왜 필요한가. 이동의 종류에 따라 할 수 있는 일이 다르다. 어떤 이동은 레이블 없는 운영 데이터만으로 고칠 수 있고, 어떤 이동은 새 레이블 없이는 원리적으로 고칠 수 없다. 종류를 먼저 정해야 대응이 정해진다.
정의. 결합분포 는 두 가지로 인수분해할 수 있다: 또는 . 학습(source) 분포 와 운영(target) 분포 사이에서 어느 인수가 바뀌고 어느 인수가 그대로인지로 이동을 분류한다.
| 유형 | 바뀌는 것 | 그대로인 것 | 예 |
|---|---|---|---|
| 공변량 이동(covariate shift) | 학습은 상온, 운영은 고온 위주. 같은 온도에서의 열화 법칙은 같다 | ||
| label shift(prior shift) | 결함률이 2%에서 10%로. 결함 제품의 모습은 같다 | ||
| conditional shift(concept shift) | — | 장비 교체로 같은 신호가 다른 값을 뜻한다. 판정 기준이 바뀐다 |
직관. 공변량 이동에서 모델이 참 관계를 정확히 표현할 수 있다면 문제가 거의 없다. 같은 를 학습하므로 어디서나 맞다. 문제는 모델이 틀렸을 때다. 틀린 모델은 데이터가 많은 영역에 맞춘 타협을 한다. 그 타협이 운영 영역에서는 나쁜 타협일 수 있다. 휜 관계 를 직선으로 학습하는데, 학습 입력은 , 운영 입력은 인 경우를 본다.
중요도 가중. 가능도 비 를 학습 손실에 곱하면
이므로, 학습 데이터로 운영 분포의 손실을 최소화하는 셈이다. 이것이 중요도 가중(importance weighting)이다. Shimodaira(2000)는 모델이 오지정일 때 이 가중이 점근적으로 최적이고, 잘 지정된 모델에서는 가중하지 않은 최대우도가 최적임을 보였다.
import numpy as np
from scipy.stats import norm
rng = np.random.default_rng(0)
f = lambda x: x + 0.3 * x ** 2 # 참 관계: 조금 휘어 있다
x_s = rng.normal(0.0, 1.0, 500) # 학습(source) 입력
y_s = f(x_s) + rng.normal(0, 0.3, 500)
x_t = rng.normal(1.5, 0.6, 20000) # 운영(target) 입력: 오른쪽으로 이동
y_t = f(x_t) + rng.normal(0, 0.3, 20000) # p(y|x)는 그대로 (공변량 이동)
def wls(x, y, w): # 가중 최소제곱 직선 (일부러 틀린 모델)
A = np.stack([np.ones_like(x), x], axis=1) # (N, 2)
return np.linalg.solve(A.T @ (w[:, None] * A), A.T @ (w * y))
w_true = norm.pdf(x_s, 1.5, 0.6) / norm.pdf(x_s, 0.0, 1.0) # 가능도 비 p_t(x) / p_s(x)
ess = w_true.sum() ** 2 / np.sum(w_true ** 2)
for name, w in (("가중 없음", np.ones_like(x_s)), ("중요도 가중", w_true)):
c = wls(x_s, y_s, w)
mse_s = np.mean((c[0] + c[1] * x_s - y_s) ** 2)
mse_t = np.mean((c[0] + c[1] * x_t - y_t) ** 2)
print(f"{name:7s} 기울기 {c[1]:.2f} source MSE {mse_s:.3f} target MSE {mse_t:.3f}")
print(f"유효 표본 수 {ess:.0f} / {len(x_s)}")가중 없음 기울기 0.94 source MSE 0.310 target MSE 0.800 중요도 가중 기울기 1.88 source MSE 2.042 target MSE 0.116 유효 표본 수 100 / 500
가중하지 않은 직선은 학습 영역에서는 좋고(source MSE 0.310) 운영 영역에서는 나쁘다(target MSE 0.800). 가중한 직선은 운영 영역의 기울기에 맞춰 target MSE를 0.116으로 줄이는 대신 학습 영역을 포기한다(source MSE 2.042). 대가는 또 있다. 가중치가 운영 영역 근처의 몇몇 학습 점에 몰려 유효 표본 수
가 500개 중 100개로 줄었다. 두 분포가 멀수록 가 작아지고 추정이 불안정해진다. 운영 입력이 학습 입력이 전혀 없는 곳에 있으면 이라 가중치가 정의되지 않는다. 가중은 이미 본 영역의 비중을 바꿀 뿐, 본 적 없는 영역의 정보를 만들지 못한다.
가능도 비의 추정. 실제로는 와 를 모른다. 대신 레이블 없는 운영 입력은 쉽게 모을 수 있다. 학습 입력에는 0, 운영 입력에는 1을 붙이고 둘을 구분하는 도메인 분류기를 학습하면, 베이즈 정리로
이다. 로지스틱 회귀라면 는 로짓의 지수다. 두 정규분포 사이의 로그 가능도 비는 의 2차식이므로 특징 을 쓴다.
def logreg_newton(F, t, iters=25): # F: (N, D) 특징, t: (N,) 0/1 레이블
b = np.zeros(F.shape[1])
for _ in range(iters):
p = 1 / (1 + np.exp(-F @ b))
H = F.T @ (F * (p * (1 - p))[:, None]) + 1e-6 * np.eye(F.shape[1])
b += np.linalg.solve(H, F.T @ (t - p)) # Newton 갱신
return b
feats = lambda x: np.stack([np.ones_like(x), x, x ** 2], axis=1) # (N, 3)
x_unlab = x_t[:500] # 레이블 없는 운영 입력 500개면 충분하다
F = feats(np.concatenate([x_s, x_unlab]))
n_s, n_t = len(x_s), len(x_unlab)
t = np.concatenate([np.zeros(n_s), np.ones(n_t)]) # 0: source, 1: target
b = logreg_newton(F, t)
w_hat = np.exp(feats(x_s) @ b) * n_s / n_t # p(t|x)/p(s|x) × n_s/n_t
c = wls(x_s, y_s, w_hat)
print(f"log 가중치 상관 (추정 vs 참) {np.corrcoef(np.log(w_hat), np.log(w_true))[0, 1]:.3f}")
print(f"추정 가중치로 학습: 기울기 {c[1]:.2f} target MSE {np.mean((c[0] + c[1] * x_t - y_t) ** 2):.3f}")log 가중치 상관 (추정 vs 참) 0.999 추정 가중치로 학습: 기울기 1.94 target MSE 0.116
레이블 없는 운영 입력 500개로 추정한 가중치가 참 가중치와 로그 척도에서 거의 같고(상관 0.999), 그 가중치로 학습한 모델의 target MSE도 참 가중치일 때와 같다. 이 예는 분류기의 함수 꼴이 참 로그 비와 맞아 떨어지는 유리한 경우다. 고차원 입력에서는 분류기가 과신해 가중치가 극단으로 치우치기 쉬우므로, 가중치를 자르거나(clipping) 확률을 보정한(21.2장) 뒤 쓴다.
label shift의 보정. 가 그대로이면 베이즈 정리로 출력 확률을 다시 가중할 수 있다: . 운영 환경의 class 비율 를 모르면 모델 예측의 혼동 행렬과 운영 데이터의 예측 분포로 추정한다. 보정된 확률이 필요하다는 점은 같다.
conditional shift는 레이블 없이 고칠 수 없다. 같은 가 다른 를 뜻하게 되었으니, 운영 환경의 레이블을 새로 얻어 다시 학습하거나 보정하는 수밖에 없다. 장비 교체 뒤의 재보정 측정이 이 경우다.
OOD 탐지와 OOD 일반화
두 과제의 차이. "OOD"(out-of-distribution)라는 말은 서로 다른 두 과제를 가리킨다.
- OOD 탐지(detection): 이 입력(또는 이 배치)이 학습 분포와 다른가? 출력은 경보다. 레이블이 필요 없다.
- OOD 일반화(generalization): 분포가 다른 입력에서도 예측이 맞는가? 출력은 성능이다. 운영 분포의 레이블이 있어야 평가할 수 있다.
두 질문은 독립이다. 예측과 상관없는 방향의 이동(배경 밝기, 단위 표기)은 탐지되지만 성능을 해치지 않을 수 있다. 반대로 conditional shift는 입력 분포가 그대로라 탐지되지 않지만 성능을 크게 해친다. 탐지기가 조용하다는 것은 성능이 유지된다는 증거가 아니다.
입력 단위의 탐지. 개별 입력이 학습 범위 밖인지 판단하는 점수로는 다음을 쓴다.
- 학습 데이터까지의 거리: 최근접 이웃 거리, 특징 공간의 Mahalanobis 거리
- 밀도 추정: 학습 입력의 밀도가 낮은 곳(19부의 생성모델로 밀도를 추정할 수 있지만, 고차원에서는 밀도가 OOD를 잘 구분하지 못하는 경우가 보고되어 있어 주의한다)
- 모델 불확실성: 앙상블 불일치(21.1장). softmax 최대 확률은 학습 범위 밖에서도 1에 가까울 수 있어 약한 점수다
배치 단위의 탐지: 2-표본 검정. 운영 데이터를 모아 학습 데이터와 같은 분포인지 검정한다(12.4장의 가설 검정). 두 가지 접근이 있다.
- 특징별 검정: 특징마다 Kolmogorov–Smirnov(KS) 검정 같은 1차원 검정을 하고 다중 비교를 보정한다. 단순하지만 특징 사이의 관계 변화는 보지 못한다.
- 분류기 기반 검정(classifier two-sample test): 두 표본을 구분하는 분류기를 절반으로 학습하고, 나머지 절반에서 정확도(또는 AUC)가 우연 수준(0.5)보다 큰지 검정한다(Lopez-Paz & Oquab, 2017). 분류기가 표현할 수 있는 모든 차이를 잡고, 앞 절의 도메인 분류기와 같은 모델이라 가능도 비 추정으로 바로 이어진다.
데이터셋 이동(dataset shift)을 탐지하는 여러 방법을 비교한 실험 연구는, 학습된 모델의 표현으로 차원을 줄인 뒤 2-표본 검정을 하는 방법이 전반적으로 좋았다고 보고했다(Rabanser 외, 2019). 두 특징의 주변분포는 그대로이고 상관만 0에서 0.8로 바뀐 이동을 두 방법으로 200번씩 검정해 기각률을 비교한다.
from scipy.stats import ks_2samp, mannwhitneyu
G = lambda X: np.column_stack([np.ones(len(X)), X, X[:, 0] * X[:, 1]]) # 상호작용 특징 포함
L = np.array([[1.0, 0.0], [0.8, 0.6]]) # 상관 0.8을 만드는 Cholesky 인자
def trial(n, shifted):
A = rng.normal(size=(n, 2)) # (n, 2) 기준 데이터: 두 특징 독립
B = rng.normal(size=(n, 2)) @ (L.T if shifted else np.eye(2)) # 각 특징은 여전히 N(0, 1)
ks = min(ks_2samp(A[:, j], B[:, j]).pvalue for j in range(2)) * 2 # Bonferroni
h = n // 2 # 절반으로 분류기 학습, 나머지 절반으로 검정
b = logreg_newton(G(np.vstack([A[:h], B[:h]])), np.repeat([0.0, 1.0], h))
u = mannwhitneyu(G(B[h:]) @ b, G(A[h:]) @ b, alternative="greater")
return ks < 0.05, u.pvalue < 0.05, u.statistic / (n - h) ** 2
for shifted in (False, True):
r = np.array([trial(400, shifted) for _ in range(200)]) # (200, 3)
label = "상관 0 → 0.8" if shifted else "이동 없음 "
print(f"{label} 기각률: 특징별 KS {r[:, 0].mean():.2f} 분류기 검정 {r[:, 1].mean():.2f}"
f" held-out AUC 평균 {r[:, 2].mean():.3f}")이동 없음 기각률: 특징별 KS 0.05 분류기 검정 0.02 held-out AUC 평균 0.499 상관 0 → 0.8 기각률: 특징별 KS 0.06 분류기 검정 1.00 held-out AUC 평균 0.702
이동이 없을 때 두 방법의 기각률은 유의수준 0.05 근처다(1종 오류). 상관만 바뀌었을 때 특징별 KS 검정의 기각률은 0.06으로 이동이 없을 때와 다르지 않다. 각 특징의 분포가 그대로이므로 볼 수 없는 것이다. 상호작용 특징 를 쓰는 분류기 검정은 200번 모두 기각했고 held-out AUC가 0.70이었다. AUC 값 자체가 이동의 크기를 해석 가능한 단위로 알려 준다는 것도 장점이다.
일반화 전략
왜 필요한가. 탐지는 문제를 알려 줄 뿐 고치지 않는다. 분포 이동에 강한 모델을 만드는 전략은 운영 분포에 대해 무엇을 알 수 있느냐에 따라 나뉜다.
- domain adaptation: 운영(target) 분포의 입력을 학습 때 볼 수 있다. 레이블은 없거나 적다. 중요도 가중, label shift 보정, 두 도메인의 표현을 맞추는 방법이 여기에 속한다. 운영 환경이 정해져 있고 그 입력을 모을 수 있을 때 쓴다.
- domain generalization: 운영 분포를 학습 때 전혀 볼 수 없다. 대신 여러 학습 도메인(여러 실험실, 여러 장비)을 이용해 도메인이 바뀌어도 변하지 않는 관계를 학습하려 한다. 도메인 무작위화(시뮬레이션 조건을 넓게 흔드는 것), 도메인별 손실의 최악값 최소화 등이 있다.
불변 표현. 두 전략의 공통 아이디어는 "도메인마다 달라지는 신호"를 버리고 "어디서나 같은 신호"에 기대는 것이다. 장비 C만 내부저항을 0.3만큼 높게 재는 데이터에서, 내부저항의 절댓값은 장비마다 다른 신호이고, 같은 장비 안에서의 변화량은 더 불변에 가깝다. 과학 문제에서는 물리 법칙과 보존량, 무차원 수, 대칭성이 가장 좋은 불변 표현이 된다(24부). 어떤 신호가 불변인지는 데이터만으로 알기 어렵고, 도메인 지식이 필요하다.
한계. 실제 분포 이동이 있는 데이터셋 여러 개를 모은 벤치마크 WILDS는, 실제 분포 이동에서 도메인 내 성능과 도메인 밖 성능 사이에 큰 차이가 남는다는 것을 보였다(Koh 외, 2021). 어떤 일반화 전략도 "학습 도메인이 운영 도메인과 어떻게 다를 수 있는가"를 충분히 덮는 데이터 없이 일반화를 보장하지 못한다. 그래서 일반화 주장은 결국 다음 절의 평가로 뒷받침해야 한다.
조건별 평가
집단별 성능과 worst-group 성능. 평균 성능은 큰 집단이 정한다. 전체의 5%인 집단에서 모델이 크게 틀려도 평균은 거의 움직이지 않는다. 그래서 집단(환자군, 장비, 재료 계열, 실험 조건)마다 성능을 따로 보고, 그중 가장 나쁜 집단의 성능(worst-group)을 함께 보고한다. 21.2장의 조건별 coverage와 같은 원리를 성능 지표 전반으로 넓힌 것이다.
일반화 대상별 분할. 15.4장에서 주장에 맞는 분할을 골랐다. 분포 이동의 관점에서는 하나의 주장이 아니라 여러 일반화 대상을 따로 평가한다. 각 대상마다 그 대상 하나를 통째로 빼는 분할(leave-one-group-out)을 쓴다.
| 일반화 대상 | 분할 | 무엇을 검증하나 |
|---|---|---|
| 새 셀(같은 조건) | 셀 단위 group split | 제조 편차에 대한 일반화 |
| 새 온도 | 온도 하나씩 빼기 | 조건 내삽(가운데 온도)과 외삽(양 끝 온도) |
| 새 충방전 조건 | C-rate 하나씩 빼기 | 운전 조건의 내삽·외삽 |
| 새 측정 장비 | 장비 하나씩 빼기 | 측정 계통 오차에 대한 강건성 |
| 새 시점 | 시간 순 분할 | 노화·계절·공정 변화 |
빼낸 값이 학습 범위의 가운데인지 끝인지 구분해 적는다. 가운데 온도를 빼면 내삽, 가장 높은 온도를 빼면 외삽이고, 둘의 성능은 크게 다를 수 있다(실습).
강건성
왜 필요한가. 분포 이동의 특수한 경우로, 운영 중에 입력이 손상되는 일이 흔하다. 센서 하나가 꺼져 값이 빠지고, 잡음이 커지고, 이상치가 섞인다. 이런 상황은 학습 데이터에 거의 없으므로 따로 시험해야 한다.
강건성 시험. 시험 데이터에 손상을 인위적으로 넣고 성능이 어떻게 떨어지는지 곡선으로 본다.
- 센서 결측: 특징 하나씩(또는 센서 그룹 단위로) 결측시키고, 운영 때와 같은 결측 처리(평균 대체, 마지막 값 유지 등)를 적용한다. 특정 센서가 빠졌을 때 성능이 무너진다면 그 센서에 대한 의존을 문서화한다.
- 잡음 증가: 입력 잡음의 표준편차를 측정 사양의 1배, 2배, 5배로 키운다.
- 이상치: 일부 값에 스파이크를 넣는다.
- 계통 오차: 센서 하나에 일정한 offset이나 이득(gain) 오차를 넣는다. 장비 교체·보정 오류를 흉내 낸다.
결과는 "손상 강도 대 성능" 곡선으로 보고한다. 하나의 숫자보다, 어느 강도에서 성능이 급격히 떨어지는지가 운영에 필요한 정보다. 손상을 학습 데이터에 섞어 학습하는 데이터 증강은 강건성을 높이지만, 증강하지 않은 손상 유형에 대해서는 보장하지 않는다.
운영 중 drift
왜 필요한가. 배포한 모델의 입력 분포와 입출력 관계는 시간에 따라 서서히 변한다(drift). 센서가 노화하고, 공정이 바뀌고, 측정 대상이 계절을 탄다. 운영 중에는 레이블이 늦게 오거나 아예 오지 않으므로, 성능 저하를 직접 보기 전에 입력의 변화로 먼저 감지해야 한다.
drift 탐지. 배포 시점의 데이터를 기준으로 저장해 두고, 운영 데이터를 배치(하루, 한 lot)마다 기준과 비교한다. 비교에는 앞 절의 2-표본 검정을 쓴다. 문제는 반복 검정이다. 매일, 여러 특징을 검정하면 이동이 없어도 경보가 난다. 경보 기준을 엄격하게 하면 오경보가 줄지만 실제 drift를 늦게 잡는다. 센서 온도가 60번째 배치부터 배치마다 0.03 °C씩 어긋나는 상황을 본다.
K, START = 100, 60 # 배치 100개, 60번째부터 센서가 서서히 어긋난다
ref_temp_c = rng.normal(25.0, 2.0, 2000) # 배포 시점의 센서 온도 기준 분포
offset_c = np.where(np.arange(K) < START, 0.0, 0.03 * (np.arange(K) - START + 1))
p_batch = np.array([ks_2samp(ref_temp_c, rng.normal(25.0 + o, 2.0, 200)).pvalue for o in offset_c])
for level, name in ((0.05, "α = 0.05"), (0.05 / K, "α = 0.05/100")):
alarm = p_batch < level
first = START + int(np.argmax(alarm[START:]))
print(f"{name:12s} drift 전 오경보 {alarm[:START].sum()}회 drift 후 첫 경보: 배치 {first}"
f" (어긋남 {offset_c[first]:.2f} °C)")α = 0.05 drift 전 오경보 3회 drift 후 첫 경보: 배치 73 (어긋남 0.42 °C) α = 0.05/100 drift 전 오경보 0회 drift 후 첫 경보: 배치 78 (어긋남 0.57 °C)
로 배치마다 검정하면 drift가 시작되기 전 60개 배치에서 오경보가 3번 났다(기댓값 ). 배치 수로 나눈 기준 (Bonferroni, 12.4장)을 쓰면 오경보는 0번이지만 첫 경보가 다섯 배치 늦고, 그사이 센서는 0.42 °C에서 0.57 °C까지 어긋났다. 어느 쪽이 나은지는 오경보 한 번과 탐지 지연 한 배치의 비용이 정한다(21.6장). 실무에서는 여러 배치에 걸쳐 증거를 누적하는 순차 검정이나, 연속 몇 번의 경보에만 반응하는 규칙을 쓴다.
재학습 정책. drift를 탐지한 뒤의 대응을 미리 정해 둔다.
- 무엇을 확인하나: 탐지된 이동이 성능을 해치는지. 지연되어 들어오는 레이블로 성능을 계산하거나, 일부를 우선 측정해 확인한다. 탐지와 성능 저하는 다른 사건이다.
- 언제 재학습하나: 정해진 주기, 성능이 기준 아래로 떨어질 때, drift 경보가 지속될 때 중 무엇을 기준으로 할지 정한다.
- 무엇으로 재학습하나: 최근 데이터만 쓰면 오래된 조건을 잊고, 전체를 쓰면 새 조건이 묻힌다. 시간 가중치나 창 크기를 정한다.
- 재학습한 모델은 어떻게 검증하나: 15.4장의 시간 순 분할로, 재학습 시점 이후의 데이터에서 이전 모델과 비교한다. 재학습이 오히려 나빠지는 경우도 있다.
실습
새로운 셀·온도·충방전 조건·측정 장비 각각에 대해 일반화를 따로 평가하는 실험을 설계하고 실행한다. 코드는 labs/reliability/distribution-shift/generalization_axes.py다. 데이터는 배터리 열화를 흉내 낸 합성 데이터다(실제 배터리 모델이 아니다). 셀 72개가 온도 4개(15–45 °C) × C-rate 3개 × 측정 장비 3개 × 반복 2로 구성되고, 셀마다 측정 창 25개가 있다. 목표인 용량 감소율은 온도에 대해 지수적으로 커지고, 셀마다 제조 편차가 있으며, 장비 C는 내부저항을 0.3만큼 높게 잰다. 모델은 gradient boosting이다. 일반화 대상마다 그 대상의 값 하나를 통째로 빼고 학습해 평가한다. 집필 시점의 실행 결과는 다음과 같다(시드 0).
샘플 1800개, 셀 72개. 목표의 표준편차 0.947 일반화 대상 평균 RMSE 최악 그룹별 (무작위 창 분할) 0.141 0.148 새 셀 (셀 단위 5-fold) 0.228 0.333 새 온도 (하나씩 빼기) 0.409 0.899 15°C 0.241 25°C 0.270 35°C 0.224 45°C 0.899 새 C-rate (하나씩 빼기) 0.289 0.504 1C 0.140 2C 0.225 3C 0.504 새 장비 (하나씩 빼기) 0.281 0.332 A 0.292 B 0.218 C 0.332
같은 모델, 같은 데이터인데 RMSE가 0.141부터 0.899까지 여섯 배 넘게 차이 난다.
- 무작위 창 분할(0.141)은 어떤 일반화도 검증하지 않는다. 같은 셀의 창들이 학습과 평가에 나뉘어 들어가 셀 편차가 샌다(15.4장).
- 새 셀(0.228)은 같은 조건의 새 셀에 대한 일반화다. 무작위 분할보다 60% 크다.
- 새 온도의 평균 0.409는 내삽과 외삽을 섞은 숫자다. 가운데 온도(25·35 °C)를 빼면 0.22–0.27로 새 셀 수준이지만, 가장 높은 45 °C를 빼면 0.899로 무너진다. 트리 모델은 학습 범위 밖 온도에서 가장 가까운 학습 온도의 값을 그대로 쓰는데, 열화는 온도에 대해 지수적으로 커지기 때문이다. 15 °C도 끝 온도지만 열화가 작은 쪽이라 피해가 작다.
- C-rate도 같다. 가장 높은 3C를 빼면 0.504다.
- 새 장비는 0.22–0.33이다. 장비 C의 치우침이 성능을 해치지만 온도 외삽만큼은 아니다.
"이 모델은 RMSE 0.14로 열화를 예측한다"는 문장은 어떤 일반화를 검증했는지 말하지 않으므로 의미가 없다. "같은 조건의 새 셀에서 0.23, 학습 범위 안의 새 온도에서 0.27 이하, 45 °C로의 외삽에서는 0.90"이 검증한 내용을 정확히 전한다.
이어서 연습문제로 중요도 가중 위험 추정과 유효 표본 수를 구현한다.
실패 사례
- 어떤 종류의 일반화를 검증하는지 명시하지 않는 것. 무작위 분할 성능을 "일반화 성능"으로 보고하면 셀·조건·장비 중 어느 것에 대한 주장인지 알 수 없다. 일반화 대상마다 분할과 결과를 따로 쓴다.
- 내삽과 외삽을 한 숫자로 평균 내는 것. 하나씩 빼기 결과의 평균은 가장 위험한 외삽의 실패를 희석한다. 그룹별 값과 최악값을 함께 보고한다.
- OOD 탐지 결과를 성능 보장으로 읽는 것. 탐지기가 조용해도 conditional shift는 일어날 수 있고, 탐지기가 울려도 성능이 유지될 수 있다.
- 특징별 검정만으로 이동이 없다고 결론 내리는 것. 특징 사이의 관계 변화는 주변분포 검정에 보이지 않는다.
- 중요도 가중치를 그대로 쓰는 것. 분포가 멀면 몇몇 점이 가중치를 독차지해 유효 표본이 작아진다. 를 보고하고, 필요하면 가중치를 자른다.
- drift 경보 기준을 다중 비교 없이 정하는 것. 매일 여러 특징을 검정하면 이동이 없어도 경보가 쏟아지고, 운영자는 결국 경보를 무시한다.
통과 기준
- 연구 주장에 포함된 일반화 대상(새 샘플·그룹·조건·장비·시점 중 해당하는 것)을 모두 적고, 각각에 맞는 분할로 따로 검증한 결과를 그룹별 값과 최악값을 포함해 보고한다.
- 학습 데이터와 운영(또는 외부 검증) 데이터 사이의 이동을 2-표본 검정으로 점검하고, 이동의 유형(공변량·label·conditional)에 대한 판단과 근거를 쓴다.
- 연습문제
importance-weighting의 테스트를 통과한다.
참고 문헌
- Shimodaira (2000). Improving predictive inference under covariate shift by weighting the log-likelihood function. Journal of Statistical Planning and Inference, 90(2), 227–244. — 공변량 이동과 중요도 가중, 오지정 모델에서의 최적성
- Lopez-Paz, Oquab (2017). Revisiting classifier two-sample tests. International Conference on Learning Representations (ICLR 2017). — 분류기 기반 2-표본 검정
- Rabanser, Günnemann, Lipton (2019). Failing loudly: An empirical study of methods for detecting dataset shift. Advances in Neural Information Processing Systems 32 (NeurIPS 2019). — 데이터셋 이동 탐지 방법의 실험적 비교
- Zech, Badgeley, Liu, Costa, Titano, Oermann (2018). Variable generalization performance of a deep learning model to detect pneumonia in chest radiographs: A cross-sectional study. PLOS Medicine, 15(11), e1002683. — 영상으로 병원 시스템을 구분하는 모델과 외부 성능 저하
- Koh 외 (2021). WILDS: A benchmark of in-the-wild distribution shifts. Proceedings of the 38th International Conference on Machine Learning, PMLR 139, 5637–5664. — 실제 분포 이동 벤치마크