> For the complete documentation index, see [llms.txt](https://lswkim322.gitbook.io/til/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lswkim322.gitbook.io/til/til-ml/boostcamp/u-stage-nlp/07-08-transformer.md).

# (07-08강) Transformer

> Transformer(Self-Attention)에 대해 알아본다.

## 1. Transformer

### 1.1. 소개

* Attention is all you need, NeurIPS'17 &#x20;

  입출력 처리에 사용되었던 RNN 모델 대신 Attention만을 사용하여 처리하게 되었다.
* 순차적인 데이터가 항상 순서를 맞춰서 발생하지 않는 이슈를 해결하기 위한 방법론이다.

### 1.2. Basic Structure

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk14PnpJv7eWnk2OXPV%2F-Mk5L4NQsfRF_BvVDsRQ%2Fimage.png?alt=media\&token=6e4593f0-3b06-41b0-9563-381ee2567e9a)

* 위의 기존 Seq2Seq와 달리 여러개의 Encoder와 Decoder를 층으로 쌓게 된다.
* Input과 Output의 갯수와 도메인이 동일하지 않다.
* Encoder는 N개의 단어에 대해 한번에 처리할 수 있는 구조로 되어있다.

#### 1.2.1. 주요 하이퍼파라미터

* $$d\_{model}$$ = 512 &#x20;

  트랜스포머의 인코더와 디코더에서의 정해진 입력과 출력의 크기
* num\_layers = 6 &#x20;

  트랜스포머에서 하나의 인코더와 디코더를 층으로 생각하였을 때, 트랜스포머 모델에서 인코더와 디코더가 총 몇 층으로 구성되었는지를 의미한다. (논문에서는 각 6개 층으로 구성하였다.)
* num\_heads = 8 &#x20;

  트랜스포머에서는 어텐션을 사용할 떄, 1번 하는 것보다 여러개로 분할해서 병렬로 어텐션을 수행하고 결과값을 다시 하나로 합친다.
* $$d\_{ff}$$ = 2048 &#x20;

  트랜스포머 내부에는 피드 포워드 신경망이 존재합니다. 이때 은닉층의 크기를 의미합니다. 피드 포워드 신경망의 입력층과 출력층의 크기는 $$d\_{model}$$입니다.

#### 1.2.2. Encoder 구조

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk14PnpJv7eWnk2OXPV%2F-Mk5LPnWdGOFhQUzpbWj%2Fimage.png?alt=media\&token=e69252bf-d5c4-461a-bbc4-a19e88cd139e)

하나의 Encoder는 Self-Attention과 FFNN(Feed Forward Neural Network)으로 구성되어 있다.&#x20;

1. &#x20;Input 문장에 대해 Embedding 백터를 구한다.&#x20;
2. Positional Encoding 과정을 거친다.&#x20;
3. Multi-Head Attention (Self Attention의 병렬처리)&#x20;
4. Add & Norm (Residual connection and Layer Normalization, 잔차연결과 층 정규화)&#x20;
5. Position-wise FFNN&#x20;
6. Decoder에 Key Vector, Value Vector 전달

위와 같은 순서로 Encoder의 구조를 뜯어보기로 한다.

**1.2.2.1. Embedding**

자연어를 기계가 이해할 수 있는 숫자형태인 Vector 형태로 변환한 값. (2강 참고)

**1.2.2.2. Positional Encoding**

트랜스포머는 단어 입력을 순차적으로 받는 방식이 아니어서 ABCD = ADCB 모두 같은 값이 나오게 된다. 하지만 문장에서의 단어는 위치에 따라 의미하는 바가 변하기 마련이다. Embedding된 Vector에 단어의 위치정보를 더하는 과정을 Positional Encoding이라고 한다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk14PnpJv7eWnk2OXPV%2F-Mk5LryGIvSFe3m7PAk7%2Fimage.png?alt=media\&token=be8bf306-4323-4f31-9a7e-33a07d7b55b3)

&#x20;                                                             $$PE\_{(pos, 2i)} = sin(pos/10000^{2i/d\_{model}})$$&#x20;

&#x20;                                                            $$PE\_{(pos, 2i+1)} = cos(pos/10000^{2i/d\_{model}})$$

{% embed url="<https://skyjwoo.tistory.com/entry/positional-encoding%EC%9D%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80>" %}

**1.2.2.3. Self Attention and Multi-head Attention**

**Attention** : 전체 입력 문장을 동일 비율이 아닌 가중치를 줌으로서 연관이 있는 입력 단어부분을 더 집중(Attention) 한다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5MBMI29-58AOphZOR%2F-Mk5MIn62e4yxydJS4i7%2Fimage.png?alt=media\&token=c83d6bf4-e129-4d09-95a9-31393c641fd3)

* $$Attention(Q, K, V) = Attention Value$$
  * Q(Query) : decoder의 t시점에서의 hidden state($$s\_t$$)
  * K(Key)   : encoder의 모든 hidden state($$h$$)
  * V(Value) : encoder의 attention value 를 도출하기 전의 hidden state
* 어텐션 함수는 주어진 쿼리(Q) 에 대해서 모든 키(K) 와의 유사도를 각각 구합니다.
* 구해낸 유사도를 키와 매핑되어있는 각각의 값(V) 에 반영해줍니다.
* 유사도가 반영된 값(V)를 모두 더해서 리턴하며 이를 'Attention Value' 라고 한다. &#x20;

**✔ Self Attention**

* 각 단어마다 Self Attention 구조는 3가지 Vector를 만든다 (Q, K, V)
* Score = $$q\_t \cdot k^T$$ 스칼라 값 (Attention Function을 사용한 값, dot product가 아닐 수 있음) &#x20;

  \=> 두 Vector의 내적을 통해 i번째 단어가 나머지 단어와 얼마나 유사도를 가지는지 구한다.
* Score Vector를 Normalize 해준다 (divide by 8, $$\sqrt{d\_{key}}$$)
* softmax를 통해 확률로 나타내어 그 확률이 각각 얼마나 영향을 가지는지 볼 수 있도록 한다. &#x20;

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5MBMI29-58AOphZOR%2F-Mk5MdMiOKfhZ3n7N3e7%2Fimage.png?alt=media\&token=a685fc7f-0cbc-4388-aa32-560f2e7cdb4d)

* 각 단어에서 나오는 V(value) Vector와의 weighted sum(가중합)으로 encoding vector z를 구한다. &#x20;

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5MBMI29-58AOphZOR%2F-Mk5MkopaW6Y_78YHTVv%2Fimage.png?alt=media\&token=f88912df-d032-4353-9096-8cfb95cada3a)

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5MBMI29-58AOphZOR%2F-Mk5Mss8uOdg0Phr3aqk%2Fimage.png?alt=media\&token=16084721-04ea-4354-94ea-f783a0557c8c)

$$Attention(Q, K, V) = softmax(\frac{QK^T}{\sqrt{d\_k}})V$$

❓왜 Transformer가 추정이 잘 될까?

* CNN, MLP를 할 경우 Input이 Fix되면 Output도 Fix 된다.
* Transformer는 Input이 Fix되더라도 주위의 단어에 따라 Output이 달라진다.

  \=> Flexible 하여 더 많은걸 표현하게 된다. &#x20;

❕ check

* n개의 단어가 주어지면 nxn개의 Matrix가 필요하고 이를 한번에 처리할 수 있어야한다.

**✔ Multi-headed Attention (MHA)**\
위 single-attention의 과정을 n번 진행하는 것이다. 하나의 encoding된 vector에 대해 n개의 query, key, value vector를 만드는 것. 이 논문에서는 8개의 attention head를 가진다.

* 동일한 seq가 주어지더라도 다른 기준으로 여러 지표를 뽑아와야할 필요가 있을 수 있다. 예를 들어 "나는 학교에서 공부를 했다." "나는 집에 와서 휴식을 취했다." 라는 문장이 있을 때 "나"에 대해 위치정보(학교, 집)의 정보가 중점이 될 수 있고, 행동("공부", "휴식")의 정보가 중점이 될 수 있다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5NLSfkVSvRixx0CNQ%2Fimage.png?alt=media\&token=56dcc1a6-4f36-4722-bf85-dd6bf9a5ca10)

* 생성된 8개의 head-attention을 concat하여 합치고 이를 원하는 출력의 차원으로 선형변환하는 $$W^O$$를 행렬곱을 하여 Z를 구해낸다.

**1.2.2.4. 성능적인 측면**

Maximum path lengths, per-layer complexity and minimum number of sequential operations for different layer types

* $$n$$ is the sequence length
* $$d$$ is the dimension of representation (Query와 Key의 dim)
* $$k$$ is the kernel size of convolution&#x20;
* $$r$$ is the size of the neighborhood in restricted self-attention

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5NgGwjKbClxdLfQ4o%2Fimage.png?alt=media\&token=ca685ff5-f503-43ec-8a63-003920766688)

* **Self Attention**
  * Complexity per Layer의 핵심 연산인 $$softmax(\frac{QK^T}{\sqrt{d\_k}})V$$ 에서 $$QK^T$$의 연산의 크기로 보면 된다. (nxd) x (dxn) 으로 $$n^2\cdot d$$ 번의 연산이 발생함을 알 수 있다. 이 부분에서 메모리에서 저장해야할 크기가 매우 크다는 것을 알 수 있다.&#x20;
  * Sequential Operations : PC의 성능이 좋다(GPU Core 수)는 가정하에 행렬곱 연산은 1의 시간복잡도를 가진다.
* **RNN**
  * Self Attention에 비해 메모리 사용량이 적다. $$W\_{hh} \times h\_{t-1} => (d\times d) \times (d \times 1)$$ 즉, d개 만큼의 곱이 d개 만큼 있는 $$d^2$$개를 가지게 되고 이런 연산이 문장의 길이 n번 발생하여 $$n \cdot d^2$$ 의 시간복잡도를 가지게 된다.
  * 순차적으로 진행하기 때문에 Sequential Operation이 n의 시간복잡도를 가지게 된다.

**1.2.2.5. Add & Norm (Residual connection and Layer Normalization)**

**✔ Add(Residual connection)**

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5OaEFq93EKuCc_KVT%2Fimage.png?alt=media\&token=16813cac-e48d-4ee1-9546-2e1b34ebbab8)

서브 층의 입력과 출력을 더하는 것으로 위와 같이 볼 수 있다.\
우리가 하고 있는 Encoder에서 보게 되면 (multi-head attenion의 input + multi-head attenion의 output) 이 되는 것이다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5Oge42dYt1aElSjDe%2Fimage.png?alt=media\&token=4aeecad5-ea88-421b-920d-d3a0a2d4112e)

**❗** Residual Connection은 ResNet 모델에서 사용된 아이디어이다. 이는 기존에 학습한 정보를 보존하고, 거기에 새로운 정보를 학습하도록 하는 것, Gradient Vanishing 문제를 해소한다. (매회 학습해야하는 양을 축소할 수 있다.)

[관련 논문](https://arxiv.org/pdf/1512.03385.pdf)

**✔ Norm (Layer Normalization, 층정규화)**\
정규화는 gradient의 안정화가 주된 목표이다.

$$LN = LayerNorm(x + Sublayer(x))$$

텐서의 마지막 차원($$d\_{model}$$)에 대해서 평균과 분산을 구하고, 정한 정규화 함수를 통해 정규화를 진행하여 학습을 돕게 된다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5PFMvRU0zPcmJxl8o%2Fimage.png?alt=media\&token=01200377-8dd2-4a7a-b4f3-7ad6bd16cf21)

정규화를 수행한 후 벡터 $$x\_i$$는 $$ln\_i$$라는 벡터로 정규화 된다.\
$$ln\_i = LayerNorm(x\_i)$$

**❗ 정규화 공식**

1. **평균 분산 정규화**

   $$\hat{x}*{i,k} = \frac{x*{i,k}-\mu\_i}{\sqrt{\sigma\_i^2}+\epsilon}$$, ($$k$$ = 벡터 $$x\_i$$의 각 차원)
2. **감마 벡터 정규화**\
   $$ln\_i = \gamma \hat{x}\_i + \beta = LayerNorm(x\_i)$$, ($$\gamma$$의 초기값은 1, $$\beta$$의 초기값은 0)<br>

**1.2.2.6. Position-wise FFNN**

단순히 선형 변환 해주는 것이라고 생각해도 된다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5RUbMoiy-vk8D1gw6%2Fimage.png?alt=media\&token=6766d251-202d-4fe0-a552-a5c81e032359)

$$FFNN(x) = MAX(0, xW\_1+b\_1)W\_2 + b\_2$$

* 매개변수 $$W\_1, W\_2, b\_1, b\_2$$는 하나의 인코더 층내에서 모두 동일하게 사용된다. (인코더 층마다는 다른 값을 가짐)
* $$x$$ : Multi-head Attention에서 나온 (seq\_len, $$d\_{model}$$)의 크기를 가지는 행렬
* $$W\_1$$: ($$d{model}, \ d\_{ff}$$)의 크기
* $$W\_2$$: ($$d\_{ff}, \ d\_{model}$$)의 크기

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5RYV_6dZLS0GxNyvF%2Fimage.png?alt=media\&token=e9e8cf7b-447b-4359-afc2-bcea996c33de)

* 다음 인코더의 입력값으로 사용되기 때문에 출력값을 입력값과 같은 크기로 맞춰주어야한다.

#### 1.2.3. Decoder의 구조

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5Rkzqj16KvfYH4NfG%2Fimage.png?alt=media\&token=c2fb4e7c-451e-4034-8253-1d47832fe141)

1. **Input 문장에 대해 Embedding 백터를 구한다.**
2. **Positional Encoding 과정을 거친다.**
3. **🔅Masked Multi-head Self Attention**
4. **Add & Norm (Residual connection and Layer Normalization, 잔차연결과 층 정규화)**
5. **Position-wise FFNN**
6. **🔅Encoder에서 Decoder로 넘어가는 변수는 가장 상위 Layer의 Key와 Value 값이다.(Encoder-Decoder Attention)** &#x20;
   * Decoder의 Query와 Encoder에서 넘어온 K, V값으로 Attention을 진행한다. &#x20;

**1.2.3.1 Masked Multi-head Self Attention**

Encoder에서의 Self Attention과 동일하다. 하지만 Decoder에서는 앞으로 나올 단어를 자기학습하는 것은 치팅이 된다. 그러므로 과거에 나온 단어들에 대해서만 자기학습을 진행하게 된다.

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5RwxGEnZrJ16U1NE1%2Fimage.png?alt=media\&token=16f0557c-b748-4e5e-a7eb-a872aeb40cc5)

**1.2.3.2. Encoder-Decoder Attention**

Encoder의 최상위 Layer로 부터 넘어온 K(Key), V(Value) 값과 Decoder에서의 Q(Query)를 활용한 Attention 과정

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5S4Dm-GQinZP9QIT5%2Fimage.png?alt=media\&token=214bb3ec-0632-4e24-8207-4340f58a3ec4)

### 1.2.3. 기타

#### 1.2.3.1. Warm-up Learning rate Schedular

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5Sf-ocRig_UnUlMBH%2Fimage.png?alt=media\&token=cf1e3e44-7236-41c3-a2d6-e4e972e0c2ad)

### 1.3. 정리

![](https://3944465397-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MjcKlzGhHYe2bvmxTwS%2F-Mk5NJC2FocES-rPOgYb%2F-Mk5SmKf-iLd0c7p9IJ0%2Fimage.png?alt=media\&token=c31ff201-f12f-4559-8c1d-c9bc70146163)

## 관련코드 Link

{% embed url="<https://drive.google.com/file/d/1j7GMHCwFLcanYqi6EFXgMfljdN-YGMX5/view?usp=sharing>" %}

{% embed url="<https://drive.google.com/file/d/1qzS4_qsrj80AYG6oOo-MfJLR3WS_GidE/view?usp=sharing>" %}

{% embed url="<https://drive.google.com/file/d/1c35FCm88f4nr3CuVVhPmtcQaVnWq9_mE/view?usp=sharing>" %}

{% embed url="<https://drive.google.com/file/d/1JWeEr3DowKZziGddC9xrPaC_yesFk7oK/view?usp=sharing>" %}

## Reference

{% embed url="<https://arxiv.org/abs/1706.03762>" %}

{% embed url="<http://jalammar.github.io/illustrated-transformer/>" %}
