데이터 한 그릇

BERT시작하기 - 트랜스포머 입문 본문

NLP/구글 BERT의 정석

BERT시작하기 - 트랜스포머 입문

장사이언스 2022. 2. 3. 16:57

트랜스포머 소개

 

RNN과 LSTM 네트워크는 다음 단어 예측, 기계번역, 텍스트 생성에 사용된다.

그러나 RNN 기반의 모델들은 네트워크 장기 의존선 문제가 있다.

이러한 한계를 극복하고자 "Attention is all you Need" 라는 논문에서 트랜스포머 아키텍처를 제안한다.

트랜스포머 기반으로 BERT, GPT-3, T5 등과 같은 혁명적인 아키텍처가 발전하는 기반이 마련됐다.

트랜스포머는 RNN에서 사용한 순환 방식을 사용하지 않고 순수하게 어텐션만 사용한다.

트랜스포머는 셀프 어텐션이라는 특수한 형태의 어텐션을 사용한다.

(순수하게 어텐션만 사용, 셀프 어텐션 기술 사용)

트랜스포머의 인코더 디코더의 작동원리는 대략적으로 이해해보자.

먼저 영어를 프랑스어로 바꾸는 작업을 하고 싶다고 하자.

인코더에 영어 시퀀스를 입력값으로 주어 그 결과값을 디코더에 보낸다.

디코더는 인코더가 도출한 결과값을 입력값으로 받아들인다.

그리고 이를 이용해서 프랑스어를 도출한다.

자세한 원리를 이제 알아보도록 하자.

 

트랜스포머 인코더

 

트랜스포머는 N개의 인코더가 쌓인 형태다.

인코더의 결과값은 그 다음 인코더의 입력값으로 들어간다.

가장 마지막에 있는 인코더의 결과값이 입력값의(입력 시퀀스의) 최종 표현 결과가 된다.

(논문 Attention is all you Need는 인코더를 6개 쌓았다. 6개를 쌓을수도 있지만 2개, 3개 쌓아도 무관하다.)

그러면 인코더의 세부 구성 요소를 살펴보자.

  1. 멀티 헤드 어텐션
  2. 피드포워드 네트워크

트랜스포머 인코더의 내부 구성은 위와 같이 두 개로 이루어져있다. 입력값이 들어가면 멀티 헤드 어텐션을 거치게 되고 그 다음 피드포워드 네트워크를 거치게 된다.

이제, 두 가지 요소가 어떻게 작동하는지 알아보자. 먼저 멀티 헤드 어텐션이 어떻게 작동하는지 알아보려고 하는데, 멀티 헤드 어텐션이 어떻게 작동하는지 알기 위해서는 "셀프 어텐션"의 작동 원리를 알아야만 한다.

 

따라서 셀프 어텐션의 작동원리를 살펴보도록 하자.

 

정리 : 트랜스포머 인코더의 구성요소는 멀티 헤드 어텐션과 피드 포워드 어텐션이며, 각각의 작동 원리를 알아야 인코더의 작동 원리를 이해할 수 있다. 그리고 멀티 헤드 인텐션을 이해하기 위해서는 셀프 어텐션을 알아야만 한다.

 

셀프 어텐션의 작동 원리

 

"A dog ate the food because it was hungry"

위 문장에서 it에 대해 주목해보도록 하자. it은 dog를 지칭할수 있고, food를 지칭할 수 있다. 우리 인간은 이 문장을 보자마자 it이 dog임을 알아차릴 수 있다. 그러면 모델은 어떻게 it 이 dog이라는 것을 알 수 있을까?

모델이 이를 수행하기 위해서는 셀프 어텐션이 필요하다.

위의 예시 문장이 모델에 들어갔을 때, 모델은 가장 먼저 단어 A에 대한 표현을 계산하고 그 다음 dog 그 다음 ate 표현을 계산한다. 이때 각 단어의 표현은 문장 안에 있는 다른 단어의 표현과 연결해 단어가 문장 내에서 갖는 의미를 이해한다.

 

위의 예시의 단어들은

A, dog, ate, the, food , because, it, was, hungry 이다.

it 단어를 표현할 때, it이외의 모든 단어 표현들과 it단어를 연결지어서 문장내에서 it이 어떤 의미를 가지고 있는지 이해한다.

즉, it이라는 단어를 이해하기 위해서 it이외의 문장 내의 모든 단어들과 it을 연결짓는 작업을 시행하고 의미를 이해한다. (연결 짓고 it이 어떤 의미를 지니는지 이해한다.)

 

여기까지가 셀프 어텐션의 큰 개념.

더 작동원리를 자세히 살펴보도록 하자.

먼저 입력 시퀀스 문장에 대해서 입력 행렬로 만드는 작업을 거친다.

예를 들어서 I am good 이라는 문장이 있다고 가정하자.

 

문장 내 각각의 단어들에 대해서 임베딩 작업을 거쳐 벡터로 만들었다고 가정하자. 그러면 위의 문장은 세 개의 단어 벡터가 도출될 것이다. 이를 행순으로 이어 붙이면 행렬을 만들 수 있다.


즉, x1벡터를 0행으로, x2벡터를 1행으로 x3벡터를 2행으로 붙일 수 있다. 그러면 최종적인 입력 행렬의 shape은

(단어의 개수, 임베딩 벡터 차원) 이다.

 

만일 단어 임베딩 차원이 512 라고 한다면, 이 행렬의 shape은 (3, 512) 다.

이제 입력행렬을 만들었으면 이 입력행렬로부터 쿼리 (Q) 행렬, 키(K) 행렬, 밸류(V) 행렬을 생성한다.

(입력행렬 => 쿼리행렬, 키행렬, 밸류행렬, Q,K,V)

이 세 가지 행렬은 셀프 어텐션에 사용된다.

세 개의 Q,K,V 행렬을 만들기 위해서 세 개의 가중치 행렬 W_q, W_k, W_v 을 만든다.

이 가중치 행렬을 행렬 X에 곱해서 3개의 Q,K,V 행렬을 얻는다.

이때 가중치 행렬들은 초기에는 임의의 값을 가지며 학습을 거치면서 최적의 값을 가지게 된다.

 

최적의 가중치 행렬값을 가지게 되면 더욱더 정확한 Q,K,V 행렬을 만들 수 있다.

이때 Q,K,V 의 행렬은 입력벡터의 행개수와 똑같이 생성된다.

위의 예시로는 3개의 행이 똑같이 생성된다.

Q,K,V 각각의 행은 입력행렬의 각각의 행 벡터 단어들과 일치한다.

 

즉, Q행렬의 0번째 행은 입력행렬의 0번째 행 단어와 일치한다. 따라서 Q행렬의 0번째 행은 단어 I에 대한 쿼리 벡터다.

마찬가지로 K행렬의 0번째 행은 단어 I에 대한 키 벡터다. V행렬의 0번째 행도 단어 I에 대한 밸류 벡터다.

만일 Q,K,V 행렬의 차원의 수가 64라고 한다면 위의 이유 때문에 Q,K,V의 Shape은 (3,64) 이다.

 

그렇다면 이렇게 구한 Q,K,V 행렬은 어떻게 사용되는가? 그리고 이와 같은 방법의 장점은 무엇인가?

 

Q,K,V 행렬 사용

 

앞서, 셀프 어텐션은 문장 내 특정 단어에 대해서 표현하려고 할 때, 그 단어 이외의 문장 내 다른 모든 단어들과 연결하는 과정을 거친다는 것을 살펴봤다.

그 단어가 문장 내 다른 모든 단어들과 어떤 연관을 가지고 있는지 파악하면 그 단어에 대해서 훨씬 더 좋은 표현을 할 수 있기 때문이다.

그렇다면 특정단어와 문장 내 모든 단어들과 연결짓는 방법은 무엇인가?

 

이때 Q,K,V 행렬을 사용해서 특정 단어와 문장 내에 있는 모든 단어를 연결할 수 있다.

  • 1단계
    • 쿼리 Q 행렬과 키 K 행렬의 내적 연산을 수행한다.(한 쿼리는 행렬곱을 하기 위해서 transpose 한다.)
    • 내적을 하게 되면 각 단어간의 유사도를 측정할 수 있다.
    • 예를 들어서 (3,4) 형태의 쿼리 행렬과 키 행렬이 있다고 가정해보자. 둘의 곱을 위해서 키 행렬은 전치 해주고 곱하면 다음과 같은 형태일 것이다. (3 X 4) * (4 X 3). 그럼 최종 형태는 3X3의 형태일 것이다.
    • 쿼리 행렬의 행들은 각 문장 내 단어들을 의미하고, 전치된 키 행렬은 열이 이를 의미한다. 행렬곱의 계산 형식을 살펴보면 쿼리 행렬의 각 행은 키 행렬의 모든 열들과 곱해짐을 알 수 있다. 이 곱이 의미하는건 쿼리 행렬의 단어 벡터 한 개와 키 행렬의 단어 벡터 3개 각각이 곱해진것을 의미한다.
    • 벡터간 곱은 두 벡터의 유사도를 의미한다. 따라서 쿼리 행렬과 키 행렬의 내적을 진행하면 위의 예시 I am good 에서는 I단어와 (i,am,good) 단어들간의 유사도, am 단어와 (i,am,good) 단어들간의 유사도, good 단어와 (i,am,good) 단어들의 유사도를 측정하는 것과 같다.
    • 결국 어떤 특정 단어가 문장 내의 다른 각각의 모든 단어들과 얼마나 유사한지 파악하는데 도움을 준다.(문장 내 다른 모든 단어들과 연결지었다고 볼 수 있다.)
  • 2단계
    • 앞서 계산한 쿼리 Q행렬과 키 K행렬의 내적 QK^t 의 키 행렬의 벡터 차원의 제곱근으로 QK^t 행렬을 나눈다.
    • 위의 예에서 키 벡터의 차원은 64 였다. 따라서 키 벡터 차원의 제곱근은 8이다.
    • 위에서 구한 8을 QK^t 행렬에 나눠준다.
    • 이와 같은 방법을 적용하면 안정적인 경삿값(gradient) 를 얻을 수 있다.
  • 3단계
    • 2단계의 결과값은 비정규화된 값이다.
    • 따라서 정규화 시켜주기 위해 Softmax 함수를 적용한다.
    • 전체 값의 합은 1이 되고 각각의 원소는 0에서 1사이의 값을 가진다.
    • 이러한 행렬을 스코어 행렬(score matrix) 라고 부른다.
    • 이 %를 활용해서 문장 내의 특정 단어가 다른 단어와 %로 관련있는지 확인할 수 있다.
  • 4단계
    • 어텐션 Z 행렬을 계산하는 것.
    • 3단계에서 구한 softmax 를 적용한 행렬에 밸류 행렬 V를 곱하면 어텐션 Z 행렬을 구할 수 있다.
    • 즉 어떤 단어 x의 셀프 어텐션은 밸류 벡터값의 가중치 합으로 계산된다.
    • 여기서 가중치는 3단계에서 구한 soft맥스 행렬이다. 이 행렬에는 각 단어에 대한 가중치 정보가 담겨 있다.

 

 

셀프 어텐션은 쿼리와 키 벡터의 내적을 계산한 다음 차원의수 제곱근으로 나누기 때문에 스케일 닷 프로덕트 어텐션 이라고 부르기도 한다.

 

멀티 헤드 어텐션 원리

멀티 헤드 어텐션의 원리를 이해하기 위해서 셀프 어텐션의 작동 원리를 알아야 하기 때문에 앞서 셀프 어텐션의 원리를 살펴봤다.

 

어텐션으르 사용할 때 헤드 한 개만 사용한 형태가 아닌 헤드 여러 개를 사용한 어텐션 구조도 사용할 수 있다.

앞에서 어텐션 Z행렬을 계산하는 방법을 배웠다. 단일 어텐션 행렬 Z 이 아닌 다중 어텐션 행렬을 계산해보자.

먼저 어떤 단어에 셀프 어텐션을 한다고 가정해보자.

셀프 어텐션을 하게 되면 어텐션 Z행렬이 나오게 된다.

예를 들어서 "All is well" 이라는 문장이 있다고 가정해보자.

단어 well 의 셀프 어텐션을 계산한다고 하자. 즉, Z_well 을 계산한다고 하자.

그러면 각 단어(All, is, well) 벡터에 가중치가 곱해지게 되고 그 값들을 모두 더하는 과정을 거치게 된다.

All 단어 벡터에 0.6 가중치가, is 에 0, well 에 0.4가 곱해졌다고 가정해보자.

그렇다면 단어 well 벡터는 all 단어 벡터가 60%, well 단어 벡터가 40% 반영됐음을 의미한다.

따라서 well 벡터값은 단어 all 의 영향이 가장 크다고 할 수 있다.

 

앞선 예에서 A dog ate the food because it was hungry 를 셀프 어텐션 했었다.

가정으로 it에 대한 셀프 어텐션을 했을 때, dog 단어 벡터에 대해서 가중치가 1이 부여되고 나머지는 0이 부여됐다고 해보자.

이는 단어의 의미가 올바르게 연결된 경우라고 할 수 있다. 하지만 단어의 의미가 올바르게 연결되지 않는 경우가 있다. 즉, 단어간 연결이 올바르게 연결되지 않은 경우가 있을 수 있다. 이때 결과의 정확도를 높이기 위해서 단일 헤드 어텐션을 사용하지 않고 멀티 헤드 어텐션을 사용할 수 있다. (멀티로 한 값들을 더한다.)

 

이제 어텐션 행렬 Z1 ~ Z8 가지 만들고 연결한다고 가정해보자.

입력 시퀀스 각 단어에 대해서 벡터로 변환한 값들을 연결하여 입력 행렬 X를 만든다.

그 이후, 가중치 3개를 주어 입력행렬과 3개의 가중치들을 곱하여 Q, K, V 행렬을 만든다.

Q X K 행렬을 통해서 단어간 유사도를 구하고 정규화 작업과 SOFTMAX 작업을 거쳐서 스코어 행렬을 만든다.

스코어 행렬과 V행렬을 곱해서 어텐션 행렬 Z1을 만든다.

 

이 작업을 Z8 어텐션 행렬을 만들 때까지 반복한다.

그리고 만든 8개의 어텐션 행렬을 Concatenate 한다. 그리고 새로운 가중치 행렬 W를 곱하여 최종적으로 우리가 원하는 행렬곱을 구한다.

위치 인코딩으로 위치 정보 학습

RNN 에서는 입력 시퀀스의 문장을 단어 단어로 나눠서 입력한다.

하지만 트랜스포머는 RNN의 순환 구조를 따르지 않는다. 단어 단위로 문장을 입력하는 대신에, **문장 안에 있는 모든 단어를 병렬 형태**로 입력한다.

병렬로 단어를 입력하는 것은 학습 시간을 줄이고 RNN 장기 의존성 문제를 해결하는데 도움을 준다.

 

그럼에도 불구하고 병렬로 단어를 입력하는 것도 이슈가 발생.

바로 단어의 순서 정보가 유지되지 않은 상태로 문장의 의미를 어떻게 이해할 수 있냐는 점이다.(RNN과 다르게)

문장의 의미를 이해하기 위해서는 "단어의 위치 정보" 를 반드시 이해해야 한다.

 

결국 트랜스포머 방식에도 문장의 단어의 순서 정보를 제공해야만 한다.

따라서 문장을 이용해서 생성한 입력행렬을 그대로 트랜스포머의 입력값으로 사용하지 않고, "위치 인코딩" 을 적용해서 트랜스포머 입력값으로 사용한다.

(위치 인코딩 행렬 P)

 

입력 행렬 X에 위치 인코딩 행렬 P를 더한 후 트랜스포머 입력값으로 활용한다.

이제 입력 행렬은 "단어의 임베딩값" 뿐만 아니라 문장의 "단어 위치 정보"도 포함한다.

(임베딩 + 위치)

 

위치 인코딩 계산법

"Attention is all you need" 저자는 사인파 함수(sinusoidal function) 을 사용했다.

사인파 함수에서 생소한 변수들이 존재한다.

pos, i 그리고 d_model 이다.

pos 는 문장에서 그 단어의 위치를 의미한다.

i am good 이면 i 단어는 pos 가 0이고 am 은 1, good 은 2이다.

i는 임베딩 벡터 내의 차원의 인덱스를 의미한다. (512 차원중 3번째 차원이면 i는 3)

여기서 짝수 차원이면 sin 함수를 적용하고 홀수 차원이면 cos 함수를 적용한 것을 알 수 있다.

 

d_model 은 출력 차원의 수를 의미한다.

입력 벡터의 차원의 수가 512 라고 하면 d_model 도 512가 된다.

 

정리하자면, 트랜스포머는 RNN과 달리 문장을 입력할 때 문장을 단어 단위로 나누어 순차적으로 입력하는 게 아니라, 입력 벡터 행렬을 만들어 트랜스포머에 입력한다.

하지만 RNN과 달리 입력 벡터 행렬을 만들어 입력하는 방식은 문장내의 단어 순서 정보가 반영되지 않는다.

따라서 문장 내에서 단어의 위치 정보를 가지게끔 입력행렬에 대해서 위치 인코딩을 해줘야만 한다.

위치 인코딩 방식은 위치 행렬 P를 만들어서 입력 행렬 X에 더해주는 방식이다.

이때 위치 행렬 P를 만드는 방식은 사인파 함수를 이용한다. 이 함수의 주목할만한 변수는 POS, i 그리고 d_model 이다. pos 는 문장 내 단어의 위치를 의미한다. "i am good" 이면 i는 pos가 0, am 은 1, good 은 2를 값으로 가진다. 그리고 i는 입력 벡터의 차원의 인덱스를 의미한다. 만일 512차원 중에 2차원값을 가리키면 i = 2를 가진다.

d_model 은 출력벡터의 차원을 의미하며 만일 입력 벡터의 단어 차원이 512 라면 d_model 또한 512이다.

 

이렇게 사인파 함수를 통해서 행렬 P를 구했다면 이 값을 입력행렬 X에 더해준다.(요소별 합)

그러면, 단어의 위치 정보가 입력 행렬에 포함되게 된다. 이 값을 트랜스포머 인코더의 입력 행렬로 입력한다.

그 입력값은 인코더 내에 있는 멀티 헤드 어텐션과 피드포워드를 거치게 된다.

 

(임베딩 벡터의 위치 인코딩 및 멀티 헤드 어텐션까지 살펴봄, 이는 트랜스포머 인코더 내의 구성 요소 두 개중 한개를 익힌 것과 같다. 나머지 피드포워드에 대해서 살펴보자.)

피드포워드 네트워크

피드 포워드 네트워크는 2개의 전결합층(dense layer) 과 ReLU 활성화 함수로 구성된다.

add와 norm 요소

"입력값 -> 멀티 헤드 어텐션 -> ADD & NORM -> 피드 포워드 -> ADD & NORM"

  • 서브레이어에서 멀티 헤드 어텐션의 입력값과 출력값을 서로 연결한다.
  • 서브레이어에서 피드 포워드의 입력값과 출력값을 서로 연결한다.

기본적으로 레이어 정규화 (layer normalization) 그리고 잔차 연결(residual connection) 이다.

각 레이어의 값이 크게 변화하는 것을 방지해 모델이 더 빠르게 학습할 수 있도록 한다.

모든 인코더 구성 요소 통합

인코더 1개가 입력 문장 시퀀스를 표현하는 과정은 다음과 같다.

먼저 표현하려고 하는 시퀀스 문장은 입력 행렬로 만들어진다.

입력행렬은 위치 정보가 포함되어 있지 않기 때문에 위치 인코딩화 된다.

위치 인코딩화까지 끝난 입력값은 인코딩의 입력으로 들어간다.

입력값은 인코딩의 서브레이어인 멀티 헤드 어텐션의 입력값으로 들어가고 "어텐션 행렬" 을 출력값으로 도출한다.

ADD & NORM 스케일을 거쳐서 피드포워드 레이어에 들어가서 인코더 표현을 출력값으로 내놓는다.

이 값은 또 ADD & NORM 스케일을 거치게 되고 그 출력값을 다음 인코더의 입력값으로 넣는다.

 

이게 1개 인코더의 입력 시퀀스 데이터에 대한 출력 과정이다.

인코더를 N개 쌓아서 이 과정을 반복할 수 있다.

최종 인코더의 출력 값을 R 이라고 하자.

이 최종 인코더의 출력 R은 이제 디코더로 입력된다.

트랜스포머 디코더 이해하기

인코더를 여러 겹으로 쌓을 수 있었던 것처럼, 디코더 또한 여러 겹으로 쌓을 수 있다.

이때 각각의 디코더는 입력값을 두 개를 가진다.

인코더의 출력값은 최초의 디코더에만 들어가는 게 아니라 모든 디코더의 입력값으로 들어간다.

또한 각각의 디코더는 이전 디코더의 출력값을 입력값으로 받는다.

 

기본적으로 디코더는 시각(t) 에 따라서 입력값이 달라진다.

디코더는 입력값으로 현재까지의 입력값 + 이전 단계(t-1)에서 생성한 단어를 추가해서 문장의 다음 단어를 생성한다.

맨 초반 시각에는 "<sos> " 를 입력값으로 넣어준다. 그리고 a라는 단어가 출력이 된다.

이제 t = 2가 된다. 이때는 현재까지의 입력값이 sos이고, 그 이전 단계의 출력값이 a이기 때문에 입력값으로 sos, a 를 가진다. 그래서 출력 b가 나왔다고 해보자.

다음 t = 3도 마찬가지다. 이전까지의 입력값이 sos, a이며 그 이전 단계의 출력값이 b이기 때문에 t=3 일 때의 입력값은 sos, a 그리고 b이다. 이 출력값이 c라고 가정해보자.

계속 이 과정을 반복.

 

디코더의 입력값도 인코더와 마찬가지로 위치 인코딩을 수행해야만 한다.

특정 t시각의 입력값들에 대해서 입력행렬을 만들고 여기에 위치 인코딩을 수행한다.

 

디코더 블록의 요소

  • 마스크된 멀티 헤드 어텐션
  • 멀티 헤드 어텐션
  • 피드 포워드

디코더도 인코더와 비슷한 구조를 가지고 있는데, 바로 멀티 헤드 어텐션을 사용한다는 점에서 그렇다.

하지만, 다른 점이 존재하는데, 두 가지 형태의 멀티 헤드 어텐션을 사용한다는 점이다.(마스크된 멀티 헤드 어텐션 포함)

먼저 디코더의 각각의 구성요소를 세심하게 살펴보고 작동원리를 살펴보자.

마스크된 멀티 헤드 어텐션

언어 모델에서 모델을 학습시킬시 문장을 생성하는 과정과 달리 입력값이 정답 값이 들어온다. 즉 문장 전체를 디코더에 넣어준다.

예를 들어서 "나는 고양이다" 가 정답이면 이 값을 디코더에 모두 넣어서 학습한다.

하지만 트랜스포머의 마스크된 멀티 헤드 어텐션에 넣기 전에 조금 수정을 거진다.

입력값으로 "나는 고양이다" 만 들어가는 게 아니라, 언어 모델에서 문장을 생성한다고 가리키는 "<sos>나는 고양이다" 를 포함하여 입력값으로 넣어준다.

본래 어텐션은 어떤 단어에 대해서 전체 단어와의 연결을 통해 그 의미를 규정지었다. 하지만, 디코더는 시각에 따라서 그 입력값이 달라진다. 따라서 각 시각에 따라서 입력값으로 들어가는 단어들에 한해서만 단어를 연결지을 수 있다. 나머지는 모두 mask 해준다.

 

먼저 "sos 나는 고양이다" 가 들어가면, 이를 입력 행렬로 바꿔주고 위치 인코딩을 진행한다.

그 결과 행렬을 Q,K,V 행렬로 나눈다.

그리고 어텐션 행렬을 얻는 과정을 그대로 따라간다. Q와 K의 내적 후 행렬의 키 벡터 차원으로 나눈다.

그리고 그 행렬에 대해서 SOFTMAX 함수를 적용하고 어텐션 행렬을 구하기 전에,

시각 T마다 입력값이 달라지므로 각 시각마다 참조하지 않는 단어에 대해서 MASK작업을 실행한다.

SOS 가 입력값으로 들어가면 SOS만 알고 다른 단어에 대해서 모르므로 SOS이외에 모든 단어들을 "-무한" 으로 바꾼다.

SOS다음에는 SOS가 출력한 값 "나" 도 입력값으로 들어간다(SOS, 나) 따라서 SOS, 나 이외의 단어들에 대해서 "-무한" 으로 바꾼다.

이제 이 행렬에 SOFTMAX함수를 적용하고 V 행렬을 곱해서 어텐션 행렬을 구한다.

멀티 헤드 어텐션이면 각 출력값들을 Concatenate 하고 가중치 W_o를 곱한다.

이 출력값이 마스크된 멀티 헤드 어텐션 출력값이다.

이 출력값은 다음 서브 레이어인 멀티 헤드 어텐션의 입력값이 된다.

멀티 헤드 어텐션

(인코더의 멀티 헤드 어텐션과 같지만 여기서 차이점은 인코더는 셀프 어텐션인 반면에 디코더는 셀프 어텐션이 아니다. 입력값을 두 개 받는다.)

멀티 헤드 어텐션은 입력값을 두 개 받는다. (그 이전 마스크된 멀티 헤드 어텐션은 입력값이 하나였다.)

이전 서브 레이어 출력값 즉, 마스크된 멀티 헤드 어텐션의 출력값과 인코더의 최종 출력값 R을 입력값으로 받는다. 마스크된 멀티 헤드 어텐션의 결과로 나온 어텐션 행렬을 M이라고 하자.

여기서 인코더의 결과 R과 디코더의 결과 M의 상호작용이 일어난다. 이를 **"인코더-디코더 어텐션 레이어"** 라고 부른다.

 

디코더에서의 멀티 헤드 어텐션의 작동은 다음과 같다.

멀티 헤드 어텐션에 사용하는 쿼리, 키, 밸류 행렬을 생성한다. 이전에는 쿼리, 키, 밸류 행렬을 생성할 때 가중치 행렬을 곱해서 만들었었다. 그때는 입력값이 1개였다.

하지만 이번 디코더에서의 멀티 헤드 어텐션은 R행렬과 M행렬 두 개의 입력값을 가진다.

따라서 어텐션 행렬 M을 사용해 Q행렬을 만들고, 인코더 표현 값인 R을 활용해서 K,V 행렬을 만든다.

 

그렇다면 왜 Q행렬은 M을 이용해서 만들고 K,V 는 R을 활용해서 만드는가?

일반적으로 Q행렬은 타깃 문장의 표현을 포함하고 K,V행렬은 입력 문장의 표현을 가지기 때문에,

Q행렬은 M행렬을 K,V행렬은 R행렬을 참조한다.

 

이것의 장점은??????

 

셀프 어텐션 행렬을 구하는 첫 번째 단계는 Q행렬과 K행렬의 내적을 수행하는 것.

우리는 Q행렬을 M을 참조했고, K는 R을 참조했다.

따라서 두 행렬의 내적은 쿼리 행렬(타깃 문장 표현)과 키 행렬(입력 문장 표현) 간의 유사도를 계산한 것과 같다.

 

이후 과정을 앞선 과정과 똑같이 단어 벡터의 차원의 수의 제곱근을 나누고 SOFTMAX 함수 적용 단계까지 거친다.

그리고 구한 스코어 행렬에 V행렬을 곱해서 어텐션 행렬을 얻는다.

(각 스코어에 대한 가중치를 반영한 벡터값의 합)

책 58PG 의 Je 의 셀프 어텐션을 살펴보면, "i" 를 가중치 0.98로 가진다. 결국 Je 는 i와 98%로 유사함을 의미하고 결국 i와 동의어라고 결론 지을 수 있다.

 

멀티 헤드 어텐션은 헤드마다 얻은 어텐션 행렬을 CONCATENATE 한 이후에 가중치 W를 곱한 값을 의미한다.

피드 포워드 네트워크

지금까지 서브 레이어 두 개를 살펴봤다.

하나는 마스크된 멀티 헤드 어텐션이였고 그 다음은 멀티 헤드 어텐션 레이어였다.

다음 서브 레이어는 피드 포워드 네트워크다.

디코더의 피드 포워드 네트워크는 앞에서 배운 인코더의 피드포워드 네트워크와 동일한 구조다.

add와 norm 요소

add와 norm 의 구성요소는 서브레이어의 입력과 출력을 서로 연결한다.

선형과 소프트맥스 레이어

디코더는 여러 겹으로 쌓을 수 있는데, 최상위 디코더의 출력값은 선형 레이어에 입력값으로 들어간다.

선형 레이어는 그 크기가 어휘(vocabulary) 크기와 같은 로짓 형태다.

가정으로 vocab = ["I","like","banana"] 라고 해보면 선형 레이어가 반환하는 로짓은 크기가 3인 벡터 형태가 된다.

선형 레이어가 반환한 로짓 값을 소프트맥스 함수를 이용해서 확률값으로 바꾸고 가장 높은 확률 값을 가지고 있는 인덱스의 단어로 출력한다.

이런 방식으로 다음 단어에 대해 추론한다.

인코더와 디코더 결합

인코더에서 입력 문장에 대한 표현 결과를 디코더에 내뱉으면 디코더에서는 타깃 문장을 생성한다.

트랜스포머 학습

여러 개 중에서 한 개를 선택하는 과정을 거치기 때문에 손실 함수를 교차 엔트로피 함수를 사용한다.

학습은 adam 방식 사용.

과적합을 방지하기 위해서는 각 서브레이어의 출력에 드롭아웃을 적용.

임베딩 및 위치 인코딩의 합을 구할 때도 드롭아웃.

'NLP > 구글 BERT의 정석' 카테고리의 다른 글

텍스트 요약을 위한 BERTSUM 탐색  (0) 2022.02.17
BERT 파생 모델 2 : 지식 증류 기반  (0) 2022.02.16
BERT 파생 모델  (0) 2022.02.15
BERT 활용하기  (0) 2022.02.10
BERT 이해하기  (0) 2022.02.09
Comments