// 문제 상황
거두절미하고 우선 아래 링크를 보자.
https://discuss.pytorch.org/t/how-to-add-graphs-to-hparams-in-tensorboard/109349/2
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스크립트를 여러번 돌리면 서치가 가능하겠다.
끝.
'딥러닝 머신러닝 데이터 분석 > PyTorch' 카테고리의 다른 글
[ PyTorch ] DataLoader 잘 짜서 병목 극복하기, GPU util 높이기 (2) | 2021.08.26 |
---|
댓글