반려동물 품종 분류기 만들기 (2) 개발환경 세팅
uv로 프로젝트를 만들고 PyTorch와 torchvision을 설치합니다. CUDA, MPS, CPU를 자동으로 고르는 device 선택 함수와 seed 고정, 실험 기록 방식까지 학습 전에 필요한 기반을 정리했습니다.
프로젝트 구조
코드는 노트북이 아니라 스크립트로 관리합니다. 실험을 반복하면서 셀 실행 순서에 따라 결과가 달라지는 문제를 피하기 위해서입니다. 구조는 다음과 같습니다.
1
2
3
4
5
6
7
8
9
10
pet-classifier/
├── pyproject.toml
├── data/ # 다운로드된 데이터 (git 제외)
├── outputs/ # 체크포인트, 실험 기록 (git 제외)
└── src/
├── config.py # 하이퍼파라미터와 경로
├── data.py # Dataset, DataLoader, transform
├── models.py # SmallCNN, ResNet 로더
├── train.py # 학습 루프
└── evaluate.py # 평가와 오류 분석
uv로 환경 만들기
패키지 관리는 uv를 사용합니다. 설치와 프로젝트 생성은 세 줄입니다.
1
2
3
uv init pet-classifier --python 3.12
cd pet-classifier
uv add torch torchvision matplotlib scikit-learn
uv add가 pyproject.toml에 의존성을 기록하고 lock 파일을 만들기 때문에, 다른 머신에서도 uv sync 한 번으로 같은 환경이 복원됩니다. Colab에서 돌릴 때는 torch와 torchvision이 이미 설치되어 있으므로 저장소를 clone한 뒤 나머지만 설치합니다.
Device 선택
이 프로젝트는 세 가지 환경에서 돌아가야 합니다. Colab의 CUDA GPU, 로컬 Mac의 MPS, 그리고 둘 다 없을 때의 CPU입니다. 학습 코드가 환경을 신경 쓰지 않도록 선택 함수를 하나 둡니다.
1
2
3
4
5
6
7
8
import torch
def get_device() -> torch.device:
if torch.cuda.is_available():
return torch.device("cuda")
if torch.backends.mps.is_available():
return torch.device("mps")
return torch.device("cpu")
PyTorch 기초 5편에서 정리한 대로, 모델과 데이터를 같은 device로 옮기는 것만 지키면 나머지 코드는 세 환경에서 동일하게 동작합니다. MPS에서 일부 연산이 미구현이라는 에러가 나면 PYTORCH_ENABLE_MPS_FALLBACK=1 환경변수로 해당 연산만 CPU로 넘길 수 있습니다.
재현성: seed 고정
같은 코드로 두 번 돌렸을 때 결과가 다르면 하이퍼파라미터를 바꾼 효과인지 우연인지 구분할 수 없습니다. 실험 시작 시점에 seed를 한 번에 고정합니다.
1
2
3
4
5
6
7
8
9
import random
import numpy as np
import torch
def set_seed(seed: int = 42) -> None:
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
DataLoader의 augmentation 순서까지 완전히 같아지지는 않지만, 모델 초기화와 데이터 분할이 고정되는 것만으로도 실험 간 비교에는 충분합니다. 완전한 결정성이 필요하면 torch.use_deterministic_algorithms(True)를 추가로 켭니다. 이때, 속도는 느려집니다.
실험 기록
이 프로젝트는 실험 횟수가 많지 않아서 MLflow 같은 도구 대신 JSON 파일로 기록합니다. 학습이 끝날 때마다 config와 지표를 함께 저장합니다.
1
2
3
4
5
6
7
8
import json
from pathlib import Path
def save_run(name: str, config: dict, metrics: dict) -> None:
out = Path("outputs") / name
out.mkdir(parents=True, exist_ok=True)
with open(out / "run.json", "w") as f:
json.dump({"config": config, "metrics": metrics}, f, indent=2)
체크포인트는 같은 폴더에 best.pt로 저장합니다. validation accuracy가 갱신될 때만 덮어쓰는 방식이며, 학습 루프에서의 사용법은 4편에서 다룹니다.
정리
- 코드는 src/ 아래 스크립트로 관리하고, 데이터와 출력물은 git에서 제외합니다
- uv로 의존성을 lock하고, Colab과 로컬 양쪽에서 같은 코드를 돌립니다
- device 선택, seed 고정, 실험 기록 함수를 학습 코드보다 먼저 만들어둡니다
다음 글에서는 데이터를 내려받아 살펴보고 Dataset과 DataLoader를 구성합니다.