해당 포스팅은 다음의 유튜브 강의와 논문을 기반으로 작성되었습니다.
1. Seq2Seq
설명하고자 하는 내용에 앞서 Attention과 Transformer의 등장 이전의 SOTA 방법론인 Seq2Seq에 대해 간단히 살펴보자.
Seq2Seq는 인코더와 디코더라는 두개의 모듈로 구성된다.
인코더는 입력문장의 모든 단어들을 순차적으로 입력받은 뒤에 마지막에 모든 단어 정보들은 압축해 하나의 context vector를 만들게 된다. 좀 더 정확히 말하면 인코더 LSTM의 마지막 hidden state이다.
context vector로 압축된 이후 이는 디코더로 전송되고 디코더는 컨텍스트 벡터를 디코더 LSTM 셀의 첫번째 hidden state로 사용하여 번역된 단어를 한개씩 순차적으로 출력한다.
이런 Seq2Seq 모델은 다음의 두가지 문제점을 가지고 이로 인해 입력문장이 길면 번역 품질이 떨어지는 현상들이 나타나곤 했다.
- 하나의 고정된 크기의 context vector로 input의 모든 정보를 압축하기에 정보 손실이 발생한다.
- RNN 계열의 고질적인 문제인 gradient vanishing 문제가 발생한다.
2. Attention Mechanism
위의 seq2seq 문제점을 해결하고자 고안된 것이 Attention이다.
seq2seq는 위 사진 기준 마지막 hidden state인 h3만을 context vector로 담았지만, attention은 h1, h2, h3 모든 hidden state를 모두 보존해 디코더로 전달한다.
- 보존한 모든 인코더의 hidden state와 디코더의 hidden state를 내적 연산해 alignment score를 구함.
- 이를 softmax를 통해 attention weight을 구하고 예측을 위한 확률값으로 반환함.
- 인코더 각각의 hidden state와 weighted sum 값을 가중합하여 attention score를 구함.
- attention score와 디코더 hidden state 값을 concat한 후 softmax를 통해 최종 단어를 예측함.
위와 같은 과정을 통해 현재 출력 대상에 대해 인코더의 모든 hidden state를 고려할 수 있게 되었다.
이후 서술한 transformer에서 사용하는 attention의 종류는 다음과 같이 세가지이다.
- 인코더-디코더 attention layers
- query는 이전 디코더 layer에서 나옴
- memory key와 value는 인코더의 output에서 나옴
- -> 따라서 디코더의 모든 position이 input sequence의 모든 position을 다룸
- 전형적인 sequence-to-sequence model에서의 인코더-디코더 attention 방식임
- 인코더의 self-attention layer
- self-attention layer에서 key, value, query는 모두 같은 곳(인코더의 이전 layer의 output)에서 나옴
- 인코더의 각 position은 인코더의 이전 layer의 모든 position을 다룰 수 있음
- 디코더의 self-attention layer
- 마찬가지로, 디코더의 각 position은 해당 position까지 모든 position을 다룰 수 있음
- 디코더의 leftforward information flow는 auto-regressive property 때문에 막아줘야 할 필요가 있음
- -> 이 연구에서는 scaled-dot product attention에서 모든 softmax의 input value 중 illegal connection에 해당하는 값을 −∞로 masking out해서 구현함
하나씩 설명해보겠다.
3. Encoder - Training Architecture
3-1. Input into Encoder (인코더 self attention layer)
인코더의 input값 형태를 먼저 살펴보자.
먼저 문장의 각 시퀀스를 학습을 위한 벡터로 임베딩하는 embedding layer를 갖는다.
그리고 trainable parameter인 임베딩 행렬 W에서 look-up을 수행해 해당하는 벡터를 그대로 반환한다.
이를 seq2seq와 비교해보면 seq2seq2는 각 시퀀스가 순서대로 RNN에 입력되어 시퀀스의 순서 정보가 보존이 되었지만
transformer는 한번에 모든 시퀀스를 입력하기 때문에 순서정보를 가지지 못한다.
이때문에 Positional Encoding을 추가적으로 진행한다.
순서 정보를 반영해야 하는 만큼 다음의 정보를 파악 및 구현할 수 있어야 한다.
- 각 토큰의 위치마다 유일한 값을 가짐.
- 토큰 간 차이가 일정한 의미를 지녀야 하고 이는 '나는' 대비 '호두'보다 ''사랑해'나 더 멀리있는 시퀀스이기에 그 차이를 유의미하게 구분할 수 있어야 함을 의미한다.
- 긴 길이의 문장이 입력되더라도 사용가능한 임베딩 방법이여야 한다.
아래 수식과 같은 주기함수 sin, cos 함수를 통해 positional embedding을 수행한다.
3-2. Multi-Head Self Attention
해당 attention에서는 Key, Query, Value의 개념이 차용된다.
Query라는 검색어와 유사한 Key는 2번째 Key인데 각각의 key와의 유사도 [a1, a2, a3, a4]를 구한다.
이후 이 유사도를 가중치로한 key와의 가중치 합 a1*[0.1, 0.5] + a2*[-0.1, 0.7] + .... 을 구하는데 이는 query와 관련이 깊은 key의 value 위주로 값을 가져오게 된다.
encoder에서의 구현은 다음 과정을 통해 이뤄진다.
위와 같은 6개의 token input과 4개의 input dk가 설정되었을 때 해당 embedding layer를 총 3개 copy한다.
이후 trainable parameter인 가중치 매트릭스 W를 각각 내적해주고 그 결과 값이 Query, Key, Value의 매트릭스가 된다.
Query와 Key의 내적 연산을 수행하고 dk로 scaling하게 된다. (논문 dk = 512)
이렇게 scaling하는 이유는 dk가 커질 경우 내적값이 매우 커지는데 이후 softmax를 수행하면 특정값이 1에 매우 근사하게 되며 gradient vanishing 문제가 생길 수 있기 때문이다.
이렇게 최종적인 attention을 구하게 된다. 이는 인코더의 input과 동일한 크기의 텐서이다.
여기까지는 masking의 기능을 가정하지 않은 과정이다.
위 구조에서 존재하는 Masking의 경우 설정한 임베딩 차원보다 적은 token이 입력되었을 경우 부족한 차원을 매우 작은 값을 padding 하는 것을 의미한다.
여기까지는 Multi-Head가 설정되지 않은 경우이다.
Multi-Head가 설정된 경우는 다음의 도식과 같은 차이만 가질 뿐, 위에서 설명한 같은 메커니즘이 사용된다.
(논문에서는 dmodel = 512, num_head = 8 이므로 dk = 64로 설정됨)
위 예시처럼 2개의 num_head를 최종 concat하여 attention을 구하게 된다.
이처럼 multi-head를 사용하게 되면 앙상블의 효과처럼 각각의 head들로 더 다양한 task를 수행할 수 있도록 학습된다.
3-3. Feed Forward
feed forward는 아래의 과정으로 간단히 수행된다.
위 일련의 과정은 하나의 feed forwar net의 연산인데 각각의 head별 multi-head attention 결과에 대해 모두 이뤄지게 되고
하나의 ffn의 파라미터 (W, b)는 같은 encoder layer 내에서 동일한 값을 가지게 된다.
3-4. Residual Connection & Layer Normalization
위 도식은 모델 구조의 add에 해당하는 부분으로 multi-head attention 결과에 input값을 그대로 더해준다.
add한 이후 위 수식대로 normalization을 진행한다.
지금까지의 encoder 수행과정을 한번에 도식화하면 다음과 같다.
이 때 한 encoder layer의 최종 output 크기는 input 크기와 같은데, 이 때문에 output 값이 그대로 다음 layer의 input이 되게 된다.
그리고 논문에서는 layer가 6개인데 이 때의 최종 인코더 ouput이 다음에서 다룰 decoder의 첫 input으로 사용된다.
4. Decoder - Training Architecture
decoder의 많은 부분이 encoder의 내용과 동일하다.
target 문장에 대한 embedding layer를 구축하고 look up table로 해당하는 벡터를 반환하고 positional embedding까지 거치게 된다.
인코더의 attention은 Masked Multi-Head Self attention이라 불리는데 디코더는 Multi-Head Attention이라 불린다.
용어에서의 차이 그대로 인코더와 디코더의 차이점을 짚어보면 다음과 같다.
4-1. Maksed ? (디코더 self attention layer)
먼저 masked의 차이이다.
이 차이는 디코더의 self attention layer에서 발생한다.
인코더와 다르게 padding 된 부분 이외의 요소, 정확히 말하면 행렬의 대각의 윗부분도 매우 작은 값을 가진다는 것을 알 수 있다.
이렇게 진행하는 이유는 token의 시퀀스대로 입력되는 rnn과 달리 순서 관계없이 모든 토큰들이 하나의 행렬로 입력되기에 디코딩 시 예측해야 할 이후의 token에 대한 정보까지 알고 있는 상태이기에 정확한 예측이 될 수 없다.
따라서 예측해야 할 이후의 token에 대해서는 참조하지 못하도록 이렇게 설정한 것이다.
4-2. Self ? (인코더 - 디코더 self attention layer)
또한 self에 대한 차이는 다음과 같다.
이 차이는 Encoder-Decoder self attention layer에서 발생한다.
도식화한 것 처럼 key와 value는 encoder에서 query는 decoder의 self attention을 사용한다. self 즉, 같은 decoder의 output이 아닌 encoder의 output을 사용한다는 점에서 차이가 생긴다.
위 두가지 차이점을 제외하고는 encoder의 구현과 같다.
decoder 또한 최종 output 크기는 input 크기와 같다.
최종 decoder의 과정을 도식화하면 다음과 같다.
5. Last Layer
일반적인 dl 모델 과정과 같다.
최종 decoder의 output에 linear layer를 추가하고 softmax를 통해 target word 전체의 길이만큼 다음 단어에 등장할 sequence 토큰의 등장 확률을 반환하게 된다.
6. Result
이렇게 구현한 transformer는 성능과 학습 비용 측면에서 SOTA를 달성하게 되고, 특히 번역 task에서 좋은 성능을 보였다.
또한 논문에서는 model 설정에 따른 비교 실험도 진행하였는데, head의 갯수가 늘어나면 성능향상이 있었지만 또 너무 많게되면 오히려 성능이 떨어졌다고 한다.
그리고 key의 크기를 줄이면 모델의 성능이 하락했으며 위에서 설명하지는 않았지만 drop-out과 label smoothing의 추가가 성능향상에 효과적이었다고 한다.
Ref
- 고려대 산경공 DSBA 논문 리뷰 강의
- Attention is All You Need 논문
- 위키독스, 딥러닝을 이용한 자연어처리 입문
- https://github.com/jadore801120/attention-is-all-you-need-pytorch
'Advance Deep Learning > NLP' 카테고리의 다른 글
Word2Vec - CBOW & Skip-Gram (0) | 2023.02.23 |
---|---|
BERT - pytorch 구현 (0) | 2023.02.21 |
BERT - 이론 (0) | 2023.02.20 |
GPT (0) | 2023.02.10 |