본문 바로가기
딥러닝 머신러닝 데이터 분석/PyTorch

[PyTorch 삽질] pytorch tensoboard에서 hparams 기능 100% 활용하기

by SteadyForDeep 2021. 9. 8.
반응형

// 문제 상황

 

거두절미하고 우선 아래 링크를 보자.

https://discuss.pytorch.org/t/how-to-add-graphs-to-hparams-in-tensorboard/109349/2

 

How to add graphs to hparams in tensorboard?

Having dug a little deeper into torch.utils.tensorboard, I can’t seem to find how to use this functionality. However I can achieve it by modifying the SummaryWriter.add_hparams() function as such: def add_hparams(self, hparam_dict, metric_dict, hparam_do

discuss.pytorch.org

 

wandb로 갈아타는게 정신건강에 이롭겠지만 텐서보드도 만만치 않게 유용하니까

이때까지 사용해온 지식들을 어딘가에 묻어둬야 나중에 어쩔 수 없을 때 파 볼 수 있다.

 

파이토치에서 텐서보드를 쓰면서 가장 불편했던 점은

바로 hyperparameter를 search 하고 기록을 남길 때 였는데

기록하는 함수의 구조상 metric이든 loss든

가장 마지막에 찍힌 스칼라값 하나만 점으로 띡 찍어버리고 끝나서

이게 오버피팅이 난건지 아닌지 알 수도 없고

더 훈련을 시켜볼 만한지 아닌지 알 수가 없었기 때문이다.

 

점 하나 남기고 떠나가신 님

 

위의 링크에서도 그런 상황을 잘 지적하고있고 해결법까지 멋지게 알려주고 있다.

이걸 해결하는 과정을 생략해서 간단해 보이는거지 생각보다 간단하지는 않았다.

파이토치에서 공식적으로 함수를 바꿔서 릴리즈하기 전까지는

어떤 환경에서도 수정이 가능해야하므로 그런 점에 집중해서 글을 작성해보고자 한다.

 

// 해결 방법

위의 링크에 다 나와있다. 

torch.utils.tensorboard 에서 제공하는 SummaryWriter객체로 가서 add_hparams를 수정한다.

 

// 자세하게

가장 큰 문제는 add_hparams로 기록한 실험은 디렉토리를 따로 만들어서 저장되고

add_scalar로 기록한 실험은 tag만 달라지면서 기록된다는 것이다.

따라서 add 어쩌구 메소드들의 디렉토리를 통일하던가 아니면

태그를 통일하던가 하는 작업으로 문제를 해결할 수 있다.

 

그러기 위해서는 내 torch가 어디에 깔려있는지 알아내야한다.

pip show torch

pip로 다운로드 받았다면 show 명령어를 통해서 자세한 스팩을 알 수 있다.

나는 요렇게 나오고 location을 보면 위치를 알 수 있다.

pip로 깔지 않은 사람은 에러를 발생시키면 해당 함수가 어디 있는지 파이썬이 알려준다.

SummaryWriter를 아무거나 하나 만들어서 None 같은걸 집어넣으면

어디서 에러가 발생했는지 알려주려고 저렇게 writer.py 의 위치를 알려준다.

아무튼 저 위치의 writer.py 파일을 열어준다.

위치를 복사하고 vim 으로 열면 편하다.

그러면 torch의 docs 와 똑같은 파일이 하나 열린다.

여기서 313 라인으로 가거나 add_hparams 를 검색해서 이동한다.

그리고 위에 주석처리한 부분을 지우거나 주석으로 바꿔서

내가 writer를 만들때 처음 지정한 로그 위치에 저장하도록 한다.

이때 with 문에 있는 log_dir을 self.log_dir 로 바꿔주는 것도 잊지 말자.

그리고 더 중요한 부분은 아래 metric_dict를 까서 add_scalar로 저장하는 부분인데

저 부분을 저렇게 if 문으로 None이 아닌 경우에만 기록하도록 바꿔줘야 한다.

 

이유는 동일한 위치에 내가 iteration이나 epoch 마다 scalar를 저장해 뒀는데

저런식으로 덮어써 버리면 그냥 점만 하나 띡 찍히는 상황이 또 연출되기 때문.

 

아래의 코드를 통해서 어떻게 기록되는지 간단하게 테스트해 볼 수 있다.

import numpy as np
from torch.utils.tensorboard import SummaryWriter

LEARNING_RATE = [1, 0.1, 0.01, 0.001, 0.0001, 0.00001]
BATCH_SIZE = [1, 10, 100, 1000, 10000, 100000]
WEIGHT_DECAY = [1,2,3,4,5]

for i in range(5):
    train_writer = SummaryWriter(f'logs/exp_number_{i}/train')
    val_writer = SummaryWriter(f'logs/exp_number_{i}/validation')
    
    for gstep in range(100):
        train_loss = np.random.randn(1)
        train_metric = np.random.randn(1)
        train_writer.add_scalar("loss", train_loss, global_step = gstep)
        train_writer.add_scalar("metric", train_metric, global_step = gstep)
        
        val_loss = np.random.randn(1)
        val_metric = np.random.randn(1)
        val_writer.add_scalar("loss", val_loss, global_step = gstep)
        val_writer.add_scalar("metric", val_metric, global_step = gstep)
        
    val_writer.add_hparams(
        {
            "learning_rate": LEARNING_RATE[i],
            "batch_size"   : BATCH_SIZE[i],
            "weight_decay" : WEIGHT_DECAY[i],
        },
        {
            "loss"   : None,
            "metric" : None
        },
         run_name = None
    )

어째서 이렇게 설계를 해 둔 것인지는 참 알 수 없지만 일단은 꽁짜니까.... 불평하지 않고 그냥 고생해서 쓰는게 좋겠다.

위의 코드를 실행하면

 

train과 validation이 잘 겹쳐져 보이고

 

요렇게 hyperparameter 마다 loss와 metric도 볼 수 있고

 

맨 마지막에 찍힌 loss와 metric을 이용해서 parallel cooedinater도 볼 수 있다.

쉘 스크립트를 이용해서 py스크립트를 여러번 돌리면 서치가 가능하겠다.

 

끝.

반응형

댓글