🤖 AI/ML

하이퍼파라미터

Hyperparameter

학습 전 설정하는 파라미터. 학습률, 배치 크기, 에포크 수 등. 튜닝으로 성능 최적화.

📖 상세 설명

하이퍼파라미터(Hyperparameter)는 머신러닝 모델의 학습 과정을 제어하는 외부 설정값입니다. 모델이 데이터로부터 학습하는 가중치(weight)와 달리, 하이퍼파라미터는 학습 전에 사람이 직접 설정해야 합니다. 대표적인 예로 학습률(learning rate), 배치 크기(batch size), 에포크 수(epochs), 은닉층 수(hidden layers), 드롭아웃 비율(dropout rate) 등이 있습니다. 하이퍼파라미터 선택은 모델 성능에 결정적인 영향을 미칩니다.

하이퍼파라미터의 종류는 크게 세 가지로 나눌 수 있습니다. 첫째, 모델 구조 관련 - 레이어 수, 뉴런 수, 필터 크기, Attention 헤드 수 등 아키텍처를 결정합니다. 둘째, 학습 알고리즘 관련 - 학습률, 옵티마이저 종류(Adam, SGD), 모멘텀, 가중치 감쇠(weight decay) 등이 있습니다. 셋째, 정규화 관련 - 드롭아웃, L1/L2 정규화 계수, 조기 종료(early stopping) 인내값 등 과적합을 방지합니다.

2024-2025년 LLM 시대에도 하이퍼파라미터는 여전히 중요합니다. GPT-4, Claude 같은 대형 모델은 수조 개의 파라미터를 가지지만, 이를 학습하거나 파인튜닝할 때 학습률 스케줄, 워밍업 스텝, 그래디언트 클리핑 임계값 같은 하이퍼파라미터가 성공을 좌우합니다. LoRA 파인튜닝에서는 rank, alpha, target modules 같은 새로운 하이퍼파라미터가 등장했습니다.

하이퍼파라미터와 파라미터의 차이를 명확히 이해해야 합니다. 파라미터(가중치)는 모델이 데이터로부터 학습하는 값으로, 신경망의 W와 b가 여기에 해당합니다. 하이퍼파라미터는 학습 과정 자체를 설정하는 값으로, 이 값에 따라 파라미터가 어떻게 업데이트될지가 결정됩니다. 예를 들어 학습률 0.001과 0.01은 동일한 아키텍처에서도 완전히 다른 최종 모델을 만들어냅니다.

💻 코드 예제

PyTorch에서 주요 하이퍼파라미터를 설정하고 관리하는 예제입니다.

import torch
import torch.nn as nn
import torch.optim as optim
from dataclasses import dataclass
from typing import Optional

@dataclass
class HyperParameters:
    """모델 학습을 위한 하이퍼파라미터 설정"""
    # 모델 구조 하이퍼파라미터
    hidden_dim: int = 256
    num_layers: int = 3
    num_heads: int = 8  # Transformer용
    dropout: float = 0.1

    # 학습 알고리즘 하이퍼파라미터
    learning_rate: float = 1e-4
    weight_decay: float = 0.01
    batch_size: int = 32
    num_epochs: int = 100

    # 옵티마이저 하이퍼파라미터
    optimizer: str = "adamw"  # adam, sgd, adamw
    beta1: float = 0.9
    beta2: float = 0.999
    momentum: float = 0.9  # SGD용

    # 학습률 스케줄러 하이퍼파라미터
    scheduler: str = "cosine"  # cosine, step, linear
    warmup_steps: int = 1000
    min_lr: float = 1e-6

    # 정규화 하이퍼파라미터
    gradient_clip: float = 1.0
    early_stopping_patience: int = 10
    label_smoothing: float = 0.1

    # LoRA 파인튜닝 하이퍼파라미터 (LLM용)
    lora_rank: int = 8
    lora_alpha: int = 16
    lora_dropout: float = 0.05

class SimpleMLP(nn.Module):
    """하이퍼파라미터 기반 MLP 모델"""
    def __init__(self, input_dim: int, output_dim: int, hp: HyperParameters):
        super().__init__()
        layers = []
        dims = [input_dim] + [hp.hidden_dim] * hp.num_layers + [output_dim]

        for i in range(len(dims) - 1):
            layers.append(nn.Linear(dims[i], dims[i+1]))
            if i < len(dims) - 2:  # 마지막 층 제외
                layers.append(nn.ReLU())
                layers.append(nn.Dropout(hp.dropout))

        self.network = nn.Sequential(*layers)

    def forward(self, x):
        return self.network(x)

def create_optimizer(model: nn.Module, hp: HyperParameters) -> optim.Optimizer:
    """하이퍼파라미터에 따른 옵티마이저 생성"""
    if hp.optimizer == "adam":
        return optim.Adam(
            model.parameters(),
            lr=hp.learning_rate,
            betas=(hp.beta1, hp.beta2),
            weight_decay=hp.weight_decay
        )
    elif hp.optimizer == "adamw":
        return optim.AdamW(
            model.parameters(),
            lr=hp.learning_rate,
            betas=(hp.beta1, hp.beta2),
            weight_decay=hp.weight_decay
        )
    elif hp.optimizer == "sgd":
        return optim.SGD(
            model.parameters(),
            lr=hp.learning_rate,
            momentum=hp.momentum,
            weight_decay=hp.weight_decay
        )
    else:
        raise ValueError(f"Unknown optimizer: {hp.optimizer}")

def create_scheduler(optimizer: optim.Optimizer, hp: HyperParameters, total_steps: int):
    """학습률 스케줄러 생성"""
    if hp.scheduler == "cosine":
        return optim.lr_scheduler.CosineAnnealingLR(
            optimizer,
            T_max=total_steps - hp.warmup_steps,
            eta_min=hp.min_lr
        )
    elif hp.scheduler == "step":
        return optim.lr_scheduler.StepLR(
            optimizer,
            step_size=total_steps // 3,
            gamma=0.1
        )
    elif hp.scheduler == "linear":
        return optim.lr_scheduler.LinearLR(
            optimizer,
            start_factor=1.0,
            end_factor=hp.min_lr / hp.learning_rate,
            total_iters=total_steps
        )

def train_with_hyperparameters(
    model: nn.Module,
    train_loader,
    hp: HyperParameters
):
    """하이퍼파라미터를 사용한 학습 루프"""
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    model = model.to(device)

    criterion = nn.CrossEntropyLoss(label_smoothing=hp.label_smoothing)
    optimizer = create_optimizer(model, hp)

    total_steps = len(train_loader) * hp.num_epochs
    scheduler = create_scheduler(optimizer, hp, total_steps)

    best_loss = float('inf')
    patience_counter = 0

    for epoch in range(hp.num_epochs):
        model.train()
        epoch_loss = 0.0

        for batch_idx, (data, target) in enumerate(train_loader):
            data, target = data.to(device), target.to(device)

            optimizer.zero_grad()
            output = model(data)
            loss = criterion(output, target)
            loss.backward()

            # 그래디언트 클리핑 적용
            torch.nn.utils.clip_grad_norm_(model.parameters(), hp.gradient_clip)

            optimizer.step()
            scheduler.step()

            epoch_loss += loss.item()

        avg_loss = epoch_loss / len(train_loader)
        print(f"Epoch {epoch+1}/{hp.num_epochs}, Loss: {avg_loss:.4f}, LR: {scheduler.get_last_lr()[0]:.2e}")

        # 조기 종료 체크
        if avg_loss < best_loss:
            best_loss = avg_loss
            patience_counter = 0
        else:
            patience_counter += 1
            if patience_counter >= hp.early_stopping_patience:
                print(f"Early stopping at epoch {epoch+1}")
                break

# 사용 예시
if __name__ == "__main__":
    # 하이퍼파라미터 설정
    hp = HyperParameters(
        hidden_dim=512,
        num_layers=4,
        learning_rate=3e-4,
        batch_size=64,
        dropout=0.2
    )
    print(f"하이퍼파라미터: {hp}")

    # 모델 생성
    model = SimpleMLP(input_dim=784, output_dim=10, hp=hp)
    print(f"모델 파라미터 수: {sum(p.numel() for p in model.parameters()):,}")

📊 주요 하이퍼파라미터 가이드

하이퍼파라미터 일반적 범위 높으면 낮으면
Learning Rate 1e-5 ~ 1e-2 빠른 학습, 발산 위험 느린 수렴, 안정적
Batch Size 16 ~ 512 빠른 학습, 일반화 저하 노이즈, 일반화 향상
Dropout 0.1 ~ 0.5 과적합 방지, 언더피팅 과적합 위험
Weight Decay 1e-5 ~ 1e-2 작은 가중치, 과적합 방지 과적합 위험
Hidden Dim 64 ~ 4096 높은 표현력, 과적합 언더피팅

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"학습 초반에 loss가 발산하는 건 learning rate이 너무 높아서예요. 1e-4에서 시작해서 워밍업을 1000 스텝 정도 주고, 코사인 스케줄러로 점진적으로 줄여보겠습니다."
💬 면접에서
"하이퍼파라미터는 모델이 학습하지 않고 사람이 설정하는 값입니다. Learning rate, batch size, layer 수 등이 있고, 이 값들이 최종 모델 파라미터가 어떻게 학습될지를 결정합니다. Grid Search, Random Search, Bayesian Optimization 등으로 최적값을 찾습니다."
💬 기술 토론에서
"LoRA 파인튜닝에서 rank는 압축률을, alpha는 스케일링을 조절해요. rank=8, alpha=16이 기본인데, 복잡한 태스크는 rank=32까지 올려야 할 수도 있어요. alpha/rank 비율이 학습 강도를 결정합니다."

⚠️ 흔한 실수 & 주의사항

모든 하이퍼파라미터를 한 번에 변경

여러 하이퍼파라미터를 동시에 바꾸면 어떤 변경이 성능에 영향을 줬는지 알 수 없습니다. 한 번에 하나씩 변경하고 효과를 측정하세요.

테스트 세트로 하이퍼파라미터 튜닝

테스트 세트 성능으로 하이퍼파라미터를 선택하면 테스트 세트에 과적합됩니다. 반드시 검증 세트(validation set)를 별도로 사용하세요.

실험 로깅과 재현성 확보

모든 하이퍼파라미터와 결과를 기록하세요. Weights & Biases, MLflow 같은 도구로 실험을 추적하고, random seed를 고정해 재현 가능하게 만드세요.

🔗 관련 용어

📚 더 배우기