끄적거림

[논문 실습] Dropout as a Bayesian Approximation 실습 코드 - pytorch ver 본문

개인 공부 정리/Bayesian

[논문 실습] Dropout as a Bayesian Approximation 실습 코드 - pytorch ver

Signing 2021. 4. 20. 13:57
728x90
반응형

[논문 리뷰] Dropout as a Bayesian Approximation - 1.Prologue

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 2.Abstract

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 3.Introduce

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 4.Related Research (1): Background(MC-Integration, Dropout)

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 4.Related Research (2): Background(Gaussian Process)

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 4.Related Research (3): Background(Bayesian Neural Network, Variational Inference, Re-parameterization trick)

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 5.Methodolgy

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 6.Experiment

[논문 리뷰] Dropout as a Bayesian Approximation 설명 - 7.Conclusion

[논문 실습] Dropout as a Bayesian Approximation 실습 코드 - pytorch ver
Dropout 고찰: output에 scaling하는 이유(Dropout 구현)


참고 URL: xuwd11.github.io/Dropout_Tutorial_in_PyTorch/

 

Tutorial: Dropout as Regularization and Bayesian Approximation

Dropout as Regularization and Bayesian Approximation

xuwd11.github.io

위의 글에는 논문에 대한 설명이 있지만 그것은 스킵하고, 코드 실습부분부터 보도록 하겠다.

그리고, 위의 글을 그대로 진행했을 때는 환경 차이일 수도 있지만, 에러가 발생하여 일부를 수정하였다.

코드 실습 환경은 간단히 colab으로 진행하였다.

 


 

1. Load Packages

import warnings
warnings.filterwarnings("ignore")

import numpy as np
import pandas as pd
import time
import h5py
from scipy.ndimage.interpolation import rotate

import matplotlib
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import matplotlib.gridspec as gridspec

import seaborn as sns
%matplotlib inline

import torch
import torchvision
from torchvision import datasets
from torchvision import transforms
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data.sampler import SubsetRandomSampler

import pymc3 as pm

 

 

2. Dropout Implementation

class MyDropout(nn.Module):
  def __init__(self, p=0.5):
    super(MyDropout, self).__init__()
    self.p = p
    # multiplier is 1/(1-p)
    # Set multiplier to 0 when p = 1 to avoid error
    # --> 
    if self.p < 1:
      self.multiplier_ = 1.0 / (1.0 - p)
    else:
      self.multiplier_ = 0.0
    
  def forward(self, input):
    # if model.eval(), don't apply dropout
    if not self.training:
      return input
    
    # So that we have `input.shape` numbers of Bernoulli(1-p) samples
    # --> input의 데이터 사이즈를 고려하여 베르누이(1-p)의 샘플을 만들기 위한 과정
    # --> 0~1사이의 난수를 발생시켜 지정 확률 p보다 큰지 작은지를 boolean으로 설정 
    selected_ = torch.Tensor(input.shape).uniform_(0, 1) > self.p
    
    # To suppert both CPU and GPU
    # --> boolean 값을 0, 1로 바꾸는 작업
    if input.is_cuda:
      selected_ = Variable(selected_.type(torch.cuda.FloatTensor), requires_grad = False)
    else:
      selected_ = Variable(selected_.type(torch.FloatTensor), requires_grad = False)

    # Multiply output by multiplier as described in the paper [1]
    # --> 0,1의 값들을 곱하여 선택된 input을 골라내는 과정
    res = torch.mul(selected_, input)*self.multiplier_
    return res

 

 

3. Dropout as Regularization

# Normalize data with mean=(0,0,0), std=(1,1,1)
transform = transforms.Compose([
    transforms.ToTensor(),
    # transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))
    transforms.Normalize((0,), (1,))
])

path = './drive/MyDrive/paper/data/'
trainset = datasets.MNIST(root=path,   # root directory of dataset where `MNIST/processed/[training.pt | test.pt]`
                          train=True,     # if True, creates dataset from training.pt, otherwise from test.pt
                          download=True,  # if True, downloads from the internet and puts it in root directory. If dataset is already downloaded, it is not downloaded again.
                          transform=transform   # A function/transform that takes in an PIL image and returns a tranformed version. E.g, `transforms.RandomCrop`
                          # target_tranform=    # A function/transform that takes in the target and transforms it.
                          )
testset = datasets.MNIST(root=path, train=False, download=True, transform=transform)
# Visualize 10 images samples in MNIST dataset
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True, num_workers=2)
data_iter = iter(trainloader)
images, labels = data_iter.next()

# plot 10 sample images
_, ax = plt.subplots(1, 10)
ax = ax.flatten()
iml = images[0].numpy().shape[1]
[ax[i].imshow(np.transpose(images[i].numpy(), (1,2,0)).reshape(iml, -1), cmap='Greys') for i in range(10)]
[ax[i].set_axis_off() for i in range(10)]
plt.show()

print('lable:', labels[:10].numpy())
print('image data shape:', images[0].numpy().shape)
  • Deep NN에서 regularization으로 작동하는 dropout을 먼저 살펴보고자 한다.(L1, L2와 같은)
  • Dropout이 작동하는 것을 확인하기 위해 fully connected network인 MultiLayer Perceptron을 만들고, 그 후에 dropout이 다른 네트워크 아키텍쳐에서도 잘 작동하는지 확인하기 위해서 LeNet(CNN 계열)을 만들 것이다.
  • MNIST를 사용하였다.

 

 

4.1 MultiLayer Perceptron

class MLP(nn.Module):
  def __init__(self, hidden_layers=[800, 800], dropRates=[0,0]):
    super(MLP, self).__init__()
    self.model = nn.Sequential()
    self.model.add_module("dropout0", MyDropout(p=dropRates[0]))
    self.model.add_module("input", nn.Linear(28*28, hidden_layers[0]))
    self.model.add_module("tanh", nn.Tanh())

    # Add hidden layer
    for i, d in enumerate(hidden_layers[:-1]):
      self.model.add_module("dropout_hidden"+str(i+1), MyDropout(p=dropRates[1]))
      self.model.add_module("hidden"+str(i+1), nn.Linear(hidden_layers[i], hidden_layers[i+1]))
      self.model.add_module("tanh_hidden"+str(i+1), nn.Tanh())
    self.model.add_module("final", nn.Linear(hidden_layers[-1], 10))

  def forward(self, x):
    # Trun to 1-Dimension
    x = x.view(x.shape[0], 28*28)
    x = self.model(x)
    return x
  • 간단한 네트워크 구조를 만들기 위해 기본적인 MLP class를 만들고자 한다.
    • hidden layer: 2개
    • hidden unit: 800개
  • MLP class를 먼저 만들고 후에 MLPClassifier class를 만든다.

 

class MLPClassifier:
  def __init__(self, hidden_layer=[800, 800], dropRates=[0,0], batch_size=128, max_epoch=10, lr=0.1, momentum=0):
    # Wrap MLP model
    self.hidden_layer = hidden_layer
    self.dropRates = dropRates
    self.batch_size = batch_size
    self.max_epoch = max_epoch

    self.model = MLP(hidden_layers=hidden_layers, dropRates=dropRates)
    self.model.cuda()
    self.criterion = nn.CrossEntropyLoss().cuda()
    self.optimizer = optim.SGD(self.model.parameters(), lr=lr, momentum=momentum)

    self.loss_ = []
    self.test_acc = []
    self.test_err = []
  
  def fit(self, trainset, testset, verbose=True):
    # GPU 확인하고 진행하길,, 안그러면 매우 느릴수 있음
    trainloader = torch.utils.data.DataLoader(trainset, batch_size=self.batch_size, shuffle=True)
    testloader = torch.utils.data.DataLoader(testset, batch_size=len(testset), shuffle=False)
    X_test, y_test = iter(testloader).next()
    X_test = X_test.cuda()

    for epoch in range(self.max_epoch):
      running_loss = 0
      for i, data in enumerate(trainloader, 0):
        inputs, labels = data
        inputs, labels = Variable(inputs).cuda(), Variable(labels).cuda()
        self.optimizer.zero_grad()
        outputs = self.model(inputs)
        loss = self.criterion(outputs, labels)
        loss.backward()
        self.optimizer.step()
        running_loss += loss.data.cpu().numpy()
      self.loss_.append(running_loss / len(trainloader))

      if verbose:
        print('Epoch {} loss: {}'.format(epoch+1, self.loss_[-1]))
      
      y_test_pred = self.predict(X_test).cpu()
      tmp_test_acc = y_test == y_test_pred
      self.test_acc.append(np.mean(tmp_test_acc.data.cpu().numpy()))
      # self.test_acc.append(np.mean(y_test == y_test_pred))
      self.test_err.append(int(len(testset)*(1-self.test_acc[-1])))

      if verbose:
        print('Test error: {}; test acc: {}'.format(self.test_err[-1], self.test_acc[-1]))
    
    return self

  def predict(self, x):
    # Used to keep all test errors after each epoch
    model = self.model.eval()
    outputs = model(Variable(x))
    _, pred = torch.max(outputs.data, 1)
    model = self.model.train()
    return pred
  
  def __str__(self):
    return 'Hidden layers: {}; dropout rate: {}'.format(self.hidden_layers, self.dropRates)
  • sklearn과 비슷한 classifier를 만들어보고자 한다.
  • 위의 코드에서 만든 MLP class를 _init_ 함수에서 사용하였다.

 

hidden_layers = [800, 800]

### Below is training code, uncomment to train your own model... ###
### Note: You need GPU to run this section ###

# Define networks
mlp1 = [MLPClassifier(hidden_layers, dropRates=[0, 0], max_epoch=300), 
        MLPClassifier(hidden_layers, dropRates=[0, 0.5], max_epoch=300),
        MLPClassifier(hidden_layers, dropRates=[0.2, 0.5], max_epoch=300)]
        
# Training, set verbose=True to see loss after each epoch.
[mlp.fit(trainset, testset,verbose=True) for mlp in mlp1]
  • dropout을 전혀 고려하지 않았을 때와 일부를 부여하였을 때, 모두를 부여하였을 때에 대해 모델을 만들고 순차적으로 학습시켰다.
  • 참고 URL에서는 max_epoch를 원래는 1500으로 설정했었는데 그러면 너무 많은 시간이 소요되기 때문에 300으로 설정하였다.
    • 그럼에도 충분히 성능 차이를 확인할 수 있었다.

 

# Save torch models
for ind, mlp in enumerate(mlp1):
    torch.save(mlp.model, './drive/MyDrive/paper/mnist_mlp1_'+str(ind)+'.pth')
    # Prepare to save errors
    mlp.test_error = list(map(str, mlp.test_err))

# Save test errors to plot figures
open("./drive/MyDrive/paper/mlp1_test_errors.txt","w").write('\n'.join([','.join(mlp.test_error) for mlp in mlp1])) 
  • 학습이 완료된 모델들을 원하는 곳에 저장시켜 다음에도 사용할 수 있도록 하였다.(또 학습하면 시간이 오래 걸리니까!)

 

# Load saved models to CPU
mlp1_models = [torch.load('./drive/MyDrive/paper/mnist_mlp1_'+str(ind)+'.pth',map_location={'cuda:0': 'cpu'}) for ind in [0,1,2]]

# Load saved test errors to plot figures.
mlp1_test_errors = [error_array.split(',') for error_array in open("./drive/MyDrive/paper/mlp1_test_errors.txt","r").read().split('\n')]
mlp1_test_errors = np.array(mlp1_test_errors,dtype='f')
  • 저장했던 모델들을 다시 불러오는 코드와 test error를 준비하는 코드이다.

 

label = ['MLP no dropout',
         'MLP 50% dropout in hidden layers',
         'MLP 50% dropout in hidden layers + 20% in input layer']

plt.figure(figsize=(8,7))
for i, r in enumerate(mlp1_test_errors):
  plt.plot(range(1, len(r)+1), r, '.-', label=labels[i], alpha=0.6)
# plt.ylim([50,250])
plt.legend(loc=1)
plt.xlabel('Epochs')
plt.ylabel('Number of errors in test set')
plt.title('Test Error on MNIST dataset for MLP')
plt.show()
  • 전의 코드에서 구했던 test error를 그림으로 보여줌으로써 성능이 어떠한지를 확인할 수 있는 코드이다.
  • 이것으로 visualization을 실행해보면 아래와 같은 그림이 나온다.

 

 

 

4.2 CNN with LeNet

def caloutdim(hin, kernel_size, stride=1, padding=0, dilation=1):
    return int(np.floor((hin+2*padding-dilation*(kernel_size-1)-1)/stride+1))

d = [28]
d.append(caloutdim(d[-1], 5, padding=2))
d.append(caloutdim(d[-1], 2, 2))
d.append(caloutdim(d[-1], 5, padding=2))
d.append(caloutdim(d[-1], 2, 2))
print(d)
  • 일단은 conv layer와 pooling layer를 통과한 후 이미지의 dimension을계산해야한다.
  • pyrorch의 linear layer 때문에 이와 같은 작업을 수행해야함.

 

class Flatten(nn.Module):
    def __init__(self):
        super(Flatten, self).__init__()

    def forward(self, x):
        x = x.view(x.size(0), -1)
        return x

class LeNet(nn.Module):
    def __init__(self, droprate=0.5):
        super(LeNet, self).__init__()
        self.model = nn.Sequential()
        self.model.add_module('conv1', nn.Conv2d(1, 20, kernel_size=5, padding=2))
        self.model.add_module('dropout1', nn.Dropout2d(p=droprate))
        self.model.add_module('maxpool1', nn.MaxPool2d(2, stride=2))
        self.model.add_module('conv2', nn.Conv2d(20, 50, kernel_size=5, padding=2))
        self.model.add_module('dropout2', nn.Dropout2d(p=droprate))
        self.model.add_module('maxpool2', nn.MaxPool2d(2, stride=2))
        self.model.add_module('flatten', Flatten())
        self.model.add_module('dense3', nn.Linear(50*7*7, 500))
        self.model.add_module('relu3', nn.ReLU())
        self.model.add_module('dropout3', nn.Dropout(p=droprate))
        self.model.add_module('final', nn.Linear(500, 10))
        
    def forward(self, x):
        return self.model(x)
  • 위의 코드는 LeNet 코드이다.
  • 본 논문이 2015년에 나왔기 때문에 최신의 모형들은 고려하지 않은 상태이다.
  • 여기에서 nn.Dropout2d를 사용했다.
  • 이것은 MyDropout class와 같은 것이다.
    • 2차원인 것 빼고
    • 효율은 더 좋다.

 

class LeNetClassifier:
    def __init__(self, droprate=0.5, batch_size=128, max_epoch=300, lr=0.01):
        self.batch_size = batch_size
        self.max_epoch = max_epoch
        self.lr = lr
        self.model = LeNet(droprate)
        self.model.cuda()
        self.criterion = nn.CrossEntropyLoss().cuda()
        self.optimizer = optim.SGD(self.model.parameters(), lr=lr)
        self.loss_ = []
        self.test_error = []
        self.test_accuracy = []
        
    def fit(self, trainset, testset, verbose=True):
        trainloader = torch.utils.data.DataLoader(trainset, batch_size=self.batch_size, shuffle=True)
        testloader = torch.utils.data.DataLoader(testset, batch_size=len(testset), shuffle=False)
        X_test, y_test = iter(testloader).next()
        X_test = X_test.cuda()
        print(self.model)
        for epoch in range(self.max_epoch):
            running_loss = 0
            for i, data in enumerate(trainloader, 0):
                inputs, labels = data
                inputs, labels = Variable(inputs).cuda(), Variable(labels).cuda()
                self.optimizer.zero_grad()
                outputs = self.model(inputs)
                loss = self.criterion(outputs, labels)
                loss.backward()
                self.optimizer.step()
                running_loss += loss.data.cpu().numpy()
            self.loss_.append(running_loss / len(trainloader))
            if verbose:
                print('Epoch {} loss: {}'.format(epoch+1, self.loss_[-1]))
            y_test_pred = self.predict(X_test).cpu()

            tmp_test_accuracy = y_test == y_test_pred
            self.test_accuracy.append(np.mean(tmp_test_accuracy.data.cpu().numpy()))
            # self.test_accuracy.append(np.mean(y_test == y_test_pred))
            self.test_error.append(int(len(testset)*(1-self.test_accuracy[-1])))
            if verbose:
                print('Test error: {}; test accuracy: {}'.format(self.test_error[-1], self.test_accuracy[-1]))
        return self
    
    def predict(self, x):
        model = self.model.eval()
        outputs = model(Variable(x))
        _, pred = torch.max(outputs.data, 1)
        model = self.model.train()
        return pred
  • 위의 class를 가지고 만든 LeNet Classifier이다.

 

### Below is training code, uncomment to train your own model... ###
### Note: You need GPU and CUDA to run this section ###

# Define networks
lenet1 = [LeNetClassifier(droprate=0, max_epoch=300),
          LeNetClassifier(droprate=0.5, max_epoch=300)]
        
# Training, set verbose=True to see loss after each epoch.
[lenet.fit(trainset, testset,verbose=True) for lenet in lenet1]
  • training 코드이다.
  • epoch를 300으로 주었지만, 참고URL에서는 1500으로 되어 있다.
  • dropout은 0.5로 주었다.

 

# Save torch models
for ind, lenet in enumerate(lenet1):
    torch.save(lenet.model, './drive/MyDrive/paper/mnist_lenet1_'+str(ind)+'.pth')
    # Prepare to save errors
    lenet.test_error = list(map(str, lenet.test_error))

# Save test errors to plot figures
open("./drive/MyDrive/paper/lenet1_test_errors.txt","w").write('\n'.join([','.join(lenet.test_error) for lenet in lenet1])) 
# Load saved models to CPU
lenet1_models = [torch.load('./drive/MyDrive/paper/mnist_lenet1_'+str(ind)+'.pth', map_location={'cuda:0': 'cpu'}) for ind in [0,1]]

# Load saved test errors to plot figures.
lenet1_test_errors = [error_array.split(',') for error_array in 
                      open("./drive/MyDrive/paper/lenet1_test_errors.txt","r").read().split('\n')]
lenet1_test_errors = np.array(lenet1_test_errors,dtype='f')
  • MLP와 마찬가지로 훈련을 진행하고 난 학습 모델을 따로 저장 후 다시 로딩한다.
  • test error를 계산한다.

 

labels = ['MLP no dropout', 
          'MLP 50% dropout in hidden layers', 
          'MLP 50% dropout in hidden layers + 20% in input layer',
          'LeNet no dropout',
          'LeNet 50% dropout']

plt.figure(figsize=(8, 7))
for i, r in enumerate(mlp1_test_errors.tolist() + lenet1_test_errors.tolist()):
    plt.plot(range(1, len(r)+1), r, '.-', label=labels[i], alpha=0.6);
plt.ylim([50, 250]);
plt.legend(loc=1);
plt.xlabel('Epochs');
plt.ylabel('Number of errors in test set');
plt.title('Test Error on MNIST Dataset for All Networks')
plt.show()
  • 그림은 아래와 같다.
  • 보면 알겠지만 LeNet 모델에 50%의 dropout 비율을 적용했을 때가 가장 낮은 test error를 갖는 것을 볼 수 있다.
  • 학습 epoch를 1500번 정도 진행하면 언제 수렴하는지 여부를 확인 가능하지만 너무 오래 걸리므로 300번만 진행하였다.

 

 

5. Dropout as Bayesian Approximation

  • 이번 절에서는 본격적으로 dropout으로 bayesian approximation 하여 불확실성에 대해 살펴보고자 한다.
  • 두 모델(MLP와 LeNet)에서 dropout을 사용하여 모델 불확실성을 구하는 작업이다.

 

5.1 Dropout as Bayesian Approximation in Classification Task

testloader = torch.utils.data.DataLoader(testset, batch_size=len(testset), shuffle=False)
X_test, y_test = iter(testloader).next()
X_test = X_test.numpy()
X1 = np.array([rotate(X_test[9978].squeeze(), i, reshape=False) for i in range(50, 130, 7)])
X1 = X1.reshape(X1.shape[0], 1, X1.shape[1], X1.shape[2])

plt.figure(figsize=(8, 1))

gs = gridspec.GridSpec(1, 12)
gs.update(wspace=0, hspace=0)

for i in range(len(X1)):
    plt.subplot(gs[i])
    plt.imshow(X1.squeeze()[i], cmap='gray');
    plt.axis('off');

  • 숫자 1이 적힌 이미지 데이터를 조금씩 돌려가며 회전시킨 12개의 이미지 데이터이다.
  • 정상적인 숫자 1은 학습이 잘되어 분류를 잘 할테지만, 가로로 뉘어진 1에 대해서는 학습해본 적이 없기 때문에 어떻게 그에 대한 불확실성을 확인할 수 있을지에 대한 실험이다.

 

def predict_class(model, X):
    model = model.eval()
    outputs = model(Variable(X))
    # print('outputs.data: \n{}'.format(outputs.data))
    _, pred = torch.max(outputs.data, 1)
    # print('_, pred: \n{}, {}'.format(_, pred))
    model = model.train()
    return pred.numpy()

def predict(model, X, T=1000):
    standard_pred = predict_class(model, X)
    y1 = []
    y2 = []
    for _ in range(T):
        _y1 = model(Variable(X))
        _y2 = F.softmax(_y1, dim=1)
        y1.append(_y1.data.numpy())
        y2.append(_y2.data.numpy())
    return standard_pred, np.array(y1), np.array(y2)    # return pred, softmax input, softmax output
  • 각 모델들에 대해, 1000번의 시뮬레이션을 진행하여, model의 마지막 layer인 softmax input과 output에 대한 분포를 확인해야한다.
model = mlp1_models[2]

# Need to flatten X1 before feeding into MLP
y1_pred, y1_si, y1_so = predict(model, torch.from_numpy(X1.reshape(-1,784)))    # si: softmax input, so:softmax output
print('Predictions: {}'.format(y1_pred))

#############################################################################
################################## RESULT  ##################################
#############################################################################

# Predictions: [1 1 1 1 1 3 3 7 7 7 7 7]
  • MLP 모델들 중에서 dropout을 [0.2, 0.5] 주었던 모델로 위의 회전된 숫자 1에 대해 분류를 해보았다.
  • 결과 해석
    • 처음 조금만 회전된 숫자 1을 보고 올바르게 숫자 1이라고 분류했지만
    • 그 이후부터는 3과 7로 오분류한 것을 볼 수 있다.
plt.figure(figsize=(10, 3))
plt.subplot(1, 2, 1)
plt.scatter(np.tile(np.arange(1, 13), y1_si.shape[0]), y1_si[:, :, 1].flatten(), \
            color='g', marker='_', linewidth=None, alpha=0.2, label='1');
plt.scatter(np.tile(np.arange(1, 13), y1_si.shape[0]), y1_si[:, :, 7].flatten(), \
            color='r', marker='_', linewidth=None, alpha=0.2, label='7');
plt.scatter(np.tile(np.arange(1, 13), y1_si.shape[0]), y1_si[:, :, 3].flatten(), \
            color='b', marker='_', linewidth=None, alpha=0.2, label='3');
plt.title('Softmax input scatter');
plt.legend(framealpha=0.7);

plt.subplot(1, 2, 2)
plt.scatter(np.tile(np.arange(1, 13), y1_so.shape[0]), y1_so[:, :, 1].flatten(), \
            color='g', marker='_', linewidth=None, alpha=0.2, label='1');
plt.scatter(np.tile(np.arange(1, 13), y1_so.shape[0]), y1_so[:, :, 7].flatten(), \
            color='r', marker='_', linewidth=None, alpha=0.2, label='7');
plt.scatter(np.tile(np.arange(1, 13), y1_so.shape[0]), y1_so[:, :, 3].flatten(), \
            color='b', marker='_', linewidth=None, alpha=0.2, label='3');
plt.title('Softmax output scatter');
plt.legend(framealpha=0.7);

plt.tight_layout();
  • 위에서 나온 class의 분포를 softmax input과 output에 대하여 그려놓은 것이다.
  • 논문에서도 설명이 되어 있지만, 정상적인 숫자 1의 경우 softmax output의 분포가 좁은 분산과 1에 수렴하는 평균을 갖고 있지만
  • 회전된 숫자들을 보면 1,3,7 각 class의 분산이 크게 분포되어 있음을 알 수 있다.

 

 


 

 

이 밖에도 다른 데이터 셋으로 regression도 진행한 부분도 있기는 하지만, 핵심적인 실험을 pytorch로 어떻게 진행했는지를 살펴보았다.

 

 

 

728x90
반응형
Comments