네이버 부스트캠프/LEVEL-2

[부스트캠프][WK07 / Day30] Transformer (1)

1. 강의 내용

Transformer (1) (주재걸 교수님)

1) Transformer

Transformer는 attention만을 사용해서 구현한 Sequence to Sequence 형태의 모델구조를 가지고 있습니다.

RNN을 사용할 시 RNN 구조를 통해 Sequence 데이터를 인코딩해 주는데, Long-Term Dependecy가 발생하여 이를 해결하기 위해 동일한 시퀀스에 대해 정방향으로 인코딩한 값과 역방향으로 인코딩한 값을 concat하는 Bi-directional RNN 구조를 사용함으로써 앞뒤 문맥을 모두 고려하여 Encoding vector를 만들어주게 됩니다.

 

Transformer에서 Encoding vector를 만들어주는 과정을 아래와 같습니다.

[출처][http://jalammar.github.io/illustrated-transformer]

기존의 attention 구조에서는 Encoder hidden state vector들을 Decoder의 hidden state vector와 내적하여 Attention score를 구해주고 그 값을 softmax에 넣어주어 Attention 분포를 만들어 해당 분포(Attention vector)를 Encoder hidden state vector값과 가중평균하는 방식으로 output을 만들었습니다. Transformer에서도 이와 비슷한 과정으로 진행되지만 Encoder hidden state vector들을 Decoder의 hidden state vector와 내적하는 것이 아닌 $x_1$을 Decoder hidden state vector라 생각하고 $x_1, x_2, x_3$을 Encoder hidden state vector라 하고 내적을 하게 되면 $x_1$은 자기자신과 내적을 하는데 이것을 self attention이라고 합니다. 이 과정에서 자기자신과 내적을 할 경우 다른 값과의 내적보다 큰 유사도를 가지게 되어 자기자신에 큰 가중치를 가지게 됩니다. 이렇게되면 인코딩한 결과벡터도 자기자신의 정보만 주로 포함하고 있는 벡터로 나오게 되는데, 이를 해결하기 위해 위의 그림과 같은 방식을 사용하게 됩니다.

 

주어진 벡터 중 어느 벡터를 선별적으로 가져올지의 기준이 되는 벡터를 query라 표현하고 유사도가 계산되도록 query와 각각 내적되는 벡터들을 key라 하며 내적 후 softmax를 거쳐 가중평균하게되는 Encoder hidden state vector의 역할을 하는 벡터들을 value라 합니다. 여기서 동일한 세트의 벡터에서 출발해도 query, key, value로 변환할 수 있도록 하는 linear trainform matrix가 $W^Q, W^K, W^V$로 따로 존재합니다. 여기서 key, value 벡터는 각각이 대응되는 값이기 때문에 분리되어 있지만 개수는 동일해야 합니다. query, key값을 내적해주고 이를 softmax를 통과시켜 확률값이 나오면 이는 value 벡터의 가중치가 되어 가중평균해 결과 벡터가 나오는데, 이는 해당 step의 query 벡터에 대한 $h_t$가 됩니다. 결국 위의 과정을 거치면 모든 time step의 벡터를 모두 고려하기 때문에 Long-Term Dependecy 문제를 해결하게 됩니다.

 

위의 과정을 수식으로 표현하면 아래와 같습니다.

-> 소문자: 벡터, 대문자: 행렬

 

여기서 보면 query와 key 벡터는 내적이 가능해야 하기 때문에 같은 차원의 벡터여야 하며, value 벡터는 몇차원이든 벡터의 개수는 같고 상수(softmax 결과) 배를 해서 가중평균을 내기 때문에 query나 key와 반드시 같은 차원일 필요는 없습니다.

2) Scaled Dot-Product Attention

위의 수식을 다수의 query가 주어지는 입력을 받았을 때로 바꿔주면 아래와 같습니다.

matrix Q는 query의 개수 $|Q|$와 각 query의 차원(열)의 개수 $d_k$를 곱해준 것이 되며 matrix K를 tranpose해 주어 곱해주면 query의 개수 x key의 개수인 $|Q| * |K|$의 행렬이 나옵니다. 여기에 row-wise softmax를 해주면 각 query에 대한 $|K|$개의 값의 합이 1인 형태의 가중치가 각 행에 표현됩니다. 다음으로 $|K|$와 $|V|$의 개수가 같으므로 $|V| * d_v$를 곱해주면 각 가중치를 $|V| * d_v$의 row vector별로 곱해줘 결과 matrix의 각 행을 형성합니다.

[출처][http://jalammar.github.io/illustrated-transformer]

query와 key를 내적하게되면 차원의 개수가 같아야 합니다. 만약 query와 key가 2차원의 벡터이고 평균 0, 분산 1의 분포를 가진다면, 아래의 그림과 같이 둘의 내적값의 평균은 0, 분산은 2이 됩니다.

 

만약 query와 key가 100차원을 가진다면 분산은 100이 될 것 입니다. 이렇게 분산이 큰 값을 softmax에 넣어주면, softmax의 확률분포가 큰 값에 몰리는 현상이 발생하게 됩니다. 이를 보완하기 위해서 Scaled Dot-Product라는 방법으로 내적값에 차원에 루트를 씌워준 값인 $\sqrt{d_k}$를 나눠줘서 분산을 조정해줍니다.


2. 과제 수행 과정 / 결과물 정리


3. 피어세션 정리

https://www.notion.so/9-13-01c03ad9b52244c89839aded7547f4da


4. 학습 회고

트랜스포머를 공부하고 프로젝트에도 적용해 봤지만 Q, K, V의 연산과 나눠지는 기준에 관한 디테일은 제대로 알고 있지 않았는데, 이번 강의를 통해 조금 더 확실하게 기억할 수 있었습니다. 처음 몇 번 공부할 때는 전체적인 개념을 머리에 담고 기억했지만, 이번에 복습하게되며 디테일한 수식 등에 대해 공부하니 또다른 재미가 있는 것 같습니다.