티스토리 뷰

반응형

Weights & Biases란?

wandb는 MLOps 플랫폼으로 머신러닝, 딥러닝을 학습하는데 필요한 다양한 기능들을 제공한다. 대표적으로 아래의 기능등을 갖추고 있다.

  • 실험관리
  • 하이퍼파라미터 튜닝
  • 데이터, 모델 버저닝
  • 모델 관리
  • 데이터 시각화
  • 협업 리포트

wandb 기초 사용법

pytorch를 사용하여 학습하는 환경에서 wandb를 이용해서 필요한 metric의 log를 기록하고, 그래프 형태로 확인하는 것을 먼저 알아본다.

코랩 샘플 링크를 통해서 pytorch에서 사용하는 기본적인 wandb 사용법을 익힐 수 있다.

W&B 설치

  • wandb.ai 에 접속하여 회원가입하면 API key를 발급받을 수 있다.
  • pip을 통해 wandb를 설치하고 위에서 발급받은 API key로 로그인을 한다.
pip3 install wandb
wandb login # API key 입력

pytorch에서 W&B 사용하기

  • 아래 코드를 통해 프로젝트를 wandb에 등록해준다.
  • 기존에 같은 이름으로 등록된 project가 없으면 wandb에서 새로 생성하고, 기존에 등록된 project가 있으면 같은 project끼리 묶어 실험 결과를 비교할 수 있다.
import wandb
wandb.init(project='project-name')
  • config 설정
    • metric으로 log를 기록하거나, 추후에 파라미터 튜닝에 필요한 변수들을 wandb.config에 넣어준다.
    • wandb.config에 담긴 파라미터 값들은 wandb 웹에서 모두 확인할 수 있다.
# init config setting
wandb.config = {
  "learning_rate": 0.001,
  "epochs": 5,
  "batch_size": 128
}
  • 학습 중 metric 기록하기
    • wandb.log 함수를 통해 metric 값들을 logging할 수 있다.
    • log 함수의 파라미터는 항상 dictionary 형태로 들어가야 한다.
wandb.log({"loss": loss,
					 "acc": acc})
  • alert 알람 보내기(wandb 설정에서 슬랙이나 이메일 체크하여 사용)
wandb.alert(title='제목', text='내용')
학습이 끝났을때, 에러로 중단됐을때, wandb.alert()를 호출했을 때 Email을 보내준다.

기타 상세 사용방법

wandb.init 관련 사용법

  • run name 알거나 지정하고 싶을때
  • 직접 지정하면 sequence 번호가 적히지 않음(like snowy-owl-10→snowy-owl)
import wandb

wandb.init()

# get run name
run_name = wandb.run.name 

# set run name
wandb.run.name = '원하는 이름'
wandb.run.save()
  • 실험단위로 간단한 메모
    • notes, tags를 통해서 하면 됨
    • tags는 리스트 형태로 넣어 줌
wandb.init(
  project="mnist",
  notes="baseline",
  tags=["custom loss", "custom optimizer"],
)

wandb.config 관련 사용법

  • config 지정하는 다양한 방법
# init set
wandb.config = {'lr':1e-3}
# later set
wandb.config.update({"drop_rate":0.5})

# argparse를 사용할 때
args = parser.parse_args()
wandb.config.update(args)
  • unique identifier를 추가해서 config로 실험을 tracking 하는 방법이 있다.
wandb.config.update({'dataset': 'ver1'})
  • 이미 업로드한 config 파일을 추후에 수정하여 업데이트 할 수 있다.
import wandb
api = wandb.Api()
run = api.run("username/project/run_id")
run.config["foo"] = 32
run.update()

wandb.log 상세 사용법

  • wandb.log(dict) 형태로 어떤 metric, media, custom object 등 다양한 값들을 log할 수 있다.
wandb.log({"loss": 0.314, "epoch": 5,
           "inputs": wandb.Image(inputs),
           "logits": wandb.Histogram(ouputs),
           "captions": wandb.Html(captions)})
  • 기본적으로 wandb 차트의 x축은 자동적으로 step을 지정한다. epoch, step과 같이 custom 값으로 x축을 지정할 수도 있고, step 파라미터를 넣어서 x축 값을 넣어줄 수 있다.
    • (추천) step 파라미터를 넣어서 현재의 step(x축)을 알려줌
    wandb.log({'train_loss':train_loss}, step=epoch)
    • epoch을 따로 log함 (wandb UI 차트에서 따로 x축 지정을 해줘야함)
    wandb.log({'train_loss':train_loss, 'epoch':epoch})
  • best value 값을 summary에 지정하지 않으면 summary에는 마지막값이 입력된다. 따라서 실험간 metric을 비교하고 싶으면 best 값을 summary에 입력해 준다.
wandb.run.summary['best_accuracy'] = best_accuracy
  • summary를 customize 하여 자동으로 원하는 operation에 따라 summary값을 지정해준다.
    • 지원 summary 방법: min, max, mean, best, last, none
import wandb

wandb.init()
wandb.define_metric("loss", summary="min")
wandb.define_metric("acc", summary="max")
for i in range(10):
  log_dict = {
      "loss": random.uniform(0,1/(i+1)),
      "acc": random.uniform(1/(i+1),1),
  }
  wandb.log(log_dict)

실제 적용 예시

  • 아래 코드는 pytorch에서 제공하는 fashion mnist 학습하는 코드에 wandb를 추가한 코드이다.
  • Fishion MNIST Training Code with WandB
    import torch
    from torch import nn
    from torch.utils.data import DataLoader
    from torchvision import datasets
    from torchvision.transforms import ToTensor
    import wandb
    
    # init wandb settings
    run = wandb.init(project="f-mnist")
    
    cfg = {
        "learning_rate": 1e-3,
        "epochs": 5,
        "batch_size": 64
    }
    wandb.config.update(cfg)
    
    # Download training data from open datasets.
    training_data = datasets.FashionMNIST(
        root="data",
        train=True,
        download=True,
        transform=ToTensor(),
    )
    
    # Download test data from open datasets.
    test_data = datasets.FashionMNIST(
        root="data",
        train=False,
        download=True,
        transform=ToTensor(),
    )
    
    # Create data loaders.
    train_dataloader = DataLoader(training_data, batch_size=cfg['batch_size'])
    test_dataloader = DataLoader(test_data, batch_size=cfg['batch_size'])
    
    for X, y in test_dataloader:
        print(f"Shape of X [N, C, H, W]: {X.shape}")
        print(f"Shape of y: {y.shape} {y.dtype}")
        break
    
    # Get cpu or gpu device for training.
    device = "cuda" if torch.cuda.is_available() else "cpu"
    print(f"Using {device} device")
    
    # Define model
    class NeuralNetwork(nn.Module):
        def __init__(self):
            super(NeuralNetwork, self).__init__()
            self.flatten = nn.Flatten()
            self.linear_relu_stack = nn.Sequential(
                nn.Linear(28 * 28, 512),
                nn.ReLU(),
                nn.Linear(512, 512),
                nn.ReLU(),
                nn.Linear(512, 10)
            )
    
        def forward(self, x):
            x = self.flatten(x)
            logits = self.linear_relu_stack(x)
            return logits
    
    
    model = NeuralNetwork().to(device)
    print(model)
    
    loss_fn = nn.CrossEntropyLoss()
    optimizer = torch.optim.SGD(model.parameters(), lr=cfg['learning_rate'])
    
    
    def train(dataloader, model, loss_fn, optimizer, epoch):
        size = len(dataloader.dataset)
        model.train()
        total_loss = 0
        for batch, (X, y) in enumerate(dataloader):
            X, y = X.to(device), y.to(device)
    
            # Compute prediction error
            pred = model(X)
            loss = loss_fn(pred, y)
            total_loss += loss.item()
    
            # Backpropagation
            optimizer.zero_grad()
            loss.backward()
            optimizer.step()
    
            if batch % 100 == 0:
                loss, current = loss.item(), batch * len(X)
                print(f"loss: {loss:>7f}  [{current:>5d}/{size:>5d}]")
    
        wandb.log({"train_loss": total_loss / len(dataloader)}, step=epoch)
    
    
    def test(dataloader, model, loss_fn, epoch):
        size = len(dataloader.dataset)
        num_batches = len(dataloader)
        model.eval()
        test_loss, correct = 0, 0
        with torch.no_grad():
            for X, y in dataloader:
                X, y = X.to(device), y.to(device)
                pred = model(X)
                test_loss += loss_fn(pred, y).item()
                correct += (pred.argmax(1) == y).type(torch.float).sum().item()
        test_loss /= num_batches
        correct /= size
        print(f"Test Error: \n Accuracy: {(100*correct):>0.1f}%, Avg loss: {test_loss:>8f} \n")
        wandb.log({"test_loss": test_loss, "test_acc": correct}, step=epoch)
    
    epochs = cfg['epochs']
    for t in range(epochs):
        print(f"Epoch {t+1}\n-------------------------------")
        train(train_dataloader, model, loss_fn, optimizer, t)
        test(test_dataloader, model, loss_fn, t)
    print("Done!")
    
    torch.save(model.state_dict(), "model.pth")
    print("Saved PyTorch Model State to model.pth")
    
    model = NeuralNetwork()
    model.load_state_dict(torch.load("model.pth"))
    
    classes = [
        "T-shirt/top",
        "Trouser",
        "Pullover",
        "Dress",
        "Coat",
        "Sandal",
        "Shirt",
        "Sneaker",
        "Bag",
        "Ankle boot",
    ]
    
    model.eval()
    x, y = test_data[0][0], test_data[0][1]
    with torch.no_grad():
        pred = model(x)
        predicted, actual = classes[pred[0].argmax(0)], classes[y]
        print(f'Predicted: "{predicted}", Actual: "{actual}"')

Uploaded by N2T

반응형
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday