문제를 수학적으로 정의하기

먼저 읽을 장 1.1 AI 연구의 생애주기

"배터리 상태를 예측하는 모델을 만든다"는 문장은 연구 주제처럼 들리지만, 아직 문제가 아니다. 무엇이 입력이고 무엇이 출력인지, 예측하는 순간에 어떤 정보를 쓸 수 있는지, 어떤 셀과 어떤 조건에서 통해야 하는지가 정해지지 않았다. 이 빈칸을 채우지 않고 시작하면 두 사람이 같은 데이터로 전혀 다른 실험을 하게 되고, 점수는 높은데 쓸 수 없는 모델이 나온다.

1.1장의 생애주기에서 수학적 정의는 세 번째 단계다. 이 장은 그 단계를 구체적인 작업으로 만든다. 변수의 역할을 나누고, 문제의 유형을 정하고, 추론 시점에 이용 가능한 정보를 명시하고, 예측 범위와 일반화 대상을 정한다. 마지막에는 이 결정들을 동료가 읽고 같은 실험을 설계할 수 있는 한 장짜리 문서로 묶는다. 분포의 관점에서 문제를 다시 정의하는 일은 12.3장에서 이어진다.

학습 목표

  • 입력·출력·상태·파라미터·잠재변수를 구분한다
  • 추론 시점에 이용 가능한 정보를 명시한다
  • 문제 유형을 분류한다

변수의 역할

왜 역할을 나누는가. 데이터 파일의 열(column)은 모두 숫자로 보이지만, 문제 안에서 맡는 역할은 다르다. 어떤 열은 연구자가 고른 값이고, 어떤 열은 측정한 결과이고, 어떤 열은 다른 모델로 계산한 추정값이다. 역할을 구분하지 않으면 출력을 입력에 넣거나, 고를 수 있는 값을 예측하려 들거나, 추정값을 측정값처럼 믿게 된다.

정의. 이 책은 다음 기호를 쓴다(부록 A 표기법).

기호 이름 뜻 배터리 예 감쇠 진동자 예
xx 입력(input) 모델이 받는 값 측정한 전압·전류·온도 측정 시각 tt
yy 출력(output), 정답(label) 모델이 내야 하는 값 건강 상태(SOH) 위치 측정값
uu 제어입력(control input) 연구자나 제어기가 고르는 값 충전 전류 프로파일 가한 외력
θ\theta 파라미터(parameter) 시스템에 고정된 성질 전극의 확산 계수 감쇠비 ζ\zeta, 고유진동수
ss 상태(state) 시간에 따라 변하며 미래를 결정하는 양 충전 상태(SOC), 전극 내 농도 분포 위치와 속도
zz 잠재변수(latent variable) 관측되지 않지만 데이터를 설명하는 데 쓰는 변수 셀마다 다른 제조 편차 측정 장비의 숨은 offset

이 기호들은 모델에 따라 겹친다. 같은 전압이 한 문제에서는 입력 xx, 다른 문제에서는 출력 yy가 된다. 역할은 변수 자체가 아니라 문제가 정한다.

동적 시스템을 다룰 때는 이 변수들을 상태공간 모델(state-space model)로 묶는 것이 편하다.

st+1=f(st,ut;θ)+wt,yt=h(st;θ)+vt.s_{t+1} = f(s_t, u_t; \theta) + w_t, \qquad y_t = h(s_t; \theta) + v_t.

첫 식은 상태가 제어입력과 파라미터에 따라 어떻게 변하는지(동역학), 둘째 식은 상태가 어떻게 관측되는지(관측 모델)를 말한다. wtw_t는 모델이 설명하지 못하는 변화(과정 잡음), vtv_t는 측정 잡음이다. 이 장에서 다룰 문제 유형의 대부분은 이 두 식에서 "무엇을 알고 무엇을 구하는가"로 정의된다.

관측 가능한 것과 숨은 것. 상태 sts_t는 대개 직접 보이지 않는다. 배터리의 충전 상태(SOC)를 재는 센서는 없고, 전압·전류에서 추정할 뿐이다. 진동자의 속도도 위치만 측정한다면 숨은 상태다. 숨은 변수를 출력으로 삼는 문제는 정답 label을 어떻게 얻었는지가 핵심 질문이 된다.

직접 측정값과 추정된 label. 정답 yy가 측정이 아니라 다른 방법으로 계산한 값인 경우가 많다.

  • 배터리의 SOH는 정해진 조건에서 완전 방전해 잰 용량을 기준 용량으로 나눈 값으로 정의하는 경우가 많다. 이 값은 측정에 가깝다. 그러나 운행 중인 셀의 SOH label을 다른 추정 알고리즘이 계산했다면, 모델은 실제 SOH가 아니라 그 알고리즘을 흉내 내게 된다.
  • 기후 연구의 "관측"은 흔히 관측과 수치 모델을 결합한 재분석 자료다. 정답에 이미 모델의 가정이 들어 있다.
  • 분자의 물성 label이 실험값인지 양자화학 계산값인지에 따라, 모델이 도달할 수 있는 정확도와 의미가 다르다.

추정된 label을 쓰는 것이 잘못은 아니다. 다만 문제 정의서에 label이 어떻게 만들어졌는지 적어야 하고, label과 비교해 잰 모델의 오차는 label 자체의 오차보다 의미 있게 작아질 수 없다는 점을 염두에 둔다.

문제의 유형

왜 유형을 정하는가. 유형이 정해지면 입력과 출력의 형태, 쓸 수 있는 방법, 적절한 평가 방법이 함께 정해진다. 반대로 유형이 모호하면 "예측"이라는 한 단어 아래 서로 다른 문제가 섞인다.

유형 알고 있는 것 구하는 것 수식 배터리 예 다루는 곳
정적 예측 입력 xx 출력 yy p(y∣x)p(y \mid x) 또는 y^=f(x)\hat{y} = f(x) 전극 조성으로 초기 용량 예측 16부
시계열 예측 과거 관측 y≤ty_{\le t} 미래 관측 yt+hy_{t+h} p(yt+h∣y≤t)p(y_{t+h} \mid y_{\le t}) 다음 100 사이클의 용량 곡선 16.7장, 18.7장
상태 추정 관측 y≤ty_{\le t} 숨은 상태 sts_t p(st∣y≤t)p(s_t \mid y_{\le t}) 운행 중 현재 SOC 추정 24.6장
역문제 관측 yy 파라미터 θ\theta p(θ∣y)p(\theta \mid y) 전압 곡선으로 확산 계수 추정 24.7장
최적화 목적함수 가장 좋은 설계 변수 arg⁡max⁡uJ(u)\arg\max_u J(u) 수명을 최대화하는 충전 프로토콜 하나 10부, 25.3장
제어 지금까지의 관측 관측에 반응하는 규칙(정책) ut=π(y≤t)u_t = \pi(y_{\le t}) 온도를 보며 매 순간 충전 전류를 정함 20부
생성 데이터 표본 데이터 분포에서 새 표본 x∼p(x)x \sim p(x) 그럴듯한 사이클 곡선 합성 19부

헷갈리기 쉬운 쌍 두 개를 짚는다.

  • 상태 추정과 역문제. 둘 다 숨은 양을 관측에서 거꾸로 추정한다. 상태 sts_t는 시간에 따라 변하고, 파라미터 θ\theta는 (적어도 관심 있는 시간 동안은) 변하지 않는다. 실제로는 둘을 함께 추정하는 경우가 많다(시스템 식별, 24.6장).
  • 최적화와 제어. 최적화는 미리 정해 두는 답(충전 프로토콜 하나)을, 제어는 관측에 따라 매번 달라지는 규칙을 찾는다. 제어에는 관측 → 결정 → 새 관측으로 이어지는 되먹임이 있다.

정보의 시점

왜 필요한가. 학습 데이터에는 모든 시각의 모든 값이 이미 들어 있다. 그래서 학습할 때는 "이 값을 예측 시점에 정말 알 수 있는가"를 잊기 쉽다. 예측 시점에 존재하지 않는 정보를 입력에 넣으면, 오프라인 평가 점수는 좋아지지만 실제로는 그 모델을 돌릴 수 없다. 이를 미래 정보 누수(look-ahead leakage)라 한다.

정의. 시각 tt에 이용 가능한 정보의 집합을 It\mathcal{I}_t라 하자. 입력이 인과적(causal)이라는 것은 시각 tt의 입력이 It\mathcal{I}_t만으로 계산된다는 뜻이다. 실시간 측정이라면 It={y1,…,yt}\mathcal{I}_t = \{y_1, \dots, y_t\}와 미리 정해 둔 제어입력, 그리고 학습 데이터에서 얻은 고정된 값(모델 파라미터, 정규화 상수)이다.

미래 정보는 의외의 경로로 들어온다.

  • 중심 이동평균. 잡음을 줄이려고 t−2t-2부터 t+2t+2까지의 평균을 입력으로 쓰면, t+1t+1과 t+2t+2의 측정이 들어간다.
  • 전체 데이터로 계산한 정규화. 시계열 전체의 평균과 표준편차로 표준화하면, 미래 구간의 통계가 과거의 입력에 섞인다.
  • 사후에 정해지는 label이 특징이 된 경우. "고장 난 셀"이라는 표시, 시험 종료 후 측정한 값이 입력 열에 남아 있다.
  • 데이터 정제의 기준. 시험이 끝까지 간 셀만 남기면, 예측 시점에는 알 수 없는 "끝까지 갔다"는 사실로 데이터를 고른 셈이다.

첫 번째 경로를 직접 확인한다. 실내 온도가 천천히 변하고 센서 잡음(표준편차 0.3 °C)이 섞인 측정값으로 다음 시각의 측정값을 예측한다. 입력은 이동평균 하나이고, 과거 5개 평균과 중심 5개 평균을 비교한다. 앞의 2000개 시각으로 학습하고 뒤의 1000개로 테스트한다.

import numpy as np
from sklearn.linear_model import LinearRegression

rng = np.random.default_rng(0)
T = 3000
temp_c = 25.0 + np.cumsum(rng.normal(0, 0.1, size=T))     # (T,) 실내 온도의 느린 변화
obs_c = temp_c + rng.normal(0, 0.3, size=T)                # (T,) 잡음 섞인 센서 측정

def window_mean(x, lo, hi):
    """t마다 x[t+lo : t+hi+1]의 평균. 창이 범위를 벗어나는 t는 NaN."""
    out = np.full(len(x), np.nan)
    for t in range(-lo, len(x) - hi):
        out[t] = x[t + lo : t + hi + 1].mean()
    return out

target = np.roll(obs_c, -1)                                # (T,) 다음 시각의 측정값
features = {"과거 5개 평균 (t-4..t)  ": window_mean(obs_c, -4, 0),
            "중심 5개 평균 (t-2..t+2)": window_mean(obs_c, -2, 2)}
t_idx = np.arange(T)
for name, f in features.items():
    ok = ~np.isnan(f) & (t_idx < T - 1)                    # 마지막 시각은 정답이 없다
    tr, te = ok & (t_idx < 2000), ok & (t_idx >= 2000)     # 앞 2000개 학습, 뒤는 테스트
    model = LinearRegression().fit(f[tr, None], target[tr])
    mae = np.mean(np.abs(model.predict(f[te, None]) - target[te]))
    print(f"{name}  테스트 MAE {mae:.3f} °C")
과거 5개 평균 (t-4..t)    테스트 MAE 0.290 °C
중심 5개 평균 (t-2..t+2)  테스트 MAE 0.222 °C

시간 순서로 나누었으니 분할은 정직하다. 그런데도 중심 평균이 훨씬 좋아 보인다. 이 숫자가 왜 의심스러운지는 계산으로 알 수 있다.

다음 측정값에는 그 시각에 새로 생긴 센서 잡음이 들어 있다. 시각 tt까지의 정보로는 이 잡음을 알 수 없으므로, 참 온도를 정확히 맞혀도 MAE는 0.32/π≈0.2390.3\sqrt{2/\pi} \approx 0.239 °C 아래로 내려갈 수 없다. 중심 평균의 0.222 °C는 이 하한보다 작다. 과거 정보만으로는 불가능한 숫자가 나왔다는 것 자체가 누수의 증거다. 중심 평균 안에 정답 yt+1y_{t+1}이 5분의 1의 가중치로 들어 있기 때문이다.

연구에서의 의미. 문제 정의서에는 입력마다 "예측 시점에 어떻게 얻는가"를 적는다. 그리고 시계열 문제라면 입력을 만드는 함수가 미래 값을 쓰지 않는다는 것을 테스트로 확인한다. 시각 tt 이후의 값을 바꿔도 시각 tt의 입력이 변하지 않아야 한다. 이 장의 연습문제가 이 테스트를 다룬다.

범위의 명시

왜 필요한가. "예측한다"는 말에는 언제까지, 어디서, 얼마나 자주, 무엇에 대해서라는 범위가 빠져 있다. 범위를 정하지 않으면 평가 결과를 다른 연구와 비교할 수 없고, 무엇보다 데이터를 어떻게 나눌지 정할 수 없다.

정해야 할 범위는 네 가지다.

  • 예측 구간(horizon) hh: 얼마나 앞을 예측하는가. 1단계 뒤와 50단계 뒤는 다른 문제다.
  • 공간 범위: 어느 지역, 어느 격자, 어느 형상에서 쓰는가.
  • 시간 해상도: 1초마다인가, 사이클마다인가, 하루마다인가. 해상도가 바뀌면 같은 "다음 값"이 다른 양이 된다.
  • 일반화 대상: 무엇에 대해 새로운 데이터에서 통해야 하는가. 새 측정, 새 셀, 새 조건(온도·충전 속도), 새 장비, 새 화학 조성.

같은 온도 데이터로 예측 구간만 바꿔 본다. 입력은 앞에서 정직했던 과거 5개 평균이다.

past = window_mean(obs_c, -4, 0)                           # (T,) 시각 t까지의 정보만 쓴 입력
for h in (1, 10, 50):
    y_h = np.roll(obs_c, -h)                               # (T,) h 단계 뒤의 측정값
    idx = np.arange(4, T - h)
    tr, te = idx[idx < 2000], idx[idx >= 2000]
    model = LinearRegression().fit(past[tr, None], y_h[tr])
    mae = np.mean(np.abs(model.predict(past[te, None]) - y_h[te]))
    print(f"h = {h:2d} 단계 뒤 예측  테스트 MAE {mae:.3f} °C")
h =  1 단계 뒤 예측  테스트 MAE 0.290 °C
h = 10 단계 뒤 예측  테스트 MAE 0.358 °C
h = 50 단계 뒤 예측  테스트 MAE 0.653 °C

같은 모델, 같은 데이터인데 오차가 두 배 넘게 차이 난다. "MAE 0.29 °C"라는 숫자는 예측 구간을 함께 적지 않으면 의미가 없다.

일반화 대상과 분할. 네 범위 중 실험 설계를 가장 크게 바꾸는 것은 일반화 대상이다. 테스트 데이터는 일반화 대상의 단위로 떼어야 한다. 가상의 배터리 셀 20개에서 사이클마다 SOH를 40번씩 측정한 데이터로 확인한다. 셀마다 열화 속도가 다르고, 입력은 사이클 수와 셀의 초기 용량이다. 무작위로 측정의 25%를 떼는 분할과, 셀 5개를 통째로 떼는 분할을 비교한다.

from sklearn.ensemble import RandomForestRegressor

n_cells, n_meas = 20, 40
cell = np.repeat(np.arange(n_cells), n_meas)               # (800,) 셀 번호
cycle = np.tile(np.linspace(0, 1000, n_meas), n_cells)     # (800,) 사이클 수
fade = rng.uniform(0.5e-4, 2.5e-4, size=n_cells)           # (20,) 셀마다 다른 열화 속도(숨은 값)
cap0_ah = rng.normal(2.0, 0.05, size=n_cells)              # (20,) 셀마다 다른 초기 용량
soh = 1.0 - fade[cell] * cycle + rng.normal(0, 0.005, size=cell.size)   # (800,)
X = np.column_stack([cycle, cap0_ah[cell]])                # (800, 2) 입력: 사이클, 초기 용량

def test_mae(is_test):
    rf = RandomForestRegressor(n_estimators=50, random_state=0)
    rf.fit(X[~is_test], soh[~is_test])
    return np.mean(np.abs(rf.predict(X[is_test]) - soh[is_test]))

random_test = rng.random(cell.size) < 0.25                 # 측정 단위로 무작위 25%
group_test = np.isin(cell, rng.choice(n_cells, 5, replace=False))   # 셀 5개를 통째로
print(f"무작위 분할   테스트 MAE {test_mae(random_test):.4f}")
print(f"셀 단위 분할  테스트 MAE {test_mae(group_test):.4f}")
무작위 분할   테스트 MAE 0.0070
셀 단위 분할  테스트 MAE 0.0240

무작위 분할의 오차는 측정 잡음의 MAE(약 0.004)에 가깝고, 셀 단위 분할보다 세 배 넘게 작다. 이 데이터에서 초기 용량은 열화 속도와 아무 관계가 없다. 그런데도 무작위 분할에서 모델이 잘 맞히는 이유는, 초기 용량이 셀을 알아보는 지문 역할을 하기 때문이다. 같은 셀의 다른 측정이 학습에 있으니, 모델은 그 셀의 열화 속도를 기억해 두었다가 쓴다. 처음 보는 셀에서는 이 기억이 없다.

두 숫자는 모두 "맞는" 숫자다. 다만 서로 다른 질문에 답한다. 무작위 분할은 "이미 시험 중인 셀의 빠진 측정을 메울 수 있는가", 셀 단위 분할은 "새로 들어온 셀의 열화를 예측할 수 있는가"에 답한다. 어느 질문이 연구 질문인지는 데이터가 아니라 문제 정의가 정한다.

문제 정의 문서

지금까지의 결정을 한 장의 문서로 묶는다. 이 문서의 목표는 동료가 읽고 같은 실험을 설계할 수 있는 것이다. 동료가 "이건 어떻게 하지?"라고 물어야 하는 곳이 있다면 정의가 빠진 곳이다.

항목 써야 할 내용
연구 질문 한 문장. 답이 예/아니오 또는 숫자로 나올 수 있게
문제 유형 정적 예측 · 시계열 예측 · 상태 추정 · 역문제 · 최적화 · 제어 · 생성 중 무엇인가
변수 입력 xx, 출력 yy, (있으면) uu, θ\theta, ss, zz와 각각의 단위
정답 정의 label을 어떻게 측정 또는 계산했는가, label의 잡음은 얼마인가
정보의 시점 예측 시점이 언제이고, 각 입력을 그 시점에 어떻게 얻는가
범위 예측 구간, 공간 범위, 시간 해상도
일반화 대상 새 측정 · 새 개체(셀, 환자, 시료) · 새 조건 · 새 장비 중 무엇인가, 그에 따른 분할 단위
평가 단위와 지표 오차를 어떤 단위(측정, 개체, 조건)로 모아 어떤 지표로 보고하는가
baseline 무엇과 비교하는가(평균 예측, 선형 모델, 분야의 물리 모델)
성공 기준 무엇보다 얼마나 좋아야 성공인가(예: 측정 잡음의 1.5배 이내, 물리 모델 대비 20% 개선)

이 문서는 데이터를 보기 전에 쓴다(1.1장). 데이터를 탐색하다가 정의를 바꿔야 할 이유가 생기면, 바꾼 내용과 이유를 문서에 남긴다.

실습

'배터리 SOH 추정'을 동료가 같은 실험을 설계할 수 있는 수준의 한 장짜리 명세로 작성한다. 공개 데이터셋 하나를 정해(데이터셋을 정하기 어렵다면 가상의 데이터셋이라도 좋다) 위의 문제 정의 문서 양식을 채운다. 다음 다섯 항목은 반드시 구체적으로 쓴다.

  1. 입력 구간. 어느 사이클의 어떤 측정(전압 곡선, 전류, 온도)을 입력으로 쓰는가. 완전 충방전 곡선이 필요한가, 부분 구간만으로 되는가.
  2. 정답 정의. SOH를 무엇으로 정의하는가(예: 기준 조건에서 측정한 방전 용량 ÷ 정격 용량). 기준 용량 측정은 얼마나 자주 이루어지고, 그 사이의 사이클에는 label이 있는가.
  3. 대상 셀. 어떤 화학 조성·형상·제조사의 셀에 쓰는 모델인가. 데이터에 없는 셀에 대해서는 무엇을 주장하지 않는가.
  4. 미래 정보 사용 여부. 각 입력이 추정 시점에 존재하는지 하나씩 확인한다. 정규화 통계는 어느 데이터로 계산하는가.
  5. 일반화 대상. 새 측정·새 셀·새 충방전 조건·새 장비 중 무엇인가. 그에 맞는 분할 단위를 쓴다.

작성한 명세를 동료에게 주고, 명세만 보고 데이터 분할과 평가 방법을 말해 달라고 한다. 동료의 답이 자신의 의도와 다른 곳이 명세의 빈칸이다.

이어서 연습문제로, 미래 값을 쓰지 않는 lag 특징을 만들고 그 인과성을 테스트로 확인한다.

실패 사례

  • 추론 시점에 존재하지 않는 정보를 입력에 넣는 것. 중심 이동평균, 전체 시계열로 계산한 정규화, 시험 종료 후의 측정값, "끝까지 간 셀만" 고른 정제 기준이 대표적이다. 오프라인 점수는 좋아지지만, 실제 시점에는 그 입력을 만들 수 없다. 테스트 오차가 측정 잡음의 하한보다 작게 나오면 가장 먼저 의심한다.
  • 일반화 대상을 정하지 않은 채 random split을 쓰는 것. 같은 셀·같은 시료·같은 실험 회차의 측정이 학습과 테스트에 흩어지면, 모델은 개체를 알아보고 기억한 값을 쓴다. 이 점수는 새 개체에 대한 성능이 아니다. 분할 단위를 먼저 정하고, 그 단위로 나눈다(15.4장).
  • 추정값을 측정값처럼 쓰는 것. 다른 알고리즘이 계산한 label로 학습하고 "실제 SOH를 예측했다"고 쓰면, 그 알고리즘의 오차가 결론에 숨는다. label의 출처를 정의서에 적는다.
  • 예측 구간과 해상도 없이 오차를 보고하는 것. "MAE 0.29 °C"는 1단계 뒤인지 50단계 뒤인지에 따라 전혀 다른 성능이다.

통과 기준

  • 자신의 연구 문제(또는 실습의 배터리 SOH 추정)를 한 장짜리 명세로 쓴다. 명세에는 문제 유형, 변수와 단위, 정답 정의, 입력별 이용 시점, 범위, 일반화 대상과 분할 단위, 평가 지표, baseline, 성공 기준이 들어 있다.
  • 동료가 명세만 보고 자신과 같은 분할·평가 방법을 설계한다. 다른 답이 나온 항목은 명세를 고쳐 다시 확인한다.
  • 연습문제 causal-lag-features의 테스트를 통과한다.