Transformer
기존 seq2 seq모델에는 한계점이 있었다. 인코더가 결과적으로 하나의 context vector를 만드는 과정에서 동일한 layer를 time step 횟수만큼 거쳐서 정보가 전달되어야 한다. 결과적으로 정보가 같은 모듈을 반복적으로 통과해 가면서 변질되고 유실될 수 있다는 것이다. 이를 보정하기 위해서 어텐션이 고안된 것이기도 하다.
Transformer는, 어텐션을 RNN을 보정하기 위한 용도가 아니라 이것만으로 인코더와 디코더를 만들어보자라는 아이디어를 가지고 구현되었다. 즉, 기존 seq2seq의 구조인 인코더-디코더를 따르지만 이를 모두 attention만으로 구현한 모델인 것이다. RNN을 사용하지 않고, 인코더-디코더 구조를 설계하였지만 RNN보다 우수한 성능을 보여준다. Transformer 은 2017년에 구글에서 발표한 <Attention is All You Need>라는 논문에서 소개되었다.
Self attention이라는 것은 문장 안에서 각 단어끼리의 관계성을 계산하여 반영한다. 즉, self attention을 이용하며, 문장안에서 단어들 간의 관계를 파악할 수 있는 것이다. 이러한 각 단어 간의 관계를 attention score로 표현하는데, 이를 구할 때에는 embedding 된 word vector들끼리 내적 연산을 함으로써 구하게 된다. 그 후 softmax를 통과시켜 다른 단어들 간의 유사도를 구하게 되는 것이다. 그 후, 가중합 과정을 거치고 나면 단어에 대한 context vector가 나오게 되는 것이다.
다시 말하면, attention socre를 각 word vector와 곱해주고(가중치를 벡터에 곱해주는 과정) 모두 더해주는(가중합과정) 것을 문장 내의 모든 단어들에 대해 수행하게 되면 단어 쌍 사이의 의미적, 문법적 관계를 파악할 수 있게 된다.
Transformer의 하이퍼파라미터
하이퍼파라미터라는 것은 모델을 설계할 때 사용자가 임의로 변경할 수 있는 값을 의미한다. 트랜스포머의 주요 하이퍼파라미터는 총 4개를 들 수 있는데,
1) 입력과 출력값의 크기. 주로 d로 표현되며, embedding 차원의 크기도 이와 같고, 하나의 인코더층에서 다음 인코더층으로 넘겨줄때, 하나의 디코더 층에서 다음의 디코더 층에 넘겨줄 때에도 이 값은 유지된다. 논문에서는 512라고 정의하였다.
2) 인코더와 디코더의 층의 개수. 트랜스포머는 여러개의 인코딩 층과 여러 개의 디코딩 층을 쌓아 인코더와 디코더를 설계한다. 그 층이 몇 개로 구성되어 있는지를 나타낸다. 이렇게 층을 쌓아 구성한다는 것 때문에 인코더나 디코더를 encoders/decoders라고 s를 붙여 표현하기도 한다. 논문에서는 num_layers라는 변수이름으로 하였고 6이라고 정의하였다.
3) 어텐션 병렬의 개수. 트랜스포머에서는 어텐션을 여러개로 분할하여 계산한다. 여러 개로 분할하여 병렬처리를 한 후에 다시 하나의 값으로 합치는 과정을 거치게 되는데, 이때 수행하는 병렬의 개수를 의미한다. 논문에서는 num_heads라는 이름으로 8이라고 정의하였다.
4) 피드포워드 신경망의 은닉층의 크기. 트랜스포머의 내부에는 Feed Forward 신경망이 존재한다. 이것의 은닉층의 크기를 의미하며, 해당 신경망의 크기는 d와 같다. 논문에서는 은닉층의 크기를 2048이라고 하였다.
Transformer의 입력 - positional encoding
RNN은 단어의 입력을 순차적으로 받아서 time step에 맞게 처리하였기 때문에 각 단어의 위치정보를 자연스럽게 알 수 있었다. 순서가 바뀌면 encoding 되는 vector들이 바뀌게 되므로, 즉, 정보가 누적되는 순서가 바뀌므로 결과가 바뀌게 된다. 하지만 transformer의 경우, 단어 입력을 순차적으로 받지 않기 때문에 단어의 위치정보를 알 수 있는 다른 방법이 필요하고 그것이 바로 포지셔널 인코딩(positional encoding)이라고 한다.
트랜스포머는 positional encoding에 사인,코사인 함수를 사용한다. 사인 코사인 함수는 주기를 가지는 함수이기 때문에 상대적인 위치를 쉽게 알 수 있게 된다.
인코더의 입력값으로 사용되기 전에 word embedding vector에 positional encoding vector를 더한 vector를 인코더의 최종 입력으로 사용한다.
Attention
Transformer에서는 총 3가지의 어텐션이 사용된다.
- Encoder Self Attention
- Masked Decoder Self Attention
- Encoder-Decoder Attention
첫번째 어텐션은 인코더에서, 두 번째와 세 번째 어텐션을 디코더에서 사용된다.
셀프어텐션은 기본적으로 Query, Key, Value가 동일한 경우이다. 첫 번째와 두 번째 어텐션의 경우 세 가지가 모두 동일하기 때문에 Self-Attention이라고 부르지만 세 번째 어텐션의 경우, Query는 디코더벡터이고, Key와 Value는 인코더 벡터이기 때문에 Self-Attention이라고 부르지 않는다.
위의 그림은 Transformer 의 구조이다.
Encoder
위의 모델구조 그림에서 왼쪽에 해당하는 부분이 인코더이다. N은 인코더 층의 개수를 의미하면 위에서 언급한 파라미터 중 num_layers에 해당하는 부분이다. 하나의 인코더 층에는 위와 같이 2개의 layer로 구성되어 있다. 그것이 바로 self attention과 feed forwarding neural network이다. 이때 셀프어텐션 부분은 병렬적으로 그 계산을 이루었기 때문에 Multi-Head Attention인 것이다.
Multi-Head Attention의 구조는 아래와 같다.
self attention은 입력문장의 단어 벡터들을 사용하는 것은 맞지만 초기 입력의 차원을 가지는 벡터들을 사용하는 것이 아니라, Q, K, V 벡터를 사용하게 된다. 이는 초기입력의 차원보다 작으며 이 값은 위에서 언급한 num_heads라는 변수로 초기 입력의 차원을 나눈 값이다.
word vector에 더 작은 사이즈를 가진 각각의 가중치 행렬을 곱하여 Q,K,V vector를 얻어내게 되며 해당 가중치 행렬은 training과정에서 학습된다.
Scaled Dot-Product Attention
위의 수식은 dot-product 수식이다. 각 단어에 해당하는 query vector가 하나씩 나오게 되며, 각 value의 weight는 query와 그에 상응하는 key의 내적으로 구한다. q·k 가 그 내적계산을 나타내며, 분홍색 박스 안의 계산이 softmax가지 통과하고 난 attention 값이다. 이것을 value vector에 가중치로 걸어서 합친 게 전체인 파란색 박스인데 이것이 해당 query에 대한 encoding vector이다. 해당 계산은 for loop를 돌려서 계산할 수 있는데, 이것을 벡터 연산이 아니라 행렬 연산으로 바꾸어 계산하면 계산속도가 올라간다. (즉, GPU가 잘할 수 있는 걸로 변환해 준 것이다.)
각 워드들의 입력으로 주어진 embedding vector가 다 WQ(query vector 만드는 변환과정)을 통과해서 나온 query vector를 row vector로 구성한 것이 Q 행렬이다. K행렬의 경우 key vector 작용으로 변환되고나서 만들어진 key vector들을 row vector로 구성한 것이고, 이를 transpose 시켜 column vector로 만들었다. V 행렬도 마찬가지로 value vector들을 row vector로 가지고 있는 행렬이다.
attention을 좀 더 일반화해서 생각해보면, query는 query대로, key와 value는 따로 존재한다. 즉, 다른 set의 vector가 제공될 수 있는 것이다. 위의 수식을 행렬을 이용하여 직접 표현해 보면 아래와 같다. 위의 식에서의 박스의 색깔을 아래 그림에서의 행렬을 나타내는 색깔과 동일하게 표현하였다.
초록색 박스 부분은 softmax를 거친 query와 key vector의 행렬을 나타낸다. 이것을 value vector의 행렬과 연산해 주면 파란박스, 즉 결과 행렬이 출력되게 된다. 결과 행렬에서 하나의 행은 value vector들에 가중치를 곱해서 구해진 가중합 vector이라고 할 수 있다. 지금까지의 설명은 Dot-Production이었다. 하지만 이것에는 문제가 있다. softmax를 거치기 전, 내적값이 너무 클 경우 similarity 값 간의 차이는 유지되지만 softmax의 격차가 너무 커지게 된다.
softmax는 지수함수를 통과시키는 것과 같기 때문에 큰 값을 통과시키게 되면 전체 중 해당 값이 차지하는 비율이 너무 극대화된다. 극단적으로 설명하면 제일 큰 내적값의 softmax 확률이 0.99 정도로 몰리게 된다는 것이다. attention 모델에서는 적당히 단어들의 정보를 배합하여 encoding 하고 싶은 것인데, 이렇게 극단적인 값이 생겨버리면 정보를 "조합한다"의 의미가 아니라 "하나를 고른다"의 의미가 되어버린다. 따라서 이것을 dk로 나눠주게 된 것인데, 나눠주게 되면 값이 더 작아지게 되고, 그 후에 softmax를 취하면 확률값의 대소관계가 바뀌진 않지만 확률값 간의 격차가 줄어든다.
다시 말하면 dimension이 커지게 됨에 따라 softmax값에 영향을 미치는 것을 방지하고자 dk로 나누게 되었고 이를 통해 scale을 유지할 수 있게 하는 것이다.
따라서, Scaled Dop-Production Attention의 연산은 다음과 같다.
Multi-Head Attention
Attention을 병렬로 수행한다는 것은 다양한 시각을 가지겠다는 것과 같은 의미로 생각할 수 있다. 이것은 단 한 번의 attention을 수행하는 것보다 효과적이며 attention head는 각각의 attention 값 행렬을 의미한다. 병렬 attention을 모두 수행하고 나면 모든 attention head를 이어 붙인다.(concatenation)
이후, dimension을 줄여주기 위해 Linear Transformation을 한번 더 거치게 되고 이것의 결과물이 Multi-Head Attention 행렬이다. 다시 말하면, 각 head에서 나타난 attention weighted 된 value vector들(서로 다른 기준에서 추출되어 encoding 된 vector들)을 Linear Transformation을 통해 dimension 줄여진 벡터를 만들어내는 것이 Multi-Head Attention이다. Multi-Head Attention의 수식은 아래와 같다.
Feed Forward Neural Network(순방향 신경망)
FFNN은 인코더에도 있고 디코더에도 있는데 이것은 두 개의 Linear transformation으로 구성되어 있으며, 그 사이에 ReLU가 위치해 있다. 입력층, 은닉층, 출력층으로 구성되어 있으며, 입력층(input layer)에서 데이터를 전달받아 은닉층(hidden layer)은 데이터의 정보를 추출하고, 출력층(output layer)에서는 추출한 정보를 바탕으로 추론한 내용을 출력한다.
Multi-Head Attention의 결과로 나온 행렬이 FFNN의 입력값인 x로 들어가게 되며, 최종 출력값의 크기는 보존된다. 아래의 그림과 같이 Multi-head Self-Attention을 통과한 각각의 word vector들이 FFNN을 통과하여 나온 각각의 벡터가 다시금 그다음 층의 multi head self attention의 입력값이 되면서 인코딩을 진행하게 된다.
Residual Connection & Layer Normalization
위의 구조 그림을 보면 알 수 있듯이 Multi head self attention과 FFNN만 존재하는 것이 아니라 추가적으로 사용하는 Add&Norm이라는 것이 있는데 이것은 Residual connection과 Layer Normalization을 의미한다.
Residual Connection(잔차연결)이라는 것은 컴퓨터 비전 분야에서 많이 사용되는 기법인데, 서브층의 입력과 출력값을 더하는 것이다. 가령 F라는 함수를 통과하는 입력값 x가 있다고 하면, 잔차연결을 한 후의 값은 x + F(x)인 것이다. 트랜스포머의 경우 sub layer의 입력과 출력은 동일한 크기를 가지므로 덧셈연산이 가능하다. 따라서 residual connection 연산은 x + MultiHeadAttention(x)인 것이다.
Residual Connection을 수행한 이후에는 층 정규화 과정을 거치게 된다. 층 정규화(Layer Normalization)는 batch norm 과는 다른 기준으로 선정된 샘플들로부터 얻어진 평균, 분산으로 정규화하는 것으로, 이것의 취지는 학습을 안정화하고 이후에 통과할 Non Linear Unit 전에 포화되지 않도록(saturated 되지 않도록) 값들을 적절하게 바꿔주기 위함이다.
층 정규화 과정은 두 단계를 거치게 된다. 각각의 word vector들로 하여금 평균값 0과 분산값 1을 가지도록 한다. 그 후 노드 별로(=차원별로) 동일한 transformation을 적용한다. 예를 들어 y = 3x + 1과 같은 변환과정을 거친다고 하면, 이러한 식은 각 노드 별로 다른 식으로 적용되며 3과 1은 학습을 통해 최적화된 값이다.
Decoder
여러 층의 인코더 블록을 거쳐 나온 값들을 decoder에게 전달하여 디코더 연산을 시작하게 된다. 디코더도 마찬가지로 num_layers 만큼의 층으로 구성되어 있으며 이때마다 인코더에서 나온 값들을 디코딩 층에 사용한다.
Masked Self-Attention
Decoder 블록의 첫 번째 sub layer은 masked self attention이다. 나중에 정리할 내용이지만, 현재엔 디코더를 학습시킬 때 처음부터 끝까지 Teacher Forcing이라는 기법으로 학습시키게 되는데, 간단히 말하면 정답이 되는 문장을 디코더의 입력으로 처음부터 다 제공하는 것이다. 또, RNN과는 다르게 미래의 sequence에 해당하는 단어들까지 참고할 수 있게 된다. 이를 막기 위해 현재 시점의 예측에서 미래에 있는 단어들을 참고하지 못하도록 attention weight 값을 0으로 하는 masking 한다.
위의 그림은 Q와 K 행렬이 연산되고 softmax를 거치고 나서의 모습인데, 분홍색으로 색칠해 둔 인덱스는 해당시점에서의 미래단어에 대한 내용을 담고 있는 부분이다. 현재시점의 단어예측에서 미래에 있는 단어들을 참고하지 못하도록 해야 하기 때문에 0으로 만들어주는 것이다.
Encoder Decoder Attention
Decoder의 두 번째 sub layer로 이는 multi head attention을 수행한다는 점에서 이전 어텐션과 공통점이 있지만, self attention이 아님을 주의해야 한다. Key와 Value vector는 인코더 쪽에서 입력되고 Query vector 는 디코더로부터 얻게 된다. 모든 vector의 출처가 같지 않으므로 self attention이라고 할 수 없다.
세 번째 sub layer은 인코더 부분에서 설명했던 FFNN과 동일한 구조를 거치게 된다.
Complexity
Self-Attention과 Recurrent만 비교해 보자면, squencial operation의 수가 현저히 self attention이 적은 것을 알 수 있다. RNN의 경우 코어수가 많아도 n번 돌려야 하는 것은 변하지 않는다. Self-Attention의 단점이 있다면 메모리가 많이 필요하다는 것인데, d의 경우엔 encoding vector의 dimension으로 sequence가 길다고 크진 않으며 어느 정도 제어 가능한 부분이다. 반면 n은 제어가 되지 않아 critical 하다고 할 수 있으며 메모리가 많이 필요하다.