2020년 11월 8일 일요일

가장 짧게 transformer 설명

어떤 시계열 데이터가 있는데, 시계열 길이는 32이고 속성 수는 16개라 가정하자.  

그러면 데이터 shape은 original=(bs, slen=32, nfeat=16)이다. bs는 batch_size이다. 여기서, 첫번째 데이터인 (32,16) 행렬만 추출하여 tansformer연산을 해보자.


1. (32,16)을 속성 수가 16이 아닌 8로 만드는 linear층을 적용한다. 물론 8은 바꿀수 있다. 

그러면 데이터는 (32,8)이된다. 그리고 속성은 더이상 origianl이 아닌 latent텐서가 된다. 


2. transformer의 self attention사용할 예정이므로 1에 설명된 방법으로 original로부터 (32,8)인 query, key, value 텐서 3개를 만든다. 


3. 먼저 query와 key에 대해 attention(가중치) 연산을 수행한다 (self attention연산 이해는 이미지를 활용한 아래 사례를 참조한다). 

query*key'=(32,8)x(8,32)을 하면 (32,32)크기가 나온다. 이것은 시간 t=i에서 8개 속성과 t=j에서 8개 속성을 유사도 비교 연산한 것이다. 

즉, 서로 다른 시간에서 신호 속성들의 유사도를 따지는 것이다. 현 신호는 이전 어떤 시간대에서 관련성이 있는지를 평가한다. 


따라서 (32,32)행렬 첫 행은 t=1(8속성)과 t=1,2,3,...,32까지를 비교한 값들이고, 이 값을 정규화(softmax)하여 저장한 것이다. 

이 값을 value의 첫번째 속성인 (32,1)에다 곱해준다: a1*v1+a2*v2+a3*v3+...+a32*v32


또, (32,32)행렬의 두번째 행은 t=2(8속성)와 t=1,2,3,...,32까지 속성을 비교한 것이다. 이 값도 마찬가지로 

value의 두번째 속성인(32,2)에 있는 32개 벡터와 차례로 곱해준다: a1*v1+a2*v2+...+a32*v32



4. 이런 식으로 연산을 하면 결과 행렬식 (32,8)이 생기는데, 이것이 한개의 self-attention head이다. 


5. attention head는 보통 여러개가 되고, 이를 함께 연결하여(concat) 큰 행렬 하나로 묶어 내고, 이를 linear층을 통과시켜 original data와 크기가 같은 (32,16) 행렬을 만든다. 


6. original 입력(32,16)은 attention head 출력(32,16)과 더해주는데 이는 original data의 크기값(scale)이 Attention Head 출력에 잘 반영되도록 하기 위함이다.



(사례)



그림은 Input sequence에 대한 Transformer 연산을 좀 더 쉽게 이해하기 위해 dog and dog 이미지를 이용하여 self attention 방법을 보여준다. 이미지를 4개의 patch로 분할하여 patch가 나타난 순서대로 일렬로 세워서 벡터로 만들고 이를 곱해준다. 

곱한 결과인 softmax($QK^T$) 행렬을 보면, 


- 자기 자신 patch끼리의 상관성 높음 (대각방향)    

- Noisy한 배경 끼리의 상관성은 낮음 (비대각 방향)

- Patch 2와 Patch3은 둘 다 dog이므로 상관성 높음 ($a_3^2$와 $a_2^3$ 높음)

- $V$와 곱하면 Output 2, 3 만 높음 (attention 됨). dog가 있는 patch가 attention 되었음. 

- 입력에서 반복 출현하는 유의미(salient) 객체는 상관성 높음 (자기 상관성이던 다른 dog와 상관성이던 배경보다 높아짐)

 

Output행렬의 첫 행을 보면 t=1~4의 4개의 데이터 $V$에 attention(가중치) 값 $a_j^i$값이 곱해진 형태이다. 이것은 sequence 데이터(t=1~4)에 가중치 weight($a_j^i$)가 곱해진 것이며, fully connected net이나 convolution연산과 모양이 동일하다.  

Transformer는 학습되고 나면 고정된 가중치를 가지는 FCN이나 CNN구조와 달리, 위 그림에서 나타나는 가중치 $a_j^i$처럼 Input의 함수이다. 달라지는 Input에 따라 고정된 값이 아니라 바뀌는 값이다. 따라서 FCN이나 CNN에 비해 inductive bias가 휠씬 적게 된다 [1]. 



Reference

1. PR-297 Youtube

2. ViT pytorch 코드 리뷰 (github 원본)