본문 바로가기

인공지능/Toy Projects

DeepMC_4 / Decoder

목차

     

    Introduction

    E) Attention Mechanism과 연결되어있는 F) Decoder 부분을 살펴본다.

    Decoder의 output이 Attention의 input으로 사용되기 때문에 맨 처음에 Decoder LSTM을 어떻게 구현해야할지 고민을 많이 했다.

    일반적인 nn.LSTM을 사용하면 time step별로 output을 뽑을 수 없기 때문이다.

     

    Method & Material

    E) Attention Mechanism은 2 level attention (Position Based Content Attention Layer, Scale Guided Attention Layer)로 이루어져 있고, 각각 Context vector c, c`을 time step 별로 출력해준다.

    그리고 Decoder에서는 이전 timestep의 output(m_{i-1}), LSTM의 이전 timestep의 hidden state(s_{i-1}), 현재 timestep의 context vector(c_i)를 입력한다.

    자세한 설명은 원문을 인용한다.

    The LSTM decoder (described in Section 6.6) parallels the encoder by associating each output 𝑚_𝑖 , 1 ≤ 𝑖 ≤ 𝑇 ′ to a hidden state vector 𝑠_𝑖 that is directly used to predict the output:
    𝑚𝑖 = 𝐺(𝑚_{𝑖−1}, 𝑠_{𝑖−1}, 𝑐_𝑖),
    with 𝑠_𝑖 ∈ R^𝐻 ′ , 𝐻 ′ is the dimension of the decoder hidden layer, 𝑐_𝑖 is usually referred to as a context and corresponds to the output of the memory model. For DeepMC function G corresponds to an LSTM with a context integration

    그림과 수식을 보면 알 수 있지만, 중요한 것은 Decoder LSTM의 hidden state인 s_i와 output(m_i)가 attention layer의 input으로 들어간다는 점이다.

    이부분을 구현하기 위해 LSTMCell을 이용해서 time step 별로 s_i와 context vector를 계산하게끔 코드를 작성했다.

    LSTM 이후에는 2개의 FC Layer가 연결되어있고, 구조는 supplementary에 다음과 같이 적혀있다.

    The decoder described in Section 6.6 uses a 20 node LSTM layer with the ReLU activation function. Additionally, the decoder also uses ReLU activation for the first dense layer and a linear activation function for the second dense layer. The first dense layer has 50 nodes for each of the time series steps and the second dense layer has 1 node for each of the time series steps.

    LSTM layer의 hidden node는 20개, 첫번째 FC layer는 50개, 두번째 FC layer는 1개의 output node를 가진다.

    즉 첫번째 FC layer는 50x20의 weight를 가지고, 두번째 FC layer는 1x50의 weight를 가진다.

    Results

    맨 처음에 이 아이디어가 이해가 되지 않아서 어떻게 구현해야하나 한참 고민했지만, 논문을 계속읽다보니 생각보다 Layer구조가 복잡하지는 않다는 것을 느끼고 금방 코드를 구현할 수 있었다.

    코드자체가 어렵진 않지만 혹시 헷갈릴 수 있기 때문에 변수에 대한 설명을 주석에 충분히 달았다.

    from torch import nn
    
    class Decoder(nn.Module):
        def __init__(self,num_encoder_hidden : int , num_decoder_hidden : int, cnn_output_size : int):
            
            super().__init__()
            
            # Hyper parameter
            self.num_encoder_hidden = num_encoder_hidden
            self.num_decoder_hidden = num_decoder_hidden
            self.cnn_output_size = cnn_output_size
            
            # m_i = G(m_i-1, s_i-1, c_i)
            # m_i-1 / (1)
            # s_i-1 / (num_decoder_hidden)
            # c_i   / (num_of_CNN_stacks + num_encoder_hidden * 2) 
            self.Decoder = nn.LSTMCell(1+self.cnn_output_size+self.num_encoder_hidden * 2, self.num_decoder_hidden)
    
            # FC Layer for hidden state to output
            # 2 layers / each layer has 50, 1 output dimension
            self.FC_layer = nn.Sequential(
                nn.Linear(self.num_decoder_hidden, 50),
                nn.ReLU(),
                nn.Linear(50, 1)
            )
        
        def forward(self, decoder_input, s_i, cell_state):
            # 1 <= j <= T  , num_encoder_times T is lstmstack seq length, in this case T = 18
            # 1 <= i <= T' , num_decoder_times T' is lstm decoder seq length, in this case T' = 12
        
            # decoder_input / input of decoder / (m_i-1, (s_i-1, cell_state), (c_i+c_prime_i))
            # m_i / output of decoder / (batch size, 1)
            # s_i-1 / hidden state of Decoder LSTM / (batch size, decoder hidden size)
            # cell_state / cell state of Decoder LSTM / (batch size, decoder hidden size)
            # c_i / (batch size, 1, encoder hidden size)
            # c_prime_i / (batch size, 1, output size of CNN stack)
            s_i, cell_state = self.Decoder(decoder_input,(s_i,cell_state))
    
            # m_i / output of decoder / (batch size, 1)
            m_i = self.FC_layer(s_i)
            
            return m_i,(s_i,cell_state)

     

    Conclusion & Discussion

    Decoder를 마지막으로 모델 구현 자체는 끝났다.

    논문을 낸 MS에서 코드를 제공해주지 않아서 힘들어질뻔 했지만, 덕분에 attention도 구현해보고, 이렇게 큰 모델도 처음부터 만들어보는 등, 여러가지로 성장할 수 있던 프로젝트인 것 같다.

    trainer를 만들고 학습하는 과정에서 발생한 여러가지 문제나 삽질은 블로그에 따로 정리중이다.

     

    DeepMC 모델에 대한 전체 코드는 다음 github에 있다.

    https://github.com/wlsdml1114/DeepMC