이미지 로딩 중...
AI Generated
2025. 11. 20. · 2 Views
학습 과정 모니터링 및 체크포인트 관리 완벽 가이드
머신러닝 모델 학습 중 Loss와 학습률을 시각화하고, 실험을 추적하며, Overfitting을 감지하는 방법을 다룹니다. 체크포인트 저장 전략과 최적 모델 선택, 그리고 학습 재개 방법까지 실무에서 바로 활용할 수 있는 모니터링 기법을 친절하게 안내합니다.
목차
- TensorBoard로 Loss/LR 시각화
- Wandb 통합 및 실험 추적
- Overfitting 감지 및 Early Stopping
- 체크포인트 저장 전략 (매 N steps)
- 최적 모델 선택 기준
- 학습 재개 (Resume Training) 방법
1. TensorBoard로 Loss/LR 시각화
시작하며
여러분이 모델을 학습시킬 때 이런 상황을 겪어본 적 있나요? 학습이 3시간째 진행 중인데, Loss가 제대로 줄어들고 있는 건지, 학습률이 적절한지 전혀 알 수 없어서 불안한 마음으로 터미널 로그만 바라보고 있는 상황 말이죠.
이런 문제는 실제 개발 현장에서 자주 발생합니다. 터미널에 출력되는 숫자만으로는 학습이 잘 진행되는지 판단하기 어렵고, 나중에 여러 실험을 비교하려고 해도 로그 파일을 일일이 찾아보는 것은 정말 번거로운 일이죠.
더 큰 문제는 학습이 잘못된 방향으로 가고 있어도 늦게 발견해서 시간과 컴퓨팅 리소스를 낭비하게 된다는 점입니다. 바로 이럴 때 필요한 것이 TensorBoard입니다.
TensorBoard를 사용하면 학습 과정을 실시간으로 그래프로 확인할 수 있어서, Loss가 어떻게 변하는지, 학습률이 적절한지를 한눈에 파악할 수 있습니다.
개요
간단히 말해서, TensorBoard는 텐서플로우와 파이토치에서 제공하는 시각화 도구로, 학습 과정의 모든 지표를 실시간 그래프로 보여주는 대시보드입니다. 왜 이 도구가 필요한지 실무 관점에서 설명하자면, 모델 학습은 보통 몇 시간에서 며칠까지 걸리는 긴 작업입니다.
이 긴 시간 동안 학습이 제대로 진행되고 있는지, 문제가 생긴 건 아닌지를 실시간으로 확인할 수 있어야 합니다. 예를 들어, Loss가 갑자기 폭발하거나(NaN이 되는 경우), 학습률이 너무 높아서 진동하는 경우를 즉시 발견해서 조치를 취할 수 있습니다.
기존에는 print문으로 로그를 찍고 나중에 엑셀이나 matplotlib으로 그래프를 그려야 했다면, 이제는 TensorBoard가 자동으로 아름다운 그래프를 생성해주고 실시간으로 업데이트해줍니다. TensorBoard의 핵심 특징은 첫째, 여러 실험을 동시에 비교할 수 있다는 점, 둘째, 학습률, Loss, 정확도 등 다양한 지표를 동시에 모니터링할 수 있다는 점, 셋째, 웹 브라우저에서 인터랙티브하게 확인할 수 있다는 점입니다.
이러한 특징들이 중요한 이유는 데이터 과학자가 빠르게 문제를 발견하고 실험을 반복할 수 있게 해주기 때문입니다.
코드 예제
from torch.utils.tensorboard import SummaryWriter
import torch
# TensorBoard writer 초기화 - 로그를 저장할 디렉토리 지정
writer = SummaryWriter('runs/experiment_1')
# 학습 루프
for epoch in range(100):
# 가상의 학습 과정
train_loss = train_one_epoch(model, train_loader)
val_loss = validate(model, val_loader)
learning_rate = optimizer.param_groups[0]['lr']
# Loss와 학습률을 TensorBoard에 기록
writer.add_scalar('Loss/train', train_loss, epoch)
writer.add_scalar('Loss/validation', val_loss, epoch)
writer.add_scalar('Learning_Rate', learning_rate, epoch)
# 사용 후 반드시 닫기
writer.close()
설명
이것이 하는 일: 이 코드는 모델 학습 중에 발생하는 중요한 지표들(Loss, 학습률)을 자동으로 기록하고, 나중에 웹 브라우저에서 그래프로 확인할 수 있게 해줍니다. 첫 번째로, SummaryWriter('runs/experiment_1')를 통해 TensorBoard writer 객체를 생성합니다.
여기서 'runs/experiment_1'은 로그 파일이 저장될 디렉토리 경로입니다. 이렇게 실험마다 다른 디렉토리를 지정하면 나중에 여러 실험을 비교할 때 매우 편리합니다.
Writer는 마치 일기장처럼 학습 과정의 모든 기록을 저장하는 역할을 합니다. 그 다음으로, 학습 루프 안에서 매 에포크마다 writer.add_scalar()를 호출합니다.
add_scalar는 "스칼라 값(단일 숫자)을 추가한다"는 뜻으로, 첫 번째 인자는 그래프 이름(예: 'Loss/train'), 두 번째는 값, 세 번째는 x축 값(보통 에포크 번호)입니다. 예를 들어 'Loss/train'과 'Loss/validation'처럼 슬래시(/)로 구분하면 TensorBoard가 자동으로 같은 그룹으로 묶어서 보기 좋게 표시해줍니다.
학습이 끝난 후에는 writer.close()를 호출해서 파일을 제대로 닫아줍니다. 이것은 마치 워드 문서를 저장하고 닫는 것과 같은 원리로, 버퍼에 남아있는 데이터를 모두 디스크에 기록하고 리소스를 정리합니다.
여러분이 이 코드를 사용하면 터미널에서 tensorboard --logdir=runs를 실행한 후 브라우저에서 localhost:6006에 접속하면 아름다운 그래프를 볼 수 있습니다. 실시간으로 그래프가 업데이트되어서 학습이 잘 진행되는지 바로바로 확인할 수 있고, 나중에 여러 실험의 그래프를 겹쳐서 비교할 수도 있어서 어떤 하이퍼파라미터가 더 좋은지 한눈에 판단할 수 있습니다.
실전 팁
💡 실험마다 의미 있는 이름을 디렉토리에 붙이세요. 예를 들어 'runs/lr_0.001_batch_32' 같은 식으로 하이퍼파라미터를 이름에 포함하면 나중에 찾기 쉽습니다.
💡 writer.add_scalar() 외에도 add_histogram()으로 가중치 분포를, add_image()로 중간 결과 이미지를 기록할 수 있습니다. 특히 CNN 모델의 경우 필터 시각화가 매우 유용합니다.
💡 학습 중 실시간으로 확인하려면 터미널을 두 개 띄워서 하나는 학습 스크립트, 다른 하나는 TensorBoard 서버를 실행하세요. 그러면 학습하면서 동시에 그래프를 볼 수 있습니다.
💡 여러 실험을 비교할 때는 tensorboard --logdir_spec=exp1:runs/exp1,exp2:runs/exp2 형식으로 여러 디렉토리를 동시에 로드하면 그래프가 겹쳐서 표시됩니다.
💡 writer.close()를 까먹지 않도록 with 문을 사용하는 것도 좋은 방법입니다. with SummaryWriter('runs/exp1') as writer:처럼 사용하면 자동으로 닫힙니다.
2. Wandb 통합 및 실험 추적
시작하며
여러분이 여러 개의 실험을 동시에 돌리고 있을 때 이런 상황을 겪어본 적 있나요? 어제 돌린 실험의 하이퍼파라미터가 뭐였는지 기억이 안 나고, 로컬 컴퓨터와 서버에 흩어진 실험 결과들을 정리하느라 시간을 낭비하는 상황 말이죠.
이런 문제는 실제 연구 및 개발 현장에서 정말 흔합니다. 특히 팀으로 일할 때는 동료가 어떤 실험을 했는지, 어떤 결과가 나왔는지 공유하기가 어렵습니다.
엑셀 시트나 노션에 수동으로 기록하는 것은 번거롭고, 실수로 잘못 기록하기도 쉽죠. 더 큰 문제는 나중에 논문이나 보고서를 쓸 때 "그때 그 실험이 뭐였더라?" 하면서 찾느라 고생한다는 점입니다.
바로 이럴 때 필요한 것이 Wandb(Weights & Biases)입니다. Wandb는 클라우드 기반 실험 추적 플랫폼으로, 모든 실험을 자동으로 기록하고 팀원들과 쉽게 공유할 수 있게 해줍니다.
개요
간단히 말해서, Wandb는 머신러닝 실험을 자동으로 추적하고 관리해주는 클라우드 서비스로, 코드 한 줄로 모든 하이퍼파라미터, 지표, 모델 체크포인트까지 자동으로 기록하고 시각화해줍니다. 왜 이 도구가 필요한지 실무 관점에서 설명하자면, 데이터 과학자나 ML 엔지니어는 보통 수십에서 수백 개의 실험을 진행합니다.
각 실험마다 다른 하이퍼파라미터, 다른 데이터셋, 다른 모델 아키텍처를 시도하죠. 예를 들어, 학습률을 0.001에서 0.0001로 바꾸고, 배치 크기를 32에서 64로 늘리고, 옵티마이저를 Adam에서 AdamW로 바꾸는 등의 실험을 계속 반복합니다.
이 모든 실험의 결과를 체계적으로 관리하지 않으면 "어떤 조합이 가장 좋았는지" 찾기가 정말 어렵습니다. 기존에는 TensorBoard를 사용해도 로컬에만 저장되어서 다른 컴퓨터에서 접근하기 어려웠고, 하이퍼파라미터를 별도로 기록해야 했다면, 이제는 Wandb가 자동으로 모든 것을 클라우드에 저장하고 어디서든 접근할 수 있게 해줍니다.
Wandb의 핵심 특징은 첫째, 자동으로 시스템 정보(GPU 사용률, 메모리 등)까지 기록한다는 점, 둘째, 실험 간 비교가 매우 쉽다는 점(테이블 뷰, 병렬 좌표계 등 다양한 시각화 제공), 셋째, 팀원들과 실시간으로 공유할 수 있다는 점입니다. 이러한 특징들이 중요한 이유는 연구 생산성을 획기적으로 높여주고, 재현 가능한 실험을 가능하게 하기 때문입니다.
코드 예제
import wandb
from transformers import Trainer, TrainingArguments
# Wandb 프로젝트 초기화 - 자동으로 로그인 및 실험 추적 시작
wandb.init(
project="my-llm-finetuning", # 프로젝트 이름
name="bert-lr-0.001", # 실험 이름
config={ # 하이퍼파라미터 자동 기록
"learning_rate": 0.001,
"batch_size": 32,
"epochs": 10,
"model": "bert-base-uncased"
}
)
# Hugging Face Trainer에 Wandb 자동 통합
training_args = TrainingArguments(
output_dir="./results",
report_to="wandb", # Wandb에 자동 로깅
logging_steps=10,
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
)
# 학습 시작 - 모든 지표가 자동으로 Wandb에 기록됨
trainer.train()
# 추가로 커스텀 지표 기록 가능
wandb.log({"custom_metric": 0.95})
# 실험 종료
wandb.finish()
설명
이것이 하는 일: 이 코드는 머신러닝 실험을 시작할 때 Wandb를 초기화하고, 학습 과정의 모든 정보를 자동으로 클라우드에 기록하며, 나중에 웹 대시보드에서 확인할 수 있게 해줍니다. 첫 번째로, wandb.init()을 호출해서 실험을 시작합니다.
project는 여러 실험을 묶는 폴더 같은 개념이고, name은 개별 실험의 이름입니다. 가장 중요한 것은 config 딕셔너리인데, 여기에 학습률, 배치 크기, 에포크 수, 모델 이름 등 모든 하이퍼파라미터를 넣어주면 Wandb가 자동으로 기록합니다.
나중에 "학습률 0.001일 때 결과가 어땠지?"를 찾을 때 config를 기준으로 필터링할 수 있어서 정말 편리합니다. 그 다음으로, Hugging Face의 Trainer를 사용하는 경우 TrainingArguments에 report_to="wandb"만 추가하면 모든 로깅이 자동으로 Wandb로 전송됩니다.
logging_steps=10은 10 스텝마다 로그를 기록하라는 뜻입니다. 이렇게 설정하면 trainer.train()을 실행하는 동안 Loss, 학습률, 그래디언트 노름 등 모든 지표가 실시간으로 Wandb 클라우드에 업로드됩니다.
학습 중에 추가로 커스텀 지표를 기록하고 싶다면 wandb.log()를 사용합니다. 예를 들어 검증 세트에서 특정 메트릭을 계산했다면 {"custom_metric": 0.95}처럼 딕셔너리 형태로 전달하면 됩니다.
이것도 자동으로 그래프에 추가됩니다. 마지막으로 wandb.finish()를 호출해서 실험을 종료합니다.
이렇게 하면 Wandb가 최종 요약 정보를 저장하고 리소스를 정리합니다. 중요한 점은 스크립트가 중간에 에러로 종료되어도 그때까지의 로그는 모두 클라우드에 저장되어 있다는 것입니다.
여러분이 이 코드를 사용하면 wandb.ai 웹사이트에 로그인해서 모든 실험을 한 곳에서 볼 수 있습니다. 실험 간 비교도 클릭 몇 번으로 가능하고, GPU 사용률이나 메모리 사용량 같은 시스템 메트릭도 자동으로 기록되어서 "왜 이 실험이 느렸는지" 같은 것도 분석할 수 있습니다.
팀원들에게 링크만 공유하면 실시간으로 여러분의 실험을 볼 수 있어서 협업이 정말 쉬워집니다.
실전 팁
💡 무료 플랜으로 시작할 수 있고 개인 프로젝트에는 충분합니다. 회사에서 사용할 때는 팀 플랜을 고려하세요. 민감한 데이터는 self-hosted 옵션도 있습니다.
💡 실험 이름을 지을 때 의미 있는 패턴을 사용하세요. 예를 들어 "bert-lr-{lr}-bs-{batch_size}"처럼 하이퍼파라미터를 포함하면 나중에 찾기 쉽습니다. Wandb가 자동으로 이름을 생성해주기도 하지만 직접 지정하는 게 더 명확합니다.
💡 wandb.watch(model)을 추가하면 모델의 그래디언트와 파라미터 분포를 자동으로 추적합니다. 그래디언트 소실/폭발 문제를 발견하는 데 아주 유용합니다.
💡 Sweep 기능을 사용하면 하이퍼파라미터 서치를 자동화할 수 있습니다. YAML 파일로 서치 공간을 정의하면 Wandb가 베이지안 최적화로 최적 조합을 찾아줍니다.
💡 Artifact 기능으로 데이터셋, 모델 체크포인트, 전처리 스크립트 등을 버전 관리할 수 있습니다. 마치 Git처럼 "이 실험은 데이터셋 v1.2와 모델 v3.1을 사용했다"를 자동으로 추적합니다.
3. Overfitting 감지 및 Early Stopping
시작하며
여러분이 모델을 학습시킬 때 이런 상황을 겪어본 적 있나요? 학습을 밤새 돌려놨는데 아침에 확인해보니 Training Loss는 계속 줄어들었지만 Validation Loss는 오히려 증가해서, 결국 과적합(Overfitting)이 발생해 귀중한 시간과 전기를 낭비한 경우 말이죠.
이런 문제는 실제 머신러닝 프로젝트에서 가장 흔하게 발생하는 문제 중 하나입니다. 과적합은 모델이 훈련 데이터를 너무 열심히 외워버려서 새로운 데이터에는 잘 작동하지 않는 현상입니다.
마치 학생이 시험 문제를 통째로 외워서 똑같은 문제는 풀지만 조금만 변형된 문제는 못 푸는 것과 같습니다. 더 큰 문제는 과적합이 시작된 시점을 놓치면 최적의 모델을 얻을 수 없다는 것입니다.
바로 이럴 때 필요한 것이 Early Stopping입니다. Early Stopping은 검증 세트의 성능이 더 이상 개선되지 않으면 학습을 자동으로 멈추는 기법으로, 과적합을 방지하고 최적의 모델을 보존해줍니다.
개요
간단히 말해서, Early Stopping은 검증 손실(Validation Loss)을 모니터링하면서 일정 기간 동안 개선이 없으면 학습을 자동으로 중단하고, 가장 성능이 좋았던 시점의 모델을 저장하는 기법입니다. 왜 이 기법이 필요한지 실무 관점에서 설명하자면, 모델 학습에는 시간과 비용이 많이 듭니다.
특히 대규모 언어 모델(LLM)이나 이미지 생성 모델을 학습할 때는 GPU를 몇 시간에서 며칠씩 사용하는데, 이때 과적합이 발생하면 낭비되는 리소스가 막대합니다. 예를 들어, 100 에포크 중 30 에포크에서 이미 최적 성능에 도달했는데 모르고 100 에포크까지 돌리면 70 에포크만큼의 시간과 전기료를 낭비하는 셈입니다.
기존에는 개발자가 직접 학습 과정을 지켜보면서 "이제 충분한 것 같다"고 판단해서 수동으로 중단해야 했다면, 이제는 Early Stopping이 자동으로 최적 시점을 찾아서 멈춰줍니다. Early Stopping의 핵심 특징은 첫째, patience 파라미터로 "몇 번까지 참을 것인가"를 설정할 수 있다는 점(예: patience=5면 5 에포크 동안 개선이 없으면 중단), 둘째, delta 파라미터로 "얼마나 개선되어야 의미 있는 개선으로 볼 것인가"를 설정할 수 있다는 점, 셋째, 최적 모델의 가중치를 자동으로 복원한다는 점입니다.
이러한 특징들이 중요한 이유는 과적합을 방지하면서도 최대한의 성능을 끌어낼 수 있게 해주기 때문입니다.
코드 예제
from transformers import TrainerCallback, TrainingArguments, Trainer
import numpy as np
# Early Stopping 콜백 정의
class EarlyStoppingCallback(TrainerCallback):
def __init__(self, patience=3, min_delta=0.001):
# patience: 개선이 없어도 참을 에포크 수
self.patience = patience
# min_delta: 이 값 이상 개선되어야 "개선됨"으로 간주
self.min_delta = min_delta
self.best_loss = float('inf')
self.counter = 0 # 개선 없는 에포크 카운터
def on_evaluate(self, args, state, control, metrics, **kwargs):
# 검증 손실 가져오기
current_loss = metrics.get("eval_loss")
# 의미 있는 개선이 있는지 확인
if current_loss < self.best_loss - self.min_delta:
self.best_loss = current_loss
self.counter = 0 # 카운터 리셋
print(f"✓ 개선됨! 최적 Loss: {self.best_loss:.4f}")
else:
self.counter += 1
print(f"✗ 개선 없음 ({self.counter}/{self.patience})")
# patience 초과 시 학습 중단
if self.counter >= self.patience:
print(f"Early Stopping! {self.patience} 에포크 동안 개선 없음")
control.should_training_stop = True
return control
# Trainer에 Early Stopping 콜백 추가
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
callbacks=[EarlyStoppingCallback(patience=3, min_delta=0.001)]
)
trainer.train()
설명
이것이 하는 일: 이 코드는 학습 중 매 검증 단계마다 성능을 체크하고, 일정 기간 동안 개선이 없으면 자동으로 학습을 중단해서 과적합을 방지하고 시간과 리소스를 절약해줍니다. 첫 번째로, EarlyStoppingCallback 클래스를 정의합니다.
__init__에서 patience(참을성)과 min_delta(최소 개선폭)를 설정합니다. patience=3이면 "3번의 검증 동안 개선이 없으면 포기한다"는 뜻이고, min_delta=0.001이면 "0.001 이상 개선되어야 진짜 개선으로 간주한다"는 뜻입니다.
왜 min_delta가 필요할까요? 손실이 0.0001만큼 줄어드는 것은 노이즈일 수 있기 때문에, 의미 있는 개선만 인정하기 위함입니다.
그 다음으로, on_evaluate 메서드가 핵심입니다. 이 메서드는 Trainer가 검증 세트를 평가할 때마다 자동으로 호출됩니다.
metrics.get("eval_loss")로 현재 검증 손실을 가져와서 이전 최적 손실(self.best_loss)과 비교합니다. 만약 current_loss < self.best_loss - self.min_delta라면, 즉 의미 있는 개선이 있다면 best_loss를 업데이트하고 counter를 0으로 리셋합니다.
개선이 없는 경우에는 counter를 1 증가시킵니다. counter가 patience에 도달하면 control.should_training_stop = True를 설정해서 Trainer에게 "학습을 멈추라"고 신호를 보냅니다.
이 신호를 받은 Trainer는 현재 에포크를 마치고 학습을 종료합니다. 마지막으로, 이 콜백을 Trainer의 callbacks 리스트에 추가하면 자동으로 작동합니다.
실제로 학습을 돌리면 콘솔에 "✓ 개선됨!" 또는 "✗ 개선 없음 (2/3)" 같은 메시지가 출력되어서 현재 상태를 한눈에 파악할 수 있습니다. 여러분이 이 코드를 사용하면 밤새 학습을 돌려놔도 안심할 수 있습니다.
과적합이 시작되는 순간 자동으로 멈추고, 불필요한 GPU 시간을 낭비하지 않습니다. 특히 하이퍼파라미터 서치를 할 때 여러 실험을 동시에 돌리는 경우, Early Stopping이 있으면 각 실험이 필요한 만큼만 돌아가서 전체 실험 시간을 크게 단축할 수 있습니다.
또한 과적합 없이 최적의 일반화 성능을 가진 모델을 얻을 수 있다는 것이 가장 큰 장점입니다.
실전 팁
💡 patience 값은 보통 3~10 사이로 설정합니다. 너무 작으면 잠깐의 정체기에도 멈출 수 있고, 너무 크면 Early Stopping의 의미가 없어집니다. 데이터셋 크기와 모델 복잡도에 따라 조절하세요.
💡 PyTorch Lightning을 사용한다면 built-in EarlyStopping 콜백이 있어서 더 편리합니다. from pytorch_lightning.callbacks import EarlyStopping으로 임포트해서 바로 사용할 수 있습니다.
💡 검증 손실뿐만 아니라 정확도나 F1 스코어 같은 다른 메트릭으로도 Early Stopping을 적용할 수 있습니다. 이 경우 mode='max'로 설정해서 "높을수록 좋은" 지표임을 명시하세요.
💡 Early Stopping과 함께 ModelCheckpoint 콜백을 사용하면 최적 모델을 자동으로 저장할 수 있습니다. 이렇게 하면 학습이 끝난 후 best_model.pt를 로드하면 바로 최적 성능의 모델을 사용할 수 있습니다.
💡 Learning Rate Scheduler와 함께 사용할 때 주의하세요. ReduceLROnPlateau 같은 스케줄러는 patience를 내장하고 있어서, Early Stopping의 patience와 겹치면 의도한 대로 작동하지 않을 수 있습니다. 보통 스케줄러의 patience를 더 작게 설정합니다.
4. 체크포인트 저장 전략 (매 N steps)
시작하며
여러분이 대규모 모델을 며칠째 학습시키고 있을 때 이런 상황을 겪어본 적 있나요? 학습이 90% 완료되었을 때 갑자기 정전이 발생하거나 서버가 다운되어서, 처음부터 다시 학습을 시작해야 하는 악몽 같은 상황 말이죠.
이런 문제는 실제 연구 및 프로덕션 환경에서 생각보다 자주 발생합니다. 클라우드 인스턴스가 예기치 않게 종료될 수도 있고, Out-of-Memory 에러로 프로그램이 죽을 수도 있고, 네트워크 문제로 연결이 끊길 수도 있습니다.
대규모 언어 모델이나 비전 모델을 학습할 때는 며칠에서 몇 주씩 걸리기 때문에, 중간에 문제가 생길 확률이 상당히 높습니다. 만약 체크포인트를 저장하지 않았다면 모든 것을 처음부터 다시 시작해야 합니다.
바로 이럴 때 필요한 것이 주기적인 체크포인트 저장 전략입니다. 매 N 스텝마다 모델의 상태를 디스크에 저장해두면, 문제가 발생해도 마지막 체크포인트부터 재개할 수 있어서 시간과 비용을 크게 절약할 수 있습니다.
개요
간단히 말해서, 체크포인트 저장은 학습 중 일정 간격마다 모델의 가중치, 옵티마이저 상태, 학습 진행 상황 등을 파일로 저장하는 것으로, 나중에 이 파일을 로드해서 중단된 시점부터 학습을 재개할 수 있게 해줍니다. 왜 이 전략이 필요한지 실무 관점에서 설명하자면, 머신러닝 학습은 본질적으로 불안정한 작업입니다.
GPU 메모리 부족, 배치 데이터의 이상치로 인한 NaN 발생, 인프라 문제 등 다양한 이유로 중단될 수 있습니다. 예를 들어, AWS의 Spot Instance를 사용해서 비용을 절약하는 경우, 인스턴스가 언제든지 회수될 수 있기 때문에 체크포인트 저장은 필수입니다.
또한 중간 체크포인트들을 비교하면 학습 과정을 분석하고 문제를 디버깅하는 데도 유용합니다. 기존에는 학습이 끝날 때만 모델을 저장했다면, 이제는 매 N 스텝(또는 에포크)마다 자동으로 저장해서 언제든지 복구할 수 있게 합니다.
체크포인트 저장 전략의 핵심 특징은 첫째, 저장 빈도를 조절할 수 있다는 점(예: 1000 스텝마다, 또는 1 에포크마다), 둘째, 여러 개의 체크포인트를 유지해서 나중에 비교할 수 있다는 점, 셋째, 단순히 모델 가중치뿐만 아니라 옵티마이저 상태, 스케줄러 상태, 현재 에포크/스텝 번호까지 저장한다는 점입니다. 이러한 특징들이 중요한 이유는 학습을 정확히 중단된 시점부터 재개할 수 있게 해주기 때문입니다.
코드 예제
import torch
from transformers import Trainer, TrainingArguments
# 체크포인트 저장 설정
training_args = TrainingArguments(
output_dir="./checkpoints",
# 500 스텝마다 체크포인트 저장
save_steps=500,
# 최대 3개의 체크포인트만 유지 (디스크 절약)
save_total_limit=3,
# 최적 모델도 함께 저장
load_best_model_at_end=True,
# 평가 메트릭 기준으로 최적 모델 선택
metric_for_best_model="eval_loss",
# 검증도 500 스텝마다 실행
eval_steps=500,
evaluation_strategy="steps",
save_strategy="steps",
)
trainer = Trainer(
model=model,
args=training_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
)
# 학습 시작 - 자동으로 체크포인트 저장됨
trainer.train()
# 학습 재개 (중단된 경우)
# 마지막 체크포인트를 자동으로 찾아서 재개
trainer.train(resume_from_checkpoint=True)
# 또는 특정 체크포인트에서 재개
trainer.train(resume_from_checkpoint="./checkpoints/checkpoint-1500")
설명
이것이 하는 일: 이 코드는 학습 중 일정 간격마다 모델의 모든 상태를 디스크에 저장하고, 필요할 때 저장된 체크포인트부터 학습을 재개할 수 있게 해줍니다. 첫 번째로, TrainingArguments에서 체크포인트 관련 설정을 합니다.
save_steps=500은 500 스텝마다 체크포인트를 저장하라는 뜻입니다. 스텝 수는 학습 속도와 디스크 용량을 고려해서 결정해야 합니다.
너무 자주 저장하면 I/O 오버헤드로 학습이 느려지고, 너무 드물게 저장하면 중단 시 손실되는 진행 상황이 많아집니다. 보통 15~30분 간격으로 저장되도록 설정하는 것이 좋습니다.
그 다음으로, save_total_limit=3은 최대 3개의 최근 체크포인트만 유지하라는 뜻입니다. 대규모 모델의 경우 체크포인트 하나가 수 기가바이트에 달할 수 있어서, 모든 체크포인트를 저장하면 디스크가 금방 차버립니다.
save_total_limit을 설정하면 오래된 체크포인트는 자동으로 삭제되고 최신 N개만 유지됩니다. 예를 들어 checkpoint-500, checkpoint-1000, checkpoint-1500이 있을 때 checkpoint-2000이 저장되면 checkpoint-500이 자동으로 삭제됩니다.
load_best_model_at_end=True와 metric_for_best_model="eval_loss"는 함께 사용됩니다. 학습이 끝나면 저장된 모든 체크포인트 중에서 eval_loss가 가장 낮은(최적의) 체크포인트를 자동으로 로드해서 trainer.model에 할당합니다.
이렇게 하면 학습 후 별도로 최적 모델을 찾아서 로드할 필요가 없습니다. 학습을 재개하는 방법은 두 가지입니다.
resume_from_checkpoint=True로 설정하면 output_dir에서 가장 최근 체크포인트를 자동으로 찾아서 재개합니다. 또는 특정 체크포인트 경로를 직접 지정할 수도 있습니다.
재개할 때는 모델 가중치뿐만 아니라 옵티마이저 상태, 학습률 스케줄러 상태, 현재 에포크/스텝 번호까지 모두 복원되어서, 마치 중단된 적이 없는 것처럼 정확히 이어서 학습됩니다. 여러분이 이 코드를 사용하면 AWS Spot Instance 같은 저렴하지만 불안정한 인프라도 안심하고 사용할 수 있습니다.
인스턴스가 회수되어도 마지막 체크포인트부터 재개하면 되니까요. 또한 실험 중 하이퍼파라미터를 바꾸고 싶을 때, 처음부터 다시 학습하는 대신 중간 체크포인트부터 fine-tuning을 시작할 수도 있습니다.
디스크 공간과 학습 안정성 사이의 균형을 save_steps와 save_total_limit로 조절하면서 여러분의 환경에 맞는 최적의 전략을 찾을 수 있습니다.
실전 팁
💡 save_steps 값은 전체 학습 시간의 12%마다 저장되도록 설정하는 것이 좋습니다. 예를 들어 총 10만 스텝 학습이라면 10002000 스텝마다 저장하세요.
💡 클라우드 스토리지(S3, GCS 등)에 체크포인트를 주기적으로 백업하면 더욱 안전합니다. 로컬 디스크가 날아가도 복구할 수 있습니다. rclone이나 aws s3 sync를 cron job으로 설정하면 자동화할 수 있습니다.
💡 체크포인트 파일명에 타임스탬프를 포함하면 나중에 시간 순서대로 찾기 쉽습니다. Hugging Face Trainer는 자동으로 checkpoint-{step} 형식으로 저장하지만, PyTorch로 직접 구현할 때는 f"checkpoint_{datetime.now().strftime('%Y%m%d_%H%M%S')}.pt" 같은 형식을 사용하세요.
💡 모델 가중치만 저장하려면 torch.save(model.state_dict(), path)를, 전체 상태를 저장하려면 torch.save({'model': model.state_dict(), 'optimizer': optimizer.state_dict(), 'epoch': epoch, 'loss': loss}, path)처럼 딕셔너리로 저장하세요.
💡 매우 큰 모델(수십 GB)의 경우 checkpoint를 저장하는 동안 학습이 멈추는 것을 방지하려면 비동기 저장을 고려하세요. PyTorch Lightning의 ModelCheckpoint는 이를 지원합니다.
5. 최적 모델 선택 기준
시작하며
여러분이 수십 개의 체크포인트를 저장한 후 이런 상황을 겪어본 적 있나요? checkpoint-1000, checkpoint-2000, checkpoint-3000...
이렇게 많은 파일 중에서 "어떤 모델이 가장 좋은 거지?"라고 고민하면서, 결국 마지막 체크포인트를 무작정 사용하거나 하나하나 평가해보느라 시간을 낭비하는 상황 말이죠. 이런 문제는 실전 프로젝트에서 매우 중요한 문제입니다.
많은 초보자들이 "학습이 길수록 좋다"고 생각해서 마지막 체크포인트를 선택하지만, 이는 과적합된 모델일 가능성이 높습니다. 또한 Training Loss만 보고 판단하면 실제 성능은 좋지 않을 수 있고, 반대로 Validation Loss만 보면 특정 메트릭에서는 부족할 수도 있습니다.
프로덕션에 배포할 모델을 선택할 때는 더욱 신중해야 합니다. 바로 이럴 때 필요한 것이 명확한 최적 모델 선택 기준입니다.
어떤 지표를 기준으로 삼을지, 여러 지표를 어떻게 종합할지, 비즈니스 요구사항을 어떻게 반영할지를 체계적으로 결정해야 합니다.
개요
간단히 말해서, 최적 모델 선택은 저장된 여러 체크포인트 중에서 실제 운영 환경에서 가장 좋은 성능을 낼 모델을 선택하는 과정으로, 단순히 손실 함수만이 아니라 정확도, F1 스코어, 추론 속도, 모델 크기 등 다양한 요소를 종합적으로 고려해야 합니다. 왜 이 과정이 필요한지 실무 관점에서 설명하자면, 모델의 "좋음"은 맥락에 따라 다릅니다.
학술 연구에서는 정확도나 F1 스코어가 0.1%만 높아도 의미가 있지만, 프로덕션 환경에서는 정확도가 조금 낮아도 추론 속도가 2배 빠르거나 모델 크기가 절반인 것이 더 가치 있을 수 있습니다. 예를 들어, 모바일 앱에 탑재할 모델이라면 정확도 95% & 100MB보다 정확도 93% & 20MB가 더 적합할 수 있습니다.
또한 불균형 데이터셋에서는 정확도보다 Recall이나 Precision이 더 중요할 수 있습니다. 기존에는 단순히 Validation Loss가 가장 낮은 모델을 선택했다면, 이제는 여러 메트릭을 동시에 고려하고, A/B 테스트나 비즈니스 지표와 연결해서 선택합니다.
최적 모델 선택의 핵심 특징은 첫째, 다중 메트릭 평가(Loss, Accuracy, F1, Precision, Recall 등을 동시에 확인)를 한다는 점, 둘째, 검증 세트뿐만 아니라 별도의 테스트 세트로 최종 검증을 한다는 점, 셋째, 추론 속도와 메모리 사용량 같은 비기능적 요구사항도 고려한다는 점입니다. 이러한 특징들이 중요한 이유는 실제 운영 환경에서 성공적으로 작동하는 모델을 선택하기 위함입니다.
코드 예제
import torch
from sklearn.metrics import accuracy_score, f1_score, precision_score, recall_score
import pandas as pd
def evaluate_checkpoint(checkpoint_path, test_loader):
"""체크포인트를 로드해서 다양한 메트릭 계산"""
# 체크포인트 로드
model.load_state_dict(torch.load(checkpoint_path))
model.eval()
predictions, labels = [], []
inference_times = []
with torch.no_grad():
for batch in test_loader:
start_time = time.time()
outputs = model(batch['input_ids'])
inference_times.append(time.time() - start_time)
preds = torch.argmax(outputs, dim=-1)
predictions.extend(preds.cpu().numpy())
labels.extend(batch['labels'].cpu().numpy())
# 다양한 메트릭 계산
metrics = {
'accuracy': accuracy_score(labels, predictions),
'f1': f1_score(labels, predictions, average='weighted'),
'precision': precision_score(labels, predictions, average='weighted'),
'recall': recall_score(labels, predictions, average='weighted'),
'avg_inference_time': sum(inference_times) / len(inference_times),
'model_size_mb': os.path.getsize(checkpoint_path) / (1024 * 1024)
}
return metrics
# 모든 체크포인트 평가
checkpoints = ["checkpoint-1000", "checkpoint-2000", "checkpoint-3000"]
results = []
for cp in checkpoints:
metrics = evaluate_checkpoint(f"./checkpoints/{cp}", test_loader)
metrics['checkpoint'] = cp
results.append(metrics)
# 결과를 DataFrame으로 정리
df = pd.DataFrame(results)
print(df.sort_values('f1', ascending=False))
# 복합 점수로 최적 모델 선택 (가중 평균)
df['composite_score'] = (
0.4 * df['f1'] + # F1이 가장 중요
0.3 * df['accuracy'] +
0.2 * (1 / df['avg_inference_time']) + # 빠를수록 좋음
0.1 * (1 / df['model_size_mb']) # 작을수록 좋음
)
best_checkpoint = df.loc[df['composite_score'].idxmax(), 'checkpoint']
print(f"\n최적 모델: {best_checkpoint}")
설명
이것이 하는 일: 이 코드는 저장된 모든 체크포인트를 테스트 세트로 평가하고, 정확도, F1 스코어, 추론 속도, 모델 크기 등 다양한 메트릭을 계산한 후, 가중 평균으로 최적의 모델을 선택해줍니다. 첫 번째로, evaluate_checkpoint 함수는 하나의 체크포인트를 평가합니다.
torch.load(checkpoint_path)로 모델 가중치를 로드한 후, model.eval()로 평가 모드로 전환합니다(Dropout이나 BatchNorm이 다르게 작동하므로 필수). 그리고 테스트 세트의 모든 배치를 순회하면서 예측값을 모으고, 동시에 추론 시간도 측정합니다.
왜 추론 시간을 측정할까요? 프로덕션 환경에서는 정확도가 조금 낮아도 응답이 빠른 것이 더 중요할 수 있기 때문입니다.
그 다음으로, sklearn.metrics의 다양한 함수로 메트릭을 계산합니다. accuracy_score는 전체 정확도, f1_score는 정밀도와 재현율의 조화 평균, precision_score는 양성으로 예측한 것 중 실제 양성 비율, recall_score는 실제 양성 중 올바르게 예측한 비율입니다.
average='weighted'는 클래스별 샘플 수에 따라 가중 평균을 내라는 뜻으로, 불균형 데이터셋에서 유용합니다. 또한 os.path.getsize()로 모델 파일 크기도 측정합니다.
모든 체크포인트를 평가한 후에는 pandas DataFrame으로 결과를 정리합니다. 이렇게 하면 sort_values()로 특정 메트릭 기준으로 정렬하거나, 테이블 형태로 예쁘게 출력할 수 있습니다.
예를 들어 df.sort_values('f1', ascending=False)는 F1 스코어가 높은 순서로 정렬합니다. 마지막으로, 복합 점수(composite_score)를 계산합니다.
이것은 여러 메트릭을 하나의 점수로 합치는 방법으로, 각 메트릭에 가중치를 곱해서 더합니다. 예를 들어 F1에 0.4, 정확도에 0.3, 추론 속도에 0.2, 모델 크기에 0.1의 가중치를 줍니다.
추론 속도와 모델 크기는 "작을수록 좋음"이므로 역수(1 / value)를 취합니다. 이 가중치들은 여러분의 비즈니스 요구사항에 맞게 조절해야 합니다.
예를 들어 모바일 앱이라면 model_size_mb의 가중치를 높이고, 학술 연구라면 f1의 가중치를 높이는 식입니다. 여러분이 이 코드를 사용하면 "이 체크포인트는 F1이 높지만 느리다", "저 체크포인트는 빠르지만 정확도가 낮다" 같은 트레이드오프를 한눈에 파악할 수 있습니다.
최종적으로 프로덕션에 배포하기 전에 선택된 모델을 실제 환경과 유사한 조건에서 A/B 테스트하는 것도 좋은 방법입니다. 데이터 과학은 단순히 정확도를 높이는 게임이 아니라, 비즈니스 가치를 최대화하는 게임이라는 것을 기억하세요.
실전 팁
💡 테스트 세트는 학습과 검증에 전혀 사용하지 않은 데이터여야 합니다. 검증 세트로 모델을 선택한 후 테스트 세트로 최종 성능을 확인하는 것이 올바른 절차입니다.
💡 불균형 데이터셋(예: 긍정 10%, 부정 90%)에서는 정확도가 아닌 F1 스코어나 AUROC를 주요 메트릭으로 사용하세요. 모든 샘플을 부정으로 예측해도 90% 정확도가 나오기 때문입니다.
💡 여러 메트릭 중 하나라도 임계값 이하면 제외하는 "hard constraint" 방식도 유용합니다. 예를 들어 "F1이 0.9 이상인 것 중에서 가장 빠른 모델"처럼 선택할 수 있습니다.
💡 추론 속도는 batch size와 하드웨어에 따라 달라지므로, 실제 운영 환경과 동일한 조건에서 측정하세요. GPU에서는 빠른 모델이 CPU에서는 느릴 수도 있습니다.
💡 Wandb나 MLflow 같은 실험 추적 도구를 사용하면 모든 체크포인트의 메트릭이 자동으로 기록되어서 나중에 대시보드에서 쉽게 비교할 수 있습니다. 일일이 스크립트를 돌릴 필요가 없어집니다.
6. 학습 재개 (Resume Training) 방법
시작하며
여러분이 학습을 시작한 지 이틀이 지났을 때 이런 상황을 겪어본 적 있나요? 갑자기 서버 접속이 끊기거나 실수로 터미널을 닫아버려서 학습이 중단되었는데, "지금까지의 진행 상황을 살릴 수 있을까?" 하고 불안해하는 상황 말이죠.
이런 문제는 장시간 학습을 진행하는 모든 프로젝트에서 발생할 수 있습니다. 대규모 모델을 학습할 때는 며칠에서 몇 주씩 걸리기 때문에, 중간에 한 번도 문제가 발생하지 않기를 기대하는 것은 비현실적입니다.
인터넷 연결이 끊기거나, 클라우드 인스턴스가 재부팅되거나, 하이퍼파라미터를 조금 조정하고 싶을 때 등 다양한 이유로 학습을 재개해야 하는 상황이 생깁니다. 만약 처음부터 다시 시작해야 한다면 엄청난 시간과 비용 낭비입니다.
바로 이럴 때 필요한 것이 학습 재개(Resume Training) 기능입니다. 저장된 체크포인트에서 모델 가중치, 옵티마이저 상태, 학습률 스케줄러 상태, 현재 에포크/스텝 번호까지 모두 복원해서 마치 중단된 적이 없는 것처럼 이어서 학습할 수 있습니다.
개요
간단히 말해서, 학습 재개는 저장된 체크포인트 파일에서 모델과 학습 상태를 완전히 복원해서, 중단된 시점부터 정확히 이어서 학습하는 기능으로, 단순히 모델 가중치만이 아니라 옵티마이저의 모멘텀, 학습률 스케줄러의 현재 상태, 랜덤 시드까지 복원해야 재현 가능한 학습이 됩니다. 왜 이 기능이 필요한지 실무 관점에서 설명하자면, 머신러닝 학습은 연속적인 과정입니다.
옵티마이저는 과거 그래디언트 정보를 누적해서 사용하고(예: Adam의 모멘텀), 학습률 스케줄러는 현재 에포크에 따라 학습률을 조절합니다. 만약 모델 가중치만 로드하고 옵티마이저를 새로 초기화하면, 학습 역학(learning dynamics)이 완전히 달라져서 제대로 재개되지 않습니다.
예를 들어, 50 에포크까지 학습해서 학습률이 0.0001로 감소했는데, 재개할 때 옵티마이저를 새로 만들면 학습률이 다시 0.001로 초기화되어서 학습이 불안정해집니다. 기존에는 모델 가중치만 저장하고 로드하는 방식이 흔했다면, 이제는 옵티마이저, 스케줄러, RNG 상태까지 모두 저장하고 복원하는 것이 표준입니다.
학습 재개의 핵심 특징은 첫째, 모든 학습 관련 상태를 하나의 체크포인트 파일에 저장한다는 점, 둘째, 에포크/스텝 번호를 저장해서 로깅이 연속적으로 이어지게 한다는 점, 셋째, 랜덤 시드(PyTorch RNG, NumPy RNG, Python RNG)까지 저장해서 완전히 재현 가능하게 한다는 점입니다. 이러한 특징들이 중요한 이유는 학습을 재개했을 때도 중단 없이 학습한 것과 동일한 결과를 얻을 수 있게 해주기 때문입니다.
코드 예제
import torch
import numpy as np
import random
def save_checkpoint(model, optimizer, scheduler, epoch, step, loss, path):
"""완전한 학습 상태 저장"""
checkpoint = {
'epoch': epoch,
'step': step,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'scheduler_state_dict': scheduler.state_dict(),
'loss': loss,
# 재현성을 위한 랜덤 시드 상태 저장
'rng_state': torch.get_rng_state(),
'numpy_rng_state': np.random.get_state(),
'python_rng_state': random.getstate(),
}
torch.save(checkpoint, path)
print(f"✓ 체크포인트 저장: {path}")
def load_checkpoint(model, optimizer, scheduler, path):
"""완전한 학습 상태 복원"""
checkpoint = torch.load(path)
# 모델과 옵티마이저 상태 복원
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
scheduler.load_state_dict(checkpoint['scheduler_state_dict'])
# 랜덤 시드 상태 복원 (재현성 보장)
torch.set_rng_state(checkpoint['rng_state'])
np.random.set_state(checkpoint['numpy_rng_state'])
random.setstate(checkpoint['python_rng_state'])
epoch = checkpoint['epoch']
step = checkpoint['step']
loss = checkpoint['loss']
print(f"✓ 체크포인트 로드: Epoch {epoch}, Step {step}, Loss {loss:.4f}")
return epoch, step, loss
# 학습 루프에서 사용
start_epoch = 0
if resume_training:
start_epoch, global_step, last_loss = load_checkpoint(
model, optimizer, scheduler, "checkpoint_latest.pt"
)
start_epoch += 1 # 다음 에포크부터 시작
for epoch in range(start_epoch, total_epochs):
for batch in train_loader:
# 학습 진행...
loss = train_step(model, batch)
# 주기적으로 체크포인트 저장
if global_step % 500 == 0:
save_checkpoint(model, optimizer, scheduler,
epoch, global_step, loss,
f"checkpoint_step_{global_step}.pt")
설명
이것이 하는 일: 이 코드는 학습 중 모든 상태를 체크포인트 파일에 저장하고, 나중에 이 파일을 로드해서 중단된 시점부터 정확히 동일하게 학습을 재개할 수 있게 해줍니다. 첫 번째로, save_checkpoint 함수는 학습과 관련된 모든 정보를 딕셔너리에 담아서 저장합니다.
model.state_dict()는 모델의 모든 가중치와 버퍼를, optimizer.state_dict()는 옵티마이저의 모멘텀과 RMS 같은 내부 상태를, scheduler.state_dict()는 현재 학습률과 스케줄러의 진행 상태를 반환합니다. 특히 중요한 것은 epoch와 step 번호를 저장하는 것인데, 이것을 저장하지 않으면 재개할 때 에포크 번호가 0부터 다시 시작되어서 로그가 혼란스러워집니다.
loss도 함께 저장하면 나중에 "이 체크포인트의 성능이 어땠는지" 파일명만 봐도 알 수 있습니다. 그 다음으로, 재현성을 위한 랜덤 시드 상태도 저장합니다.
torch.get_rng_state()는 PyTorch의 랜덤 넘버 생성기 상태를, np.random.get_state()는 NumPy의 RNG 상태를, random.getstate()는 Python 내장 random 모듈의 상태를 반환합니다. 왜 이것들이 필요할까요?
학습 중 데이터 셔플링, Dropout, 가중치 초기화 등 많은 부분이 랜덤에 의존하는데, 이 상태를 저장하지 않으면 재개했을 때 데이터 순서가 달라져서 결과가 미묘하게 달라집니다. load_checkpoint 함수는 저장된 모든 상태를 복원합니다.
model.load_state_dict()로 가중치를 복원하고, optimizer.load_state_dict()로 옵티마이저의 모멘텀 등을 복원하고, scheduler.load_state_dict()로 학습률 스케줄러를 복원합니다. 그리고 torch.set_rng_state() 등으로 랜덤 시드 상태도 복원합니다.
이렇게 하면 다음에 샘플링되는 데이터, 다음에 적용되는 Dropout 마스크까지 모두 중단되지 않았을 때와 똑같아집니다. 마지막으로, 학습 루프에서 사용하는 방법입니다.
resume_training 플래그가 True면 load_checkpoint를 호출해서 start_epoch를 복원하고, range(start_epoch, total_epochs)로 남은 에포크만 학습합니다. global_step도 복원해서 로깅과 체크포인트 저장이 연속적으로 이어지게 합니다.
예를 들어 50 에포크에서 중단되었다면 51 에포크부터 시작하고, 스텝 번호도 5000부터 계속 증가합니다. 여러분이 이 코드를 사용하면 언제든지 안심하고 학습을 중단하고 재개할 수 있습니다.
AWS Spot Instance처럼 저렴하지만 불안정한 인프라도 활용할 수 있고, 하이퍼파라미터를 조금 조정하고 싶을 때 중간 체크포인트부터 fine-tuning을 시작할 수도 있습니다. 논문을 쓸 때 "완전히 재현 가능한 실험"이라고 당당히 말할 수 있게 해주는 것도 큰 장점입니다.
학습이 며칠씩 걸리는 프로젝트에서는 이러한 체크포인트 관리가 필수입니다.
실전 팁
💡 체크포인트 파일명에 "latest"와 "best"를 구분해서 저장하세요. latest는 가장 최근 체크포인트, best는 검증 손실이 가장 낮은 체크포인트입니다. 재개할 때는 latest를 사용하고, 최종 평가할 때는 best를 사용합니다.
💡 Hugging Face Transformers를 사용한다면 trainer.train(resume_from_checkpoint=True)만으로 자동으로 재개됩니다. output_dir에서 가장 최근 체크포인트를 찾아서 모든 상태를 복원해줍니다.
💡 분산 학습(DDP, FSDP)을 사용하는 경우, rank 0(메인 프로세스)에서만 체크포인트를 저장하세요. 모든 프로세스가 동시에 저장하면 파일이 충돌합니다. if dist.get_rank() == 0: save_checkpoint(...)처럼 체크하세요.
💡 체크포인트를 로드할 때 map_location 인자를 사용하면 다른 디바이스로 이동할 수 있습니다. 예를 들어 GPU에서 저장한 모델을 CPU에서 로드하려면 torch.load(path, map_location='cpu')처럼 사용하세요.
💡 학습 재개 시 데이터로더의 시드도 복원하고 싶다면 worker_init_fn을 사용해서 각 워커의 시드를 에포크 번호에 기반해 설정하세요. 이렇게 하면 재개 후에도 데이터 순서가 정확히 일치합니다.