메인 콘텐츠로 건너뛰기
Try in Colab 원하는 메트릭(예: 모델 정확도)을 충족하는 기계학습 모델을 찾는 과정은 일반적으로 여러 번의 반복 작업이 필요한 번거로운 일입니다. 설상가상으로, 특정 트레이닝 run에 어떤 하이퍼파라미터 조합을 사용해야 할지 막막할 때도 있습니다. W&B Sweeps를 사용하면 학습률, 배치 크기, 은닉층 수, 옵티마이저 유형 등 하이퍼파라미터 값의 조합을 자동으로 탐색하는 체계적이고 효율적인 방법을 구축할 수 있습니다. 이를 통해 원하는 메트릭을 기반으로 모델을 최적화하는 값을 찾을 수 있습니다. 이 튜토리얼에서는 W&B PyTorch 인테그레이션을 사용하여 하이퍼파라미터 탐색을 생성해 보겠습니다. 비디오 튜토리얼을 함께 시청하며 따라해 보세요.
하이퍼파라미터 스윕 결과

Sweeps 개요

W&B로 하이퍼파라미터 스윕을 실행하는 방법은 매우 간단합니다. 다음 3가지 단계만 거치면 됩니다:
  1. 스윕 정의: 탐색할 파라미터, 탐색 전략, 최적화 메트릭 등을 명시하는 사전(dictionary) 또는 YAML 파일을 생성합니다.
  2. 스윕 초기화: 한 행의 코드로 스윕을 초기화하고 스윕 구성 사전을 전달합니다: sweep_id = wandb.sweep(sweep_config)
  3. 스윕 에이전트 실행: 역시 한 행의 코드로 wandb.agent()를 호출하고, 실행할 sweep_id와 모델 아키텍처를 정의하고 트레이닝하는 함수를 함께 전달합니다: wandb.agent(sweep_id, function=train)

시작하기 전에

W&B를 설치하고 W&B Python SDK를 노트북으로 임포트하세요:
  1. !pip install로 설치:
!pip install wandb -Uq
  1. W&B 임포트:
import wandb
  1. W&B에 로그인하고 안내에 따라 API 키를 입력하세요:
wandb.login()

1단계: 스윕 정의

W&B Sweep은 수많은 하이퍼파라미터 값을 시도하는 전략과 이를 평가하는 코드를 결합합니다. 스윕을 시작하기 전에 _스윕 구성(sweep configuration)_을 통해 스윕 전략을 정의해야 합니다.
Jupyter Notebook에서 스윕을 시작하는 경우, 생성하는 스윕 구성은 중첩된 사전 형태여야 합니다.커맨드라인에서 스윕을 실행하는 경우, YAML 파일로 스윕 구성을 지정해야 합니다.

탐색 메소드 선택

먼저, 설정 사전 내에 하이퍼파라미터 탐색 메소드를 지정합니다. 그리드, 랜덤 검색, 베이지안 탐색의 세 가지 하이퍼파라미터 탐색 전략 중에서 선택할 수 있습니다. 이 튜토리얼에서는 랜덤 검색을 사용합니다. 노트북 내에서 사전을 생성하고 method 키에 random을 지정하세요.
sweep_config = {
    'method': 'random'
    }
최적화하려는 메트릭을 지정합니다. 랜덤 검색 메소드를 사용하는 스윕의 경우 메트릭과 목표를 반드시 지정할 필요는 없습니다. 하지만 나중에 참조할 수 있도록 스윕 목표를 기록해 두는 것이 좋습니다.
metric = {
    'name': 'loss',
    'goal': 'minimize'   
    }

sweep_config['metric'] = metric

탐색할 하이퍼파라미터 지정

스윕 구성에 탐색 메소드를 지정했으므로, 이제 탐색할 하이퍼파라미터를 지정합니다. 이를 위해 parameter 키에 하나 이상의 하이퍼파라미터 이름을 지정하고, value 키에 하나 이상의 하이퍼파라미터 값을 지정합니다. 특정 하이퍼파라미터에 대해 탐색하는 값은 조사 중인 하이퍼파라미터의 유형에 따라 달라집니다. 예를 들어, 기계학습 옵티마이저를 선택하는 경우 Adam 옵티마이저나 확률적 경사 하강법(SGD)과 같이 유한한 옵티마이저 이름들을 지정해야 합니다.
parameters_dict = {
    'optimizer': {
        'values': ['adam', 'sgd']
        },
    'fc_layer_size': {
        'values': [128, 256, 512]
        },
    'dropout': {
          'values': [0.3, 0.4, 0.5]
        },
    }

sweep_config['parameters'] = parameters_dict
때로는 하이퍼파라미터를 추적하고 싶지만 그 값을 변경하고 싶지 않을 때가 있습니다. 이 경우 스윕 구성에 해당 하이퍼파라미터를 추가하고 사용하려는 정확한 값을 지정하면 됩니다. 예를 들어, 다음 코드 셀에서 epochs는 1로 설정됩니다.
parameters_dict.update({
    'epochs': {
        'value': 1}
    })
random 탐색의 경우, 파라미터의 모든 values는 주어진 run에서 선택될 확률이 동일합니다. 또는 이름이 지정된 distribution과 함께 해당 파라미터(예: normal 분포의 평균 mu 및 표준 편차 sigma)를 지정할 수 있습니다.
parameters_dict.update({
    'learning_rate': {
        # 0과 0.1 사이의 균등 분포
        'distribution': 'uniform',
        'min': 0,
        'max': 0.1
      },
    'batch_size': {
        # 32와 256 사이의 정수
        # 고르게 분포된 로그 값 포함
        'distribution': 'q_log_uniform_values',
        'q': 8,
        'min': 32,
        'max': 256,
      }
    })
설정이 완료되면 sweep_config는 시도하려는 parameters와 이를 시도할 method를 정확히 명시하는 중첩된 사전이 됩니다. 스윕 구성이 어떻게 보이는지 확인해 보겠습니다:
import pprint
pprint.pprint(sweep_config)
전체 설정 옵션 목록은 스윕 구성 옵션을 참조하세요.
잠재적으로 무한한 옵션을 가진 하이퍼파라미터의 경우, 몇 가지 선택된 values를 시도하는 것이 일반적입니다. 예를 들어, 앞선 스윕 구성에는 layer_sizedropout 파라미터 키에 대해 유한한 값 목록이 지정되어 있습니다.

2단계: 스윕 초기화

탐색 전략을 정의했다면, 이제 이를 구현할 준비를 할 차례입니다. W&B는 하나 이상의 머신에서 로컬 또는 클라우드로 스윕을 관리하기 위해 스윕 컨트롤러를 사용합니다. 이 튜토리얼에서는 W&B에서 관리하는 스윕 컨트롤러를 사용합니다. 스윕 컨트롤러가 스윕을 관리하는 동안, 실제로 스윕을 실행하는 컴포넌트를 _스윕 에이전트_라고 합니다.
기본적으로 스윕 컨트롤러 컴포넌트는 W&B 서버에서 시작되며, 스윕을 생성하는 컴포넌트인 스윕 에이전트는 로컬 머신에서 활성화됩니다.
노트북 내에서 wandb.sweep 메소드로 스윕 컨트롤러를 활성화할 수 있습니다. 앞서 정의한 스윕 구성 사전을 sweep_config 필드에 전달하세요:
sweep_id = wandb.sweep(sweep_config, project="pytorch-sweeps-demo")
wandb.sweep 함수는 나중에 스윕을 활성화할 때 사용할 sweep_id를 반환합니다.
커맨드라인에서는 이 함수가 다음과 같이 대체됩니다.
wandb sweep config.yaml
터미널에서 W&B Sweeps를 생성하는 방법에 대한 자세한 내용은 W&B Sweep 연습을 참조하세요.

3단계: 기계학습 코드 정의

스윕을 실행하기 전에 시도하려는 하이퍼파라미터 값을 사용하는 트레이닝 절차를 정의합니다. 트레이닝 코드에 W&B Sweeps를 통합하는 핵심은 각 트레이닝 실험에 대해 트레이닝 로직이 스윕 구성에서 정의한 하이퍼파라미터 값에 엑세스할 수 있도록 하는 것입니다. 다음 코드 예시에서 헬퍼 함수인 build_dataset, build_network, build_optimizer, train_epoch는 스윕 하이퍼파라미터 설정 사전에 엑세스합니다. 노트북에서 다음 기계학습 트레이닝 코드를 실행하세요. 이 함수들은 PyTorch에서 기본적인 완전 연결 신경망을 정의합니다.
import torch
import torch.optim as optim
import torch.nn.functional as F
import torch.nn as nn
from torchvision import datasets, transforms

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

def train(config=None):
    # 새로운 wandb run 초기화
    with wandb.init(config=config) as run:
        # 아래와 같이 wandb.agent에 의해 호출되면,
        # 이 config는 스윕 컨트롤러에 의해 설정됩니다.
        config = run.config

        loader = build_dataset(config.batch_size)
        network = build_network(config.fc_layer_size, config.dropout)
        optimizer = build_optimizer(network, config.optimizer, config.learning_rate)

        for epoch in range(config.epochs):
            avg_loss = train_epoch(network, loader, optimizer)
            run.log({"loss": avg_loss, "epoch": epoch})           
train 함수 내에서 다음과 같은 W&B Python SDK 메소드를 확인할 수 있습니다:
  • wandb.init(): 새로운 W&B Run을 초기화합니다. 각 run은 트레이닝 함수의 단일 실행입니다.
  • run.config: 실험하려는 하이퍼파라미터가 포함된 스윕 구성을 전달합니다.
  • run.log(): 각 에포크에 대한 트레이닝 손실(loss)을 로그로 기록합니다.
이어지는 셀은 build_dataset, build_network, build_optimizer, train_epoch의 네 가지 함수를 정의합니다. 이 함수들은 기본적인 PyTorch 파이프라인의 표준적인 부분이며, 그 구현은 W&B 사용에 영향을 받지 않습니다.
def build_dataset(batch_size):
   
    transform = transforms.Compose(
        [transforms.ToTensor(),
         transforms.Normalize((0.1307,), (0.3081,))])
    # MNIST 트레이닝 데이터셋 다운로드
    dataset = datasets.MNIST(".", train=True, download=True,
                             transform=transform)
    sub_dataset = torch.utils.data.Subset(
        dataset, indices=range(0, len(dataset), 5))
    loader = torch.utils.data.DataLoader(sub_dataset, batch_size=batch_size)

    return loader


def build_network(fc_layer_size, dropout):
    network = nn.Sequential(  # 완전 연결, 단일 은닉층
        nn.Flatten(),
        nn.Linear(784, fc_layer_size), nn.ReLU(),
        nn.Dropout(dropout),
        nn.Linear(fc_layer_size, 10),
        nn.LogSoftmax(dim=1))

    return network.to(device)
        

def build_optimizer(network, optimizer, learning_rate):
    if optimizer == "sgd":
        optimizer = optim.SGD(network.parameters(),
                              lr=learning_rate, momentum=0.9)
    elif optimizer == "adam":
        optimizer = optim.Adam(network.parameters(),
                               lr=learning_rate)
    return optimizer


def train_epoch(network, loader, optimizer):
    cumu_loss = 0

    with wandb.init() as run:
        for _, (data, target) in enumerate(loader):
            data, target = data.to(device), target.to(device)
            optimizer.zero_grad()

            # ➡ forward 패스
            loss = F.nll_loss(network(data), target)
            cumu_loss += loss.item()

            # ⬅ backward 패스 + 가중치 업데이트
            loss.backward()
            optimizer.step()

            run.log({"batch loss": loss.item()})

    return cumu_loss / len(loader)
PyTorch와 W&B를 함께 사용하는 방법에 대한 자세한 내용은 이 Colab을 참조하세요.

4단계: 스윕 에이전트 활성화

스윕 구성을 정의하고 해당 하이퍼파라미터를 대화형 방식으로 활용할 수 있는 트레이닝 스크립트가 준비되었으므로, 이제 스윕 에이전트를 활성화할 준비가 되었습니다. 스윕 에이전트는 스윕 구성에서 정의한 하이퍼파라미터 값 세트를 사용하여 실험을 실행하는 역할을 합니다. wandb.agent 메소드로 스윕 에이전트를 생성하세요. 다음을 제공해야 합니다:
  1. 에이전트가 속한 스윕 (sweep_id)
  2. 스윕이 실행할 함수. 이 예시에서 스윕은 train 함수를 사용합니다.
  3. (선택 사항) 스윕 컨트롤러에 요청할 구성 수 (count)
서로 다른 컴퓨팅 리소스에서 동일한 sweep_id로 여러 스윕 에이전트를 시작할 수 있습니다. 스윕 컨트롤러는 에이전트들이 정의한 스윕 구성에 따라 협력하여 작동하도록 보장합니다.
다음 셀은 트레이닝 함수(train)를 5번 실행하는 스윕 에이전트를 활성화합니다:
wandb.agent(sweep_id, train, count=5)
스윕 구성에서 random 탐색 메소드가 지정되었으므로, 스윕 컨트롤러는 무작위로 생성된 하이퍼파라미터 값을 제공합니다.
터미널에서 W&B Sweeps를 생성하는 방법에 대한 자세한 내용은 W&B Sweep 연습을 참조하세요.

스윕 결과 시각화

평행 좌표 차트 (Parallel Coordinates Plot)

이 차트는 하이퍼파라미터 값을 모델 메트릭에 매핑합니다. 최적의 모델 성능으로 이어진 하이퍼파라미터 조합을 집중적으로 파악하는 데 유용합니다.
스윕 에이전트 실행 결과

하이퍼파라미터 중요도 차트 (Hyperparameter Importance Plot)

하이퍼파라미터 중요도 차트는 어떤 하이퍼파라미터가 메트릭을 가장 잘 예측했는지 보여줍니다. 특성 중요도(랜덤 포레스트 모델에서 추출)와 상관관계(암시적으로 선형 모델 사용)를 리포트합니다.
W&B 스윕 대시보드
이러한 시각화는 가장 중요하고 추가 탐색 가치가 있는 파라미터(및 값 범위)를 좁혀줌으로써 비용이 많이 드는 하이퍼파라미터 최적화 실행 시 시간과 리소스를 모두 절약하는 데 도움이 됩니다.

W&B Sweeps에 대해 더 알아보기

직접 실행해 볼 수 있도록 간단한 트레이닝 스크립트와 몇 가지 형태의 스윕 구성을 준비했습니다. 꼭 시도해 보시길 권장합니다. 해당 레포지토리에는 Bayesian HyperbandHyperopt와 같은 고급 스윕 기능을 사용하는 데 도움이 되는 예제도 포함되어 있습니다.