본문으로 건너뛰기

AI 파이프라인을 망치는 Python 실수 7가지

오류 없이 실행된 AI 파이프라인도 데이터 누수와 상태·Shape·Artifact 오류로 배포 후 실패할 수 있어 경계별 검증이 필요합니다.

이 요약은 AI가 원문을 분석해 생성했습니다. 정확한 내용은 원문 기준으로 확인하세요.

TL;DR

AI 파이프라인은 코드가 오류 없이 실행돼도 데이터 누수, 그룹 분할 오류, 학습·Serving 간 전처리 불일치, 불완전한 재현성, 잘못된 평가 상태, 텐서 Shape 오류, 안전하지 않은 모델 Artifact 때문에 실제 배포 성능이 무너질 수 있다. 전체 행에 먼저 Fitting한 SelectKBest는 순수 무작위 데이터에서도 검증 정확도 0.83을 만들었지만, 각 Fold 안에서 변환을 학습하면 0.49로 내려갔다. 사용자 단위로 묶어야 하는 데이터에 무작위 분할을 적용하면 점수가 0.97에서 0.89로 떨어졌고, [batch, 1]과 [batch]를 MSELoss에 넘기면 32×32 브로드캐스팅이 발생해 오류 없이 다른 손실값을 산출했다. 해결책은 각 경계에서 학습에 사용된 행, 전처리 파라미터, 모델 상태, Tensor Shape, Artifact를 명시적으로 기록하고 검증하는 것이며, Pickle 계열 파일은 신뢰할 수 있는 출처와 실제 Serving 환경에서만 로드해야 한다.

섹션별 상세

01
전처리 변환을 데이터 분할 전에 전체 행으로 학습하면 검증 데이터의 정보가 Feature에 미리 반영된다. 순수 무작위 값 100개와 1,000개 Feature에 대해 전체 행에서 SelectKBest로 20개 Feature를 고른 뒤 교차 검증하면 정확도 0.83이 나오지만, 각 Fold 안에서 변환을 Fitting하면 0.49로 내려간다. Scaling, Imputation, 차원 축소도 같은 누수 구조를 가지므로 Workflow의 모든 fit과 fit_transform에서 당시 보인 행을 확인해야 정직한 평가가 가능하다.
python
sel = SelectKBest(f_classif, k=20).fit(X, y) # fit on ALL rows
scores = cross_val_score(model, sel.transform(X), y, cv=5)

전체 데이터에 먼저 Feature Selection을 적용한 뒤 교차 검증을 수행해 검증 행의 정보가 전처리에 유입되는 코드다.

02
서로 연관된 행을 무작위로 학습·검증에 흩어 놓으면 새 사용자나 환자에 대한 일반화가 아니라 기존 개체 식별 능력을 측정하게 된다. 60명의 사용자와 사용자별 유사 행으로 만든 데이터에서 train_test_split 점수는 0.97이었지만, GroupShuffleSplit으로 사용자를 한쪽에만 배치하자 0.89로 낮아졌다. 개체가 경계라면 GroupKFold 또는 GroupShuffleSplit을, 시간이 경계라면 미래 행이 과거 예측에 들어가지 않는 TimeSeriesSplit을 선택해야 한다.
03
학습 Notebook과 Serving 함수가 같은 듯한 전처리를 별도로 구현하면 학습된 파라미터, Feature 순서, dtype, 결측값 규칙이 어긋날 수 있다. Serving 배치 다섯 행에서 Scaler를 다시 학습하면 동일한 Fixture가 최대 3.95 표준 단위만큼 이동하므로 예측 결과가 크게 달라진다. Fitted Pipeline 객체를 모델과 함께 전달하고 하나의 Raw Fixture를 양쪽 경로에 통과시켜 이름, 순서, dtype, Shape, 값이 모두 같은지 검사해야 한다.
학습 데이터가 Fitted Transform과 Model을 거쳐 Pipeline과 함께 Artifact로 저장되고, Serving에서는 동일한 Transform을 사용해 Prediction을 생성하는 구조도다.
Diagram도표의 위쪽 학습 경로는 Raw Training Data에서 학습된 파라미터와 Schema를 가진 Fitted Transform, Model, Artifact로 이어진다. 아래쪽 Serving 경로는 Artifact에서 불러온 동일한 Fitted Transform을 Raw Request에 적용하지만, Hand-rebuilt Features를 사용하면 파라미터·순서·dtype 차이로 Train/Serve Skew가 발생한다는 점을 나타낸다.
04
하나의 Seed만 설정하면 Python random, NumPy, PyTorch, DataLoader Worker가 사용하는 난수 생성기가 모두 고정된다는 보장이 없다. 완전한 결정적 Kernel은 별도로 요청해야 하며 성능 비용이 생길 수 있고, PyTorch Release·플랫폼·CPU와 GPU 실행 간 동일한 결과도 보장되지 않는다. Seeds뿐 아니라 Data Snapshot, Code Version, Configuration, Dependency Version을 함께 기록해야 같은 실행 환경을 재구성할 수 있다.
05
model.eval()과 torch.no_grad()는 함께 쓰이는 경우가 많지만 서로 다른 경계를 제어한다. eval()은 Dropout과 Batch Normalization을 추론 동작으로 바꾸고 no_grad()는 Autograd 기록만 멈추므로, 학습 상태에서 no_grad()만 쓰면 같은 입력에도 Dropout 때문에 -0.1410과 0.0071처럼 다른 출력이 나올 수 있다. 검증에서는 두 호출을 함께 적용하고 이후 model.train()으로 복귀해야 하며, Gradient가 전혀 필요 없을 때는 torch.inference_mode()도 사용할 수 있다.
python
model.eval()
with torch.no_grad():
    val_loss = criterion(model(x_val), y_val)
model.train()

검증 중 Dropout과 Batch Normalization을 평가 상태로 전환하고 Gradient 기록을 끈 뒤, 검증이 끝나면 학습 상태로 되돌리는 코드다.

06
Tensor Shape의 암묵적 Broadcasting은 손실 함수에서 예외 대신 그럴듯한 오답을 만들 수 있다. 예측값이 [batch, 1]이고 정답이 [batch]인 상태로 MSELoss를 호출하면 Batch 32에서 32×32 비교 행렬이 만들어져 손실 1.63이 계산되지만, Shape를 맞춘 같은 Tensor의 손실은 1.85였다. model(x).squeeze(1)로 의도를 명시한 뒤 pred.shape == target.shape를 Assertion으로 검사하고, PyTorch UserWarning도 테스트에서 오류로 승격해야 한다.
python
pred = model(x).squeeze(1) # [batch, 1] -> [batch], on purpose
assert pred.shape == target.shape
loss = criterion(pred, target)

모델 출력의 불필요한 차원을 의도적으로 제거하고 손실 계산 전에 예측값과 정답의 Shape 계약을 검사하는 코드다.

07
Pickle, joblib, cloudpickle로 저장한 모델은 단순한 데이터 파일이 아니며 로드 과정에서 임의 코드가 실행될 수 있다. 악성 __reduce__ 메서드를 포함한 파일은 pickle.load 중 예외 없이 Payload를 실행할 수 있고, scikit-learn은 다른 Library Version에서 저장한 모델 로드를 지원하지 않는다. 검증된 출처의 Artifact만 사용하고 Training Recipe, Data Reference, Dependency Version, 검증 점수를 함께 보관한 뒤 실제 Serving 환경에서 고정 Fixture를 전체 전처리·예측 경로에 통과시켜야 한다.

용어 해설

데이터 누수(Data Leakage)
평가용 데이터의 정보가 학습이나 전처리 과정에 미리 유입되는 현상이다. 예를 들어 데이터 분할 전에 전체 행으로 Feature Selection을 학습하면 검증 데이터의 통계가 변환에 반영된다. 그 결과 실제 일반화 성능보다 높은 점수가 산출되므로, 전처리 단계마다 어떤 행을 볼 수 있었는지 확인해야 한다.
데이터 편향(Data Skew)
학습 시점과 추론 시점에 서로 다른 전처리 규칙이나 파라미터가 적용되는 문제다. Serving 코드가 학습된 Scaler를 재사용하지 않고 요청 배치에서 새로 통계를 계산하면 같은 입력도 다른 Feature로 변환된다. Feature 순서, dtype, 결측값 처리까지 학습 경로와 일치해야 예측 결과를 신뢰할 수 있다.
그룹 인식 데이터 분할(Group-Aware Splitting)
같은 사용자나 환자처럼 서로 연관된 행을 하나의 그룹으로 묶어 학습과 검증에 나누는 방식이다. GroupShuffleSplit이나 GroupKFold는 동일 그룹의 행이 양쪽에 흩어지는 것을 막아 새로운 개체에 대한 일반화 성능을 측정한다. 시간 순서가 경계라면 미래 데이터가 과거 예측에 섞이지 않도록 TimeSeriesSplit을 사용해야 한다.
평가 모드(Evaluation Mode)
모델을 추론에 맞는 동작 상태로 전환하는 PyTorch 실행 모드다. model.eval()은 Dropout과 Batch Normalization처럼 학습과 평가에서 동작이 달라지는 모듈을 바꾸지만, Gradient 기록 자체를 끄지는 않는다. 따라서 검증 루프에서는 torch.no_grad() 또는 torch.inference_mode()와 함께 사용하고 이후 model.train()으로 복귀해야 한다.
텐서 브로드캐스팅(Broadcasting)
서로 다른 Shape의 배열이나 텐서에 연산을 적용할 때 차원을 자동으로 확장하는 규칙이다. 예측값이 [batch, 1]이고 정답이 [batch]이면 MSELoss가 오류 없이 [batch, batch] 계산을 수행해 잘못된 손실값을 만들 수 있다. 손실 함수 경계에서 pred.shape와 target.shape를 직접 비교하면 암묵적 확장을 차단할 수 있다.

기술

  • Python
  • SelectKBest
  • scikit-learn
  • GroupKFold
  • GroupShuffleSplit
  • TimeSeriesSplit
  • PyTorch
  • DataLoader
  • Weights & Biases
  • MSELoss
  • pickle
  • joblib
  • cloudpickle

활용 사례

  • AI 모델 학습·검증 파이프라인
  • 사용자·환자·디바이스 단위 예측
  • 시간 순서가 있는 시계열 예측
  • 모델 Serving 및 Artifact 배포
AI 분석 전체 내용 보기

AI 요약 · 북마크 · 개인 피드 설정 — 무료

출처 · 인용 안내

원문 발행 2026. 09. 01.수집 2026. 09. 01.출처 타입 RSS

인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.