본문 바로가기
C.W.K.
Stream
Lesson 09 of 09 · published

학습 루프

~25 min · training-loop, epochs, validation

Level 0호기심
0 XP0/73 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

기본 구조

모든 PyTorch 학습 루프는 기본 구조가 같아. 에폭마다 학습 데이터 로더를 순회하면서 손실을 계산하고, 역전파를 수행한 뒤 옵티마이저를 업데이트해. 일정한 주기마다, 보통 에폭마다 또는 N단계마다 model.eval()로 전환해 검증 세트에서 평가하고 가장 좋은 체크포인트를 저장해. 검증 지표가 더 이상 좋아지지 않을 때까지 이 과정을 반복하면 돼.

이 구조는 어디서나 통하므로 한 번 직접 작성한 뒤 재사용할 수 있어. PyTorch Lightning, Hugging Face Trainer, Accelerate 같은 상위 수준 프레임워크에 맡기는 방법도 있고. 둘 다 합리적인 선택이야. 직접 작성하는 편이 학습에는 더 좋고, 프레임워크를 사용하는 편이 운영에는 더 좋아.

팁: 프레임워크를 도입하기 전에 적어도 한 번은 학습 루프를 직접 작성해 봐. 프레임워크는 타이핑을 줄여 주지만, 문제가 생겼을 때 디버깅에 필요한 단계까지 숨기거든.

초보자의 학습 루프에서 자주 생기는 문제

  • opt.zero_grad()를 잊음 — 이전 단계의 기울기가 계속 누적돼.
  • 검증할 때 model.eval()을 잊음 — 드롭아웃과 배치 정규화가 잘못 동작해 지표가 불안정해져.
  • GPU에서 손실을 계산한 뒤 .item() 없이 CPU에서 출력하거나 기록함 — 눈에 보이지 않는 CUDA 동기화가 곳곳에서 발생해.
  • 확률의 argmax와 로짓의 argmax를 일관성 없이 사용해 정확도를 계산함 — 우연히 같은 결과가 나오지만 소프트맥스가 달라지면 깨져.
  • 검증 성능이 가장 좋았던 단계가 아니라 학습이 끝난 시점의 모델 상태 사전을 저장함 — 잘못된 모델을 배포하게 돼.

반드시 추가할 요소

제대로 쓰는 학습 루프에는 기울기 클리핑과 학습률 스케줄링, GPU 혼합 정밀도 학습(autocast + GradScaler)이 더 필요해. 주기적인 체크포인트 저장과 별도 세트를 이용한 검증, 모니터링 도구에서 읽을 수 있는 기록도 갖춰야 해. 이어지는 트랙에서는 이 요소들을 하나씩 기계적으로 적용할 수 있게 만들어 줄 거야.

원칙: 진행 상황을 잃지 않고 학습을 중단했다가 다시 시작할 수 있기 전까지 학습 루프는 완성된 게 아니야. 저장하는 모든 체크포인트에는 모델, 옵티마이저, 스케줄러, 스케일러, 단계 번호가 들어 있어야 해.

Code

최소 구성의 정직한 학습 루프·python
import torch
from torch import nn, optim

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

model = MyModel().to(device)
opt   = optim.AdamW(model.parameters(), lr=3e-4)
sch   = warmup_cosine(opt, warmup_steps=200, total_steps=5_000)
loss_fn = nn.CrossEntropyLoss()

best_val_acc = 0.0
step = 0

for epoch in range(10):
    model.train()
    for xb, yb in train_loader:
        xb, yb = xb.to(device), yb.to(device)
        opt.zero_grad()
        logits = model(xb)
        loss = loss_fn(logits, yb)
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
        opt.step(); sch.step()
        step += 1

    model.eval()
    correct, total = 0, 0
    with torch.inference_mode():
        for xb, yb in val_loader:
            xb, yb = xb.to(device), yb.to(device)
            preds = model(xb).argmax(dim=-1)
            correct += (preds == yb).sum().item()
            total   += yb.size(0)
    val_acc = correct / total
    print(f"epoch {epoch} step {step} val_acc={val_acc:.4f}")

    if val_acc > best_val_acc:
        best_val_acc = val_acc
        torch.save({
            "model": model.state_dict(),
            "optimizer": opt.state_dict(),
            "scheduler": sch.state_dict(),
            "step": step, "val_acc": val_acc,
        }, "best.pt")

External links

Exercise

MNIST용 3층 MLP에 완전한 학습 루프를 작성해. 기울기 클리핑, 학습률 스케줄링, 검증, 최적 체크포인트 저장을 포함해야 해. 실제로 실행한 뒤 저장된 체크포인트를 다시 불러와 검증 정확도가 재현되는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.