데이크루 5기

GPT4가 알려주는 Transformer_5(기초부터 심화까지)

2023.04.04 14:43 2,944 조회


Transformer_1 : https://dacon.io/competitions/official/236091/talkboard/408068?page=1&dtype=recent

Transformer_2 : https://dacon.io/competitions/official/236091/talkboard/408069?page=1&dtype=recent

Transformer_3 : https://dacon.io/competitions/official/236091/talkboard/408071?page=1&dtype=recent

Transformer_4 : https://dacon.io/competitions/official/236091/talkboard/408072?page=1&dtype=recent


저번 시간

우리는

Multi-Head Attention

에 대해 배웠어요.


이번 시간에는

코드를 통해

Multi-Head Attention을

더 쉽게 이해해 봅시다!


transformer_2 게시글에서

우리는 Self-Attention이 이루어지는 과정을

코드를 통해 이해했어요.



그래서

Self-Attention과

Multi-Head Attention의

코드 구성이 어떻게 다르고

왜 다른지 이해해 봅시다.



먼저

저번 시간 이해했었던

Self-Attention 코드를

다시 한 번 보고 갈까요?



코드에 대해 다시 간단한 설명을 하자면

쿼리, 키, 밸류 선형 레이어를 정의하고,

forward 함수에서 입력 시퀀스 내 단어 간의 관계를 반영한 어텐션 출력을 계산합니다.


스케일드 닷 프로덕트 어텐션 계산:

attn_scores=torch.matmul(q, k.transpose(-2, -1))/(embed_dim ** 0.5)는 쿼리와 키 행렬의 내적(dot product)을 계산 후, 임베딩 차원의 제곱근으로 나눠 스케일링

이렇게 스케일링하는 이유는 큰 값의 닷 프로덕트가 softmax 함수에서 큰 차이를 발생시키지 않도록 하여 학습의 안정성을 높이기 위함입니다.


어텐션 확률 계산:

attn_probs = F.softmax(attn_scores, dim=-1)는 계산된 어텐션 점수를 이용해 어텐션 확률을 계산합니다. 

이 확률은 각 단어 간의 상대적인 관계를 나타냅니다.


어텐션 출력 계산:

attn_output = torch.matmul(attn_probs, v)는 어텐션 확률과 밸류 행렬을 곱하여 어텐션 출력을 계산합니다. 

이 출력은 입력 시퀀스 내 각 단어의 가중치가 반영된 결과물입니다.


어느 정도 다시 기억이 돌아오셨나요?






이제 Multi-Head Attention을

봐 볼까요?

먼저 'Head' 란




그래서 똑같은 문장에 똑같은 단어라도

각 헤드마다

쿼리-키-밸류의 값이 달라집니다!


그래서

왜 이렇게 달라지게 하냐?

쉬운 예시를 들어서 이해를 해 봅시다


.


만약, 입력 문장이 "나는 오늘 기분이 좋아" 라고 가정해 봅시다.

입력 문장을 4개의 단어로 나눌 수 있으며,

각 단어는 임베딩되어 모델에 전달됩니다.


Self-attention의 경우,

입력 문장에 대해 한 번의 어텐션만 계산됩니다.

이렇게 하면 단어 간의 관계를 학습할 수 있지만,

한 번의 어텐션만으로 문장의 모든 다양한 특징을 포착하기 어려울 수 있습니다.


Multi-head Attention의 경우,

여러 개의 어텐션 헤드를 사용하여 입력 문장의 다양한 특징을 캡처하려고 합니다.

예를 들어, 각 어텐션 헤드가 다음과 같은 다양한 정보를 포착할 수 있습니다.



헤드 1: 문법적인 관계를 포착 (예: 주어-동사, 목적어-동사 관계 등)

헤드 2: 문장 내 단어의 순서를 포착 (예: "나는" 다음에 "오늘"이 온다는 것 등)

헤드 3: 문장 내 단어들 사이의 의미 관계를 포착 (예: "기분이"와 "좋아" 사이의 관계 등)


쿼리, 키, 밸류 행렬을 생성하고 각 헤드에 대해 독립적으로 어텐션을 수행함으로써 이러한 다양한 정보를 동시에 학습할 수 있게 됩니다.

이렇게 하면 전체 모델의 표현력과 성능이 향상됩니다.


따라서 Multi-head Attention은 입력 문장의 다양한 특징을 동시에 고려하는 데 도움이 되며,

이를 위해 쿼리, 키, 밸류 행렬을 생성하고 각 헤드에 대해 독립적으로 어텐션을 수행하는 추가 작업이 필요합니다.



자! 이제 Multi-Head Attention을 사용하는 이유에 대해 이해가 되셨나요?!




이제

Multi-Head Attention

코드를 봅시다.



이전의 Self-Attention 코드에 비해

많이 어지럽죠?


쿼리-키-밸류 부분이

self-attention에 비해

어지럽게 바뀐 것을 바로 캐치하셨나요?




self-attention에서는

q = self.query(x)

k = self.key(x)

v = self.value(x)


multi-head Attention은    


q = self.query(x).view(batch_size, -1, self.num_heads, self.head_dim)

k = self.key(x).view(batch_size, -1, self.num_heads, self.head_dim)

v = self.value(x).view(batch_size, -1, self.num_heads, self.head_dim)

    q = q.transpose(1, 2)

    k = k.transpose(1, 2)

    v = v.transpose(1, 2)



이렇게 2 단계로 나누어 집니다.




Multi-head Attention이

Self-attention과

다른 이유는

여러 개의 어텐션 헤드를 사용하기 때문입니다.



각 어텐션 헤드가 독립적으로 어텐션을 수행하려면,

각 헤드에 대해 쿼리, 키, 밸류 행렬을 따로 준비해야 합니다.


이를 위해 추가 단계가 필요합니다.


  1. 먼저, 각각의 선형 레이어를 사용하여 쿼리, 키, 밸류 행렬을 얻습니다.
  2. 그 다음, 각 헤드가 독립적으로 어텐션을 수행할 수 있도록 헤드를 별도의 차원으로 분리합니다. 이를 위해 view() 함수를 사용하여 원래 형태의 텐서를 num_heads와 head_dim을 가진 새로운 형태의 텐서로 변환합니다.
  3. 그리고 각 헤드가 독립적으로 어텐션을 수행할 수 있도록 num_heads 차원을 두 번째 차원으로 전치합니다(transpose(1, 2)). 이렇게 하면 쿼리, 키, 밸류 행렬의 각 헤드가 별도로 어텐션을 수행할 수 있습니다.



이 추가 단계는 입력 시퀀스의 다양한 정보를 포착하고 학습하는 데 도움이 되는 복잡성을 높이는 것으로,

결과적으로 전체 모델의 표현력과 성능을 향상시킵니다.



이번 시간을 통해

이론으로만 알고 있었던

Multi-Head Attention

에 대한 이해가 더 높아졌을 거라고

믿어요!



혹시라도 이해가 안 되는 부분이나

궁금한 부분은 댓글 부탁드립니다!




Full CODE : https://dacon.io/competitions/official/236091/codeshare/7876?page=1&dtype=recent

로그인이 필요합니다
0 / 1000
he_is_wicked
2023.04.08 14:58

attention_mask에 대한 부분도 궁금합니다!

쥬혁이
2023.04.09 16:41

넵! attention_mask에 대한 부분도 작성하겠습니다~