Transformer

창진손·2023년 2월 8일
1
post-thumbnail

boost course 자연어 처리의 모든 것 강의를 보고 복습차원에서 정리해 보았습니다.

앞의 chapter에서 설명드린 RNN의 구조에 대해서 간단하게 살펴보고 가겠습니다. RNN은 현 시점의 input과 이전 시점의 hidden state를 입력으로 받는다고 하였습니다. 위의 그림을 보면 time step 1에서는 "I"와 h(0)가 input으로 사용이 되었고 그 결과 h(1)이라는 output을 출력하였습니다. 여기서 만들어진 h(1)의 경우 "I"라는 단어에 대한 정보를 포함한다고 말씀드렸습니다. 이러한 방식으로 time step 2에서는 이전의 hidden state인 h(1)과 "go"라는 단어를 입력으로 사용하고 h(2)를 만들었습니다. 그렇다면 h(2)에는 "I", "go" 두가지 단어에 대한 정보가 들어있을 것입니다. RNN계열의 모델들은 각 모델마다 차이는 존재하지만 큰 틀에서 보면 이러한 방식으로 작동을 하는데 이 경우 sequence의 길이가 길어지면 길어질수록 앞쪽 단어들에 대한 정보의 손실이 발생하게 되고 잘못된 예측을 하는 결과를 불러오게 됩니다.

Bi-direction RNN

이러한 RNN 계열의 모델들의 long term dependency에 대한 문제를 해결하는 방법으로 attention과 bi-direction이라는 방법이 있다고 말씀을 드렸습니다. attention에 대한 기본적인 내용은 앞의 chapter들을 참고 부탁드립니다. bi-direction RNN은 long term dependency에 대한 문제를 해결하는 방법으로 sequence에 대하여 정방향과 반대 방향을 모두 사용하여 sequence를 읽어나가는 모델입니다. bi-direction RNN 안에는 크게 두가지 모델이 존재합니다. forward RNN과 backward RNN입니다. forward RNN의 경우는 기존의 RNN과 동일합니다. 문장의 앞쪽에서부터 단어의 정보를 저장하여 hidden state를 만들어 줍니다. backward RNN의 경우는 이와 반대로 작동을 하며 문장의 뒤쪽에서부터 단어의 정보를 저장하여 hidden state를 만들어 줍니다. 이렇게 하면 forward RNN의 마지막 hidden state에는 상대적으로 문장의 뒷쪽 정보들에 대하여 잘 학습이 되었을 것이고 backward RNN의 경우는 문장의 앞쪽 정보들에 대하여 잘 학습이 되었을 것입니다. 이 두개의 hidden state를 병렬연결하여 학습을 진행하는 모델이 Bi-direction RNN입니다.

Transformer

RNN의 문제점을 해결할 수 있는 방법으로는 Bi-direction외에 attention이 있다고 하였습니다. 그리고 앞에서 말씀드린 seq2seq model은 RNN을 이용하여 encoder에서 context vector(hidden state)를 만들어 내었습니다. 이러한 기존의 방법의 문제점을 보완하기 위해 RNN대신 attention을 이용하여 seq2seq model을 구성한 것을 transformer라고 부릅니다.

transformer의 기본구조는 위의 그림과 같이 생겼습니다. 이제부터 transformer의 구조를 하나씩 살펴보도록 하겠습니다.

Encoder

encoder의 구조를 먼저 살펴보겠습니다. 위 그림은 하나의 인코더를 표현한 그림이고 실제 tranformer에서는 여러개의 층을 쌓아서 사용하였습니다. encoder 안에는 총 3가지의 요소가 존재합니다. multi-head attention부터 천천히 살펴보겠습니다.

scaled dot product attention

attention의 기본적인 내용들은 앞에서 설명을 드렸고 transformer에서 attention이 어떻게 사용되는지 한번 알아보겠습니다. scaled dot product attention은 encoder와 decoder의 구조 그림에서 multi-head attention에서 일어나는 attention 계산입니다. 우선 먼저 이계산에 대해서 먼저 설명을 드리고 왜 multi-head attention이라고 부르는지를 설명드리겠습니다. transformer에서는 크게 두가지 방법으로 attention이 사용이 됩니다. encoder나 decoder의 각각의 내부에서 입력문장끼리 일어나는 "self attention"과 encoder와 decoder 사이에서 decoder hidden state와 encoder hidden state사이에 일어나는 "edcoder-decoder attention"입니다. edcoder-decoder attention은 앞의 chapter에서 설명드린 내용과 비슷한 방법으로 진행되니 앞의 내용 참고 부탁드립니다.

self attention의 경우에는 위의 그림과 같이 진행이 됩니다. encoder를 먼저 예로들어 설명을 해보겠습니다. encoder는 입력문장의 sequence 정보를 하나의 hidden state 벡터로 잘 압축하여 표현하는 것이 목적입니다. 기존의 seq2seq model에서는 encoder 내부에서는 RNN 계열의 모델을 사용하였지만 Transformer에서는 encoder 내부에서도 RNN 계열의 모델을 사용하지 않고 self attention을 사용하여 encoder hidden state(context vector - 입력 문장의 정보를 담고 있는 벡터)를 구합니다.

self attention의 기본적인 연산과정부터 알아보겠습니다. 앞 chapter에서 설명드린 attention의 경우에는 decoder의 hidden state와 encoder의 hidden state의 dot product로 attention score가 계산이 되었었고 이 attention score는 두 벡터의 유사한 정도를 의미한다고 말씀드렸습니다. 그 후 encoder의 hidden state에 각각의 attention score를 곱해서 attention vector를 만들었습니다. 여기서 처음에 dot product를 수행하는 encoder hidden state를 "query"와 decoder hidden state를 "key"라고 할 것이고 마지막 attention score를 곱해주는 encoder hidden state를 value라고 하겠습니다.

우리는 이과정을 그대로 encoder 내부에서만 작동을 시킬 것입니다. self attention에서는 앞에서 attention score를 계산하는 부분을 encoder hidden state 1과 encoder hidden state 2로 dot product를 계산할 것입니다. 그리고 이것은 encoder 내부의 각각의 단어가 얼마나 유사한지에 대한 정보를 담게 됩니다. 그 후 이 유사도 정보를 다시 encoder hidden state 3에 곱해주고 선형변환 계산을 하여 attention 벡터를 출력하게 됩니다. 처음에 dot product를 수행하는 encoder hidden state 1을 "query", encoder hidden state 2를 "key", 마지막 attention score를 곱해주는 encoder hidden state 3를 "value"라고 하겠습니다.

여기까지 이해하고 위의 attentoion 식을 보겠습니다. 위 식에서 보시면 QK(t)의 의미는 query와 key의 dot product를 계산한 것이고 거기에 루트 d(k)로 나눠주고 softmax함수를 거칩니다. 그 후 value를 곱해주어 attention을 구하는 것을 알 수 있고 위에서 설명드린 것과 루트 d(k) 말고는 완전히 똑같은 것을 알 수 있습니다. 그렇다면 루트 d(k)는 무엇일까요?

위 그림의 예시를 한번 보겠습니다. query가 [a,b]라는 벡터이고 key가 [x1, x2]이고 각각의 분산이 1이라고 가정 하겠습니다. 만약 이 벡터들이 2차원인 경우 query와 key의 dot product의 분산은 밑의 수식에 따라 2가 되는 것을 알 수 있습니다. 그런데 만약 이 벡터들의 차원이 300이라고 생각한다면 이 dot product의 결과는 분산이 300이 될 것입니다. 그러면 이제 여기서 문제가 발생을 하는데 softmax 함수의 특성상 큰 값일수록 더 큰 확률값을 주게 되므로 분산이 크다면 softmax 함수의 결과가 과장되어 나타나게 됩니다. 이러한 문제를 해결하고자 내적값에 벡터들의 차원에 루트를 취한 값인 루트 d(k)로 나누어 주게 되는 것입니다.

multi-head attention


그러면 이제 왜 multi-head attention이라고 부르는지 알아보겠습니다. multi-head attention을 이해하기 쉽게 위의 그림으로 나타내어 보았습니다. 예를 들어 I am a student라는 문장이 있다고 가정하고 각각의 단어들을 임베딩과 선형변환을 통하여 query, key, value로 나타내었고 각각의 차원이 (1,4,512)인 행렬로 나타났다고 가정을 해 보겠습니다. multi-head attention라는 말의 의미는 나누어서 attention을 실행하겠다는 의미입니다. 옆의 그림처럼 (1,4,512)인 행렬을 8개로 나누어 (1,8,64)인 행렬을 만들고 query와 key의 attention계산을 한 후 다시 (1,4,512)인 행렬로 만들어 value와 곱해주는 것입니다. 이렇게 attention을 수행하면 각각의 8개 행렬의 attention이 다양한 position에서 다양한 시각으로 representation을 얻는 효과를 얻을 수 있습니다.

position-wise feed forward neural network


여기까지 이해하셨으면 다음 layer인 position-wise feed forward neural network로 넘어가겠습니다. position-wise feed forward neural network은 간단합니다. 위의 그림처럼 들어온 입력값에 대하여 선형변환 - ReLU - 선형변환의 구조입니다. 여기서 중요한 것은 행렬연산의 차원입니다. 여기서 중요한 것은 행렬의 차원입니다. 앞에서 인코더의 구조를 말씀드릴 때 입력값을 받고 실제 모델에서는 인코더를 여러개 쌓아서 사용했다고 말씀드렸습니다. 인코더를 여러개 쌀을려면 실제 encoder 모델에 들어오는 input과 output의 행렬의 크기가 같아야 합니다. 실제 인코더의 모델에 입력으로는 (batch size, sentence length, model dimension) 이런 size의 3차원 행렬이 들어오게 되는데 예를들어 첫 input으로 (32, 100, 512)의 차원 행렬이 들어왔고 encoder를 2개 쌓았다고 가정해 봅시다. 이 행렬은 encoder 1의 입력으로 들어갈 것이고 encoder 1은 어떤 output 행렬을 return을 할 것입니다. 여기서 나온 output 행렬이 다시 encoder 2의 input으로 들어가려면 (32, 100, 512)차원의 행렬이어야 할 것입니다. 그래서 position-wise feed forward neural network의 마지막 선형변환 layer에서는 이 차원을 맞추어 주게 됩니다.

Residual connection

Residual connection은 위의 인코더 구조 이미지를 보시면 Add&Norm이라는 것을 볼 수 있습니다. Residual connection은 여기서 Add 부분에 해당합니다. Residual connection은 Computer vision 쪽에서 레이어를 계속 쌓아감에 따라 발생하는 gradient vanishing 문제를 안정화시키고 더 높은 성능을 보이도록 하는 방밥입니다. Residual connection의 계산 방법은 간단합니다. multi-head attention의 input으로 들어오는 x와 multi-head attention의 output을 단순히 더해주는 것입니다. 그런데 여기서 주의해야 할 점은 이처럼 두개를 더할려면 앞의 position-wise feed forward neural network에서 말씀드린 것처럼 차원이 맞아야 하고 그것을 multi-head attention에서 실제 다 수행하고 난 뒤 그 결과를 선형변환을 통하여 맞추어 줄 수 있습니다.

layer normalization

layer normalization은 Add&Norm에서 Norm에 해당하는 부분입니다. 딥러닝에서 norm의 방법에는 batch norm, layer norm, instance norm, group norm 과 같은 것들이 있습니다. 여기서 norm의 의미는 평균을 0, 분산을 1로 만들어 주는 것입니다. 위의 layer norm에 대한 예시를 보겠습니다. layer norm은 처음에 thinking과 machine에 대한 벡터를 받습니다. 그 후 norm의 과정을 통하여 각각의 평균과 분산을 1로 만들어주게 됩니다. 그 후 각 노드를 ax + b 형태의 transformation에 각각의 값을 넣어주어 최종 결과물을 출력하게 됩니다. 여기서 a와 b는 학습되는 parameter로 존재하게 됩니다.

여기까지 transformer의 encoder 구조에 대해서 알아보았습니다. 다음으로는 decoder 구조에 대해서 알아보겠습니다.

Decoder

위 그림을 보시면 decoder의 구조는 encoder의 구조와 별 다른것이 없는 것을 알 수 있습니다. 여기서는 차이점만 말씀을 드리고 넘어가겠습니다.

Masked Multi-head attention

디코더의 구조를 보면 첫번째로 만나는 것이 Masked Multi-head attention인 것을 알 수 있습니다. Masked Multi-head attention에서는 위에서 말씀드린 Multi-head attention이 동일하게 진행이 됩니다. 다른점은 attention score 행렬에서 masking을 적용한다는 점입니다.

우선은 위 그림과 같이 attention score를 구하게 됩니다. 하지만 여기에는 한가지 문제점이 있습니다. 모델의 관점에서 생각해 본다면 디코더는 현재 시점에 입력된 단어만을 가지고 다음단어를 예측을 하여야 합니다. 하지만 위와 같은 그림의 형식으로 attention score를 제공을 하다면 decoder 모델은 현재 자신의 시점 뒤의 단어도 참고를 할 수 있을 것이고 이것은 그냥 모델에게 정답을 알려주는 것과 다를 것이 없게 되는 것입니다. 이것을 방지하기 위한 것이 Masked Multi-head attention입니다.

위의 그림처럼 현재시점 이후의 단어들에 대해서는 전부 다 masking 처리를 해주는 것입니다. masking된 이후의 attention socore에서는 그 시점의 이전 단어까지만 참고를 할 수 있는 것을 볼 수 있습니다.

Multi-head attention

디코더의 두번째 Multi-head attention layer는 encoder-decoder attention이라는 점 말고는 encoder와 동일하게 작동합니다.

positional encoding

이제 마지막으로는 positional encoding이라는 것입니다. RNN 계열의 모델에서 Input의 형태는 단어가 하나씩 모델로 들어가는 형태였습니다. 하지만 transformer에서는 이러한 RNN 계열의 모델을 사용하지 않기 때문에 입력이 단어 하나씩 들어가는 것이 아니라 문장 전체가 하나도 들어가게 됩니다. 이러한 경우 모델은 입력값에 sequence의 순서 정보가 없어지기 때문에 I am a student와 student a am I라는 문장을 동일한 문장으로 인식을 하게 됩니다. 이러한 문제를 해결하기 위해 나온 것이 positional encoding입니다.

위의 수식을 보시면 짝수인 경우 sin함수 홀수인 경우 cos함수를 사용하여 나타내고 있습니다.위와 같은 positional encoding 방법을 사용하면 순서 정보가 보존되는데, 예를 들어 각 임베딩 벡터에 포지셔널 인코딩의 값을 더하면 같은 단어라고 하더라도 문장 내의 위치에 따라서 트랜스포머의 입력으로 들어가는 임베딩 벡터의 값이 달라집니다. 이에 따라 트랜스포머의 입력은 순서 정보가 고려된 임베딩 벡터가 되는 것입니다.

profile
NLP취준생

0개의 댓글