Attention을 소개하기 앞서 NLP의 발전과정에 대해 설명하겠습니다. 먼저 첫 번째로 RNNNeural network에서 recurrent 순환형 구조를 추가한 것, LSTM은 기존 RNN이 역전파가 길어질 시 단점이 생겨 hidden statecell-state를 추가하여 발전시킨 것입니다. Seq2Seq2RNN을 구조를 사용해서 인코더, 디코더 구조로 변환해서 번역 수행하였습니다. Attention모든 입력 시퀀스를 참고. TransformerRNN, CNN사용 안하고 Attention만 사용. 그리고 Transformer의 인코더를 활용한게 GPT, Transformer디코더를 활용한게 BERT모델입니다. 그만큼 Transformer는 매우 중요합니다. 그리고 여기서 점선을 기준으로 RNN기반과 Attention 기반으로 나누어지는데 RNN기반은 하나의 문맥 베터가 소스 문장의 모든 정보를 가지고 있는 것이고 Attention기반은 입력 시퀀스 전체에서 정보를 추출하는 방향으로 진행됩니다. 이 두 말을 좀 더 자세히 알아보겠습니다.

 

기존의 RNN을 이용한 번역과정은 인코더를 통해 I, love, you가 순차적으로 학습 후 Context Vector라는 하나의 벡터로 변환되고, 하나의 벡터를 다시 디코더를 통해 변환합니다. 근데 이 과정은 하나의 벡터에 모든 정보를 저장함과 동시에 하나의 방향으로만 흘러가 병목현상이 일어나기 때문에 속도가 매우 느리고 성능이 저하되는 문제점이 있었습니다. Context Vector를 삭제하고 input 벡터를 병렬로 받아서 처리하면 속도가 더 빨라지지 않을까하고 나온 것이 바로 Attention입니다.

고정된 크기의 문맥 벡터를 사용하지 않고 동적으로 인코더 출력값에 어텐션 메커니즘을 사용해서 인코더의 모든 상태값을 활용합니다. 그래서 성능이 좋아졌습니다.

 

 

트랜스포머의 전체적인 구조는 inputs값이 Positional Encoding이라는 단어의 위치를 고려하는 벡터랑 더해지고 N개의 인코딩 레이어를 통해 연산을 수행. 최종 인코더 레이어의 출력값KeyValue를 받아 디코더의 두번째 Attention입력값으로 넣습니다. 디코더는 계속 query를 상위 레이어로 전달시켜 query갱신시켜 최종 Linear레이어와 softmax레이어를 거친 후 확률을 출력합니다.

Transformerrnn을 사용하지 않고 attention만 사용하기 때문에 앞 뒤 단어를 통한 상대적인 단어의 위치를 고려하지 못합니다. 그래서 이 문제점을 해결하기 위한 방법이 Positional Encoding인데, Positional Encoding사인코사인을 활용하여 position을 정의한 후 기존 임베딩과 더한다음 위치를 고려한 임베딩을 만듭니다. 사인코사인을 활용하는 -11사이의 값을 가지기 때문에 값을 곱한다고 해서 많이 변하지 않고 일종의 규칙성을 가지고 반복되기 때문에 활용한다고 합니다.

그 후 Encoding파트에서 Multi head attention을 살펴보겠습니다. attentionself-attention의 구조를 띄고 있기 때문에 문장에 있는 단어들이 다른 모든 단어들의 영향을 받습니다. 따라 이 attentio의 구조는 Query, Key, Value를 갖고 있는데 Query란 현재 구하고자 하는 단어이고 Key는 문장의 모든 단어 Value는 말 그대로 값을 나타냅니다. QueryKey Transpose를 곱하고 dimension 개수의 루트만큼 나누어 normallization을 수행합니다. 그 후 softmax를 통해 확률의 형태로 바꾸고 다시 Value 벡터를 곱해 모두 더해줍니다. 최종적으로 나온 벡터가 최종 출력입니다. 이런 AttentionScaled dot-Product attention이라고 하고, 단어들끼리 모두 연관시켜 연산을 수행했기 때문에 self-Attention의 형태를 띄고 있습니다.

앞서 말한 Self Attention을 병렬적으로 반복한 것이 바로 Multi-head Attention입니다. 입력 vector를 서로 다른 Linear Layer에 있는 다른 가중치를 곱해 여러 개의 값으로 구성한 후 (CNN에서 커널과 비슷) 각 헤드에 값을 집어 넣어 동시에 처리합니다. 그 후 나온 각각의 벡터를 더한 후, 출력을 뱉어줍니다.

앞서 Multi-head Attention을 하면서 값이 손실될 수 있기 때문에 그 전에 Residual를 그대로 Attention의 출력 레이어에 넘겨줍니다. 이 넘겨받은 ResidualMulti-head Attention을 통해 나온 값을 더한 후 normallization을 수행합니다. 그 후 다시 Residual Learning, Feed Forward, Normallization을 반복하면 인코딩 레이어 과정이 끝납니다. 이렇게 레이어 과정을 반복하면서 N개의 레이어를 순차적으로 진행한 후 최종의 출력값을 뱉어줍니다. 이 과정에서 레이어는 같은 파라미터를 공유하지 않고, 서로 다른 파라미터를 가져 성능 향상의 도움이 됩니다.

이렇게 출력된 인코더의 값은 디코더의 두 번째 Multi-head Attention입력값으로 들어갑니다. 여기서 입력 값으로 들어갈 때는 KeyValue만 넘어가게 되고 Query는 이전 디코더 레이어의 값을 받아와 갱신하게 됩니다.

디코더의 첫 번째 Multi-head AttentionMask가 붙었는데 이 이유를 알아보겠습니다. 인코더의 어텐션은 모든 값들이 서로 영향을 주면서 학습해야 하므로 서로의 값들을 Attention합니다. 하지만 디코더 과정에서는 Output 데이터의 앞에 있는 단어로 뒤에 있는 단어를 예측해야 하므로, 앞에있는 단어로만 Attention을 수행해서 뒤에오는 단어를 알지 못하게 해야 합니다.

이렇게 똑같이 디코더도 N개의 레이어를 반복 수행한 후, Linear를 통해 숫자로 변환하고 Softmax를 통해 확률로 변환합니다. 최종적으로 뱉는 값은 one-hot encodin이 아니라 Label Smoothing을 처리한 것인데 이 이유는 Thank you -> one hot encoding시 고마워와 감사합니다.는 아예 다릅니다. 그래서 Label Smoothing을 적용하면 아주 작은 값이라도 적용하여 조금이라도 가깝게 하기 때문입니다.

이렇게 트랜스포머는 그 당시 최고 성능을 달성했습니다.

또한 여러 개의 값을 조정한 후, 가장 좋은 성능의 파라미터들을 찾았습니다.

728x90
반응형
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 라이프코리아트위터 공유하기
  • shared
  • 카카오스토리 공유하기