본문으로 건너뛰기

08. 모델 학습과 검증 I

✎ 이 문서 수정하기 GitHub에서 수정

8장은 7장에서 나눈 신분증 이미지와 YOLO 라벨로 모델을 학습하고 검증한다. 노트북에서는 model.train() 한 줄이던 일이 파이프라인에서는 컨테이너 이미지, 아티팩트 경로, 지표 기록으로 나뉜다. 이 장을 읽으며 붙잡은 문제는 두 가지다. 학습을 언제든 다시 돌릴 수 있게 하려면 무엇을 고정해야 하는지, 그리고 초록색으로 끝난 검증 작업이 무엇까지 증명하는지다.

학습 컴포넌트는 입력 계약을 드러낸다

노트북에서 학습하면 데이터 경로, 패키지 버전, 하이퍼파라미터, 결과 폴더가 모두 그 PC의 상태에 기댄다. 학습을 KFP 컴포넌트로 옮기면 이것들이 밖으로 드러난다. 책의 학습 컴포넌트는 train, validation, test 세 Dataset을 받아 가중치(Model)와 data.yaml(Artifact)을 낸다. 검증을 따로 떼어 둔 것은 학습은 무겁고, 검증은 기준이 바뀔 때마다 다시 돌려야 하기 때문이다. 컴포넌트 경계는 변경과 실패의 단위에 맞춰 긋는다.

YOLO는 데이터 위치를 data.yaml 하나로 받고, 라벨은 이미지 경로의 images를 labels로 바꾼 자리에서 같은 파일 이름으로 찾는다. 이미지와 라벨의 짝은 파일 이름으로만 이어진다. 그런데 저자의 분할 코드는 이미지 목록과 라벨 목록을 따로 만든 뒤 위치로 짝지어 나눈다. 실습에서 저자 방식대로 짝지어 보니 192쌍 중 191쌍의 이름이 달랐다. YOLO는 이 상태로도 오류 없이 남의 라벨을 학습한다.

모델 크기, epoch, batch, 입력 해상도는 품질만 바꾸지 않고 학습 시간, 메모리, 서빙 지연을 함께 움직인다. 책은 가장 작은 YOLOv8n으로 시작해 부족하면 같은 파이프라인에서 크기만 바꿔 다시 돌린다. optimizer='auto'는 반복 수를 보고 최적화기를 스스로 골라 지정한 lr0와 momentum을 무시하므로, 학습률을 실험 변수로 삼으려면 최적화기를 명시해야 한다. 해상도를 서비스와 다르게 학습했다면 그 값도 서빙 조건과 함께 기록해 둔다.

실행 환경은 컨테이너 이미지로 고정한다

@dsl.component의 packages_to_install은 Pod가 시작할 때 pip install을 돌리는 데서 그친다. OpenCV가 요구하는 libGL.so.1 같은 운영체제 라이브러리는 설치하지 못한다. 책은 @dsl.container_component로 이미지와 명령을 직접 정하고, bash -c 안에서 apt-get과 pip install을 실행한 뒤 학습 스크립트를 돌린다. KFP 입력은 bash의 위치 인자로 들어가므로 인자 목록의 순서와 스크립트의 $0, $1 번호가 정확히 맞아야 한다.

이 방식은 Dockerfile 없이 끝나지만, 실행 환경이 그날의 패키지 저장소 상태를 따라간다. 책의 학습 코드는 지금 그대로 돌지 않았다. 기반 이미지가 Debian trixie로 바뀌어 libgl1-mesa-glx가 사라졌고, 버전을 고정하지 않은 torch는 CUDA용 대용량 휠을 받았으며, 최신 NumPy는 Ultralytics의 np.trapz 호출을 깨뜨렸다. 책의 검증 컴포넌트처럼 의존성을 담은 고정 이미지가 재현에 유리하고, 학습과 검증은 같은 라이브러리 버전으로 맞추는 것이 원칙이다.

산출물도 의도해서 남겨야 한다. 저자 코드는 best.pt 하나만 출력 아티팩트로 복사하고 학습 폴더는 아티팩트 경로 밖에 만든다. 혼동 행렬, PR 곡선, results.csv, 예측 샘플은 Pod와 함께 사라진다. 나중에 볼 파일은 출력 아티팩트 경로에 써야 한다.

검증 지표는 모델을 고른 데이터로 다시 잰 값이다

검증 컴포넌트는 best.pt를 다른 Pod에서 다시 읽어 model.val()로 mAP를 계산하고 KFP Metrics에 남긴다. 저장한 가중치가 다시 읽힌다는 것, 지표가 실행 기록에 붙어 다른 실행과 비교된다는 것이 여기서 확인된다. map50은 예측 상자와 정답 상자의 IoU가 0.5 이상이면 맞은 것으로 칠 때의 AP이고, map50-95는 기준을 0.5부터 0.95까지 올리며 구한 AP의 평균이다. map50이 높고 map50-95가 낮으면 카드는 찾지만 경계가 덜 정확하다. AP는 정밀도-재현율 곡선 아래 넓이라 특정 신뢰도 임계값에서의 동작은 알려 주지 않는다.

저자 코드의 검증은 학습 중 best.pt를 고르는 데 이미 쓴 validation 분할을 다시 평가한다. 실습에서 학습 로그 마지막 줄과 검증 컴포넌트의 수치가 0.995 / 0.919로 똑같았던 이유다. test 분할은 data.yaml에 적혀 있을 뿐 평가되지 않는다. 출시 판단에 쓸 수치는 선택에 쓰지 않은 분할에서 한 번 계산해야 한다. test 점수를 보고 설정을 다시 만지기 시작하면 test도 낙관적인 점수가 된다.

seed가 막지 못하는 누수

random_state=42는 같은 목록을 늘 같은 방식으로 나누게 해 줄 뿐, 그 분할이 평가하려는 상황을 닮았는지는 보장하지 않는다. MIDV-500 같은 신분증 데이터는 영상에서 뽑은 프레임이라 인접 프레임이 거의 같다. 프레임 단위로 무작위로 나누면 같은 카드, 같은 배경이 train과 validation에 함께 들어가고, 모델은 처음 보는 카드를 찾는 능력 대신 본 장면을 기억해서 점수를 얻는다.

실습의 합성 데이터에서도 validation의 18개 clip이 모두 train에 들어 있었다. clip 단위로 다시 나눠 학습해도 점수가 같았지만, 데이터가 너무 쉬웠기 때문이지 누수가 무해하다는 근거는 되지 못한다. 시간 순서가 있는 데이터라면 과거로 학습하고 미래로 평가하는 분할도 필요하다. 재현성도 같은 절차면 충분한지, 통계적으로 비슷하면 되는지, 비트 단위로 같아야 하는지 수준을 따로 정해 둔다.

실행 성공, 모델 품질, 출시 결정은 다른 상태다

실습의 KFP 실행은 네 작업 모두 성공했고 map50은 0.995였다. 같은 가중치가 강한 흐림, 작게 찍힌 카드, 어두운 조명에서는 카드를 하나도 찾지 못했다. 수치가 틀린 것은 아니고, 그 조건이 평가 분할에 없었다.

상태성공 조건
학습 실행프로세스가 정상 종료하고 가중치, 설정, 로그가 저장됨
모델 검증선택에 쓰지 않은 데이터로 평가하고, 깨끗한 환경에서 가중치를 다시 읽고, 주요 실패 유형의 샘플을 확인함
출시 결정기준선과 같은 평가셋에서 비교하고, 중요한 세부 조건에서 나빠지지 않았으며, 승인한 사람과 대상 버전이 기록됨

책이 말하는 “trust, but verify"의 수동 검토는 잘 된 사례를 다시 보는 일이 아니다. 학습에 쓰지 않은 이미지에 흐림, 회전, 작은 대상, 카드 없는 사진을 섞어 지표가 놓친 실패를 찾는 일이다. 찾은 실패는 다음 학습 데이터와 세부 집단 평가, 출시 게이트로 옮겨야 다음 검토가 사람의 기억에 기대지 않는다. 신뢰도 임계값을 정해 그 값에서의 오탐과 미탐을 세고, 누가 어떤 표본으로 보류했는지를 모델 버전 옆에 남긴다. 평가셋이 28장이라면 0.995와 0.990의 차이는 이미지 한두 장일 수 있으니 표본 수도 함께 적는다.

책 본문과 저자 코드의 차이

8장 코드는 practical-mlops/object-detection-project의 training_and_validation_pipeline.py(커밋 c6afb11)다. 이해를 바꾸는 차이만 적는다.

  • 책의 데이터 주소는 더 이상 열리지 않아 개인 정보가 없는 합성 신분증 데이터로 대신했다.
  • 이미지와 라벨을 위치로 짝지어 대부분의 쌍이 어긋난다. 파일 이름으로 짝지은 뒤 분할하도록 고쳤다.
  • 버전 없이 설치하는 시스템 패키지와 Python 패키지가 지금은 설치되지 않거나 오류를 낸다. 패키지 이름과 버전을 고정했다.
  • 책은 학습 폴더 전체를 내려받는다고 설명하지만 코드는 best.pt만 남긴다.
  • 검증은 모델 선택에 쓴 validation을 다시 평가하고 test는 쓰지 않는다.

실습

책 코드로 직접 실행한 순서와 결과 화면은 8장 실습 기록에 따로 모았다.

정리

학습을 컴포넌트로 옮기는 일은 데이터의 짝, 경로 규칙, 패키지 버전, 산출물 위치를 정하는 일이었다. 검증 작업의 초록색 체크는 가중치를 다시 읽고 정해진 분할에서 지표를 계산했다는 데까지만 말해 준다. 9장은 PVC와 TensorBoard, MLflow로 데이터 전달과 실험 기록을 넓히고, 어떤 모델 버전을 넘길지 정하는 근거를 남긴다.

이전: 07. 데이터 분석과 준비, 시리즈 목차, 다음: 09. 학습과 검증 II

마지막 수정 일자