[Deeplearning] Transformer 에 대해 알아보자
앞으로 Transformer 를 시작으로 ChatGPT 에 쓰인 모델까지 개인적으로 공부하는 흔적을 남기고, 또 추후에 공부한 내용들을 다시 참조할 수 있게 관련하여 블로그에 내용 정리를 하려고 합니다. 논문들과 여러 책 등을 참고해서 공부하고 이해한 내용들을 작성하고자 합니다만 그래도 저는 아직 많이 부족하여 잘못된 내용 혹은 잘못 이해한 내용들을 작성할 수도 있습니다. 그러니 100% 신뢰하기 보다는 참고용으로 봐주시면 좋겠습니다.
우선 Transformer 에 대해 공부하고 알아보기 전에 딥러닝 공부 관련 글을 적게된 개인적인 경위에 대해서 간략하게만 설명하고 넘어가도록 하겠습니다.
저는 대학원 석사 과정 중 딥러닝 모델들 위주로 자연어처리에 대해서 공부를 했었습니다만 당시 Transformer 모델이 발표된지 얼마 되지 않아 지금과 같이 어떻게 활용할 것인지에 대한 연구도 없었고, 프로젝트 진행이 급했기에 대략적인 논문 리뷰만 하고 넘어갔고, 이후에 나온 BERT 모델도 제가 석사 과정이 끝날 때 쯤에 나와 자세히 공부해 보지는 못했습니다. 그리고 이후에 취업한 회사에서는 딥러닝 위주 보다는 회사 자체에서 개발한 사전 기반 언어 분석기 전체를 관리하는 업무를 혼자 맡다 보니 딥러닝 공부를 하지 않았습니다. 그리고 해당 회사에 있으면서 이런 레거시 프로그램이 아닌 대학원 때 했던 딥러닝을 다시 하자는 생각을 하게 되었고 그 회사를 나오고 이렇게 개인적으로 다시 처음부터 공부를 시작하게 되었습니다. 그리고 공부를 할 때에는 이렇게 블로그로 자신이 공부한 내용들을 남기는 것으로도 충분히 공부에 대한 동기와 열정을 줄 수 있다는 글을 보고 앞으로는 공부한 내용들을 블로그로 정리를 꾸준히 해야겠다는 생각이 들었고, 또한 논문을 보면서 딥러닝 모델 공부를 하는데 이해가 안가는 부분에 대해서 블로그 글 들을 참고하고자 찾아 봤는데 모두다 똑같은 내용들을 모두 복사 붙여 넣기한 블로그들이 굉장히 많아 크게 도움이 되지 않는다는 생각이 들어 다른 사람에게 그래도 조금이라도 도움이 되는 포스트를 작성해보자 하는 마음도 들어 이렇게 딥러닝 공부를 시작하면서 블로그 글을 쓰게 되었습니다.
그럼 서두가 길었습니다. Transformer 에 대해 알아보도록 하겠습니다. 저는 이 글을 작성하기 위해 Attention is all you need 논문과 Denist Rothman 이 지은 “트랜스포머로 시작하는 자연어 처리” 를 참고하였습니다. 글의 구성은 대략적으로 Transformer 모델이 등장하게 된 배경, Transformer 의 이론적 내용 정리, 실제 코드를 이용한 실습 순으로 진행하도록 하겠습니다.
1. Transfomer 가 등장하게 된 배경
Transformer 등장 이전에는 자연어 처리에서 RNN(Recurrent Neural Network), 특히 LSTM(Long Short-Term Memory) 모델이 주로 사용되었습니다. LSTM은 RNN의 장기 의존성 문제(long-term dependency problem)를 내부의 게이트 구조를 통해 어느 정도 완화했지만, 여전히 정보 전달이 길어질수록 학습이 어려워지는 한계가 있었습니다.
이를 해결하기 위한 시도로 Attention Mechanism이 Encoder-Decoder 구조에 도입되었고, 이 메커니즘은 각 입력 토큰의 중요도를 계산하여 멀리 떨어진 토큰 간의 관계도 학습할 수 있는 가능성을 보여주었습니다.
하지만 LSTM 기반 모델은 순차적으로 계산되는 구조 때문에 병렬 처리가 어려워 속도가 매우 느리며, Attention이 도입되었음에도 불구하고 장기 의존성 완전 해결에는 여전히 한계가 존재했습니다.
이러한 문제를 극복하고자 연구자들은 Attention 자체의 표현력에 주목하기 시작했습니다. “그렇다면 굳이 순차 모델(RNN/LSTM)을 쓰지 않고, Attention만으로 시퀀스를 처리할 수 있지 않을까?”
이 아이디어로부터 완전히 Attention 기반인 Transformer 모델이 등장하게 되었습니다. Transformer는 입력 시퀀스를 한 번에 처리하고, Self-Attention 메커니즘을 통해 모든 위치 간의 상호작용을 계산함으로써 병렬화, 장기 의존성, 표현력이라는 측면에서 기존 LSTM 기반 모델을 압도하는 성능을 보였습니다.
2. Transformer 구조 및 원리
Transfomer 모델의 구조는 아래 그림과 같습니다.

Transformer 모델의 구조
인코더 스택
오리지널 트랜스포머 모델의 인코더와 디코더는 층을 쌓아 올린 스택 형태(stack of layer) 로 되어 있습니다.
오리지널 트랜스포머 모델의 인코더 층은 총 N=6 개로 모두 동일한 구조입니다. 각각의 층에 멀티-헤드 어텐션 메커니즘, 완전 연결 위치별 순방향 네트워크(fully connected position-wise feed-forward network)인 두 서브층을 가지고 있습니다.
잔차 연결(residual connection)이 트랜스포머 모델의 각 서브 층을 둘러싸고 있습니다. 잔차 연결은 서브 층의 입력 x 를 층 정규화(layer normalization) 함수에 전달하여, 위치 인코딩(positional encoding)과 같은 주용한 정보가 손실되지 않도록 보장합니다.
디코더 스택
트랜스포머의 디코더 역시 인코더처럼 층을 쌓아 올린 스택 형태입니다. 트랜스포머의 인코더처럼, N=6개 디코더 층의 구조는 모두 동일합니다. 각 층은 3개의 서브층으로 이루어져 있는데, 멀티-헤드 마스크드 어텐션(multi-head masked attention) 메커니즘, 멀티-헤드-어텐션 메커니즘, 완전 연결 위치별 순방향 네트워크입니다.
디코더에는 세 번째 주요 층인 마스크드 멀티-헤드 어텐션이 있는데 이 층에서는 주어진 위치 이후의 모든 단어를 마스킹 함으로써, 트랜스포머가 나머지 시퀀스를 보지 않고 스스로의 추론에 근거하여 연산하도록 합니다. 마스크드 멀티-헤드 어텐션은 “Attention is all you need” 논문에서 자세히 다루지 않고 “To prevent positions from attending to subsequent positions, we mask the future positions (setting them to −∞) in the scaled dot-product attention.” 로 굉장히 간단한 설명만 하고 있습니다. 그래서 지금과 달리 트랜스포머가 발표됐을 당시에는 논문만 보고 트랜스포머 모델을 구현하기에는 굉장히 어려웠습니다. 따라서 관련해서 뒤에서 트랜스포머 모델의 원리 부분에서 좀 더 자세히 알아보도록 하겠습니다.
트랜스포머의 최종 출력은 한 번에 하나의 출력 시퀀스만 생성합니다. 그래서 각 층에 사용한 차원을 vocab size 차원으로 바꾸어 주는 선형 층이 있고, 선형 층을 통해 나온 결과를 소프트맥스하여 값이 가장 큰 토큰을 출력으로 사용합니다.
Transformer 모델의 Task
Transformer 모델의 Task 는 Encoder-Decoder 구조 기반의 언어 번역 Task 입니다. 즉 입력 문장을 넣어주면 학습한 다른 언어로 번역을 해줍니다.
Transformer 모델의 Input 과 Output
Input
- 학습된 모델의 input : 번역할 문장
- 학습 데이터의 input
- Encoder input : 번역할 문장
- Decoder input : 기존 번역된 문장에서 시작 위치에 [START] 토큰을 추가하고, 마지막 토큰은 제거된 문장
학습된 모델의 input
input : I love you
학습 데이터의 Encoder input
{
"input_ids": I love you
}
학습 데이터의 Decoder input
{
"input_ids": [START, Ich, liebe]
}
Output
- 학습된 모델의 output : 번역된 문장
- 학습 데이터의 ouput : 번역된 문장의 token
학습된 모델의 output
output : Ich liebe dich
학습 데이터의 output
{
"labels": [Ich, liebe, dich]
}
Transformer 모델의 원리
입력 임베딩
Transfomer 에 사용된 입력 임베딩은 구글이 2013년 발표한 스킵 그램(skip-gram) 을 이용해 생성된 임베딩을 사용합니다. 다만 스킵 그램의 입력으로 사용되는 token 은 BPE(Byte-Pair-Encoding), 워드 피스(word piece), 센텐스 피스(sentence piece) 와 같은 토크나이저를 이용합니다.
인코더 스택에서는 번역할 언어의 문장에서 토큰을 추출하고 각 토큰을 임베딩하여 입력 임베딩으로 사용합니다. 디코더 스택에서는 번역될 언어의 문장에서 토큰을 추출하고 각 토큰을 임베딩하여 입력 임베딩으로 사용합니다.
위치 인코딩 (Positional Encoding)
Transformer 에서는 attention 기법만 사용하게 됩니다. 하지만 attention 기법은 뛰어난 성능, 장기 의존성 문제 해결 등의 장점이 있지만 한 가지 부족한 점이 각 토큰의 위치 정보가 존재하지 않아 각 토큰이 어디에 위치하는지를 구별할 수 없다는 것입니다. 그렇다고 위치 벡터를 별개로 학습하면 트랜스포머의 학습 속도가 매우 느려질 수 있고, 어텐션의 서브 층이 너무 복잡해질 위험이 있습니다. 따라서 추가적인 벡터를 사용하는 대신, 입력 임베딩에 위치 인코딩 값을 더하여 시퀀스 내 토큰의 위치를 표현하였습니다. 사용한 공식은 다음과 같습니다.
\[\begin{aligned} PE_{(pos, 2i)} &= \sin\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) \\ PE_{(pos, 2i+1)} &= \cos\left(\frac{pos}{10000^{\frac{2i}{d_{\text{model}}}}}\right) \end{aligned}\]여기서:
- $pos$는 단어의 시퀀스 상 위치를 의미합니다.
- $i$는 임베딩 차원 내 인덱스입니다.
- $d_{\text{model}}$은 전체 임베딩 벡터의 차원 수입니다 (예: 512).
- 짝수 인덱스에는 사인 함수, 홀수 인덱스에는 코사인 함수를 사용합니다.
이렇게 만들어진 위치 임베딩은 기존 입력 임베딩과 합쳐져서 Transformer 의 입력으로 사용됩니다.
멀티-헤드 어텐션
멀티 헤드 어텐션은 이전에 LSTM과 같이 모델 내부에서 학습이 되는 웨이트들을 토큰 하나씩 loop 로 보면서 학습하는 것이 아니라 입력된 문장의 전체 토큰들을 지정한 헤드의 수로 나누어 self-attention 을 수행하며, Q, K, V 라는 출력을 위해 각 다른 정보를 학습하도록 하는 웨이트들을 두어 단순히 층을 많이 쌓아서 학습이 잘 되는 것이 아닌 웨이트가 학습 될 때 필요한 정보들만 학습하도록 한 어텐션 기법입니다. 그렇다면 멀티-헤드 어텐션에 대해서 자세히 알아보도록 하겠습니다.
멀티-헤드
멀티-헤드 어텐션은 “Attention is All You Need” 논문에서 소개된 기법으로, 입력 정보를 여러 개의 다른 시각(attention subspace)에서 동시에 바라볼 수 있게 해주는 구조입니다. 여러 개의 다른 시각에서 동시에 바라볼 수 있게 해준다는 의미는 비유를 해보자면 하나의 문장을 여러 번역가가 번역을 진행하는 것에 비유할 수 있습니다. 또한 이 구조는 병렬 연산이 가능하다는 장점도 있어, 연산 속도 측면에서도 효율적입니다.
Transformer 의 self-attention 에서는 입력 임베딩을 각각 Query(Q), Key(K), Value(V) 벡터로 변환하기 위한 학습 가능한 가중치 행렬 W^Q
, W^K
, W^V
이 존재합니다. 이 가중치들은 모델의 차원 d_model
에 따라 d_model x d_k
크기를 가지며, 학습을 통해 점점 의미 있는 표현을 생성하도록 조정됩니다.
멀티-헤드는 이러한 Q, K, V 를 여러 개의 head 로 나누어 병렬적으로 attention 을 수행합니다. 예를 들어, 모델 차원이 512 이고 head 수가 8이라면 각 head 는 64차원 공간에서 attention 을 수행합니다. 이 각각의 attention 결과를 concat 후 projection 을 거쳐 다시 모델 차원으로 통합됩니다.
이러한 병렬 구조는 GPU 와 같은 병렬 연산 환경에서 for-loop 기반의 순차 처리보다 훨씬 빠르고 효과적으로 학습 및 추론을 수행할 수 있도록 합니다.
Scaled Dot-Product Attention(Q, K, V)
이제 앞의 멀티-헤드에서 언급했던 Q, K, V 와 함께 Transformer 에서의 핵심 학습 방법에 대해서 다뤄보도록 하겠습니다. 우선 Q, K, V 에 대한 설명을 하자면 다음과 같습니다.
- Query(Q) : 내가 찾고 싶은 정보
- Key(K) : 내가 가진 정보의 특징
- Value(V) : 실제 전달할 정보
Transformer 모델에서는 다른 딥러닝 모델들과 같이 학습되는 가중치를 학습 시켜 원하는 출력을 얻고자 합니다. 하지만 여기서 학습 되는 가중치들에 특정 정보만 학습 되도록 하는 장치를 추가해 학습 시에 모델 내부에서 왜 더 잘 학습되고, 왜 더 좋은 결과를 내는지에 초점을 두고자 하였습니다. Transfomer 이전에 주로 사용되던 LSTM(RNN), CNN 모델들은 단지 “layer 를 더 쌓으니 더 좋은 결과를 내더라” 그래서 더 좋은 성능을 위해 훨씬 더 많은 layer 를 쌓는 연구들이 많았습니다. 하지만 “왜 layer 를 쌓을 수록 성능이 좋아지는가?”에 대해서는 명확한 답을 주지 못했습니다. 그래서 Transformer 모델의 창시자는 Q, K, V 라는 특정 정보만을 학습하도록 하는 가중치들을 두었고, 따로 설계한 식으로 이 가중치들이 학습되도록 모델을 만들었습니다. 그리고 이 때 사용된 공식은 다음과 같습니다.
\[\text{Attention}(Q, K, V) = \text{softmax}\left( \frac{QK^\top}{\sqrt{d_k}} \right)V\]- $ Q $: Query 행렬
- $ K $: Key 행렬
- $ V $: Value 행렬
- $ d_k $: Key 벡터의 차원 (스케일링을 위해 사용)
위 수식은 다음과 같은 의미를 가집니다:
- \( QK^\top \): Query와 Key의 내적을 통해 단어 간 유사도를 계산
- \( \frac{1}{\sqrt{d_k}} \): 값이 너무 커지는 것을 방지하기 위한 스케일링
- \( \text{softmax} \): 유사도를 확률처럼 정규화
- \( \cdot V \): 확률 가중치를 이용해 Value들을 가중합하여 최종 attention 값을 계산
이 과정을 통해 모델은 입력 시퀀스 내에서 어떤 단어에 얼마나 집중할지 결정할 수 있습니다.
멀티-헤드 어텐션
그럼 위의 과정을 토대로 멀티-헤드 어텐션 전체적으로 설명을 해보도록 하겠습니다.
우리는 학습에 사용할 Q, K, V 의 가중치들을 정해준 헤드로 나누어 줍니다 그리고 나누어진 가중치들을 이용해 Scaled dot-product attention 을 진행합니다.
그러면 각 헤드 별로 결과가 나오게 되고 우리는 이 결과들을 하나로 합해줍니다. 하지만 각 헤드들을 합해주긴 했지만 각 정보들이 합해진 대로 분포 되어 있습니다. 이에 대해서 비유를 하자면 한 문장에 대해서 여러명의 번역가가 번역을 했지만 정리가 되지 않은 상태로 비유할 수 있습니다. 그러면 여러명이 번역한 것을 잘 섞어서 좀 더 좋은 결과를 얻을 수 있게 하기 위해 우리는 linear layer 를 이용하고자 합니다. 이를 식으로 나타내면 다음과 같습니다.
\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W^O\] \[\text{where} \quad \text{head}_i = \text{Attention}(Q W_i^Q, K W_i^K, V W_i^V)\] \[\text{and} \quad \text{Attention}(Q, K, V) = \text{softmax}\left( \frac{Q K^T}{\sqrt{d_k}} \right) V\]마스크드 멀티-헤드 어텐션
마스크트 멀티-헤드 어텐션이란?
마스크드 멀티-헤드 어텐션은 모델이 다음 토큰을 예측할 때 미래 정보를 미리 보지 않도록 막아주는 기법입니다. Transformer 의 Decoder 에서는 다음 단어를 예측해야 하기 때문에, 학습 중이라도 미래 토큰을 참조하지 못하도록 마스크를 씌운 self-attention 입니다.
마스크가 필요한 이유
Transformer 는 시퀀스를 한 번에 병렬 처리하므로 학습 중에도 예를 들면 “I love [MASK]” 를 보고 “[you]” 를 예측할 수 있게 됩니다. 하지만 Decoder 는 다음 토큰을 하나씩 예측하는 구조여야 하므로, 학습 중에도 지금까지 입력된 토큰만을 보고 다음 토큰을 예측해야 합니다. 즉 좀 더 간단히 설명을 하자면 마스크 행렬을 적용하지 않으면, Decoder 는 학습 도중 미래 정보를 참고하여 비현실적인 예측 성능을 가지게 됩니다. 즉 엄청난 오버피팅이 일어나게 돼서 학습 데이터가 아닌 데이터가 입력으로 들어오게 되면 치명적인 오작동을 하게 됩니다. 이러한 오작동을 방지하기 위해서 마스크가 필요합니다. 그리고 학습 데이터를 보신분들은 이런 의문도 가질 수 있습니다. Decoder 의 학습 데이터를 보니 맞춰야 하는 정답은 마지막 token 인데 어떻게 미래 정보를 참고한다는 거지라고요, 이는 Transformer 의 Decoder 모델은 매 시퀀스 마다 다음 토큰을 예측하도록 설계되어 있습니다. 즉 마지막 토큰 바로 이전 토큰외의 토큰들은 마스크가 되지 않으면 self-attention 에 의해 항상 정답을 보고 있는 상황인걸로 보시면 됩니다. 따라서 future token 을 가리는 casual mask 또는 look-ahed mask 를 사용합니다.
수식 및 마스킹 방식
\[\text{MaskedMultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W^O\] \[\text{where} \quad \text{head}_i = \text{MaskedAttention}(Q W_i^Q, K W_i^K, V W_i^V)\] \[\text{MaskedAttention}(Q, K, V) = \text{softmax} \left( \frac{Q K^T}{\sqrt{d_k}} + M \right) V\]여기서 ( M )은 마스크 행렬로, softmax가 특정 위치의 값을 무시하도록 매우 작은 값(예: ( -\infty ))을 더해줍니다. 마스크 행렬은 upper-triangular matrix 로 구성되며, 자기 자신과 이전 시점까지만 보이게 합니다. 예를 들면 시퀀스의 길이가 4일 때 마스크 행렬은 다음과 같습니다.
\[M = \begin{bmatrix} 0 & -\infty & -\infty & -\infty \\\\ 0 & 0 & -\infty & -\infty \\\\ 0 & 0 & 0 & -\infty \\\\ 0 & 0 & 0 & 0 \\ \end{bmatrix}\]이 행렬은 softmax 이전에 가중치 행렬 ( \frac{QK^T}{\sqrt{d_k}} )에 더해지며, 결과적으로 softmax에서 미래 시점에 해당하는 값의 확률은 0이 됩니다.
3. 실습
Transformer 의 학습된 모델을 이용해 결과를 출력해보는 실습을 진행해 보도록 하겠습니다.
모델은 Hugging Face 에 있는 transformers 를 사용할 예정이며, 구글 코랩을 이용해 진행해 보도록 하겠습니다.
Transformer 를 이용한 번역
허깅페이스의 미리 학습된 transformers 를 이용해 영어를 프랑스어로 번역하는 간단한 작업을 진행해 보도록 하겠습니다.
코랩에 아래 코드를 붙여 넣기 합니다.
!pip -q install transformers
from transformers import pipeline
translator = pipeline("translation_en_to_fr")
print(translator("It is easy to translate languages with transformers.", max_length=40))
그러면 아래 이미지와 같이 코드가 수행된 다음에 프랑스어로 번역된 문장이 나오게 됩니다.

그리고 번역된 프랑스어 문장인 “Il est facile de traduire des langues avec des transformateurs” 를 구글 번역기를 통해 번역을 다시 해보면 번역하고자 했던 영어 문장이 결과로 나오는 것을 확인할 수 있습니다.

마치며
이번엔 시중에 나와있는 모든 딥러닝 모델들의 베이스가 되는 Transformer 모델에 대해서 알아보았습니다. 이번에 혼자서 Trnasformer 모델에 대한 내용을 정리하면서 Transformer 모델의 내부 원리에 대해서 확실히 정리를 했고, 여러가지 의문이 들었던 부분들도 정리를 하게 되면서 이전에는 Transformer 모델은 대충 이런 거다 에서 이제는 확실하게 누군가에게 알려줄 수 있을 정도가 된 것 같습니다. 그리고 원래는 소량의 데이터를 이용해 학습까지 해보려고 하였으나 시간이 많이 걸릴 듯 하여 학습에 대해서는 추후에 좀 더 준비해서 새로운 포스트를 작성해 보고자 합니다. 긴 글 읽어 주셔서 감사드리며, 잘못된 내용이나 오타 등이 있을 경우 댓글 달아주시면 감사드리겠습니다!
Comments