[AI 인공지능 머신러닝 딥러닝/Python | PyTorch] - 인스톨! 파이토치 강의 소개
인스톨! 파이토치 강의 소개
혁펜하임 PyTorch 강의 오리엔테이션 요약혁펜하임 채널의 '[PyTorch] 0강. 오리엔테이션' 영상은 채널 5주년 기념으로 '인스톨! 파이토치' 강의를 소개하는 내용입니다. 강의자는 최근 출간한 '이론
inner-game.tistory.com

딥러닝 모델을 실전에서 학습시키려면 단순히 모델을 정의하고 학습 루프를 돌리는 것 이상의 작업이 필요합니다. Validation set을 활용한 모델 평가, 학습률 스케줄러를 통한 성능 최적화, 체크포인트 저장 등 다양한 기법이 필요합니다. 이번 강의에서는 지금까지 배운 모든 내용을 통합한 완성도 높은 코드 템플릿을 제공합니다.[^1]
딥러닝 학습 파이프라인은 크게 다음과 같은 단계로 구성됩니다:[^2][^1]
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, random_split
from torchvision import datasets, transforms, models
import copy
import time
# ==================== 1. 설정 및 하이퍼파라미터 ====================
class Config:
# 데이터 관련
data_dir = './data'
batch_size = 32
num_workers = 4
# 모델 관련
num_classes = 10
pretrained = True
# 학습 관련
num_epochs = 50
learning_rate = 0.001
momentum = 0.9
weight_decay = 1e-4
# 데이터 분할 비율
train_ratio = 0.7
val_ratio = 0.15
test_ratio = 0.15
# 기타
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
save_path = './best_model.pth'
seed = 42
config = Config()
# ==================== 2. 재현성을 위한 시드 고정 ====================
def set_seed(seed):
torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
import numpy as np
import random
np.random.seed(seed)
random.seed(seed)
set_seed(config.seed)
# ==================== 3. 데이터 준비 ====================
# Train transform (데이터 증강 포함)
train_transform = transforms.Compose([
transforms.Resize(256),
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomRotation(degrees=15),
transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
# Validation/Test transform (증강 없음)
val_test_transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])
# 전체 데이터셋 로드
full_dataset = datasets.ImageFolder(root=config.data_dir)
# Train/Val/Test 분할
train_size = int(config.train_ratio * len(full_dataset))
val_size = int(config.val_ratio * len(full_dataset))
test_size = len(full_dataset) - train_size - val_size
train_dataset, val_dataset, test_dataset = random_split(
full_dataset,
[train_size, val_size, test_size],
generator=torch.Generator().manual_seed(config.seed)
)
# Transform 적용
train_dataset.dataset.transform = train_transform
val_dataset.dataset.transform = val_test_transform
test_dataset.dataset.transform = val_test_transform
# DataLoader 생성
train_loader = DataLoader(
train_dataset,
batch_size=config.batch_size,
shuffle=True,
num_workers=config.num_workers,
pin_memory=True
)
val_loader = DataLoader(
val_dataset,
batch_size=config.batch_size,
shuffle=False,
num_workers=config.num_workers,
pin_memory=True
)
test_loader = DataLoader(
test_dataset,
batch_size=config.batch_size,
shuffle=False,
num_workers=config.num_workers,
pin_memory=True
)
# ==================== 4. 모델 정의 ====================
def build_model(num_classes, pretrained=True):
"""사전 학습된 모델 로드 및 수정"""
model = models.resnet50(pretrained=pretrained)
# 마지막 FC 레이어 교체
num_features = model.fc.in_features
model.fc = nn.Linear(num_features, num_classes)
return model
model = build_model(config.num_classes, config.pretrained)
model = model.to(config.device)
# ==================== 5. 손실 함수 및 옵티마이저 ====================
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(
model.parameters(),
lr=config.learning_rate,
momentum=config.momentum,
weight_decay=config.weight_decay
)
# ==================== 6. 학습률 스케줄러 ====================
# StepLR: 일정 epoch마다 lr을 gamma배 감소
scheduler = optim.lr_scheduler.StepLR(
optimizer,
step_size=10, # 10 epoch마다
gamma=0.1 # lr을 0.1배로 감소
)
# 다른 스케줄러 옵션들:
# ReduceLROnPlateau: validation loss가 개선되지 않을 때 lr 감소
# scheduler = optim.lr_scheduler.ReduceLROnPlateau(
# optimizer, mode='min', factor=0.1, patience=5, verbose=True
# )
# CosineAnnealingLR: cosine 함수 형태로 lr 감소
# scheduler = optim.lr_scheduler.CosineAnnealingLR(
# optimizer, T_max=config.num_epochs
# )
# ==================== 7. 학습 함수 ====================
def train_one_epoch(model, dataloader, criterion, optimizer, device):
"""1 epoch 학습"""
model.train()
running_loss = 0.0
running_corrects = 0
for inputs, labels in dataloader:
inputs = inputs.to(device)
labels = labels.to(device)
# Forward
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
_, preds = torch.max(outputs, 1)
# Backward
loss.backward()
optimizer.step()
# 통계
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / len(dataloader.dataset)
epoch_acc = running_corrects.double() / len(dataloader.dataset)
return epoch_loss, epoch_acc
# ==================== 8. 검증 함수 ====================
def validate(model, dataloader, criterion, device):
"""Validation/Test 평가"""
model.eval()
running_loss = 0.0
running_corrects = 0
with torch.no_grad():
for inputs, labels in dataloader:
inputs = inputs.to(device)
labels = labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
_, preds = torch.max(outputs, 1)
running_loss += loss.item() * inputs.size(0)
running_corrects += torch.sum(preds == labels.data)
epoch_loss = running_loss / len(dataloader.dataset)
epoch_acc = running_corrects.double() / len(dataloader.dataset)
return epoch_loss, epoch_acc
# ==================== 9. 전체 학습 루프 ====================
def train_model(model, train_loader, val_loader, criterion, optimizer,
scheduler, num_epochs, device, save_path):
"""전체 학습 파이프라인"""
since = time.time()
best_model_wts = copy.deepcopy(model.state_dict())
best_acc = 0.0
# 학습 히스토리 저장
history = {
'train_loss': [], 'train_acc': [],
'val_loss': [], 'val_acc': []
}
for epoch in range(num_epochs):
print(f'Epoch {epoch+1}/{num_epochs}')
print('-' * 60)
# 학습
train_loss, train_acc = train_one_epoch(
model, train_loader, criterion, optimizer, device
)
# 검증
val_loss, val_acc = validate(
model, val_loader, criterion, device
)
# 학습률 스케줄러 업데이트
scheduler.step()
# ReduceLROnPlateau 사용 시:
# scheduler.step(val_loss)
# 히스토리 저장
history['train_loss'].append(train_loss)
history['train_acc'].append(train_acc.item())
history['val_loss'].append(val_loss)
history['val_acc'].append(val_acc.item())
# 현재 학습률 출력
current_lr = optimizer.param_groups[^0]['lr']
print(f'Train Loss: {train_loss:.4f} Acc: {train_acc:.4f}')
print(f'Val Loss: {val_loss:.4f} Acc: {val_acc:.4f}')
print(f'Learning Rate: {current_lr:.6f}')
# 최고 성능 모델 저장
if val_acc > best_acc:
best_acc = val_acc
best_model_wts = copy.deepcopy(model.state_dict())
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'best_acc': best_acc,
}, save_path)
print(f'✓ Best model saved! (Acc: {best_acc:.4f})')
print()
time_elapsed = time.time() - since
print(f'Training complete in {time_elapsed//60:.0f}m {time_elapsed%60:.0f}s')
print(f'Best Validation Acc: {best_acc:.4f}')
# 최고 성능 모델 로드
model.load_state_dict(best_model_wts)
return model, history
# ==================== 10. 학습 실행 ====================
trained_model, history = train_model(
model, train_loader, val_loader, criterion, optimizer,
scheduler, config.num_epochs, config.device, config.save_path
)
# ==================== 11. 테스트 평가 ====================
print("=" * 60)
print("Final Test Evaluation")
print("=" * 60)
test_loss, test_acc = validate(
trained_model, test_loader, criterion, config.device
)
print(f'Test Loss: {test_loss:.4f}')
print(f'Test Acc: {test_acc:.4f}')
# ==================== 12. 학습 결과 시각화 ====================
import matplotlib.pyplot as plt
def plot_history(history):
"""학습 히스토리 시각화"""
fig, axes = plt.subplots(1, 2, figsize=(15, 5))
# Loss 그래프
axes[^0].plot(history['train_loss'], label='Train Loss')
axes[^0].plot(history['val_loss'], label='Val Loss')
axes[^0].set_xlabel('Epoch')
axes[^0].set_ylabel('Loss')
axes[^0].legend()
axes[^0].set_title('Training and Validation Loss')
axes[^0].grid(True)
# Accuracy 그래프
axes[^1].plot(history['train_acc'], label='Train Acc')
axes[^1].plot(history['val_acc'], label='Val Acc')
axes[^1].set_xlabel('Epoch')
axes[^1].set_ylabel('Accuracy')
axes[^1].legend()
axes[^1].set_title('Training and Validation Accuracy')
axes[^1].grid(True)
plt.tight_layout()
plt.savefig('training_history.png')
plt.show()
plot_history(history)
# ==================== 13. 저장된 모델 로드 ====================
def load_checkpoint(model, checkpoint_path):
"""저장된 체크포인트 로드"""
checkpoint = torch.load(checkpoint_path)
model.load_state_dict(checkpoint['model_state_dict'])
epoch = checkpoint['epoch']
best_acc = checkpoint['best_acc']
print(f'Loaded checkpoint from epoch {epoch} (Acc: {best_acc:.4f})')
return model
# 사용 예시
# loaded_model = build_model(config.num_classes, pretrained=False)
# loaded_model = load_checkpoint(loaded_model, config.save_path)
학습률 스케줄러는 학습 과정에서 학습률을 동적으로 조정하여 성능을 향상시킵니다. PyTorch는 다양한 스케줄러를 제공합니다.[^3][^4]
1. StepLR: 일정 epoch마다 학습률 감소[^5]
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=10, gamma=0.1)
# 10 epoch마다 lr을 0.1배로 감소
2. MultiStepLR: 지정한 epoch들에서 학습률 감소[^5]
scheduler = optim.lr_scheduler.MultiStepLR(optimizer, milestones=[30, 60, 90], gamma=0.1)
# 30, 60, 90 epoch에서 lr을 0.1배로 감소
3. ReduceLROnPlateau: 성능 개선이 멈추면 학습률 감소[^4][^3]
scheduler = optim.lr_scheduler.ReduceLROnPlateau(
optimizer, mode='min', factor=0.1, patience=5, verbose=True
)
# validation loss가 5 epoch 동안 개선되지 않으면 lr을 0.1배로 감소
4. CosineAnnealingLR: Cosine 함수 형태로 학습률 변화[^5]
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=50)
# 50 epoch 동안 cosine 형태로 lr 감소
5. ExponentialLR: 지수적으로 학습률 감소[^5]
scheduler = optim.lr_scheduler.ExponentialLR(optimizer, gamma=0.95)
# 매 epoch마다 lr = lr * 0.95
Validation set은 모델의 일반화 성능을 평가하고 과적합을 방지하는 데 필수적입니다:[^6][^1]
일반적으로 Train:Validation:Test = 70:15:15 또는 80:10:10 비율로 분할합니다.[^7]
# 최고 성능 모델만 저장
if val_acc > best_acc:
best_acc = val_acc
torch.save({
'epoch': epoch,
'model_state_dict': model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'scheduler_state_dict': scheduler.state_dict(),
'best_acc': best_acc,
}, 'best_model.pth')
# 일정 epoch마다 저장
if (epoch + 1) % 10 == 0:
torch.save({...}, f'checkpoint_epoch_{epoch+1}.pth')
이 템플릿 코드는 실전에서 바로 활용 가능한 완전한 학습 파이프라인을 제공합니다. Train/Validation/Test 분할, 데이터 증강, 학습률 스케줄러, 체크포인트 저장 등 모든 필수 요소가 포함되어 있습니다. 자신의 데이터와 모델에 맞게 config 부분만 수정하면 즉시 사용할 수 있습니다. 이 코드를 기반으로 다양한 딥러닝 프로젝트에 도전해보세요!