Search

Deep Learning 진행 과정 (예제: pizza)

대분류
인공지능/데이터
소분류
ML/DL 정리 노트
유형
딥 러닝
부유형
Introduction Pytorch
최종 편집 일시
2024/10/27 15:25
생성 일시
2024/09/10 03:47
14 more properties

0. import

import torch from torch import nn, optim # PyTorch의 신경망 및 최적화 함수 from torchvision import datasets, transforms, models # 이미지 데이터셋과 모델 관련 기능 from torch.utils.data import DataLoader # 데이터 로딩 기능 from sklearn.metrics import confusion_matrix, accuracy_score # 혼동 행렬 및 정확도 계산 import seaborn as sns # 데이터 시각화 라이브러리 import matplotlib.pyplot as plt # 플롯을 그리기 위한 Matplotlib import numpy as np # NumPy 사용 import random # 난수 생성
Python
복사

1. 시드 고정 & 상수 설정

# 시드 고정 함수 def set_seed(seed=42): random.seed(seed) # Python 기본 랜덤 시드 고정 np.random.seed(seed) # NumPy 랜덤 시드 고정 torch.manual_seed(seed) # PyTorch CPU 시드 고정 torch.cuda.manual_seed(seed) # PyTorch GPU 시드 고정 (CUDA) torch.cuda.manual_seed_all(seed) # PyTorch 멀티-GPU 시드 고정 (CUDA) torch.backends.cudnn.deterministic = True # CUDNN에서 난수 생성기가 동일한 결과를 보장 torch.backends.cudnn.benchmark = False # CUDNN 최적화 기능 비활성화 # 시드 고정 set_seed(42) # 배치 크기 설정 (배치 크기를 32로 조정) BATCH_SIZE = 32
Python
복사

2. Device 설정

# GPU가 사용 가능한지 확인하고 GPU로 설정 device = torch.device("cuda" if torch.cuda.is_available() else "cpu") # GPU 사용 가능하면 CUDA 사용 print(f"Using device: {device}")
Python
복사

3. Transform

# 데이터 증강 및 전처리 (학습 데이터에 다양한 변형 적용) train_transform = transforms.Compose([ transforms.RandomResizedCrop(224), # 랜덤하게 이미지 크롭 transforms.RandomHorizontalFlip(), # 좌우 반전 transforms.RandomRotation(10), # 이미지를 랜덤하게 회전 transforms.ColorJitter(), # 색상 변형 transforms.ToTensor(), # 이미지를 텐서로 변환 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 이미지 정규화 ]) # 테스트 데이터는 크기 조정 및 정규화만 적용 test_transform = transforms.Compose([ transforms.Resize(256), # 이미지 크기를 256으로 조정 transforms.CenterCrop(224), # 중앙 크롭 transforms.ToTensor(), # 이미지를 텐서로 변환 transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]) # 정규화 ])
Python
복사

4. DataLoader로 변환

# DataLoader로 변환 (데이터셋을 배치 단위로 나누어 로드) train_loader = DataLoader(train_data, batch_size=BATCH_SIZE, shuffle=True) # 학습 데이터 로더 (shuffle 활성화) test_loader = DataLoader(test_data, batch_size=BATCH_SIZE, shuffle=False) # 테스트 데이터 로더
Python
복사

5. 모델

모델 정의

# EfficientNet-B0 모델 사용 (사전 학습된 모델 활용) model = models.efficientnet_b0(pretrained=True)
Python
복사

모델 출력 레이어 변경

# 모델의 출력 레이어 변경 (사전 학습된 레이어는 동결되고, 마지막 레이어만 학습) num_features = model.classifier[1].in_features # 마지막 레이어의 입력 크기 model.classifier[1] = nn.Linear(num_features, len(train_data.classes)) # 출력 클래스 수로 레이어 변경
Python
복사

모델 device 할당

# 모델을 GPU로 이동 model = model.to(device)
Python
복사

6. 클래스 불균형 처리 (클래스 가중치 적용)

# 클래스 불균형 처리 (클래스 가중치 적용) class_counts = torch.bincount(torch.tensor(train_data.targets)) # 각 클래스의 샘플 수 계산 class_weights = 1.0 / class_counts.float() # 클래스 가중치 계산 class_weights = class_weights.to(device) # 가중치를 GPU로 이동
Python
복사

7. 손실 함수 및 옵티마이저(Optimizer) 설정

# 손실 함수 및 옵티마이저 설정 (Adam 사용) loss_fn = nn.CrossEntropyLoss(weight=class_weights) # 클래스 가중치를 적용한 손실 함수 optimizer = optim.Adam(model.parameters(), lr=0.001) # Adam 옵티마이저 설정
Python
복사

8. 학습률 Scheduler

# 학습률 스케줄러 (에포크마다 학습률을 줄여주는 StepLR 사용) scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1) # 7 에포크마다 학습률 감소
Python
복사

9. Scaler

# 학습 속도 개선을 위한 AMP(Mixed Precision Training) 사용 scaler = torch.cuda.amp.GradScaler() # 혼합 정밀도 학습을 위한 Scaler
Python
복사

10. EarlyStopping 설정

# Early Stopping 설정 class EarlyStopping: def __init__(self, patience=5, delta=0): self.patience = patience # 몇 에포크 동안 개선이 없으면 학습 중단 self.delta = delta # 개선을 판단하는 기준 self.best_loss = None # 가장 낮은 손실 값 저장 self.counter = 0 # 개선이 없을 때 카운터 증가 self.early_stop = False # 학습 중단 여부 def __call__(self, val_loss): if self.best_loss is None: # 첫 에포크에서 손실 값을 설정 self.best_loss = val_loss elif val_loss > self.best_loss - self.delta: # 개선되지 않은 경우 self.counter += 1 # 카운터 증가 print(f"EarlyStopping counter: {self.counter} out of {self.patience}") if self.counter >= self.patience: # 개선이 없으면 학습 중단 self.early_stop = True else: # 개선된 경우 self.best_loss = val_loss self.counter = 0 # 카운터 초기화
Python
복사
class EarlyStopper(object): def __init__(self, num_trials, save_path): self.num_trials = num_trials self.trial_counter = 0 self.best_loss = np.inf self.save_path = save_path def is_continuable(self, model, loss): if loss < self.best_loss: # 현재 loss가 최고 loss보다 더 낮은 경우 self.best_loss = loss # 최고 loss를 현재 loss로 업데이트 self.trial_counter = 0 # 초기화 torch.save(model, self.save_path) # 최고 loss를 갖은 모델 저장 return True elif self.trial_counter + 1 < self.num_trials: # 현재 loss가 최고 loss보다 작은 경우 & max 시도횟수보다 현재 시도횟수가 작은 경우 self.trial_counter += 1 # 기존 시도횟수 + 1 return True else: # 현재 정확도가 최고 정확도보다 작은 경우 & 현재 시도횟수가 max 시도횟수보다 큰 경우 return False def get_best_model(self, device): return torch.load(self.save_path).to(device)
Python
복사

11. 학습

def train_batch(train_loader): for inputs, labels in train_loader: # 배치별 학습 inputs, labels = inputs.to(device), labels.to(device) # 데이터를 GPU로 이동 optimizer.zero_grad() # 옵티마이저의 기울기 초기화 with torch.cuda.amp.autocast(): # 혼합 정밀도 연산 (AMP) outputs = model(inputs) # 모델의 예측값 loss = loss_fn(outputs, labels) # 손실 계산 scaler.scale(loss).backward() # 손실의 역전파 scaler.step(optimizer) # 옵티마이저 스텝 scaler.update() # Scaler 업데이트 running_loss += loss.item() * inputs.size(0) # 배치 손실을 누적 _, preds = torch.max(outputs, 1) # 예측값을 레이블로 변환 correct += (preds == labels).sum().item() # 맞은 예측 개수 누적 total += labels.size(0) # 총 샘플 개수 누적 # 학습 함수 (학습 과정을 추적 및 출력) def train_model(model, train_loader, test_loader, loss_fn, optimizer, scheduler, num_epochs=20, patience=5): early_stopping = EarlyStopping(patience=patience, delta=0.001) # Early Stopping 설정 for epoch in range(num_epochs): # 지정된 에포크 수만큼 반복 model.train() # 모델을 학습 모드로 전환 running_loss = 0.0 # 누적 손실 correct = 0 # 맞은 예측 개수 total = 0 # 총 샘플 개수 train_batch(train_loader) scheduler.step() # 학습률 스케줄러 업데이트 epoch_loss = running_loss / len(train_loader.dataset) # 에포크당 평균 손실 계산 epoch_acc = correct / total * 100 # 에포크당 정확도 계산 print(f"Epoch {epoch+1}/{num_epochs}, Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.2f}%") # 평가를 통해 Early Stopping 적용 val_loss = evaluate_model(model, test_loader, loss_fn) # 평가 함수 호출 early_stopping(val_loss) # Early Stopping 체크 if early_stopping.early_stop: # Early Stopping 조건 충족 시 print("Early stopping") # 학습 중단 메시지 출력 break
Python
복사

12. 학습 검증

# 평가 함수 (손실 값 반환) def evaluate_model(model, test_loader, loss_fn): model.eval() # 모델을 평가 모드로 전환 all_labels = [] # 실제 레이블 저장 리스트 all_preds = [] # 예측 레이블 저장 리스트 running_loss = 0.0 # 손실 초기화 with torch.no_grad(): # 평가 중에는 기울기 계산 안함 for inputs, labels in test_loader: inputs, labels = inputs.to(device), labels.to(device) # 데이터를 GPU로 이동 outputs = model(inputs) # 모델 예측 loss = loss_fn(outputs, labels) # 손실 계산 running_loss += loss.item() * inputs.size(0) # 손실 누적 _, preds = torch.max(outputs, 1) # 예측값을 레이블로 변환 all_labels.extend(labels.cpu().numpy()) # 실제 레이블 저장 all_preds.extend(preds.cpu().numpy()) # 예측 레이블 저장 val_loss = running_loss / len(test_loader.dataset) # 검증 손실 계산 acc = accuracy_score(all_labels, all_preds) # 정확도 계산 cm = confusion_matrix(all_labels, all_preds) # 혼동 행렬 계산 print(f"Validation Loss: {val_loss:.4f}, Test Accuracy: {acc * 100:.2f}%") # 검증 손실 및 정확도 출력 # 혼동 행렬 시각화 plt.figure(figsize=(8, 6)) # 플롯 크기 설정 sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=train_data.classes, yticklabels=train_data.classes) # 혼동 행렬 시각화 plt.xlabel('Predicted') # x축 라벨 plt.ylabel('Actual') # y축 라벨 plt.title('Confusion Matrix') # 제목 설정 plt.show() # 플롯 출력 return val_loss # 검증 손실 반환
Python
복사

13. 최종 실행

# 모델 학습 train_model(model, train_loader, test_loader, loss_fn, optimizer, scheduler, num_epochs=20, patience=5) # 모델 학습 호출
Python
복사