hojeomi blog

Day 19-1. 어텐션(attention), seq2seq with attention 본문

AI/Course

Day 19-1. 어텐션(attention), seq2seq with attention

호저미 2021. 2. 19. 00:56

출처: wikidocs.net/22893

 

 

0. Intro

  • seq2seq 모델은 인코더에서 입력 시퀀스를 컨텍스트 벡터라는 하나의 고정된 크기의 벡터 표현으로 압축하고, 디코더는 이 컨텍스트 벡터를 통해서 출력 시퀀스를 만듦
  • 하지만, 이러한 RNN에 기반한 seq2seq 모델에는 크게 두 가지 문제가 있음
    • 하나의 고정된 크기의 벡터에 모든 정보를 압축하려다 보니, 정보 손실이 발생함
    • RNN의 고질적인 문제인 기울기 소실(Vanishing Gradient) 문제가 존재함
  • 결국, 기계 번역 분야에서 입력 문장이 길면 번역 품질이 떨어지는 현상이 나타남
  • 이를 위한 대안으로 입력 시퀀스가 길어지면 출력 시퀀스의 정확도가 떨어지는 것을 보정해 주기 위해 등장한 기법이 어텐션(attention)

 

 

1. 어텐션의 아이디어  ✔ 부캠 3주차 트랜스포머 수업 다시 듣기

  • 기본 아이디어는 디코더에서 출력 단어를 예측하는 매 시점(time step)마다, 인코더에서의 전체 입력 문장을 다시 한 번 참고한다는 점
  • 단, 전체 입력 문장을 전부 다 동일한 비율로 참고하는 것이 아니라, 해당 시점에서 예측해야할 단어와 연관이 있는 입력 단어 부분을 좀 더 집중(attention)해서 보게 됨

 

 

2. 어텐션 함수

  • 파이썬 딕셔너리 개념 참고 - {key:value}의 맵핑
  • Attencion(Q, K, V) = Attention Value

  • 어텐션 함수는 주어진 쿼리(Query)에 대해서 모든 키(Key)와의 유사도를 각각 구함. 그리고 구해낸 이 유사도를 키와 맵핑되어있는 각각의 값(Value)에 반영함. 그리고 유사도가 반영된 값(Value)을 모두 더해서 리턴함 → 어텐션 밸류(Attention Value)
  • seq2seq with attention
    • Q = Query: t시점의 디코더 셀에서의 은닉 상태
    • K = Keys: 모든 시점의 인코더 셀의 은닉 상태들
    • V = Values: 모든 시점의 인코더 셀의 은닉 상태들

 

 

3. 닷-프로덕트 어텐션(Dot-Product Attention)

  • 어텐션은 다양한 종류가 있는데 그 중에서도 가장 수식적으로 이해하기 쉽게 수식을 적용한 닷-프로덕트 어텐션을 통해 어텐션을 이해해보자
  • seq2seq에서 사용되는 어텐션 중에서 닷-프로덕트 어텐션과 다른 어텐션의 차이는 주로 중간 수식의 메커니즘 자체는 거의 유사함

 

  • 위 그림은 디코더의 세번째 LSTM 셀에서 출력 단어를 예측할 때, 어텐션 메커니즘을 사용하는 모습
  • 디코더의 첫번째, 두번째 LSTM 셀은 이미 어텐션 메커니즘을 통해 je와 suis를 예측하는 과정을 거쳤다고 가정함
  • 디코더의 세번째 LSTM 셀은 출력 단어를 예측하기 위해 인코더의 모든 입력 단어들의 정보를 다시 한번 참고하고자 함
  • 소프트맥스 함수를 통해 나온 결과값은 I, am, a, student 단어 각각이 출력 단어를 예측할 때 얼마나 도움이 되는지의 정도를 수치화한 값임
  • 각 입력 단어가 디코더의 예측에 도움이 되는 정도가 수치화하여 측정되면 이를 하나의 정보로 담아서 디코더로 전송됨(위 그림에서 초록색 삼각형)
  • 결과적으로, 디코더는 출력 단어를 더 정확하게 예측할 확률이 높아짐

 

 

4. 트랜스포머(Transformer)(Intro)

  • 기존 seq2seq 모델의 한계
    • 기존 seq2seq 모델은 인코더-디코더 구조로 구성됨. 여기서 인코더는 입력 시퀀스를 하나의 벡터 표현으로 압축하고, 디코더는 이 벡터 표현을 통해서 출력 시퀀스를 만듦
    • 하지만, 이러한 구조는 인코더가 입력 시퀀스를 하나의 벡터로 압축하는 과정에서 입력 시퀀스의 정보가 일부 손실된다는 단점이 있었고, 이를 보정하기 위해 어텐션이 사용됨
    • 그런데, 어텐션을 RNN의 보정을 위한 용도(seq2seq with attention)가 아니라 아예 어텐션으로 인코더와 디코더를 만들어 보면 어떨까?
  • 트랜스포머의 주요 하이퍼파라미터
    • 아래에서 정의하는 수치값은 트랜스포머를 제안한 논문에서 사용한 수치값으로 사용자가 모델 설계시 임의로 변경할 수 있는 값들
    • d_model = 512
      • 트랜스포머의 인코더와 디코더에서의 정해진 입력과 출력의 크기를 의미
      • 임베딩 벡터의 차원 또한 d_model이며, 각 인코더와 디코더가 다음 층의 인코더와 디코더로 값을 보낼 때에도 이 차원을 유지함
    • num_layers = 6
      • 트랜스포머에서 하나의 인코더와 디코더를 층으로 생각했을 때, 트랜스포머 모델에서 인코더와 디코더가 총 몇 층으로 구성되었는지를 의미함
      • 논문에서는 인코더와 디코더를 각각 총 6개 쌓음
    • num_heads = 8
      • 트랜스포머에서는 어텐션을 사용할 때, 1번 하는 것보다 여러 개로 분할해서 병렬로 어텐션을 수행하고 결과값을 다시 하나로 합치는 방식을 택함. 이때 이 병렬의 개수를 의미함
    • d_ff = 2048
      • 트랜스포머 내부에는 피드 포워드 신경망이 존재함. 이때 은닉층의 크기를 의미함. 피드 포워드 신경망의 입력층과 출력층의 크기는 d_model임

 

 

5. 트랜스포머(Content)

  • 트랜스포머는 RNN을 사용하지 않지만 기존의 seq2seq처럼 인코더에서 입력 시퀀스를 입력받고, 디코더에서 출력 시퀀스를 출력하는 인코더-디코더 구조를 유지함
  • 다만 다른 점은 인코더와 디코더라는 단위가 N개 존재할 수 있음 → num_layers

  • 위 그림은 인코더로부터 정보를 전달 받아 디코더가 출력 결과를 만들어내는 트랜스포머 구조
  • 디코더는 마치 기존의 seq2seq 구조처럼 시작 심볼 <SOS>를 입력으로 받아 종료 심볼 <EOS>가 나올 때까지 연산을 진행함
  • 이는 RNN은 사용되지 않지만 여전히 인코더-디코더의 구조는 유지되고 있음을 보여줌
  • 트랜스포머의 인코더와 디코더는 단순히 각 단어의 임베딩 벡터들을 입력받는 것이 아니라 임베딩 벡터에서 조정된 값을 입력받는데 이에 대해서 알아보기 위해 입력 부분을 확대해보자

 

 

6. 포지셔널 인코딩(Positional Encoding)

  • 트랜스포머의 내부를 이해하기 위해 우선 트랜스포머의 입력에 대해서 알아보자
  • RNN이 자연어 처리에서 유용했던 이유는 단어의 위치에 따라 단어를 순차적으로 입력 받아서 처리하는 RNN의 특성으로 인해 각 단어의 위치 정보(position information)를 가질 수 있다는 점에 있었음
  • 하지만 트랜스포머는 단어 입력을 순차적으로 받는 방식이 아니므로 단어의 위치 정보를 다른 방식으로 알려줄 필요가 있음
  • 트랜스포머는 단어의 위치 정보를 얻기 위해서 각 단어의 임베딩 벡터에 위치 정보들을 더하여 모델의 입력으로 사용하는데, 이를 포지셔널 인코딩(positional encoding)이라고 함

  • 위 그림은 입력으로 사용되는 임베딩 벡터들이 트랜스포머의 입력으로 사용되기 전에 포지셔널 인코딩 값이 더해지는 것을 보여줌
  • 임베딩 벡터가 인코더의 입력으로 사용되기 전에 포지셔널 인코딩 값이 더해지는 과정을 시각화하면 아래와 같음

(1)

  • 포지셔널 인코딩 값은 어떤 값이기에 위치 정보를 반영할 수 있을까? 트랜스포머는 위치 정보를 가진 값을 만들기 위해서 아래의 두 개의 함수를 사용함

  • 사인함수와 코사인함수의 그래프는 요동치는 값의 형태, 트랜스포머는 사인함수와 코사인함수의 값을 임베딩 벡터에 더해줌으로써 단어의 순서 정보를 더하여 줌
  • 그런데 위의 두 함수에는 pos, i, d_model 등의 생소한 변수들이 있음
  • 위의 함수를 이해하기 위해서는, 위에서 본 임베딩 벡터와 포지셔널 인코딩의 덧셈은 사실 임베딩 벡터가 모여 만들어진 문장 벡터 행렬과 포지셔널 인코딩 행렬의 덧셈 연산을 통해 이루어 진다는 점을 이해해야 함(그림(1) 참고)

  • pos는 입력 문장에서의 임베딩 벡터의 위치를 나타내며, i는 임베딩 벡터 내의 차원의 인덱스를 의미함
  • 위의 식에 따르면 임베딩 벡터 내의 각 차원의 인덱스가 짝수인 경우에는 사인함수의 값을 사용하고 홀수인 경우에는 코사인함수의 값을 사용함 → 위의 수식에서 (pos, 2i)일 경우 사인함수를 사용하고, (pos, 2i+1)일 경우 코사인함수를 사용하고 있음
  • 위의 식에서 d_moel은 트랜스포머의 모든 층의 출력 차원을 의미하는 트랜스포머의 하이퍼파라미터임 → 앞으로 보게 될 트랜스포머의 각종 구조에서 d_model의 값이 계속해서 등장하는 이유
  • 임베딩 벡터 또한 d_model의 차원을 가지는데 위의 그림에서는 마치 4로 표현되었지만 논문에서는 512의 값을 가짐
  • 위와 같은 포지셔널 인코딩 방법을 사용하면 순서 정보가 보존되는데, 예를 들어 각 임베딩 벡터에 포지셔널 인코딩 값을 더하면 같은 단어라고 하더라도 문장 내의 위치에 따라서 트랜스포머의 입력으로 들어가는 임베딩 벡터의 값이 달라짐
  • 결국 트랜스포머의 입력은 순서 정보가 고려된 임베딩 벡터라고 보면 됨
Comments