task 는 주로 입력 문장과 출력 문장의 길이가 다를 경우 사용 (e.g. 번역 및 텍스트 요약)
seq2seq 는 크게 encoder 및 decoder 의 두 가지 모듈로 구성
encoder는 입력으로 임베딩 벡터를 순차 입력 받은 뒤 rnn (또는 gru, lstm cell) 의 hidden state를 거쳐 정보를 압축해 마지막에 모든 단어 정보를 압축한 하나의 벡터인 context vector 생성. 즉 encoder 의 최종 목적은 context vector 를 만드는 것이며, context vector는 float으로 이루어진 하나의 벡터이다.
입력 문장 정보가 하나의 context vector 로 압축되면 decoder 로 전달, decoder는 context vector를 받아 번역된 단어를 한 개씩 순차적으로 출력
decoder에는 초기 입력으로 문장 시작 심볼 을 입력으로 받으며, 이후 다음에 등장할 확률이 제일 높은 단어 예측함.
rnn (또는 gru, lstm cell) 을 거치며 hidden state 는 계속 다음 step으로 연결되고 (decoder의 rnn -> rnn) dense-softmax를 거쳐 이 출력됨. 이후 다시 은 rnn의 입력으로 들어가게 됨. 즉 decoder의 rnn은 와 hidden state를 입력으로 받아 을 생성함.
problem
decoder 의 input으로 encoder의 최종 출력인 context vector만을 사용하는 것에 문제점 존재
1. 하나의 고정 크기 벡터(context vector) 에 모든 정보를 압축하여 정보 손실 발생
2. vanishing gradient 문제 존재
특히 번역 task에서 입력 문장 길이가 길면 번역 품질이 떨어지는 현상 발생
Query: 질의, 찾고자 하는 대상
Key: 키, 저장된 데이터 찾을 때 참값
Value: 키에 저장된 데이터
attention에서는 주어진 '하나의' query가 어떤 key와 유사한지 모든 key와 각각 비교해 유사도를 얻고, key와 매핑되어 있는 각각의 value를 모두 더해 attention value를 만든다. 즉, query에 해당하는 dictionary의 key값들이 query와 얼마나 유사한지 계산한다. 이때 유사도가 가중치 역할을 한다고 볼 수 있음
이때 query는 decoder의 hidden state가 되며, encoder의 hidden state가 key와 value가 됨
가장 기본적인 구현 방식으로 comparison은 fully connected 방식 연산, aggregate의 경우 모든 key-value에 대해 벡터의 element-wise multiplication 연산을 한 후 element-wise sum 하여 attention value 생성. 수식은 아래와 같다.
decoder에서 라는 query가 입력되고, 그 query와 모든 key값인 와 comparison 연산을 통해 유사도를 구한 뒤, value에 해당하는 와 각각의 유사도를 곱한 뒤 element-wise sum 하여 attention value 출력.
그림에서 사용된 연산을 수식으로 표현하면 아래와 같다. ( 와 자리에 주의할 것)
이전 모델에서 입력 시퀀스의 정보 손실이 발생하는 seq2seq의 문제를 해결하기 위해 보정 용도로 attention이 사용되었는데, attention으로만 encoder와 decoder를 만들어보자는 아이디어
이전 seq2seq 구조에서는 encoder와 decoder에서 각각 1개의 rnn이 t개의 시점(time step)을 가지는 구조였다면 trnasformer는 encoder와 decoder의 단위가 N개로 구성되어 있음(논문에서는 6개를 default로 설정)
1. input에 대해 Embedding
w2v과 같은 방법으로 입력 텍스트를 token embedding으로 변환한다. 어텐션 메커니즘은 단어(토큰)의 상대적 위치를 알지 못하기 때문에 텍스트 순서 특징을 모델링하기 위해 각 토큰의 위치 정보가 담긴 positional embedding 을 토큰 임베딩 및 embedding with time signal 값과 더해 encoder block 의 input값으로 사용한다.
2. encoder block
1) self attention
:: output: 각 단어의 vector들끼리 서로간의 관계가 얼마나 중요한지 점수화된 vector
입력 문장은 위의 과정을 거쳐 크기가 512 인 vector로 변환된 뒤 첫 번째 encoder block의 attention layer로 입력됨. 이후 weight vector 를 곱해 q, k, v 벡터를 생성해냄. 이렇게 한 단어에 3가지 vector가 나오게 되고, 특정 연산을 해 attention layer의 output을 만들어냄.
2) Multi-Head Attention
3) Point-Wise Feed-Forward Netorks
attention layer를 통과한 값들은 FCN을 지나는데, 하나의 인코더 블록 내에서는 다른 문장/단어들마다 정확하게 동일하게 사용되지만 각 인코더 마다는 다른 값을 가지게 된다. (이해필요)
3. decoder block
challenge
wide range of tasks에 약간의 조정만으로도 transfer 할 수 있는 범용 representation을 학습하는 것
framework 는 2개의 stage :: 1. Pretrain, 2. fine-tuning
이때, 몇 가지 task들은 fine-tuning 시 input shape을 변형해 넣어줘야 함.
변경점
BPE란?
# vocabulary
low, lower, newest, widest
위처럼 훈련 데이터 단어집합이 있을 경우, 테스트 과정에서 'lowest' 라는 단어가 등장한다면 이 단어를 학습한 적이 없으므로 해당 단어에 대해 제대로 대응하지 못함. 이것을 Out of Vocabulary 라고 함.
이때 BPE 알고리즘을 사용할 경우, 먼저 위의 # vocabulary DB에서 단어들을 글자 단위로 분리해 초기 단어 집합을 만든다.
# vocabulary
l, o, w, e, r, n, s, t, i, d
이후 가장 빈도수가 높은 유니그램의 쌍을 하나의 유니그램으로 통합한다. (통합 Iteration은 hyperparameter)
# vocabulary update! (10회 반복 시)
l, o, w, e, r, n, s, t, i, d, es, est, lo, low, ne, new, newest, wi, wid, widest
이후 input 단어 'lowest'를 전부 글자 단위로 분할하여 'l, o, w, e, s, t'로 만든 뒤, 단어집합을 참고하여 'low'와 'est'를 찾아내어 'lowest'를 'low'와 'est'의 두 단어로 인코딩함. 두 단어는 업데이트된 DB에 존재하므로 더이상 OOV 문제가 발생하지 않음.