ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Transformer
    카테고리 없음 2021. 11. 8. 06:06

    Transformer의 개념

    Transformer는 Google에서 발표한 "Attention is All You Need"라는 논문에서 나온 모델이다. 기존의 seq2seq 모델과 동일하게 Encoder와 Decoder로 이루어져있으면서도 RNN이 아닌 Attention Mechanism만이 사용되었다는 것이 특징이다. 그럼에도 불구하고 이는 기존 RNN 기반 모델보다도 우수한 성능을 자랑한다.

    [참고] Attention is All You Need

     

     

    Transformer의 기본 아이디어

    Attention을 사용하는 이유는 입력 시퀀스의 정보 손실을 막기 위해서 였음을 이전 포스팅에서 공부했다. 즉, 기존 seq2seq 모델에서 Attention이 보조적으로 사용되었다면, Transformer의 기본 아이디어는 Attention을 RNN의 보정 용도로 사용하는 것이 아니라 Attention으로 Encoder와 Decoder를 만들자는 것이다. 

     

    기존 RNN 기반 모델이 Encoder 및 Decoder에서 하나의 RNN이 t개의 시점을 가졌다면, Transformer는 Encoder와 Decoder를 단위로서 사용한다. (Attention is All You Need 논문에서는 Encoder와 Decoder를 각각 6개 사용하였음)

    출처: 트랜스포머(Transformer) - 딥 러닝을 이용한 자연어 처리 입문 (wikidocs.net)

     

    Transformer의 이해

    출처: Transformer - Harder, Better, Faster, Stronger (pingpong.us)

     

     

     

     

    왼쪽의 그림이 Transformer의 전체적인 구조이다. 그림의 왼쪽 부분이 Encoder, 오른쪽 부분이 Decoder에 해당한다. 그림의 "Positional Encoding"은 RNN 방식을 사용하지 않게 되면서 등장한 방식이다. 기존에는 RNN 특성 상 위치에 따라 단어를 "순차적으로" 입력받기 때문에 단어의 위치 정보를 쉽게 파악할 수 있었으나, 트랜스포머의 경우 단어의 위치 정보를 다른 방식으로 전달해줘야 한다. 그래서 각각의 단어의 Embedding 벡터에 위치 정보를 더해주는데 이를 Positional Encoding이라 한다.

     

     

    Encoder 및 Decoder에서 수행되는 부분은 아래에서 Transformer의 코드와 함께 설명하도록 하겠다.

     

     

     

     

     

    Encoder

    class EncoderLayer(nn.Module):
        def __init__(self, config):
            super().__init__()
            self.self_attention = MultiHeadAttention(config)
            self.feedforward = FeedForward(config)  
    
            self.linear_1 = nn.Linear(config.hidden_size, config.hidden_size)
            self.linear_2= nn.Linear(config.intermediate_size, config.hidden_size)
            self.dropout = nn.Dropout(config.hidden_dropout_prob)
            self.layer_norm = nn.LayerNorm(config.hidden_size, eps=config.layer_norm_eps)
            
        def forward(self, hidden_states, attention_mask=None):
            # hidden_states = [batch_size, seq_len, hidden_size]
                    
            # 1. multi-head attention
            attention_output = self.self_attention(hidden_states, attention_mask)
    
            # 2. add & norm : linear -> dropout -> residual connection and layer norm
            L=self.linear_1(attention_output)
            D=self.dropout(L)
            RC=D+hidden_states
            attention_output=self.layer_norm(RC)
    
            # 3. feedforward
            feedforward_output = self.feedforward(attention_output)
    
            # 4. add & norm
            L=self.linear_2(feedforward_output)
            D=self.dropout(L)
            RC=D+attention_output
            output=self.layer_norm(RC)
    
            return output

     

    Encoder의 forward 함수 부분을 보면 Multi-Head Attention 함수(attention score 함수의 종류)를 통해 attention을 구한다.(#1) 이후 linear, drop-out 처리를 하고 residual connection 처리를 해준다. residual connection은 Multi-Head Attention 함수의 입력과 출력을 더해주는 것을 말한다. 이는 Vanishing Gradient를 예방하기 위함인데, Vanishing Gradient란 이전 layer의 출력값만을 활용할 경우, 기존의 데이터에 대한 특징을 잃어버리는 문제를 말하는데, 이는 layer의 개수가 많아질수록 쉽게 나타나는 현상이기도 하다. residual connection 처리를 해준 후에는 학습 속도를 높이기 위해 정규화 처리를 해준다.(#2) 정규화까지 된 데이터를 가지고 feedforward 처리를 해주는데 feedforward의 이해를 위해 아래의 코드를 보자.

     

    class FeedForward(nn.Module):
        def __init__(self, config):
            super().__init__()
            
            self.linear = nn.Linear(config.hidden_size, config.intermediate_size) # 768 -> 3072
                    
        def forward(self, hidden_states):
            # hidden_states = [batch size, seq len, hid dim]
            
            # linear -> gelu
            hidden_states=self.linear(hidden_states)
            hidden_states=gelu(hidden_states)
    
            return hidden_states

     

    feedforward 처리는 relu 혹은 gelu를 통해 activation을 진행해주는 것을 말하는데, gelu를 활용하였다.(#3) 마지막으로 feedforward 처리 후 결과도 Multi-Head Attention의 결과와 동일하게 "Add&Norm" 처리를 해준다.(#4)

     

     

    기존 RNN 기반의 모델과 달리 순차적인 입력이 요구되지 않는 Transformer는 이후 Positional Embedding 처리를 해주는데 이는 Encoder 층을 쌓는 작업이다. 이 작업이 끝나면 Encoder 마지막 층의 결과 행렬을 Decoder로 전달한다.

     

     

    Decoder

    Decoder는 Multi-Head Attention, residual connection, 정규화 처리를 해준다는 점에서 Encoder와 매우 유사하므로 Encoder와의 차이점을 기준으로 설명하겠다. Transformer의 경우, 기존 RNN 기반 모델과 달리 순차적인 입력을 하지 않고, Encoder에서 최종 결과(행렬)를 받아 입력으로 넣기 때문에 어떤 단어를 예측할 때 이후에 들어오는 단어까지도 참고해버리는 문제가 생길 수 있다. 이를 예방하기 위해 Masked Multi-Head Attention을 사용한다. masking 작업을 통해 Decoder에서는 자신의 앞쪽에 위치한 단어들의 attention score만을 확인할 수 있도록 하는 것이다. 이는 순차적으로 계산하는 기존 방법과는 달리 말 그대로 mask (가리는) 방법을 사용하는 것으로, 값을 미리 구해놓고 사용 시에만 가리는 방법이다. 

     

     

    https://proceedings.neurips.cc/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf

    https://blog.pingpong.us/transformer-review/

    https://wikidocs.net/31379

     

Designed by Tistory.