머신러닝에서 Test Code를 구현해보자¶
- 출처: velog - 고군분투 모델 개발에서 깨닫기 (1)
- 저자: 이영락 (AI Engineer / 의료인공지능)
- 읽은 날짜: 2025-12-23
- 태그: #MLOps #Testing #pytest #CI/CD
핵심 내용¶
PyTorch 기반 딥러닝 프로젝트에서 테스트 코드 구현의 중요성과 실제 방법론을 다룬 글이다. 전통적 소프트웨어 테스트를 머신러닝 시스템에 적용하는 방법을 5가지 테스트 유형으로 나누어 설명한다.
테스트의 필요성¶
- 시스템 신뢰성 확보 및 예상치 못한 오류 방지
- 결정론적 코드 테스트와 비결정론적 모델 특성 동시 고려
- 개발 초기 테스트 적용으로 유지보수 비용 절감
다섯 가지 테스트 유형¶
| 테스트 유형 | 목적 | 대상 |
|---|---|---|
| Unit Test | 함수/클래스 단위 독립 검증 | 데이터 전처리, 손실함수, 지표 계산 |
| Integration Test | 여러 유닛 결합 시 전체 시스템 작동 확인 | 데이터 로더 + 모델, 학습 루프 |
| Regression Test | 코드 변경 후 기존 기능 정상 작동 확인 | 모델 출력, 손실함수, 데이터 파이프라인 |
| Performance Test | 시간/메모리 사용량 기대 범위 확인 | 데이터 로딩, 추론/학습 속도 |
| Behavioral Test | 입력 변화에 따른 모델 출력 의도대로 작동 검증 | NLP, CV 모델 등 |
코드 예시¶
1. Unit Test - Forward Pass 검증¶
import torch
from model import MyModel
def test_forward_pass():
model = MyModel()
input_tensor = torch.rand(1, 3, 224, 224)
output = model(input_tensor)
assert output.shape == (1, 10) # 10개 클래스
2. Integration Test - 학습 스텝 검증¶
from torch.utils.data import DataLoader
from dataset import MyDataset
from model import MyModel
from engine import train_step
def test_training_step():
dataset = MyDataset()
dataloader = DataLoader(dataset, batch_size=32)
model = MyModel()
for batch in dataloader:
loss = train_step(model, batch)
assert loss > 0
break
3. Performance Test - 추론 속도 검증¶
import time
from model import MyModel
def test_model_inference_speed():
model = MyModel()
input_tensor = torch.rand(1, 3, 224, 224)
start_time = time.time()
for _ in range(100):
_ = model(input_tensor)
avg_time = (time.time() - start_time) / 100
assert avg_time < 0.1 # 0.1초 미만
4. 파라미터화된 테스트 (다양한 입력 조건)¶
import pytest
@pytest.mark.parametrize("input_dim, output_dim", [
(32, 10),
(64, 20)
])
def test_model_output(input_dim, output_dim):
model = MyModel(input_dim, output_dim)
input_tensor = torch.rand(1, input_dim)
output = model(input_tensor)
assert output.shape == (1, output_dim)
5. Pytest Fixture - 공통 구성요소 재사용¶
import pytest
from dataset import MyDataset
@pytest.fixture
def dataset():
return MyDataset()
def test_dataset_loading(dataset):
assert len(dataset) > 0
6. GitHub Actions CI/CD 파이프라인¶
name: ML System Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Install dependencies
run: pip install -r requirements.txt
- name: Run Tests
run: pytest tests/ --cov=project --cov-report=xml
인상 깊은 부분¶
머신러닝 시스템에서는 결정론적인 코드 테스트와 비결정론적인 모델 특성을 동시에 고려해야 한다.
기존 소프트웨어 테스트와 ML 테스트의 근본적 차이점을 명확히 짚어준 부분. 모델의 비결정론적 특성(랜덤 시드, 학습 과정 변동 등) 때문에 테스트 설계가 더 어렵다.
실무 적용 포인트¶
즉시 적용 가능한 것¶
- Unit Test 우선 도입: 데이터 전처리, 손실함수 계산 등 결정론적인 부분부터 테스트 작성
- Shape 검증 테스트: 모델 forward pass에서 입출력 shape 검증은 간단하면서도 효과적
- Performance Test: 추론 속도 테스트로 성능 회귀 방지
이 저장소에 적용¶
현재 deep_learning/pytorch_impl/tests/에 TDD 방식으로 테스트를 작성 중인데, 이 글에서 소개한 5가지 테스트 유형을 참고하여 테스트 커버리지를 확장할 수 있겠다.
고려할 점¶
- Behavioral Test는 NLP 모델에서 특히 중요 (예: "not"을 추가했을 때 감성 분석 결과가 반대로 바뀌는지)
- CI/CD에서 GPU 테스트는 비용 문제로 별도 고려 필요
- 비결정론적 테스트는 tolerance 설정이 핵심 (
torch.allclose활용)
참고자료¶
- Made With ML - Testing Machine Learning Systems
- pytest 공식 문서
- Great Expectations (데이터 품질 테스트)