함께하는 데이터 분석

[Find-A][Pytorch] 초기화 본문

학회 세션/파인드 알파

[Find-A][Pytorch] 초기화

JEONGHEON 2022. 9. 25. 19:26

초기화

모델을 학습할 때 주어진 입력과 결과, 그리고 정답 값을 통해 가중치를 학습하게 됨

 

최적의 가중치가 존재한다고 가정하면 그 가중치 역시 어떠한 값이기 때문에 그 최적의 값과 가까운 지점에서 시작할수록 빠르게 수렴할 수 있을 것

 

하지만 최적의 지점 자체가 우리가 모르는 어떤 목푯값이기 때문에 근처에서 시작한다는 말 자체가 성립할 수 없음

 

대신 모델이 학습되는 도중에 기울기 소실 현상이나 기울기 과다와 같은 현상을 겪지 않게 하거나 손실 함수 공간을 최적화가 쉬운 형태로 바꾸는 방법을 택함

 

이러한 방법 중 하나로 가중치의 초기화(initialization)가 있고 그 중 대표적인 방법으로 Xavier Glorot 초기화Kaiming HE 초기화가 있음 

 

 

Xavier Glorot 초기화

논문 : http://proceedings.mlr.press/v9/glorot10a/glorot10a.pdf

 

가중치의 초깃값을 N(0, var=2/(n_in+n_out))에서 뽑는다는 것이 핵심

 

n_in과 n_out은 해당 레이어에 들어오는 특성의 수, 나가는 특성의 수를 의미

 

간략히 만 설명하면 데이터가 몇 개의 레이어를 통과하더라도 활성화 값이 너무 커지거나 너무 작아지지 않고 일정한 범위 안에 있도록 잡아주는 초기화 방법

 

논문을 살펴보면 시그모이드와 하이퍼볼릭 탄젠트 같은 활성화 함수에 대한 실험이 나와 있음

 

이 논문 발표 이후 렐루 활성화 함수가 사용되기 시작하면서 활성화 값이 0 이하이면 바뀌어 전달하는 방식이 쓰이게 되었고 여기에 맞춰 Kaiming He 초기화가 나오게 되었음

 

 

Kaiming He 초기화

논문 : https://arxiv.org/pdf/1502.01852 

 

가중치를 N(0, var=2/((1+a^2)*n_in))에서 샘플링하는데 이때 a는 렐루 또는 리키 렐루의 음수 부분의 기울기에 해당하고 기본적으로는 렐루를 사용한다는 가정하에 기본값은 0으로 지정

 

 

결론

  • 시그모이드나 하이퍼볼릭 탄젠트를 주로 사용하는 경우는 Xavier Glorot 초기화를 사용
  • 렐루나 리키렐루를 주로 사용하면 Kaiming He 초기화를 사용

 

Pytorch

라이브러리 불러오기

import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.init as init
import torchvision
import torchvision.datasets as dset
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
batch_size = 256
learning_rate = 0.0002
num_epoch = 10

 

Data

mnist_train = dset.MNIST('MNIST_data/', train=True, transform=transforms.ToTensor(), target_transform=None, download=True)
mnist_test = dset.MNIST('MNIST_data/', train=False, transform=transforms.ToTensor(), target_transform=None, download=True)
print(mnist_train.__getitem__(0)[0].size(), mnist_train.__len__())
mnist_test.__getitem__(0)[0].size(), mnist_test.__len__()

>>> (torch.Size([1, 28, 28]), 10000)
train_loader = torch.utils.data.DataLoader(mnist_train,batch_size=batch_size, shuffle=True,num_workers=2,drop_last=True)
test_loader = torch.utils.data.DataLoader(mnist_test,batch_size=batch_size, shuffle=False,num_workers=2,drop_last=True)

 

CNN Model

class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        self.layer = nn.Sequential(
            nn.Conv2d(1,16,3,padding=1),  # 28 x 28
            nn.ReLU(),
            nn.Conv2d(16,32,3,padding=1), # 28 x 28
            nn.ReLU(),
            nn.MaxPool2d(2,2),            # 14 x 14
            nn.Conv2d(32,64,3,padding=1), # 14 x 14
            nn.ReLU(),
            nn.MaxPool2d(2,2)             #  7 x 7
        )
        self.fc_layer = nn.Sequential(
            nn.Linear(64*7*7,100),
            nn.ReLU(),
            nn.Linear(100,10)
        )             
        
        # 초기화 하는 방법
        # 모델의 모듈을 차례대로 불러옵니다.
        for m in self.modules():
            # 만약 그 모듈이 nn.Conv2d인 경우
            if isinstance(m, nn.Conv2d):
                '''
                # 작은 숫자로 초기화하는 방법
                # 가중치를 평균 0, 편차 0.02로 초기화합니다.
                # 편차를 0으로 초기화합니다.
                m.weight.data.normal_(0.0, 0.02)
                m.bias.data.fill_(0)
                
                # Xavier Initialization
                # 모듈의 가중치를 xavier normal로 초기화합니다.
                # 편차를 0으로 초기화합니다.
                init.xavier_normal(m.weight.data)
                m.bias.data.fill_(0)
                '''
                
                # Kaming Initialization
                # 모듈의 가중치를 kaming he normal로 초기화합니다.
                # 편차를 0으로 초기화합니다.
                init.kaiming_normal_(m.weight.data)
                m.bias.data.fill_(0)
            
            # 만약 그 모듈이 nn.Linear인 경우
            elif isinstance(m, nn.Linear):
                '''
                # 작은 숫자로 초기화하는 방법
                # 가중치를 평균 0, 편차 0.02로 초기화합니다.
                # 편차를 0으로 초기화합니다.
                m.weight.data.normal_(0.0, 0.02)
                m.bias.data.fill_(0)
                
                # Xavier Initialization
                # 모듈의 가중치를 xavier normal로 초기화합니다.
                # 편차를 0으로 초기화합니다.
                init.xavier_normal(m.weight.data)
                m.bias.data.fill_(0)
                '''
                
                # Kaming Initialization
                # 모듈의 가중치를 kaming he normal로 초기화합니다.
                # 편차를 0으로 초기화합니다.
                init.kaiming_normal_(m.weight.data)
                m.bias.data.fill_(0)

    def forward(self,x):
        out = self.layer(x)
        out = out.view(batch_size,-1)
        out = self.fc_layer(out)
        return out

 

Loss func & Optimizer

USE_CUDA = torch.cuda.is_available() # gpu 사용 가능하면 true or false
device = torch.device("cuda" if USE_CUDA else "cpu")
print(f'다음 기기로 학습 : {device}')

>>> 다음 기기로 학습 : cpu
model = CNN().to(device)
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)

 

Train

for i in range(num_epoch):
    for j,[image,label] in enumerate(train_loader):
        x = image.to(device)
        y_= label.to(device)
        
        optimizer.zero_grad()
        output = model.forward(x)
        loss = loss_func(output,y_)
        loss.backward()
        optimizer.step()
        
    if i % 10 == 0:
        print(loss)  
        
>>> tensor(1.9159, grad_fn=<NllLossBackward0>)

 

Test

correct = 0
total = 0

with torch.no_grad():
    for image,label in test_loader:
        x = image.to(device)
        y_= label.to(device)

        output = model.forward(x)
        _,output_index = torch.max(output,1)

        total += label.size(0)
        correct += (output_index == y_).sum().float()

    print("Accuracy of Test Data: {}".format(100*correct/total))
    
>>> Accuracy of Test Data: 85.24639129638672

https://www.hanbit.co.kr/store/books/look.php?p_code=B7818450418 

 

파이토치 첫걸음

딥러닝 구현 복잡도가 증가함에 따라 ‘파이써닉’하고 사용이 편리한 파이토치가 주목받고 있다. 파이토치 코리아 운영진인 저자는 다년간 딥러닝을 공부하고 강의한 경험을 살려 딥러닝의

www.hanbit.co.kr