해석가능성
먼저 읽을 장 21.1 불확실성 정량화
과학에서 예측 모델을 만드는 이유는 대개 예측 자체보다 깊다. 어떤 공정 변수가 수율을 좌우하는지, 어떤 유전자가 표현형과 관련되는지, 모델이 물리적으로 말이 되는 신호를 쓰는지 알고 싶다. 해석가능성(interpretability) 방법은 모델이 예측에 무엇을 썼는지 보여 주겠다고 약속한다. 그런데 같은 모델에 다른 방법을 쓰면 다른 답이 나오고, 그럴듯한 설명 그림이 모델과 거의 무관할 수도 있다.
이 장은 대표적인 해석 방법을 구현하고, 각 방법이 무엇을 가정하고 무엇을 재는지 분명히 한다. 핵심 메시지는 두 가지다. 첫째, 기여도(attribution)는 "모델이 무엇을 썼는가"이지 "세계에서 무엇이 원인인가"가 아니다. 둘째, 해석 결과도 다른 결과처럼 검증해야 하는 주장이다.
학습 목표
- 주요 해석 방법과 가정을 이해한다
- 해석 결과를 검증한다
특징 기여도
왜 필요한가. 모델이 높은 정확도를 낸다는 것만으로는 그 모델이 과학적으로 의미 있는 신호를 썼는지 알 수 없다. 측정 장비의 표식, 데이터 수집 순서, 결과의 하류 측정처럼 의미 없는 지름길(shortcut)로 정확도를 얻는 모델이 흔하다. 기여도는 그 지름길을 찾는 첫 도구다.
두 종류의 질문. 해석 방법은 묻는 범위에 따라 나뉜다.
- 전역(global): 모델 전체에서 어떤 특징이 중요한가? 순열 중요도, 부분 의존 그림.
- 국소(local): 이 예측 하나에서 각 특징이 얼마나 기여했는가? gradient 기반 방법, integrated gradients, SHAP.
순열 중요도. 평가 데이터에서 특징 의 열만 무작위로 섞고, 손실이 얼마나 늘어나는지 잰다. 섞으면 특징 와 목표의 관계가 끊기므로, 모델이 그 특징에 기댈수록 손실이 크게 는다. 랜덤 포레스트의 변수 중요도로 처음 쓰였고(Breiman, 2001), 모델 종류와 상관없이 쓸 수 있다. 다시 학습하지 않으므로 빠르다. 16.4장의 트리 불순도 기반 중요도는 학습 데이터에서 계산되고 범주가 많은 특징을 과대평가하는 경향이 있어, 평가 데이터에서 잰 순열 중요도가 더 자주 권장된다.
함정: 상관된 특징. 목표가 이고, 은 의 거의 복사본(상관 0.995), 는 무관한 잡음인 데이터에 ridge 회귀를 학습한다.
import numpy as np
rng = np.random.default_rng(0)
def make(n):
x1, x2, x4 = rng.normal(size=(3, n))
x3 = x1 + 0.1 * rng.normal(size=n) # x1의 거의 복사본 (상관 0.995)
y = 2 * x1 + x2 ** 2 + 0.3 * rng.normal(size=n) # 참 관계에 x3, x4는 없다
return np.stack([x1, x2, x3, x4], axis=1), y # (N, 4), (N,)
phi = lambda X: np.column_stack([X, X[:, 1] ** 2]) # 특징 + x2²
X_tr, y_tr = make(2000)
P = phi(X_tr)
coef = np.linalg.solve(P.T @ P + 10 * np.eye(5), P.T @ y_tr) # ridge (λ = 10)
predict = lambda X: phi(X) @ coef
print("ridge 가중치 (x1, x2, x3, x4, x2²):", np.round(coef, 2) + 0.0)
X_te, y_te = make(5000)
base = np.mean((predict(X_te) - y_te) ** 2)
def perm_importance(cols, reps=10):
out = []
for _ in range(reps):
Xp = X_te.copy()
Xp[:, cols] = X_te[rng.permutation(len(X_te))][:, cols] # 열(들)을 함께 섞는다
out.append(np.mean((predict(Xp) - y_te) ** 2) - base)
return np.mean(out)
for name, cols in (("x1", [0]), ("x2", [1]), ("x3", [2]), ("x4", [3]), ("x1+x3 함께", [0, 2])):
print(f"{name:10s} MSE 증가 {perm_importance(cols):6.2f}")
keep = [1, 2, 3, 4] # x1을 빼고 다시 학습
c2 = np.linalg.solve(P[:, keep].T @ P[:, keep] + 10 * np.eye(4), P[:, keep].T @ y_tr)
refit = np.mean((phi(X_te)[:, keep] @ c2 - y_te) ** 2) - base
print(f"x1을 빼고 다시 학습했을 때 MSE 증가 {refit:.2f}")ridge 가중치 (x1, x2, x3, x4, x2²): [1.49 0. 0.5 0. 1. ] x1 MSE 증가 4.50 x2 MSE 증가 3.82 x3 MSE 증가 0.50 x4 MSE 증가 -0.00 x1+x3 함께 MSE 증가 7.93 x1을 빼고 다시 학습했을 때 MSE 증가 0.04
과 은 거의 같은 정보인데 중요도는 4.50과 0.50으로 아홉 배 차이 난다. ridge가 둘 사이에 가중치를 1.49와 0.50으로 나눴기 때문이다. 이 분할은 데이터의 성질이 아니라 학습 알고리즘의 선택이다. 둘을 함께 섞으면 7.93으로, 묶음 전체의 중요도가 드러난다. 반대로 을 빼고 다시 학습하면 이 대신해 손실이 0.04밖에 늘지 않는다. 그러니 "이 가장 중요하다"(순열 중요도)와 "은 없어도 된다"(재학습)가 둘 다 맞는 말이다. 두 숫자는 서로 다른 질문, 즉 "이 모델이 무엇에 기대는가"와 "이 정보가 다른 특징으로 대체되는가"에 대한 답이다. 의 선형 가중치는 0인데 중요도가 큰 것은 항을 통해 쓰이기 때문이다. 순열 중요도는 특징이 모델 안에서 어떤 형태로 쓰이든 잡는다.
gradient 기반 방법. 미분 가능한 모델에서는 출력의 입력 gradient 가 "입력 를 조금 바꾸면 출력이 얼마나 바뀌는가"를 준다(8부의 자동미분). 이것을 그대로 그린 것이 saliency map이고, 입력값을 곱한 gradient×input 는 선형 모델에서 정확히 각 항의 기여가 된다. 비선형 모델에서는 국소 기울기 하나로 전체 변화를 설명하려 하므로 틀린다. 예를 들어 포화된 함수(시그모이드의 평평한 부분)에서는 입력이 출력에 크게 기여했어도 gradient가 0이다.
integrated gradients. 기준값(baseline) 에서 입력 까지 직선 경로를 따라 gradient를 적분한다(Sundararajan 외, 2017).
미적분의 기본 정리에 의해 기여의 합이 출력 차이와 같다: . 이 성질을 완전성(completeness)이라 한다. 경로 전체를 보므로 포화된 함수에서도 기여를 놓치지 않는다. 대신 기준값을 정해야 한다.
SHAP. 협력 게임 이론의 Shapley 값을 특징 기여에 적용한다(Lundberg & Lee, 2017). 특징 의 기여를, 다른 특징들의 모든 부분집합에 를 추가했을 때 예측이 바뀌는 양의 가중 평균으로 정의한다. 기여의 합이 "이 예측 − 기준 예측(평균 예측)"과 같고, 몇 가지 공정성 공리를 만족하는 유일한 분배라는 성질이 있다. 정확한 계산은 특징 수에 지수적이라 근사(표본, 트리 모델 전용 알고리즘)를 쓴다. 특징을 "빼는" 것을 어떻게 구현하느냐(기준 분포에서 채움)에 따라 결과가 달라진다는 점은 다음 절의 가정과 같은 문제다.
방법의 가정
왜 필요한가. 모든 기여도 방법은 "특징을 없애면(바꾸면) 어떻게 되는가"를 계산한다. 그런데 학습된 모델에서 특징을 정말로 없앨 수는 없다. 그래서 방법마다 특징을 무엇으로 대체할지 가정한다. 순열은 다른 사례의 값으로, PDP·SHAP은 기준 분포의 값으로, IG는 기준값으로 대체한다. 이 가정이 결과를 정한다.
특징 독립 가정. 순열과 부분 의존은 한 특징을 바꾸면서 나머지를 그대로 둔다. 특징들이 상관되어 있으면, 이렇게 만든 입력 중 상당수는 현실에 존재하지 않는 조합이다(예: 습도는 높은데 기온은 영하). 모델은 학습 때 본 적 없는 이 영역에서 아무 값이나 낼 수 있고, 기여도는 그 외삽 값을 반영한다. 순열·부분 의존 계열 방법이 특징이 상관될 때 모델을 분포 밖으로 외삽하게 만든다는 점은 Hooker, Mentch, Zhou(2021)가 정리했다. 대안으로 조건부 분포에서 대체하는 방법, 상관된 특징을 묶어서 다루는 방법, 빼고 다시 학습하는 방법이 있다.
부분 의존과 ICE. 부분 의존 함수(partial dependence, Friedman, 2001)는 특징 를 값 로 고정하고 나머지 특징 에 대해 평균한 예측이다.
평균하기 전의 사례별 곡선 를 그린 것이 ICE(individual conditional expectation)다. 평균은 상호작용을 숨긴다. 두 입력의 곱 를 학습한 모델에서 확인한다.
Z = rng.normal(size=(2000, 2)) # (N, 2) 두 입력 z1, z2 (독립)
t = Z[:, 0] * Z[:, 1] + 0.1 * rng.normal(size=2000) # z1의 효과 부호가 z2에 따라 바뀐다
Q = np.column_stack([Z, Z[:, 0] * Z[:, 1]]) # (N, 3) 특징
b = np.linalg.lstsq(Q, t, rcond=None)[0]
g = lambda Z: np.column_stack([Z, Z[:, 0] * Z[:, 1]]) @ b
grid = np.linspace(-2, 2, 5)
ice = np.array([g(np.column_stack([np.full(len(Z), v), Z[:, 1]])) for v in grid]) # (5, N)
print("z1 격자 ", grid)
print("PDP (ICE 평균)", np.round(ice.mean(axis=1), 2) + 0.0)
slopes = (ice[-1] - ice[0]) / 4 # 사례별 ICE 기울기
print(f"ICE 기울기: 10% 분위수 {np.quantile(slopes, 0.1):.2f}, 90% 분위수 {np.quantile(slopes, 0.9):.2f}")z1 격자 [-2. -1. 0. 1. 2.] PDP (ICE 평균) [-0.01 -0.01 0. 0.01 0.01] ICE 기울기: 10% 분위수 -1.27, 90% 분위수 1.30
의 부분 의존은 에서 로 거의 평평하다. 그러나 사례별 기울기(ICE)는 10% 분위수가 , 90% 분위수가 이다. 모델은 을 강하게 쓰지만, 효과의 부호가 에 따라 바뀌어 평균에서 상쇄된 것이다. 평평한 PDP를 "효과 없음"으로 읽으면 안 되는 이유다.
기준값 선택. gradient×input은 암묵적으로 기준값 0을 쓰고, IG는 기준값을 명시한다. 이미지에서는 검은 영상, 표 데이터에서는 평균이나 "측정하지 않은 상태"를 쓴다. 기준값에 따라 기여가 어떻게 바뀌는지, 포화된 항이 있는 함수 에서 본다.
def f(x): # x: (D,) 입력 3개
return x[0] ** 2 + 3 * x[1] + 2 * np.minimum(x[2], 1.0) # 셋째 항은 x3 > 1에서 포화
def grad(x, h=1e-5): # 중심 차분 gradient, (D,)
E = np.eye(len(x)) * h
return np.array([(f(x + e) - f(x - e)) / (2 * h) for e in E])
def integrated_gradients(x, base, steps=50):
alphas = (np.arange(steps) + 0.5) / steps # 경로 위 중점들
g_mean = np.mean([grad(base + a * (x - base)) for a in alphas], axis=0)
return (x - base) * g_mean
x = np.array([2.0, 1.0, 2.0])
for name, attr, ref in (("gradient×input", x * grad(x), np.zeros(3)),
("IG, 기준 0", integrated_gradients(x, np.zeros(3)), np.zeros(3)),
("IG, 기준 (1,0,0)", integrated_gradients(x, np.array([1.0, 0, 0])), np.array([1.0, 0, 0]))):
print(f"{name:16s} 기여 {np.round(attr, 2) + 0.0} 합 {attr.sum():.2f} f(x) - f(기준) {f(x) - f(ref):.2f}")gradient×input 기여 [8. 3. 0.] 합 11.00 f(x) - f(기준) 9.00 IG, 기준 0 기여 [4. 3. 2.] 합 9.00 f(x) - f(기준) 9.00 IG, 기준 (1,0,0) 기여 [3. 3. 2.] 합 8.00 f(x) - f(기준) 8.00
세 가지를 읽는다.
- gradient×input은 완전성을 어긴다. 기여의 합(11)이 출력 차이(9)와 다르다. 항에서 로 실제 변화 4의 두 배를 주고, 포화된 항에는 gradient가 0이라 기여를 0으로 준다. 을 0에서 2로 바꾸면 출력이 2만큼 변하는데도 그렇다.
- IG는 합이 출력 차이와 정확히 같고, 포화된 에도 기여 2를 준다.
- 같은 IG라도 기준값을 으로 바꾸면 의 기여가 4에서 3으로 바뀐다. 기여는 "무엇과 비교해서"를 포함한 개념이다. 기준값을 보고하지 않은 기여도는 해석할 수 없다.
설명과 인과
attribution은 인과적 설명이 아니다. 기여도는 "학습된 함수 가 입력의 어느 부분에 반응하는가"를 말한다. 세계에서 그 입력을 바꾸면 결과가 바뀌는지는 말하지 않는다. 둘이 갈리는 대표적인 경우는 다음과 같다.
- 결과의 하류 측정: 결과가 정해진 뒤 측정된 변수는 결과와 강하게 상관되어 모델이 크게 기대지만, 그것을 바꿔도 결과는 바뀌지 않는다.
- 공통 원인(교란): 원인의 대리 변수(proxy)는 원인과 함께 움직이므로 모델이 쓰지만, 대리 변수만 바꾸면 결과가 바뀌지 않는다.
- 상관된 특징 사이의 분할: 앞의 예처럼 같은 정보를 담은 특징 중 어느 쪽에 기여가 가는지는 학습 알고리즘이 정한다.
시뮬레이터로 확인한다. 반응 온도 이 수율 를 정하고, 생성물 농도 센서 은 를 잡음과 함께 잰다. 회귀 모델을 학습한 뒤, 시뮬레이터에서 실제로 개입(intervention)한다. 는 다른 것은 그대로 두고 만 로 정한다는 뜻이다(16.8장).
def simulate(n, do_x1=None, do_x3_shift=0.0):
x1 = rng.normal(size=n) if do_x1 is None else np.full(n, do_x1) # 원인 (예: 반응 온도)
x2 = rng.normal(size=n) # 무관한 변수
y = 2 * x1 + 0.5 * rng.normal(size=n) # 결과 (예: 수율)
x3 = y + 0.1 * rng.normal(size=n) + do_x3_shift # y의 하류 측정 (예: 생성물 센서)
return np.column_stack([x1, x2, x3, np.ones(n)]), y
Xs, ys = simulate(5000)
w = np.linalg.lstsq(Xs, ys, rcond=None)[0]
print("회귀 계수 (x1, x2, x3):", np.round(w[:3], 2) + 0.0)
for name, kw in (("do(x1 = 1)", dict(do_x1=1.0)), ("do(x1 = 0)", dict(do_x1=0.0)),
("x3에 +1 개입", dict(do_x3_shift=1.0)), ("개입 없음", dict())):
Xi, yi = simulate(20000, **kw)
print(f"{name:10s} 실제 y 평균 {yi.mean():6.2f} 모델 예측 평균 {(Xi @ w).mean():6.2f}")회귀 계수 (x1, x2, x3): [0.08 0. 0.96] do(x1 = 1) 실제 y 평균 2.01 모델 예측 평균 2.01 do(x1 = 0) 실제 y 평균 0.00 모델 예측 평균 0.00 x3에 +1 개입 실제 y 평균 -0.00 모델 예측 평균 0.96 개입 없음 실제 y 평균 0.02 모델 예측 평균 0.01
모델은 센서 에 가중치 0.96을, 온도 에 0.08만 준다. 기여도만 보면 센서가 수율을 정한다. 개입 결과는 반대다. 온도를 1로 정하면 실제 수율과 모델 예측이 함께 2.01로 오른다(센서가 바뀐 수율을 따라 움직이므로 모델도 맞힌다). 센서에 을 개입하면(예: 센서 재보정 오류) 실제 수율은 그대로인데 모델 예측은 0.96만큼 오른다. 모델은 관측 분포 안에서는 훌륭한 예측기이지만, 센서에 대한 개입을 예측하는 데는 쓸 수 없다.
연구에서의 의미. "모델이 X를 중요하게 여긴다"는 문장과 "X가 Y의 원인이다"라는 문장 사이에는 인과 가정이 필요하다. 그 가정을 세우는 도구는 16.8장의 인과추론이고, 확인하는 가장 강한 방법은 실제 개입 실험이다. 기여도의 정당한 쓰임은 가설 생성, 지름길 탐지, 모델 디버깅이다. 하류 측정이나 운영 시점에 없을 정보에 모델이 기대고 있다면, 그것은 15.4장의 누수를 찾은 것이다.
민감도 분석과 물리적 타당성
왜 필요한가. 과학 모델에는 해석 방법보다 강한 점검 수단이 있다. 물리·화학 법칙이 정하는 기대 반응이다. 온도가 오르면 반응 속도는 오르고, 질량이 두 배면 관성도 두 배이며, 단위를 바꿔도 예측은 바뀌지 않아야 한다. 모델의 반응을 이 기대와 비교하는 것은 어떤 기여도 방법보다 직접적인 검증이다.
민감도 분석. 입력 하나를 범위 안에서 체계적으로 바꾸며 예측이 어떻게 변하는지 본다. 앞 절의 ICE가 바로 이것이다. 확인할 것은 다음과 같다.
- 단조성: 물리적으로 단조여야 하는 관계(농도 ↑ → 흡광도 ↑)에서 예측이 단조인가
- 크기와 부호: 반응의 크기가 알려진 계수(활성화 에너지, 열팽창 계수)와 같은 규모인가
- 대칭과 불변성: 좌표계 회전, 단위 변환, 원자 번호 매기기 순서를 바꿔도 예측이 그대로인가(24부)
- 극한 거동: 입력이 0이나 매우 클 때 예측이 물리적으로 가능한 범위에 있는가
전역 민감도. 입력 불확실성이 출력 분산에 얼마나 기여하는지 분해하는 분산 기반 방법(Sobol 지수 등)도 있다. 21.1장의 Monte Carlo 전파와 같은 표본으로 계산할 수 있다. 입력이 독립이라는 가정이 필요하다는 점은 순열 중요도와 같다.
기계적 해석
아이디어. 지금까지의 방법은 모델을 입력–출력 함수로만 보았다. 기계적 해석(mechanistic interpretability)은 신경망 내부의 계산을 사람이 이해할 수 있는 단위로 분해하려 한다. 개별 뉴런이나 방향(활성화 공간의 벡터)이 어떤 개념에 반응하는지 찾고, 그런 특징들이 층을 거치며 어떻게 조합되어 출력을 만드는지 회로(circuit) 단위로 추적한다. 주로 이미지 모델과 언어 모델에서 연구되고 있다.
도구. 특정 내부 활성화를 다른 입력의 값으로 바꿔 끼우고 출력이 어떻게 바뀌는지 보는 활성화 패칭(activation patching)은, 모델 내부에 대한 개입 실험이다. 앞 절의 개입과 같은 논리를 모델 안으로 옮긴 것이다. 활성화 공간에서 개념에 대응하는 방향을 선형 분류기로 찾는 probing도 쓰인다. probing은 "그 정보가 표현에 들어 있다"를 보일 뿐 "모델이 그것을 쓴다"를 보이지는 않으므로, 개입으로 보완한다.
과학 모델에서의 의미. 과학 데이터로 학습한 모델의 내부 표현이 알려진 물리량(에너지, 대칭, 보존량)과 대응하는지 확인하는 것은 모델이 "올바른 이유로" 맞히는지에 대한 강한 증거가 될 수 있다. 다만 이 분야는 집필 시점에도 빠르게 변하고 있고, 큰 모델에서 찾은 회로가 전체 행동의 얼마를 설명하는지는 여전히 열린 문제다. 기계적 해석의 결과도 아래의 검증 기준을 똑같이 적용받는다.
해석의 검증
왜 필요한가. 해석 방법의 출력은 늘 그럴듯해 보인다. 그림은 그려지고, 순위는 매겨진다. 문제는 그 출력이 모델의 실제 작동과 관련이 있는지다. 해석 결과는 그 자체로 하나의 주장이고, 다른 주장처럼 검증해야 한다.
sanity check. Adebayo 외(2018)는 설명 방법이 기본 조건을 통과하는지 보는 무작위화 시험을 제안했다.
- 모델 무작위화: 학습한 가중치를 출력 쪽 층부터 차례로 무작위 값으로 바꾼다. 모델이 망가졌는데 설명이 거의 그대로라면, 그 설명은 모델이 배운 것을 반영하지 않는다.
- 데이터 무작위화: 레이블을 섞은 데이터로 다시 학습한 모델에 같은 방법을 쓴다. 의미 없는 레이블을 외운 모델의 설명이 원래 모델의 설명과 비슷하다면 마찬가지다.
이 연구는 일부 saliency 방법이 두 시험에서 거의 변하지 않아, 입력 영상의 경계를 보여 주는 것과 비슷하게 작동한다는 것을 보였다.
개입 실험. 기여도가 크다고 나온 입력을 실제로 바꾸거나 제거하고(가능하면 실험으로, 아니면 시뮬레이터로) 결과가 기대만큼 바뀌는지 본다. 모델 출력의 변화를 보는 것(모델에 대한 개입)과 실제 결과의 변화를 보는 것(세계에 대한 개입)을 구분한다. 앞의 센서 예처럼 둘은 다를 수 있다.
합성 데이터 검증. 참 기여를 아는 데이터를 만들어 방법이 그것을 찾는지 확인한다. 이 장의 셀들이 모두 그런 예다. 실제 데이터와 비슷한 상관 구조(상관된 특징, 하류 변수)를 넣어야 의미가 있다.
방법 간 일치. 여러 방법이 같은 결론을 내면 조금 더 믿을 만하다. 그러나 같은 가정(특징 독립)을 공유하는 방법들은 함께 틀릴 수 있으므로, 일치는 검증을 대신하지 못한다.
실습
같은 모델에 세 가지 attribution 방법을 적용해 결과가 어떻게 다른지 비교하고, 개입 실험으로 검증한다. 코드는 labs/reliability/interpretability/attribution_vs_intervention.py다. 데이터는 화학 반응을 흉내 낸 합성 시뮬레이터다(실제 반응 모델이 아니다). 반응 온도와 촉매량이 수율의 원인이고, 습도는 원인이 아니지만 온도와 상관 0.9로 함께 움직이며, 생성물 농도 센서는 수율의 하류 측정이다. 모델은 scikit-learn의 MLP이고, gradient는 중심 차분으로 계산한다. 세 방법은 순열 중요도, gradient×(입력 − 평균)의 평균, IG의 평균(기준 = 데이터 평균)이다. 검증으로, 시뮬레이터에서 각 입력에 을 개입했을 때 실제 수율 변화와 모델 예측 변화를 같은 잡음(공통 난수)으로 비교한다. 집필 시점의 실행 결과는 다음과 같다(시드 0).
모델 test MSE 0.030 (센서가 수율을 직접 재므로 수율 잡음 분산 0.09보다 작다) 입력 순열중요도 |grad×input| |IG| 개입: 실제 Δy 모델 Δŷ temp 0.136 0.152 0.265 0.831 0.841 cat 0.137 0.173 0.191 0.800 0.795 humid 0.008 0.052 0.035 0.000 0.009 sensor 1.630 0.743 0.748 0.000 0.689
결과를 세 가지로 읽는다.
- 세 방법 모두 센서를 가장 중요한 입력으로 꼽는다. 그러나 센서에 대한 개입은 실제 수율을 바꾸지 않는다(0.000). 모델 예측은 0.689 바뀐다. 기여도는 모델의 사용 방식을 정확히 보여 주었지만, 그것은 인과가 아니다.
- 방법마다 순위와 크기가 다르다. 온도와 촉매는 순열 중요도로는 비슷하고(0.136, 0.137), IG로는 온도가 크다(0.265 대 0.191). 온도의 효과가 로 휘어 있어 국소 기울기와 경로 적분이 다른 값을 주기 때문이다. 어떤 방법을 썼는지 밝히지 않은 중요도 순위는 비교할 수 없다.
- 원인인 온도와 촉매에서는 모델 예측 변화가 실제 변화와 맞는다(0.841 대 0.831, 0.795 대 0.800). 개입 실험은 모델을 어디까지 인과적 질문에 쓸 수 있는지, 즉 어느 입력에 대해서는 "바꾸면 어떻게 되는가"를 예측할 수 있는지를 직접 알려 준다.
이어서 연습문제로 순열 중요도를 구현한다. 상관된 특징을 묶어서 섞는 기능까지 넣는다.
실패 사례
- 설명 그림 하나로 물리적 인과관계를 주장하는 것. 기여도는 모델이 무엇에 반응하는지를 보여 줄 뿐이다. 인과 주장에는 개입 실험이나 명시적인 인과 가정이 필요하다.
- 상관된 특징의 개별 중요도를 그대로 해석하는 것. 같은 정보를 담은 특징 사이의 분할은 학습 알고리즘의 선택이다. 묶어서 보고, 빼고 다시 학습한 결과와 비교한다.
- 평평한 부분 의존을 "효과 없음"으로 읽는 것. 상호작용이 평균에서 상쇄될 수 있다. ICE를 함께 본다.
- 기준값을 밝히지 않은 기여도. IG·SHAP의 값은 기준값(기준 분포)에 따라 바뀐다.
- 검증 없이 그럴듯함으로 설명을 받아들이는 것. 무작위 모델의 설명도 그럴듯해 보일 수 있다. sanity check와 합성 데이터 검증을 거친다.
통과 기준
- 자신의 모델(또는 실습 모델)에 두 가지 이상의 해석 방법을 적용하고, 각 방법의 가정(대체 방식, 기준값)과 결과의 차이를 함께 보고한다.
- 해석에서 나온 주장 하나 이상을 별도의 개입 실험(실제 또는 시뮬레이터)이나 무작위화 sanity check로 검증하고 그 결과를 보고한다.
- 연습문제
permutation-importance의 테스트를 통과한다.
참고 문헌
- Breiman (2001). Random forests. Machine Learning, 45(1), 5–32. — 순열 기반 변수 중요도
- Friedman (2001). Greedy function approximation: A gradient boosting machine. The Annals of Statistics, 29(5), 1189–1232. — 부분 의존 그림
- Sundararajan, Taly, Yan (2017). Axiomatic attribution for deep networks. Proceedings of the 34th International Conference on Machine Learning, PMLR 70, 3319–3328. — integrated gradients와 완전성
- Lundberg, Lee (2017). A unified approach to interpreting model predictions. Advances in Neural Information Processing Systems 30 (NIPS 2017), 4765–4774. — SHAP
- Adebayo, Gilmer, Muelly, Goodfellow, Hardt, Kim (2018). Sanity checks for saliency maps. Advances in Neural Information Processing Systems 31 (NeurIPS 2018). — 모델·데이터 무작위화 시험
- 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. — 영상에서 병원 시스템을 구분하는 지름길과 외부 성능 저하
- Hooker, Mentch, Zhou (2021). Unrestricted permutation forces extrapolation: Variable importance requires at least one more model, or there is no free variable importance. Statistics and Computing, 31, 82. — 상관된 특징에서 순열·부분 의존 방법의 외삽 문제