딥러닝 하이퍼파라미터 튜닝 기초

1. 조정해야 하는 하이퍼파라미터 종류

네트워크 구조 관련 파라미터:

  • 신경망의 레이어 수
  • 각 레이어의 유형과 구성 순서
  • 은닉층 뉴런 수 설정
  • 손실 함수 선택
  • 정규화 파라미터

학습 과정 관련 파라미터:

  • 네트워크 가중치 초기화 방법
  • 학습률 스케줄링 전략
  • 반복 횟수
  • 배치 크기
  • 입력 데이터 관련 설정

2. 언제 하이퍼파라미터 튜닝이 필요한가?

  • 적합한 적합 (Generally no tuning needed)
  • 과대적합 (Overfitting)
  • 과소적합 (Underfitting)
  • 수렴하지만 진동하는 상황
  • 수렴하지 않는 상황

3. 하이퍼파라미터 튜닝 방법

3.1 과대적합 상황에서의 튜닝

  • 데이터량 증가: 더 많은 훈련 데이터를 수집하거나 데이터 증강(Data Augmentation) 기법을 활용
  • 정규화 기술 적용: L1 또는 L2 정규화, 드롭아웃(Dropout), 조기 종료(Early Stopping)
  • 모델 복잡도 감소: 파라미터 수 감소 (레이어 수 또는 뉴런 수 줄이기)
  • 교차 검증 활용: 교차 검증을 통해 모델 성능 평가 및 최적 하이퍼파라미터 선택
  • 학습률 조정: 학습률 감소(Learning Rate Decay)를 활용하여 점진적으로 학습률 감소
  • 배치 크기 조정: 배치 크기 증가 또는 감소 - 데이터셋과 모델에 따라 다른 배치 크기가 최적
  • 층별 정규화 적용: BatchNorm, LayerNorm 등을 활용하여 각 레이어 입력 전에 정규화 수행, 특성 분포 안정화

3.2 과소적합 상황에서의 튜닝

  • 모델 복잡도 증가: 신경망 레이어 수 또는 뉴런 수 증가
  • 장기 훈련: 에포크 수 증가
  • 학습률 조정: 학습률 증가로 수렴 속도 향상
  • 정규화 감소: 정규화 항 감소 또는 제거 (L2 정규화), 드롭아웃 비율 감소
  • 데이터 처리 최적화: 데이터 전처리 및 정규화 확인, 데이터 분포가 모델 훈련에 적합하도록 조정
  • 배치 크기 증가

3.3 수렴하지만 진동하는 상황에서의 튜닝

  • 학습률 감소: 학습률이 높으면 진동 발생 가능, 학습률 감소로 안정적 수렴 도모
  • 학습률 스케줄러 활용: 학습률 감쇠, 코사인 어닐링 등 동적 학습률 조정
  • 배치 크기 증가
  • 그래디언트 클리핑: 그래디언트 클리핑(Gradient Clipping)으로 최대 노름 제한, 그래디언트 폭발 및 진동 방지
  • 정규화 증가: L2 정규화 증가 또는 드롭아웃 비율 증가로 가중치 업데이트 완화
  • 데이터 확인: 데이터 전처리 및 정규화 단계 정확성 검증
  • 모델 아키텍처 단순화: 지나치게 깊거나 넓은 네트워크 구조 감소

3.4 수렴하지 않는 상황에서의 튜닝

  • 학습률 조정: 학습률이 너무 높으면 파라미터 업데이트过大로 수렴 불가, 학습률이 너무 낮으면 수렴 속도가 느리거나 국소 극소값에 갇힘
  • 모델 복잡도 조정: 모델이 너무 단순하면 데이터 피팅 불가, 너무 복잡하면 훈련 어려움
  • 활성화 함수 변경: ReLU, Leaky ReLU, ELU, Swish 등 다양한 활성화 함수 시도
  • 옵티마이저 변경: Adam, RMSprop, 모멘텀 SGD 등 다양한 옵티마이저 시도
  • 배치 크기 증가
  • 훈련 횟수 증가
  • 적절한 가중치 초기화: He 초기화 또는 Xavier 초기화 활용, 훈련 초기에 불합리한 가중치로 인한 수렴 실패 방지

4. 튜닝 실습 예제

기본 지식:

len(dataloader): 배치 수 반환 (데이터셋 총 배치 개수)
len(dataloader.dataset): 데이터셋 샘플 수 반환

"""
MNIST 필기체 숫자 인식 하이퍼파라미터 튜닝 예제
기본 모델 (튜닝 전)
"""

import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
from torch import nn, optim
from torch.utils.data import DataLoader

# 하이퍼파라미터 정의
batch_dim = 64
hidden_dim = 64
learning_rate = 0.001
num_epochs = 10
input_dim = 784  # 28*28
output_dim = 10

# 손실 값 저장용 리스트
train_loss_history = []
test_loss_history = []

# 이미지 전처리 정의
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))
])

# 데이터셋 다운로드 및 전처리
train_data = dsets.MNIST(root="./MNIST_DATA", train=True, download=True, transform=transform)
test_data = dsets.MNIST(root="./MNIST_DATA", train=False, download=True, transform=transform)

# 데이터로더 설정
train_iter = DataLoader(train_data, batch_size=batch_dim, shuffle=True)
test_iter = DataLoader(test_data, batch_size=batch_dim, shuffle=False)


# 네트워크 구조 정의
class ClassificationNet(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(ClassificationNet, self).__init__()
        self.layer1 = nn.Linear(input_dim, hidden_dim)
        self.activation = nn.ReLU()
        self.layer2 = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = self.layer1(x.view(-1, input_dim))
        x = self.activation(x)
        x = self.layer2(x)
        return x


# 모델 인스턴스 생성
model = ClassificationNet(input_dim, hidden_dim, output_dim)

# 손실 함수 정의
criterion = nn.CrossEntropyLoss()

# 옵티마이저 정의
optimizer = optim.SGD(model.parameters(), lr=learning_rate)

# 훈련 수행
total_batches = len(train_iter)
for epoch in range(num_epochs):
    for batch_idx, (images, labels) in enumerate(train_iter):
        outputs = model(images)
        loss = criterion(outputs, labels)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        train_loss_history.append(loss.item())

        if (batch_idx + 1) % 100 == 0:
            print(f"Epoch [{epoch+1}/{num_epochs}], Step [{batch_idx+1}/{total_batches}], Train Loss: {loss.item():.4f}")

    # 평가 모드로 전환
    model.eval()

    with torch.no_grad():
        accumulated_test_loss = 0.0
        for images, labels in test_iter:
            outputs = model(images)
            loss = criterion(outputs, labels)
            accumulated_test_loss += loss.item() * images.size(0)

        average_test_loss = accumulated_test_loss / len(test_iter.dataset)
        test_loss_history.extend([average_test_loss] * total_batches)

    # 훈련 모드로 재전환
    model.train()

    print(f"Epoch [{epoch+1}/{num_epochs}], Test Loss: {average_test_loss:.4f}")

# 훈련 및 테스트 손실 곡선 시각화
plt.plot(train_loss_history, label="Train Loss")
plt.plot(test_loss_loss, label="Test Loss")
plt.title("Model Loss Curve")
plt.xlabel("Iterations")
plt.ylabel("Loss")
plt.legend()
plt.show()

튜닝 적용:

SGD 옵티마이저를 Adam 옵티마이저로 변경:

optimizer = optim.Adam(model.parameters(), lr=learning_rate)

배치 크기를 128로, 학습률을 0.0001로 변경하여 모델 성능 확인

정리

과대적합, 과소적합, 수렴 진동 또는 수렴 실패 발생 시 해당 튜닝 방법을 적용하여 최적의 결과를 도출하시기 바랍니다. 이미 잘-tuning된 백본 네트워크를 기반으로 모델을 수정하면 대부분의 파라미터가 이미 최적화되어 있으므로 모듈 추가에 집중하고, 성능이不佳하면 모듈을 교체하는 것을 권장합니다.

태그: deep-learning hyperparameter-tuning machine-learning neural-network PyTorch

7월 22일 20:07에 게시됨