일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Jupyter notebook
- WSSS
- docker attach
- cs231n
- HookNet
- IVI
- vscode
- numpy
- Decision Boundary
- aiffel exploration
- docker
- AIFFEL
- docker exec
- 도커
- 프로그래머스
- CellPin
- airflow
- 기초확률론
- GIT
- cocre
- Multi-Resolution Networks for Semantic Segmentation in Whole Slide Images
- ssh
- 백신후원
- logistic regression
- 코크리
- 티스토리챌린지
- Pull Request
- 사회조사분석사2급
- 히비스서커스
- 오블완
Archives
- Today
- Total
히비스서커스의 블로그
[error] ValueError: CategoricalDistribution does not support dynamic value space. (feat. 파이썬 내장함수 getattr() 활용) 본문
Programming/Python
[error] ValueError: CategoricalDistribution does not support dynamic value space. (feat. 파이썬 내장함수 getattr() 활용)
HibisCircus 2022. 5. 23. 22:39728x90
optuna를 통해 최적의 하이퍼 파라미터를 찾는 코드를 작성 후 실행하다가 에러를 마주하였다. 먼저, 실행하였던 코드들을 간략하게 정리해보겠다.
실행하고 있던 코드가 나와있는 원문
라이브러리를 불러오고 dataloader 함수를 작성한다.
from __future__ import print_function
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
def get_mnist_loaders(train_batch_size, test_batch_size):
"""Get MNIST data loaders"""
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=train_batch_size, shuffle=True)
test_loader = torch.utils.data.DataLoader(
datasets.MNIST('../data', train=False, transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=test_batch_size, shuffle=True)
return train_loader, test_loader
다음으로 실행시킬 network 함수를 작성한다.
class Net(nn.Module):
def __init__(self, activation):
super(Net, self).__init__()
self.conv1 = nn.Conv2d(1, 32, 3, 1)
self.conv2 = nn.Conv2d(32, 64, 3, 1)
self.dropout1 = nn.Dropout2d(0.25)
self.dropout2 = nn.Dropout2d(0.5)
self.fc1 = nn.Linear(9216, 128)
self.fc2 = nn.Linear(128, 10)
self.activation = activation
def forward(self, x):
x = self.activation(self.conv1(x))
x = self.conv2(x)
x = F.max_pool2d(x, 2)
x = self.dropout1(x)
x = torch.flatten(x, 1)
x = self.activation(self.fc1(x))
x = self.dropout2(x)
x = self.fc2(x)
output = F.log_softmax(x, dim=1)
return output
다음으로 network를 통해 train하는 함수와 test하는 함수를 작성한다.
def train(log_interval, model, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data.to(device)
loss = F.nll_loss(output, target.to(device)
loss.backward()
optimizer.step()
if batch_idx % log_interval == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
def test(model, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
output = model(data.to(device)
test_loss += F.nll_loss(output, target.to(device), reduction='sum').item() # sum up batch loss
pred = output.argmax(dim=1, keepdim=True) # get the index of the max log-probability
correct += pred.eq(target.to(device).view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
test_accuracy = 100. * correct / len(test_loader.dataset))
print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
test_loss, correct, len(test_loader.dataset),
100. * correct / len(test_loader.dataset)))
return test_accuracy
return
이제 optuna를 통해 'lr', 'momentum', 'optimizer'에서 최적의 값을 찾아보기 위해 아래와 같은 코드를 작성 후 실행한다.
def train_mnist(trial):
cfg = { 'device' : "cuda" if torch.cuda.is_available() else "cpu",
'train_batch_size' : 64,
'test_batch_size' : 1000,
'n_epochs' : 1,
'seed' : 0,
'log_interval' : 100,
'save_model' : False,
'lr' : trial.suggest_loguniform('lr', 1e-3, 1e-2),
'momentum' : trial.suggest_uniform('momentum', 0.4, 0.99),
'optimizer': trial.suggest_categorical('optimizer',[optim.SGD, optim.RMSprop]),
'activation': F.relu}
torch.manual_seed(cfg['seed'])
train_loader, test_loader = get_mnist_loaders(cfg['train_batch_size'], cfg['test_batch_size'])
model = Net(cfg['activation']).to(device)
optimizer = cfg['optimizer'](model.parameters(), lr=cfg['lr'])
for epoch in range(1, cfg['n_epochs'] + 1):
train(cfg['log_interval'], model, train_loader, optimizer, epoch)
test_accuracy = test(model, test_loader)
if cfg['save_model']:
torch.save(model.state_dict(), "mnist_cnn.pt")
return test_accuracy
if __name__ == '__main__':
study = optuna.create_study(sampler=optuna.samplers.TPESampler(), direction='maximize')
study.optimize(train_mnist, n_trials=20, direction='maximize')
joblib.dump(study, '/content/gdrive/My Drive/Colab_Data/studies/mnist_optuna.pkl')
이때, 다음과 같은 에러가 발생하였다.
ValueError: CategoricalDistribution does not support dynamic value space.
확실하지는 않지만 cfg에 들어가는 값들은 특정 값 (int, str 등) 이어야지 함수나 메서드 같은 것들로 설정하면 안되는 듯 하다. 따라서, 위 cfg의
'optimizer': trial.suggest_categorical('optimizer',[optim.SGD, optim.RMSprop]),
부분에서 optim,SGD, optim,RMSprop 부분이 특정 값으로 들어가야 한다. 이때, 활용할 수 있는 파이썬 내장함수로 getattr()이 있다.
getattr()란?
이름에 해당하는 객체 속성의 값을 가져오는 Build-in 함수이다.
getattr(object, name[, default])
위에 적용해보자면 optim.SGD와 같이 불러왔던 것을 getattr(optim, 'SGD')와 같이 활용할 수 있다는 것이다.
이제 getattr()을 적용하여 train_mnist에서 두 곳을 바꿔주면 코드가 잘 돌아갈 수 있게 된다.
# 바꾸기 전
'optimizer': trial.suggest_categorical('optimizer',[optim.SGD, optim.RMSprop]),
optimizer = cfg['optimizer'](model.parameters(), lr=cfg['lr'])
# 바꾼 후
'optimizer': trial.suggest_categorical('optimizer',['SGD', 'RMSprop']),
optimizer = getattr(optim, cfg['optimizer'])(model.parameters(), lr=cfg['lr'])
getattr()이란 내장함수가 존재하는지도 몰랐으나 optuna를 사용하는 상황과 같이 특정 상황일 때 잘 활용하면 유용하게 쓸 수 있을 듯 하다.
-히비스서커스-
728x90