데이터 분할, 누수, 불균형: 점수가 실제보다 좋게 나오는 이유
AI 모델을 만들 때 데이터에서 자주 생기는 문제를 정리했어요. 연습 문제를 풀면서 놓친 부분도 같이 적었어요. 데이터를 나누는 법, 누수, 클래스 불균형, 편향, 분포 이동, 프롬프트로 나가는 데이터를 다루고, 평가 지표의 세부 내용과 피처 엔지니어링, 라이브러리 코드는 다루지 않아요.
1. 데이터가 모델의 상한을 정해요
모델은 데이터에 있는 패턴만 배울 수 있어요. 데이터가 틀리거나 한쪽으로 치우쳐 있으면 모델도 똑같이 틀리고 치우쳐요.
데이터를 더 넣는다고 해결되지는 않아요. 같은 오류가 더 많이 들어갈 뿐이거든요. 그래서 양보다 질을 먼저 봐요. 라벨이 정확한지, 표본이 실제 현장을 대표하는지가 먼저예요.
2. 데이터를 셋으로 나눠요
| 이름 | 쓰는 곳 | 규칙 |
|---|---|---|
| 학습 (train) | 모델이 패턴을 배워요 | |
| 검증 (validation) | 설정을 고르고, 학습을 언제 멈출지 정해요 | 여러 번 봐도 돼요 |
| 테스트 (test) | 최종 성능을 재요 | 마지막에 한 번만 봐요 |
테스트 점수를 보면서 모델을 고치기 시작하면 테스트셋도 사실상 학습에 쓰인 셈이에요. 그 점수는 처음 보는 데이터에서의 성능을 더 이상 보여 주지 못하고요.
과적합(overfitting)은 학습 데이터에서는 점수가 아주 높은데 새 데이터에서는 크게 떨어지는 상태예요. 학습 데이터의 답을 외워 버린 거죠. 학습 점수와 검증 점수의 차이가 크면 과적합을 의심해요.
3. 데이터 누수
누수 판별 연습에서 설비 고장 예측 모델에 "고장 원인 코드"를 피처로 넣는 문제를 틀렸어요. 저는 누수가 아니라고 골랐어요. 답은 누수였어요. 이번 고장의 원인 코드는 고장이 난 뒤에 정비하면서 적는 값이라, 예측하는 시점에는 없거든요.
고장 직전 24시간 동안의 챔버 압력 평균을 피처로 쓰는 문제에서는 "24시간 뒤면 고장이니까" 누수라고 답했어요. 판정은 맞았어요. 더 정확히 말하면 그 24시간 구간을 고장 시각에 맞춰 잘랐다는 게 문제였어요. 현장에서는 고장이 언제 날지 모르니까요.
누수(leakage)는 평가할 때 알 수 없어야 할 정보가 학습에 섞이는 거예요. 점수가 실제보다 좋게 나오고, 현장에 배포하면 성능이 크게 떨어져요. 판별할 때는 질문 하나면 돼요.
실제로 예측하는 그 순간에 이 정보가 손에 있나? 없으면 누수예요.
반도체 현장 데이터로 자주 나오는 경우는 넷이에요.
같은 묶음이 train과 test 양쪽에 들어가요. 함께 공정을 거친 웨이퍼 묶음(lot)은 같은 장비, 같은 레시피, 같은 시간대의 흔적을 공유해요. 칩을 lot 구분 없이 무작위로 섞어 나누면, 모델은 lot마다 다른 특징만 외워도 test에서 좋은 점수를 받아요. 현장에는 항상 처음 보는 lot이 들어오니까 그 점수가 나오지 않고요. 그래서 lot이나 웨이퍼 단위로 나눠요.
시간 순서를 무시해요. 3월 데이터로 학습한 모델로 1월 불량을 맞히면 미래 정보를 쓴 거예요. 시계열은 과거로 학습하고 미래로 테스트해요.
정답에서 나온 값을 피처로 써요. "재작업 여부", "불량 처리 코드"처럼 불량 판정이 난 뒤에 기록되는 값을 입력으로 쓰면, 모델은 정답을 보고 정답을 맞혀요. 앞의 고장 원인 코드가 이 경우예요.
다만 같은 이름의 피처라도 언제 기록된 값이냐에 따라 판정이 갈려요.
| 피처 | 예측 시점에 있나 | 판정 |
|---|---|---|
| 맞히려는 이번 고장의 원인 코드 | 없어요. 고장 뒤에 기록돼요 | 누수 |
| 지난 고장들의 원인 코드 이력 | 있어요 | 누수 아님 |
그래서 피처 이름만 보고 판정하지 않고, 그 값이 언제 기록되는지를 확인해요. 모호하면 "이 값은 언제 기록되나요?"라고 데이터를 준 사람에게 물어보는 게 좋아요.
전처리를 전체 데이터로 해요. 평균과 표준편차로 정규화하거나 결측값을 평균으로 채울 때, 그 통계를 test까지 포함한 전체 데이터로 구하면 test의 정보가 학습에 들어가요. 먼저 나누고, 통계는 train에서만 구해서 test에 그대로 적용해요.
예측 시점을 먼저 정해요
24시간 압력 평균 문제가 여기에 해당해요. 학습 데이터를 만들 때는 고장 시각을 이미 알아요. 그래서 그 시각부터 거꾸로 24시간을 잘랐어요. 현장에서는 고장이 언제 날지 모르니까, 자를 수 있는 건 지금부터 거꾸로 24시간뿐이에요.
학습 데이터를 만든 방식
|------- 24시간 -------|
고장 시각 <- 정답을 알아야 자를 수 있는 위치
현장에서 쓸 때
|------- 24시간 -------|
지금 <- 고장이 언제 날지 모르는 시점
이렇게 만들면 고장 데이터는 늘 고장 바로 앞 구간이고, 정상 데이터는 아무 시점이나 자른 구간이 돼요. 모델은 고장 바로 앞에서만 보이는 패턴을 배우고요. 게다가 구간이 고장 순간에 끝나니까, 맞히더라도 정비할 시간이 남지 않아요.
고칠 때는 예측 시점 t를 먼저 정하고, 피처와 정답을 그 기준으로 나눠요.
|-- 피처: t 이전 24시간 --|-- 정답: t 이후 48시간 안에 고장이 나나? --|
t
- 피처는
t까지 쌓인 데이터로만 계산해요. - 정답은
t이후 정해 둔 기간 안에 고장이 나는지로 정해요. - 고장 데이터와 정상 데이터 모두 같은 규칙으로
t를 잡아요.
이러면 학습할 때와 현장에서 쓸 때의 조건이 같아지고, 48시간이라는 정비 여유도 생겨요.
4. 클래스 불균형
반도체 불량은 아주 드물어요. 칩 100,000개 중 불량이 0.1%(100개)일 때 두 모델을 비교해 볼게요.
| 모델 | 정확도 | 재현율 | 정밀도 | 놓친 불량 |
|---|---|---|---|---|
| A. 전부 "정상"이라고 답해요 | 99.90% | 0% | 경보 없음 | 100개 |
| B. 불량의 80%를 잡고, 정상의 2%를 불량으로 잘못 경보해요 | 97.98% | 80% | 3.85% | 20개 |
재현율은 실제 불량 중 잡아낸 비율이고, 정밀도는 경보 중 진짜 불량의 비율이에요. 정확도만 보면 아무것도 잡지 못하는 A가 B보다 높아요. 그래서 불균형한 데이터에서는 정확도 하나로 모델을 판단하지 않아요.
B의 정밀도 3.85%도 볼 만해요. 경보 2,078건 중 진짜 불량은 80건이에요. 불량이 드물면 오경보 비율이 작아도 오경보 건수가 진짜 불량보다 훨씬 많아져요. 지표를 고르는 문제는 다음 글에서 이어서 다뤄요.
데이터 쪽에서 쓰는 대응은 이래요.
- 드문 클래스를 더 뽑거나 흔한 클래스를 덜 뽑아요(오버샘플링, 언더샘플링).
- 드문 클래스를 틀렸을 때 손실을 더 크게 줘요(클래스 가중치).
- 불량 샘플을 합성해서 늘려요. 합성 데이터는 실제 분포와 다를 수 있으니까 평가는 실제 데이터로 해요.
5. 편향
편향은 데이터를 모으는 과정에서 생겨요.
| 종류 | 예 |
|---|---|
| 표본 편향 | A 라인 설비 데이터로만 학습한 모델을 B 라인에 적용해요 |
| 라벨 편향, 라벨 노이즈 | 검사자마다 불량 기준이 달라서 같은 패턴에 다른 라벨이 붙어요 |
| 생존자 편향 | 공정 중간에 폐기된 웨이퍼는 최종 데이터에 없어요. 심각한 불량일수록 데이터에서 빠져요 |
같은 방식으로 더 많이 모으면 같은 편향이 더 커져요. 편향을 줄이려면 모으는 방식을 바꿔야 해요.
6. 분포 이동
공정 레시피를 바꾸거나, 장비를 교체하거나, 원자재가 바뀌면 입력 데이터의 분포가 학습할 때와 달라져요. 이걸 분포 이동(drift)이라고 해요. 어제까지 잘 맞던 모델이 오류 없이 틀린 답을 내기 시작해요.
그래서 배포한 뒤에도 입력 분포와 성능을 계속 지켜보고, 크게 달라지면 다시 학습해요.
LLM에도 같은 문제가 있어요. 학습 시점(knowledge cutoff) 이후의 사실이나 사내 문서는 모델 안에 없어요. 지난 글에서 다룬 RAG가 이 빈자리를 채우는 방법이었어요.
7. 프롬프트에 넣는 것도 데이터예요
학습 데이터만 문제가 되는 건 아니에요. 프롬프트에 붙여 넣은 내용은 외부 서버로 전송되고 저장돼요. 한 번 넣으면 회수할 수 없어요.
2023년 3월 삼성전자 반도체(DS) 부문이 사내에서 ChatGPT 사용을 허용한 뒤, 설비 정보 유출 2건과 회의 내용 유출 1건이 보도됐어요. 설비 계측, 수율·불량과 관련된 프로그램 내용이 입력됐다고 전해져요(이코노미스트). 회사는 입력 용량을 제한했고, 5월에는 사내 PC에서 생성형 AI 사용을 제한했어요(파이낸셜뉴스, SBS Biz). 유출된 내용을 "소스 코드"라고 쓴 보도도 있고 "설비 계측 프로그램"이라고 쓴 보도도 있어서, 세부 내용은 기사마다 조금씩 달라요.
공정 조건, 수율, 고객사 정보는 기밀이에요. 어느 AI에 어떤 계약 조건으로 넣는지도 데이터를 다루는 판단에 들어가요.
누수 판별 연습
각 상황이 누수인지 골라 보세요. 기준은 3절의 질문 하나예요.
1. 웨이퍼 수율을 예측하는 모델에 "최종 테스트 bin 결과"를 입력 피처로 넣었어요.
정답
누수예요. 최종 테스트 bin은 수율이 결정된 뒤에 나오는 값이에요.
2. 1~6월 설비 센서 로그로 학습하고, 7월 로그로 테스트했어요.
정답
누수가 아니에요. 과거로 학습하고 미래로 테스트했어요.
3. 칩 단위 데이터를 lot 구분 없이 무작위로 섞어 8:2로 나눴어요.
정답
누수예요. 같은 lot의 칩이 train과 test에 함께 들어가요.
4. 식각 직후의 계측값으로 최종 불량 여부를 예측해요.
정답
누수가 아니에요. 식각 직후 계측값은 예측하는 시점에 이미 있어요.
5. 전체 데이터의 평균과 표준편차로 정규화한 다음 train과 test로 나눴어요.
정답
누수예요. test의 값이 평균과 표준편차에 섞여 들어갔어요. 먼저 나누고 train의 통계로만 정규화해요.
6. test 점수를 보면서 설정을 스무 번 바꾸고, 가장 좋았던 점수를 최종 성능으로 보고했어요.
정답
누수예요. test로 설정을 골랐으니 test가 검증셋 역할을 했어요. 설정은 validation으로 골라요.
7. 설비 고장을 예측하는 모델에, 맞히려는 이번 고장의 정비 기록에 적힌 "고장 원인 코드"를 피처로 넣었어요.
정답
누수예요. 이번 고장의 원인 코드는 고장이 난 뒤에 기록돼요.
8. 고장 예측 모델에 "고장 직전 24시간 챔버 압력 평균"을 넣었어요. 구간은 고장 시각을 기준으로 거꾸로 잘랐어요.
정답
누수예요. 구간을 자르는 위치를 정할 때 고장 시각, 즉 정답을 썼어요. 예측 시점 t를 먼저 정하고 t 이전 데이터로만 피처를 만들어요.
다시 정리하면
- 데이터의 질이 모델의 상한을 정하고, 양으로는 질을 메울 수 없어요.
- 테스트셋은 마지막에 한 번만 봐요.
- 누수는 "예측하는 순간 이 정보가 손에 있나?"로 판별해요. 피처는 이름보다 기록 시점을 확인하고, lot과 시간 단위로 나누고, 전처리 통계는 train에서만 구해요.
- 불균형한 데이터에서는 정확도만으로 모델을 판단할 수 없어요.
- 편향은 모으는 방식을 바꿔야 줄어들어요.
- 배포한 뒤에도 분포가 바뀌니까 계속 지켜봐요.
- 프롬프트에 넣는 내용도 외부로 나가는 데이터예요.