반응형

안녕하세요. 오늘은 RNN을 Pytorch로 직접 구현해보고, Tanh(hyperbolic tangent) 대신, Sigmoid나 ReLU를 사용하면 어떻게 되는지 실험을 한 번 해보겠습니다. 

 

www.youtube.com/watch?v=tlyzfIYvMWE&list=PLSAJwo7mw8jn8iaXwT4MqLbZnS-LJwnBd&index=26

제가 Pytorch를 처음 공부할 때 위 영상을 많이 참고 했습니다. 

 

Pytorch를 처음 공부하시는 분이시라면, 위 딥러닝 홀로서기 Pytorch Kist 영상을 보시는 걸 추천드립니다. 

 

자료도 아낌없이 GIt에 올라와 있고, 라이브 코딩을 하면서 수업이 진행되기 때문에 접근하는 노하우를 기를 수 있다고 생각합니다. 

 

코드는 위 영상 GIthub의 자료를 수정한 내용입니다. 

 

우선 RNN(Recurrent Neural Network)에 구조 대해 이야기 해보겠습니다. 

 

RNN은 Input과 Output을 Sequence 단위로 처리하는 네트워크 구조입니다. 

 

일반 신경망과 달리 순환 신경망은 Cell 부분이 순환하게 됩니다.

Hidden Layer는 바로 이전 Hidden Layer의 입력을 현재 입력으로 사용하는 것이 가장 큰 특징입니다.

 

이런 RNN의 순환 구조 때문에 시계열 데이터에 가장 많이 사용되고 있습니다. 

 

위 구조는 간단한 식으로 표현할 수 있습니다.

 

그렇다면 activation function인 tanh 말고, 지금 가장 많이 사용한다는 ReLU를 사용하면 안될까 라는 궁금증이 생겼습니다. 

 

Sigmoid의 미분의 최대값이 0.25이기 때문에, Deep해질수록 Vanishing Gradient 가 발생합니다. 

 

Vanishing 문제를 해결하기 위해 만든 것이 Tanh 입니다. 

 

Tanh는 0~1인 Sigmoid 확장판이며, 미분의 최대값이 1로 Vanishing Graidient를 해결합니다. 

 

ReLU는 -1~1을 반환하는 Tanh 대신, x가 0보다 크면 그대로 값을 보내게 되어, 속도와 학습률이 향상됐습니다.  

 

하지만, RNN의 내부는 계속 순환하는 구조로 값이 1보다 크게 되면, ReLU 특성상 값이 발산할 수 있기 때문에 적합하지 않다고 합니다.   

 

그렇다면, 간단한 데이터에서 발산하지 않는 환경에서 ReLU를 사용하게 된다면 어떻게 될지 궁금했습니다. 

 

위 영상의 Git 코드를 사용했으며, 학습이 실패한 영상입니다. 

 

수정을 하진 않고, 코드를 그대로 사용했으며, 활성화 함수만 바꿔가면서 학습 결과를 확인했습니다. 

 

import torch
import torch.nn as nn


class RNN(nn.Module):
    def __init__(self, input_dim, output_dim, hid_dim, batch_size): 
        super(RNN, self).__init__()
        
        self.input_dim = input_dim
        self.output_dim = output_dim
        self.hid_dim = hid_dim
        self.batch_size = batch_size
        
        self.wx = nn.Linear(self.input_dim, self.hid_dim, bias=False)
        self.wh = nn.Linear(self.hid_dim, self.hid_dim, bias=False)
        self.wy = nn.Linear(self.hid_dim, self.output_dim, bias=False)
        self.act_fn = nn.Tanh()  # nn.Sigmoid() nn.ReLU() nn.LeakyReLU() 
        
        self.hidden = self.init_hidden()
        
    def init_hidden(self, batch_size=None):
        if batch_size is None:
            batch_size = self.batch_size
        return torch.zeros(batch_size, self.hid_dim)
    
    def forward(self, x):
        h = self.act_fn(self.wx(x) + self.wh(self.hidden))
        y = self.wy(h)
        return y, h

대략 이런 그런 그림이 그려집니다. 분명 Loss 전부 떨어졌으나 모델 성능은 별로 인 것 같습니다. 

 

ReLU가 조금이나마 따라가는 듯하나 값을 예측을 하지 못했습니다. 

 

그래서 LeakyReLU를 사용해 또 결과를 확인 했습니다. 

 

Sinc함수???

LeakyReLU를 사용했을 땐, Sinc 함수가 그려졌습니다. 

 

궁금증을 해결하고자 활성화함수를 바꿔가면서 학습을 시켰으나 오히려 궁금증이 더 커졌습니다.

 

이 부분은 좀 더 공부를 해봐야 할 것 같습니다... 딥러닝 고수분들 피드백 부탁드립니다. 

728x90
반응형

+ Recent posts