Skip to content

Latest commit

 

History

History
329 lines (245 loc) · 9.43 KB

10-3. visdom.md

File metadata and controls

329 lines (245 loc) · 9.43 KB

1. Visdom 설치

  • pip install visdom



2. Visdom 서버 켜기

  • 프롬프트 들어가서 -> python -m visdom.server -> 나온 서버 명 주소창에 입력



3. Visdom 심플 예제

  • 쥬피터 노트북과 Visdom 서버를 동시에 켜 놓고 예제를 진행한다.
  • 코드는 쥬피터 노트북에 작성하고, Visdom 서버를 통해 시각화를 확인한다.

(1) 라이브러리 로드

import torch
import torch.nn as nn
import torchvision
import torchvision.datasets as dsets

(2) Visdom 라이브러리 로드

  • Visdom 서버를 미리 켜 놓고 진행하지 않으면 오류가 발생한다!
import visdom
vis = visdom.Visdom()

(3) Test 예제

  • env를 설정하면, 같은 env인 것 끼리 한 번에 통제(종료 등) 가능!
  • Visdom 서버에 Hello, world! 창이 뜬다.
vis.text("Hello, world!", env="main")

(4) 이미지 예제

  • 이미지를 랜덤으로 생성해 본다. 3(RGB)로 설정하고, 200 * 200의 랜덤 이미지를 생성해 보자.
  • Visdom 서버에 랜덤 이미지 창이 뜬다.
  • Visdom 서버에 뜬 이미지 창을, Ctrl로 늘릴 수 있고 창도 조절 가능하다.
a = torch.randn(3, 200, 200)
vis.image(a)

(5) 여러 이미지 예제

  • 여러 이미지를 랜덤으로 생성해 본다. 3(RGB)를 3개 설정하고, 28 * 28의 랜덤 이미지를 생성하자.
  • Visdom 서버에 여러 랜덤 이미지 창이 뜬다.
vis.images(torch.Tensor(3, 3, 28, 28)) 



4. Visdom을 사용한 CIFAR10과 MNIST 예제

(1) 데이터 로드

# 데이터 로드
MNIST = dsets.MNIST(root="./MNIST_data", train = True, transform = torchvision.transforms.ToTensor(), download = True)
cifar10 = dsets.CIFAR10(root="./cifar10", train = True, transform = torchvision.transforms.ToTensor(), download = True)

# CIFAR10 데이터 하나를 Visdom에 띄워 보기
data = cifar10.__getitem__(0) # CIFAR10 데이터를 data에 담는다.
print(data[0].shape) # 데이터의 0번째 인덱스 shape 확인
vis.images(data[0], env="main") # Visdom에 띄우기

# MNIST 데이터 하나를 Visdom에 띄워보기
data = MNIST.__getitem__(0) # MNIST 데이터를 data에 담는다.
print(data[0].shape) # 데이터의 0번째 인덱스 shape 확인
vis.images(data[0], env="main") # Visdom에 띄우기

(2) 데이터 로더 이용하기

# 데이터 로더로 만들기
data_loader = torch.utils.data.DataLoader(dataset = MNIST, # MNIST 데이터셋
                                          batch_size = 32, # batch size 설정
                                          shuffle = False)

# Visdom에 MNIST 데이터 32개 띄우기
for num, value in enumerate(data_loader):
  value = value[0]
  print(value.shape)
  vis.images(value)
  break

# Visdom에서 env가 main인 것 모두 종료 (직접 손으로 다 꺼도 되긴함!)
vis.close(env="main")

(3) Line Plot 그리기

# Y 데이터 선언
Y_data = torch.randn(5) # 5개짜리 랜덤 데이터 만듦
plt = vis.line (Y = Y_data) # visdom에 라인을 그림

# X 데이터 선언
X_data = torch.Tensor([1, 2, 3, 4, 5])
plt = vis.line(Y = Y_data, X = X_data)

# 라인 업데이트
Y_append = torch.randn(1) # 업데이트 할 Y 값
X_append = torch.Tensor([6]) # 업데이트 할 X 값

vis.line(Y=Y_append, X=X_append, win=plt, update='append') # plt 라인 그래프에 append로 업데이트 가능!

(4) 창 하나에 여러 라인 그리기

num = torch.Tensor(list(range(0, 10))) # 10개의 텐서 생성
num = num.view(-1, 1)
num = torch.cat((num, num), dim=1)

plt = vis.line(Y=torch.randn(10, 2), X = num)

(5) Line에 정보 부여하기

  • Line에 Dictionary 형태로 타이틀 등의 정보를 부여할 수 있다.
  • showlegend=True : 축에 이름이 보이게 한다.
  • legend = ['1번'] : 축의 이름을 '1번'으로 설정한다.
plt = vis.line(Y=Y_data, X=X_data, opts = dict(title='Test', showlegend=True)) # 타이틀을 'Test'로 설정
plt = vis.line(Y=Y_data, X=X_data, opts = dict(title='Test', legend = ['1번'], showlegend=True)) # 타이틀을 'Test'로 설정하고, 축의 이름을 '1번'으로 설정
plt = vis.line(Y=torch.randn(10, 2), X = num, opts = dict(title='Test', legend=['1번', '2번'], showlegend=True))

(6) loss를 계속 업데이트 해서 라인을 그리게 하기

# loss 업데이트 함수 만들기!
def loss_tracker(loss_plot, loss_value, num): # 업데이트를 반영할 플롯 이름, loss 값, 몇 번째 인덱스(X축)에 들어갈지 설정. loss_value와 num은 Tensor값이어야 한다.
  vis.line(X=num, # 인덱스
           Y=loss_value, # loss 값
           win = loss_plot, # 플롯 이름
           update='append') # 추가
           
# plt 플롯 하나 만들기
plt = vis.line(Y=torch.Tensor(1).zero_())

for i in range(500):
  loss = torch.randn(1) + i # loss 값을 랜덤으로 만든다.
  loss_tracker(plt, loss, torch.Tensor([i])) # plt 플롯에 loss 값을 넣는다. i번째 인덱스의 X축에 반영하는 것!

(7) 창 모두 끄기

vis.close(env="main")



5. MNIST CNN과 Visdom

  • 다른 부분은 앞에서 배운 MNIST CNN과 완전히 똑같다!
  • loss를 Visom으로 시각화 해주는 코드들만 추가됨
# 1. 라이브러리 로드
import torch
import torch.nn as nn
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init

# 2. Visdom 라이브러리 로드
import visdom

vis = visdom.Visdom()
vis.close(env="main") # Visdom 서버가 기존에 열려 있다면, 기존의 창들을 닫기 위한 작업

# 3. loss 추적 함수 정의
def loss_tracker(loss_plot, loss_value, num):
  vis.line(X=num,
           Y=loss_value,
           win = loss_plot
           update='append'
           )

# 4. CNN 과정 (앞에서 배운 부분과 동일)
device = 'cuda' if torch.cuda.is_available() else 'cpu'

torch.manual_seed(777)
if device == 'cuda':
  torch.cuda.manual_seed_all(777)
  
learning_rate = 0.001
training_epochs = 15
batch_size = 32

mnist_train = dsets.MNIST(root='MNIST_data/',
                          train = True,
                          transform = transforms.ToTensor(),
                          download=True)
                          
mnist_test = dsets.MNIST(root='MNIST_data/',
                         train=False,
                         transform = transforms.ToTensor(),
                         download=True)

data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size = batch_size,
                                          shuffle = True,
                                          drop_last = True)
                                          
class CNN(nn.Module):
  def __init__(self):
    super(CNN, self).__init__()
    self.layer1 = nn.Sequential(
      nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1),
      nn.ReLU(),
      nn.MaxPool2d(2)
    )
    
    self.layer2 = nn.Sequential(
      nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1),
      nn.ReLU(),
      nn.MaxPool2d(2)
    )  
    
    self.layer3 = nn.Sequential(
      nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
      nn.ReLU()
      nn.MaxPool2d(2)
    )
    
    self.fc1 = nn.Linear(3 * 3 * 128, 625)
    self.relu = nn.ReLU()
    self.fc2 = nn.Linear(625, 10, bias = True)
    torch.nn.init.xavier_uniform_(self.fc1.weight)
    torch.nn.init.xavier_uniform_(self.fc2.weight)
    
  def forward(self, x):
    out = self.layer1(x)
    out = self.layer2(out)
    out = self.layer3(out)
    
    out = out.view(out.size(0), -1)
    out = self.fc1(out)
    out = self.relu(out)
    out = self.fc2(out)
    return out
    
model = CNN().to(device)
value = (torch.Tensor(1, 1, 28, 28)).to(device)
print( (model(value)).shape )

criterion = nn. CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr = learning_rate)

# 5. Plot 만들어 두기 (그릴 그래프와 좌표만 미리 만들어 놓는 것)
loss_plt = vis.line(Y=torch.Tensor(1).zero_(), opts=dict(title='loss_tracker', legend=['loss'], showlegend=True)) # line 플롯을 만들며, 0으로 초기화 해둔다. title을 설정해 두고, 라인 이름도 설정해 둔다.

# 6. 학습하며 loss값 Plot에 반영하기
total_batch = len(data_loader)

for epoch in range(training_epochs):
  avg_cost = 0
  
  for X, Y in data_loader:
    X = X.to(device)
    Y = Y.to(device)
    
    hypothesis = model(X)
    cost = criterion(hypothesis, Y)

    optimizer.zero_grad()
    cost.backward()
    optimizer.step()
    
    avg_cost += cost / total_batch
  # 한 Epoch이 돌 때 까지 Batch 사이즈만큼씩 데이터를 모델에 넣어 학습시키는 과정이다.

  print('[Epoch:{}] cost = {}'.format(epoch+1, avg_cost))
  loss_tracker(loss_plt, torch.Tensor([avg_cost]), torch.Tensor([epoch])) # 한 epoch이 돌 때 마다의 loss_plt 플롯에 avg_cost를 업데이트 해준다. 플롯의 X축은 Epoch으로 한다.
print('Learning Finished!')

# 7. 모델 평가 (앞에서 배운 부분과 동일)
with torch.no_grad():
  X_test = mnist_test.test_data.view(len(mnist_test), 1, 28, 28).float().to(device)
  Y_test = mnist_test.test_labels.to(device)
  
  prediction = model(X_test)
  correct_prediction = torch.argmax(prediction, 1) == Y_test
  accuracy = correct_prediction.float().mean()
  print('Accuracy:', accuracy.item())