* 이 글은 구부정.. 스터디의 일환으로, '구글 BERT의 정석' 책을 읽고 정리한 글입니다.
트랜스포머 소개
NLP의 다양한 문제들을 해결하기 위해 주로 사용되었던 RNN과 LSTM 네트워크에는 장기 의존성 문제(long-term dependency)가 있다. 이런 RNN의 한계점을 극복하기 위해서 「Attention Is All You Need」 논문에서 '트랜스포머'라는 아키텍처를 제안했다. 트랜스포머는 RNN의 순환 방식 대신 순수하게 어텐션만 사용한 모델이다. 트랜스포머는 셀프 어텐션(self attention)이라는 특수한 형태의 어텐션을 사용한다.
기계번역에서의 사용 예시를 통해 트랜스포머의 작동 원리를 살펴보자. 트랜스포머는 인코더-디코더로 구성된 모델로, 인코더에 원문을 입력하면 인코더는 입력 문장의 표현 방법을 학습시키고, 그 결과를 디코더로 보낸다. 디코더는 인코더에서 학습한 표현 결과를 입력받아 사용자가 원하는 문장을 생성한다.
트랜스포머의 구성 요소: 인코더와 디코더
* 인코더: 입력 문장의 표현 방법을 학습
* 디코더: 인코더의 출력을 받아 사용자가 원하는 문장 생성
트랜스포머의 인코더 이해하기
트랜스포머의 인코더 파트는 $N$개(논문에서는 $N=6$)의 인코더가 직렬로 쌓인 형태다. 인코더의 아웃풋은 그 다음 인코더의 인풋으로 들어가며, 가장 마지막 인코더의 아웃풋이 입력 문장에 대한 표현 방법을 담은 최종 아웃풋이 된다. N개의 인코더를 그림으로 표현해 보자면 아래와 같다.
이 인코더 묶음은 어떤 방식으로 작동하는지 알아보기 위해 인코더의 세부 구성 요소를 알아보도록 하자. 인코더 블록은 멀티 헤드 어텐션 레이어와 피드포워드 네트워크를 가지며, 모든 인코더 블록은 동일한 형태를 갖는다.
인코더의 구성 요소: 멀티 헤드 어텐션(multi-head attention)과 피드포워드 네트워크(feedforward network)
두 구성 요소가 어떻게 작동하는지 알아보도록 하자. 멀티 헤드 어텐션을 이해하기 위해서는 먼저 셀프 어텐션이 어떻게 작동하는지 알아야 한다.
셀프 어텐션의 작동 원리
셀프 어텐션은 각 단어를 기준으로 주어진 문장의 모든 단어와 연결하는 과정을 수행한다. 이 과정을 통해 각 단어가 문장 내의 모든 단어와 각각 얼마나 관련이 있는지를 알 수 있다. 문장 내에서 등장한 순서대로 각 단어의 표현을 다른 모든 단어의 표현과 연결해 단어가 문장 내에서 갖는 의미를 이해한다.
셀프 어텐션의 내부 작동 원리를 알아보자. 예시 입력 문장이 'I ate sandwich'일 때, 이 문장을의 각 단어를 표현하는 임베딩 값을 추출한다. 이 임베딩 값은 모델 학습 과정에서 같이 학습된다. 각 단어의 임베딩 벡터를 합쳐 행렬로 나타낸 것이 입력 행렬(임베딩 행렬) $X$이며, 이 행렬 $X$가 인코더의 인풋이다. 행렬 $X$의 차원은 [문장 길이 X 임베딩 차원]이며, 아래의 예시에서 임베딩 차원은 512이다.
다음으로, 입력 행렬 $X$로부터 Q(Query) 행렬, K(Key) 행렬, V(Value) 행렬을 생성한다. $W^Q$, $W^K$, $W^V$의 3개의 가중치 행렬을 생성한 다음, 이 가중치 행렬을 각각 $X$에 곱해 Q, K, V 행렬을 만들 수 있다. 이 가중치 행렬들은 처음에 임의의 값을 가지며, 학습 과정에서 최적값을 갖는다. 이제 셀프 어텐션이 Q, K, V 행렬을 통해 특정 단어와 문장 내에 있는 모든 단어를 연결하는 방법을 알아보자.
1단계: Q와 K 행렬의 내적 계산($QK^T$)
셀프 어텐션의 첫번째 단계는 쿼리와 키 행렬의 내적값을 계산하는 것이다. $QK^T$ 값은 문장의 각 단어가 다른 모든 단어와 얼마나 유사한지에 대한 정보다. 아래의 그림에서 민트색으로 표시된 첫번째 행을 살펴보면 쿼리 벡터 $q_1$(I)와 키 벡터 $k_1$(I), $k_2$(ate), $k_1$(sandwich)의 내적을 계산해 두 벡터가 얼마나 유사한지에 대한 정보를 얻었다. 이 결과를 통해 단어 'I'가 'ate', 'sandwich'보다 자신(I)과 연관성이 더 높은 것을 알 수 있다.
2단계: $QK^T$ 행렬을 $\sqrt{d_K}$로 나누기
다음 단계는 $Q\dot K^T$ 행렬을 키 벡터의 차원의 제곱근값으로 나눠 안정적인 경삿값(gradient)을 얻도록 하는 것이다.
3단계: $QK^T$ 행렬에 softmax 적용
1, 2단계에서 계산한 $QK^T$ 유사도 값은 비정규화된 형태이므로, softmax 함수를 통해서 정규화 작업을 진행한다. 소프트맥스 함수를 적용하면 각 벡터의 전체 값의 합은 1이 되며, 각각의 값은 0과 1 사이가 된다. 2단계의 결과에 소프트맥스를 적용하면 아래와 같은 결과를 얻는다. 이 행렬을 스코어 행렬이라고 한다.
4단계: 어텐션 행렬($Z$) 계산
어텐션 행렬은 3단계에서 계산한 스코어 행렬에 V 행렬을 곱해 구할 수 있다. 이렇게 계산된 어텐션 행렬은 각 단어의 벡터값을 갖는데, 이 벡터는 각 점수(스코어 행렬)를 기준으로 가중치가 부여된 벡터다.
멀티 헤드 어텐션 원리
입력으로 'A dog ate the food because it was hungry.' 라는 문장이 들어왔다고 하자. 이 예제에서 단어 'it'의 셀프 어텐션을 계산해 다음과 같은 결과를 얻었다고 가정해보자.
$$Z_{it}=0.0V_1(A) + 1.0V_2(dog) + ... + 0.0V_9(hungry)$$
이 경우 단어 'it'은 단어 'dog'과 가장 관련이 높다고 해석할 수 있지만, 'it'은 충분히 'dog'과 'food' 두 개 사이에서 모호한 의미를 가질 가능성이 있다. 이렇듯 문장 내 단어의 의미가 모호한 경우 모델은 의미가 맞지 않은 단어의 벡터값에 높은 영향을 받을 수 있으며, 문장의 의미가 잘못 해석될 수 있다. 그래서 어텐션의 결과의 정확도를 높이기 위해 헤드 한 개만 사용한 형태가 아닌 헤드 여러 개를 사용한 멀티 헤드 어텐션을 사용한다.
멀티 헤드 어텐션은 여러 개의 어텐션 행렬을 사용하며($Z_1$, $Z_2$, ... Z_n), 어텐션 행렬마다 각각 다른 $Q_n$, $K_n$, $V_n$ 행렬과 가중치 행렬($W_n^Q$, $W_n^K$, $W_n^V$)을 갖는다. 이 $Q_n$, $K_n$, $V_n$ 행렬을 통해 생성된 어텐션 행렬(어텐션 헤드) n개를 연결한 후 새로운 가중치 행렬 $W_0$을 곱하면 최종적으로 우리가 원하는 행렬곱을 구할 수 있다.
$$concatenate(Z_1, Z_2, ..., Z_i, ..., Z_n)W_0$$
위치 인코딩
트랜스포머는 RNN의 순환 구조를 따르지 않으며, 모든 단어를 병렬로 입력받는다. 이는 학습 시간을 줄이고 RNN의 장기 의존성 문제를 해결하는데 도움이 되지만, 순서 정보가 사라졌기 때문에 문장을 명확하게 이해할 수 없다. 그래서 트랜스포머는 위치 인코딩을 통해 단어의 순서 정보를 이해한다. 위치 인코딩 행렬 $P$의 차원은 입력 행렬(임베딩 행렬) $X$의 차원과 동일하며, 입력 행렬이 트랜스포머에 입력되기 전에 입력 행렬에 위치 인코딩 행렬을 더해 트랜스포머에 위치 정보를 전달할 수 있다.
위치 인코딩을 계산하는 데는 사인파 함수를 사용하며, 위치 인코딩에서 $i$의 값이 짝수인 경우 사인 함수를, 홀수인 경우 코사인 함수를 사용한다.
위치 인코딩을 추가하여 다시 인코더의 구조를 그려보자면 아래와 같다.
트랜스포머는 순환 구조가 아닌 병렬로 입력을 받기 때문에 위치 인코딩을 통해 위치 정보를 제공받아야 한다.
피드포워드 네트워크
피드포워드 네트워크는 멀티 헤드 어텐션 레이어의 다음 단계에 위치해 있으며, 2개의 전결합층(dense layer)과 ReLU 활성화 함수로 구성되어 있다. 피드포워드 네트워크의 파라미터는 문장의 다른 위치에서는 동일하고, 인코더 블록에서는 다르게 나타난다.
add & norm 요소
트랜스포머 인코더의 특징 중 하나는 바로 Add & Normalization이다. 이 레이어는 서브레이어의 입력과 출력 부분에 연결되어 있다. Add & Norm 요소는 서브레이어에서 멀티 헤드 어텐션, 피드포워드 네트워크 각각의 입력값과 출력값을 서로 연결한다.
이 요소는 레이어 정규화(normalization)과 잔차 연결(residual connection)의 역할을 한다. 레이어 정규화는 각 레이어 값이 크게 변화하는 것을 방지해 모델을 더 빠르게 학습할 수 있게 하며, 잔차 연결은 특정 레이어를 건너뛰어 입력하여(아래의 그림에서 주황색 화살표 참고) 그래이디언트 소실(gradient vanishing) 문제를 완화할 수 있다.
여태까지 공부했던 인코더의 구조에 add & norm 요소를 추가하여 완성한 인코더 1(가장 첫번째 인코더)의 구조다.
위와 동일한 구조의 인코더를 N개 누적해 사용하며, 최상위 인코더의 출력값은 주어진 인코더에 대한 표현값이 된다. 이 표현값은 디코더의 입력값으로 들어가며, 디코더는 이것을 바탕으로 타깃 문장을 생성한다.
다음 글에서는 트랜스포머의 디코더에 대해서 알아보도록 하자.
'Machine Learning > NLP' 카테고리의 다른 글
Stanford cs224n (Winter 2019) | Lecture 2: Word Vectors and Word Senses (0) | 2021.12.09 |
---|---|
Stanford CS224N (Winter 2019) | Lecture 1: Introduction and Word Vectors (2) | 2021.12.01 |
[파이토치로 배우는 자연어처리] 레스토랑 리뷰 감성 분류하기 - (3) 감성 분류 모델 만들기 (2) | 2021.10.28 |
[파이토치로 배우는 자연어처리] 레스토랑 리뷰 감성 분류하기 - (2) 문장 토큰화와 Dataset (0) | 2021.10.25 |
[파이토치로 배우는 자연어처리] 레스토랑 리뷰 감성 분류하기 - (1)데이터 전처리 (0) | 2021.10.22 |