Test Data
테스트 데이터는 모든 학습과 튜닝이 끝난 뒤 한 번 평가하는 별도 데이터 분할로, 새로운 데이터에 대한 성능을 추정하는 데 사용됩니다. 데이터 분할, 크기 설정, 주의점, 코드를 다룹니다.
테스트 데이터는 테스트 세트 또는 홀드아웃 세트라고도 하며, 완성된 머신러닝(ML) 모델의 성능을 측정하기 위해 데이터셋에서 따로 떼어 둔 부분입니다. 테스트 데이터는 모델 가중치 학습이나 아키텍처, 하이퍼파라미터, 체크포인트, 신뢰도 임계값 등 개발 과정의 어떤 결정에도 사용하지 않으며, 이러한 결정을 모두 확정한 뒤 한 번 평가합니다. 모델과 개발자가 테스트 데이터에 맞춰 조정한 적이 없으므로, 테스트 데이터에서 측정한 정확도, 재현율, 평균 정밀도(mAP)는 동일한 분포에서 추출한 새 데이터에 대한 모델 성능을 편향 없이 추정합니다. 팀은 이 수치를 바탕으로 모델의 배포 준비 여부를 판단합니다.
학습, 검증, 테스트 분할#
일반적으로 데이터셋은 서로 겹치지 않는 세 부분으로 나뉘며 각각 역할이 다릅니다.
- 학습 데이터: 옵티마이저가 학습에 사용하는 예제로, 손실을 줄이도록 가중치를 조정합니다.
- 검증 데이터: 개발 중 반복해서 평가해 하이퍼파라미터를 비교하고, 학습을 조기에 중단하며, 최적의 체크포인트를 선택합니다.
- 테스트 데이터: 프로젝트 평가 기준이 되는 메트릭을 보고하기 위해 마지막에 한 번 평가합니다.
예제가 수천 개 있는 데이터셋에는 80/10/10 또는 70/15/15 분할이 일반적이며, 예제가 수백만 개라면 몇 퍼센트만 홀드아웃할 수 있습니다. 필요한 테스트 세트 규모는 요구되는 정밀도에 따라 달라집니다. n개의 예제에서 측정한 정확도 p의 표준 오차는 p(1 − p)/n의 제곱근입니다. 따라서 정확도 90%인 테스트 이미지 1,000장의 95% 신뢰 구간은 약 ±1.9%포인트이며, 이미지 10,000장에서는 약 ±0.6%포인트로 좁아집니다. 분야에 따라 용어 사용이 다르며, ImageNet 테스트 라벨은 공개되지 않으므로 많은 논문이 공식 검증 세트에서 최종 ImageNet 결과를 보고합니다. Ultralytics YOLO에서는 데이터셋 YAML에 train 및 val 경로가 필요하며 test 경로는 선택 사항입니다. 학습 중 매 에포크가 끝날 때 val를 평가해 best.pt를 선택하고, model.val(data="data.yaml", split="test")은 검증 모드에서 홀드아웃 이미지로 완성된 모델을 평가합니다.
테스트 세트를 그대로 유지해야 하는 이유#
점수를 보고 내리는 모든 결정은 해당 데이터에 조금씩 맞춰집니다. 검증 세트에서 여러 구성을 비교하면 최종 선택은 특정 예제에서 운 좋게 높은 점수를 얻은 구성일 수도 있으므로, 검증 점수는 다른 데이터에서의 성능을 실제보다 높게 추정합니다. 다음 scikit-learn 실험은 작은 노이즈 데이터셋에서 K-최근접 이웃 분류기의 최적 이웃 수를 선택하고, 무작위 데이터셋 30개에서 선택된 모델의 검증 정확도와 테스트 정확도를 비교합니다.
import numpy as np
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
val_scores, test_scores = [], []
for seed in range(30):
# A small, noisy dataset split 60/20/20 into train, validation, and test
X, y = make_classification(n_samples=400, n_features=20, n_informative=4, flip_y=0.2, random_state=seed)
X_train, X_rest, y_train, y_rest = train_test_split(X, y, test_size=0.4, random_state=seed)
X_val, X_test, y_val, y_test = train_test_split(X_rest, y_rest, test_size=0.5, random_state=seed)
# Model selection: keep the neighbor count with the best validation accuracy
scores = {k: KNeighborsClassifier(k).fit(X_train, y_train).score(X_val, y_val) for k in range(1, 51)}
best_k = max(scores, key=scores.get)
val_scores.append(scores[best_k])
# The test set is scored once, after the choice is final
test_scores.append(KNeighborsClassifier(best_k).fit(X_train, y_train).score(X_test, y_test))
print(f"Chosen model, mean of 30 runs: validation {np.mean(val_scores):.3f}, test {np.mean(test_scores):.3f}")선택된 모델의 평균 점수는 검증 세트에서 0.805, 테스트 세트에서 0.758이므로 후보 50개 중에서 선택하는 과정에서 검증 추정치가 거의 5%포인트 부풀려졌습니다. 테스트 세트에 맞춰 조정하면 이러한 차이가 드러나지 않고 동일한 낙관 편향이 보고 결과에 남는데, 이는 데이터 누출의 한 형태입니다. 공개 벤치마크는 라벨을 공개하지 않는 방식으로 이를 방지합니다. COCO test-dev 결과는 평가 서버에 예측을 제출해 얻습니다. 대규모 언어 모델(LLM)의 경우 웹 규모 사전 학습 데이터에 포함된 테스트 문항이 벤치마크를 오염시킬 수 있습니다. 따라서 LiveCodeBench는 새로운 경연 문제를 계속 추가하고, 각 모델을 학습 종료 시점 이후에 공개된 문제로 평가합니다.
신뢰할 수 있는 테스트 세트 구축#
테스트 세트가 모델이 접할 데이터와 유사한 경우에만 테스트 점수로 실제 성능을 예측할 수 있습니다. 데이터가 자율주행차의 도로 장면이든 의료 영상 분석의 스캔 영상이든 마찬가지입니다.
- 배포 조건 일치: 카메라, 조명, 계절, 지역, 클래스 균형이 프로덕션 환경을 반영해야 합니다. 대부분의 주행이 맑은 날에 이뤄지더라도 주행용 검출기의 테스트 세트에는 야간, 비, 눈 장면이 필요합니다.
- 독립성 유지: 같은 동영상의 프레임, 같은 환자의 스캔, 같은 장면의 사진은 동일한 분할에 포함해야 합니다. 시간 순서가 있는 데이터는 날짜를 기준으로 분할하여 모델이 미래 데이터로 테스트되도록 합니다.
- 여러 출처에서 테스트: 의료 영상에서는 다른 병원과 스캐너 모델에서 얻은 스캔으로 외부 검증을 수행하면 모델이 해부학적 특성을 학습했는지, 특정 병원의 장비 특성을 학습했는지 확인할 수 있습니다.
- 라벨 정제: 테스트 라벨의 오류는 측정 가능한 정확도를 제한하고 모델 순위를 바꿀 수 있으므로 테스트 라벨을 가장 꼼꼼하게 검토해야 합니다.
- 세부 항목별 보고: 클래스별 및 조건별 메트릭을 보고하면 단일 평균 점수에 가려지는 오류를 확인할 수 있습니다.
테스트 세트를 신중하게 다시 구축해도 결과는 달라질 수 있습니다. 연구자들이 원래 수집 과정을 따라 ImageNet 테스트 세트를 재구성했을 때, 다양한 모델의 정확도가 11~14%포인트 하락했습니다. 원래 테스트 세트에서 얻은 성능 향상은 유지되었으며, 저자들은 하락 원인이 수년간 테스트 세트를 재사용한 데 있지 않고 이미지가 약간 더 어려웠기 때문이라고 설명했습니다.










