RNN이나 CNN 같은 기존의 순차적(sequence-based) 구조를 사용하지 않고, 오직 Attention 메커니즘만을 활용하여 자연어 처리(NLP) 모델을 설계한 최초의 연구이다. 이 모델이 바로 Transformer이며, 이후 BERT, GPT 등의 최신 AI 모델의 기반이 되었다.
기존의 Seq2Seq 모델에서 인코더는 입력 시퀀스를 하나의 벡터 표현으로 압축하는데, 이 과정에서 입력 시퀀스의 정보가 일부 손실된다는 단점이 있다.
✅ 1. Seq2Seq 모델이란?
자연어 처리(NLP)에서 입력 시퀀스를 출력 시퀀스로 변환하는 모델이다.
기계 번역(예: 영어 → 한국어), 문서 요약, 질의응답(QA) 등에서 많이 사용된다.
기본적으로 Seq2Seq 모델은 두 개의 RNN 계층(인코더와 디코더)로 구성된다.
💡 예제: "I love you" → "나는 너를 사랑해" 번역
Seq2Seq 모델은 이런 식으로 입력된 단어 시퀀스를 출력 시퀀스로 변환한다.
입력 문장을 받아서 **하나의 벡터(고정된 크기의 숫자 표현)**로 변환하는 역할.
단순히 단어를 숫자로 변환하는 게 아니라, 단어의 의미를 유지하면서 고정된 크기의 벡터로 압축하는 것이 핵심이다.
"문장을 컴퓨터가 이해할 수 있는 숫자로 변환하는 과정"
우리가 흔히 사용하는 원-핫 인코딩(One-Hot Encoding) 또는 임베딩 벡터(Word Embedding) 등을 사용할 수 있다.
📌 숫자는 아무렇게나 지정되는 게 아니다!
각 단어를 고유한 벡터로 변환하는 가장 기본적인 방법
단어를 0과 1로만 이루어진 벡터로 표현하는 방식.
단어 개수만큼의 차원을 가지며, 해당 단어 위치만 1이고 나머지는 모두 0.
단어 집합 (Vocabulary):
| 단어 | 원-핫 벡터 |
|---|---|
| "I" | [1, 0, 0, 0, 0] |
| "love" | [0, 1, 0, 0, 0] |
| "you" | [0, 0, 1, 0, 0] |
| "hello" | [0, 0, 0, 1, 0] |
| "world" | [0, 0, 0, 0, 1] |
이제 컴퓨터는 "I"를 [1, 0, 0, 0, 0]로, "love"를 [0, 1, 0, 0, 0]으로 인식할 수 있어.
❌ 차원이 너무 커짐!
❌ 단어 간의 관계를 표현할 수 없음!
단어를 의미를 반영한 숫자 벡터로 변환하는 방법
원-핫 인코딩과 다르게, 각 단어를 작은 차원의 벡터로 변환하면서 의미를 반영.
비슷한 단어들은 가까운 벡터 값을 가지도록 학습됨.
원-핫 인코딩에서는 단어가 많아질수록 벡터 크기가 커지잖아?
예시:
[0, 0, 0, ..., 1, ..., 0] (벡터 크기: 100,000)[0.2, -0.5, 0.1, ..., 0.8] (벡터 크기: 100~300)💡 즉, 차원을 줄여서 더 효율적으로 단어를 표현하는 것이 목표!
| 비교 | 차원 크기 | 단어 간 의미 반영 |
|---|---|---|
| 원-핫 인코딩 | 크기가 너무 큼 (100,000) | ❌ 없음 |
| 임베딩 벡터 | 작음 (100~300) | ✅ 있음 |
원-핫 인코딩은 차원이 너무 크고 단어 간 관계를 표현할 수 없음
임베딩 벡터는 차원을 줄이면서도 의미를 반영할 수 있음!
이 숫자는 그냥 랜덤한 값이 아니라, 단어의 의미를 학습하면서 최적의 숫자가 정해지는 거야!
즉, 임베딩 벡터 값들은 학습 과정에서 자동으로 결정됨.
우리가 "I love you"를 임베딩 벡터로 변환한다고 가정하면, 원-핫 벡터와 달리 다음과 같이 표현될 수 있음.
| 단어 | 임베딩 벡터 |
|---|---|
| "I" | [0.1, 0.3, 0.5] |
| "love" | [0.4, 0.6, 0.2] |
| "you" | [0.7, 0.2, 0.8] |
비슷한 의미의 단어들이 더 비슷한 벡터 값을 가지도록 학습된다는 점이야! 🔥
예를 들어, "love"와 "like"는 비슷한 단어니까 다음과 같이 유사한 벡터 값을 가질 수 있음.
"love" = [0.4, 0.6, 0.2]
"like" = [0.42, 0.58, 0.21]
Word2Vec은 비슷한 문맥에서 자주 등장하는 단어들은 비슷한 벡터를 가져야 한다는 아이디어를 기반으로 학습해. 🧠
1️⃣ 처음에는 모든 단어의 임베딩 벡터를 랜덤한 숫자로 초기화
2️⃣ CBOW나 Skip-gram을 이용해 예측하면서 손실 함수(loss function)를 최소화하는 방향으로 벡터를 업데이트 🔄
3️⃣ 여러 번 학습을 반복하면 비슷한 의미의 단어들이 비슷한 벡터 값으로 변환됨! 🚀
임베딩 벡터를 학습할 때, 손실 함수(loss function)를 최소화하는 방향으로 벡터 값을 조정하면서 최적의 벡터를 찾는 과정이 진행돼.
이 과정은 신경망을 학습할 때와 비슷하게 **경사 하강법(Gradient Descent)**과 **역전파(Backpropagation)**를 사용해 진행됨.
처음에는 단어 임베딩 벡터를 랜덤한 숫자로 초기화.
예: "love" = [0.3, -0.7, 0.2]
예를 들어, **Word2Vec (Skip-gram)**이라면 중심 단어 **"love"**를 보고 주변 단어 **"I", "you"**를 예측하는 과정을 수행.
즉, "love" 벡터를 입력으로 넣어 "I"와 "you"를 예측해야 함.
1️⃣ 손실 함수를 미분하여 어떤 방향으로 벡터 값을 조정해야 손실이 줄어드는지 계산.
2️⃣ 벡터를 조금씩 조정하면서 손실을 줄여 나감 → 이를 역전파(Backpropagation) 과정이라고 함.
3️⃣ 업데이트 후 "love"의 벡터 값이 조정됨. 예: "love" = [0.35, -0.65, 0.22]
같은 과정을 여러 번 반복하면서 벡터가 점점 최적화됨.
결국 "love"와 "like" 같은 단어는 유사한 벡터 값을 갖게 됨!
즉, 모델이 예측한 주변 단어 확률이 실제 단어와 다르면 손실이 커지고, 정확할수록 손실이 작아짐.
이 손실을 줄이도록 벡터를 업데이트하는 과정이 학습 과정!
예를 들어, "I love you" 문장을 Skip-gram 모델에서 학습한다고 해보자.
초기 단어 벡터를 랜덤하게 설정
| 단어 | 초기 벡터 |
|---|---|
| "I" | [0.3, -0.7, 0.2] |
| "love" | [0.1, 0.4, -0.6] |
| "you" | [-0.5, 0.2, 0.8] |
중심 단어 "love"를 보고, 주변 단어 "I"와 "you"를 예측해야 함.
모델이 "love" → "I"를 예측했는데 확률이 0.2라면?
손실 함수를 줄이는 방향으로 벡터를 업데이트
| 단어 | 업데이트된 벡터 |
|---|---|
| "love" | [0.15, 0.35, -0.55] |
✅ 업데이트됨! 🎯
이 과정을 수백만 개의 문장에 대해 반복하면, "love"와 "like" 같은 비슷한 단어들이 비슷한 벡터 값을 가지도록 학습됨! 🚀
📌 예제
| 단어 | 학습 전 벡터 | 학습 후 벡터 |
|---|---|---|
| "love" | 랜덤값 [0.3, -0.7, 0.2] | [0.4, 0.6, 0.2] |
| "like" | 랜덤값 | [0.42, 0.58, 0.21] |
결과: "love"와 의미가 비슷한 "like"가 비슷한 벡터를 가짐!
GloVe(Global Vectors for Word Representation)는 단어들이 함께 등장하는 확률을 이용해서 단어 벡터를 학습하는 방법이야.
즉, 특정 단어가 문서에서 얼마나 자주 함께 등장하는지를 분석해서 의미를 반영하는 방식이야. 📊
우리가 말을 할 때, 특정 단어들은 자주 함께 등장해.
📌 예제:
"A woman became a queen."
"A man became a king."
위 문장들을 보면 "king"과 "man", "queen"과 "woman"이 비슷한 문맥에서 자주 등장해.
즉,
GloVe는 이런 동시 등장 패턴을 분석해서 단어 벡터를 학습해! ✨
즉, 단어 간의 관계를 통계적으로 표현하는 것이야.
예를 들어,
✅ GloVe는 단어가 같은 문장이나 주변 문맥에서 얼마나 자주 등장하는지(동시 등장 확률)를 분석해서 벡터를 학습해. 🔥
📌 즉, 단순히 단어 순서나 위치만 보는 것이 아니라, 전체적인 동시 등장 확률을 고려하여 단어 간 관계를 더 풍부하게 학습하는 것! 🚀
이걸 제대로 이해하려면, 먼저 단어 벡터에서 의미가 어떻게 반영되는지를 봐야 해. 🧠
✅ "king"은 "man"과 관련 있음
✅ "queen"은 "woman"과 관련 있음
GloVe는 이런 연관성을 벡터에 반영할 수 있도록 학습해. 🔥
즉,
우리가 학습한 벡터들을 다음과 같이 설정한다고 가정하자.
| 단어 | 벡터 값 |
|---|---|
| king | [0.8, 0.6, 0.7] |
| man | [0.5, 0.2, 0.6] |
| woman | [0.4, 0.1, 0.5] |
벡터 연산을 수행하면:
queen = king - man + woman
= [0.8, 0.6, 0.7] - [0.5, 0.2, 0.6] + [0.4, 0.1, 0.5]
= [0.7, 0.5, 0.6] (≈ queen 벡터)
✅ 결과적으로 "queen" 벡터와 거의 비슷한 값이 나옴! 🎉
이런 방식으로 단어 간 의미적인 관계를 벡터 연산으로 표현할 수 있는 것이 GloVe의 핵심이야! 🚀
이제 핵심을 설명해볼게! 🔎
가정:
| 단어 | 벡터 값 |
|---|---|
| king | [8.0, 6.3, 7.1] |
| man | [4.5, 3.0, 6.0] |
| woman | [4.0, 3.3, 4.8] |
계산하면:
queen = king - man + woman
= [8.0, 6.3, 7.1] - [4.5, 3.0, 6.0] + [4.0, 3.3, 4.8]
= [7.5, 6.6, 5.9] (≈ queen 벡터)
✅ 실제 "queen" 벡터와 유사한 값이 나옴! 🎯
이런 벡터 연산이 가능한 이유는 GloVe가 단어들 간의 관계를 확률적으로 학습했기 때문이야! 📊
✅ 단어 간 동시 등장 확률을 이용해 벡터를 학습함
✅ 단어 의미를 벡터 연산으로 표현할 수 있음 (ex: king - man + woman = queen)
✅ 문맥이 아니라 전체 코퍼스(데이터셋)에서 통계적으로 학습하는 방식
✅ 비슷한 단어는 비슷한 벡터를 가지게 됨
✅ "king"과 "queen"의 의미적 관계를 벡터 연산으로 표현 가능
📌 결론: 실제 벡터 값은 학습을 통해 손실 함수를 줄여가면서 최적의 벡터를 찾는 과정에서 결정됨! 🚀
FastText는 기존 Word2Vec의 단점을 보완한 모델이야.
즉, 단어를 그대로 벡터로 바꾸는 게 아니라, 단어를 여러 개의 작은 단위(Subword)로 쪼개서 벡터를 학습하는 방식! 🔥
Word2Vec이나 GloVe는 단어 단위로 벡터를 학습하기 때문에 새로운 단어를 잘 처리하지 못함.
📌 예제: Word2Vec의 한계
🔥 FastText는 이런 문제를 해결하기 위해 단어를 Subword(부분 단어) 단위로 학습함! 🔥
✅ 단어를 여러 개의 작은 조각(서브워드, n-gram)으로 나눔
✅ 각 서브워드도 벡터를 학습하여 전체 단어의 벡터를 생성
✅ 새로운 단어라도 그 단어의 일부 조각들을 사용해서 의미를 유추할 수 있음
📌 예제: "unhappiness"를 학습할 때
FastText는 "unhappiness"를 학습할 때 부분 단어(subword)로 쪼갬.
| 원래 단어 | 3-gram 기준 서브워드 |
|---|---|
| "unhappiness" | ["unh", "hap", "ppi", "ine", "ess"] |
✅ 각 부분(서브워드)도 학습되므로,
✅ "happiness"와 "unhappiness"는 비슷한 벡터를 가질 수 있음! 🔄
✅ "happiness"를 학습한 적이 있다면 "unhappiness"도 비슷한 벡터로 변환 가능! 🎉
✅ 단어를 부분 단어(Subword, n-gram)로 쪼개서 벡터를 학습
✅ 처음 보는 단어(신조어, 복합어)도 이해할 수 있음
✅ 한국어 같은 어절 변화가 많은 언어(예: "먹다" → "먹었습니다", "먹고" 등)에서도 효과적
✅ 비슷한 단어가 비슷한 벡터를 가질 가능성이 높음
📌 결론: FastText는 기존 Word2Vec의 한계를 보완하여 새로운 단어도 이해할 수 있도록 학습하는 강력한 방법! 🚀
문맥(Context)에 따라 단어의 의미가 변하는 방식.
📌 예: "bank" (은행 vs 강둑) → 문맥에 따라 다른 벡터로 변환!
최근에는 BERT, GPT 같은 Transformer 모델에서 임베딩 벡터를 학습하는 방법이 더 많이 사용돼. 🔥
❌ 단어 벡터가 고정됨 → 문맥에 따라 다른 의미를 표현하지 못함
📌 예제:
여기서 "bank"는 다른 의미인데, Word2Vec에서는 같은 벡터를 사용함 😢
Transformer 모델은 단어 벡터를 문맥(Context)에 따라 다르게 학습해.
즉, "bank"라는 단어가 어떤 문장에서 쓰이는지에 따라 벡터 값이 변함.
📌 예제:
| 문장 | "bank" 벡터 |
|------|-------------|
| "The bank is near the river" | 강둑 의미로 변환 → [0.5, -0.2, 0.8] |
| "I deposited money in the bank" | 은행 의미로 변환 → [0.9, -0.1, 0.3] |
✅ 즉, Transformer 기반 모델은 "bank"가 문장에서 어떤 의미로 쓰였는지를 주변 단어를 통해 학습하고, 그에 따라 벡터를 다르게 설정하는 거야!
Transformer 기반 모델에서는 🔥 Self-Attention(자기-어텐션) 메커니즘을 사용해서 문장에서 각 단어가 어떤 의미로 쓰였는지를 학습해.
즉, 단어의 주변 단어(문맥)를 보고 의미를 다르게 해석할 수 있음!
📌 예제: "bank"가 포함된 두 문장
✅ "bank"의 주변 단어: "river"(강), "near"(가까운)
✅ 모델이 "bank"의 의미를 "강둑"으로 해석하도록 벡터를 조정 🔄
➡ "bank" 벡터 → [0.5, -0.2, 0.8] (강둑 의미)
✅ "bank"의 주변 단어: "money"(돈), "deposited"(입금하다)
✅ 모델이 "bank"의 의미를 "은행"으로 해석하도록 벡터를 조정 🔄
➡ "bank" 벡터 → [0.9, -0.1, 0.3] (은행 의미)
🔥 즉, Transformer 기반 모델은 "bank"가 문장에서 어떤 의미로 쓰였는지를 주변 단어를 통해 학습하고, 그에 따라 벡터를 다르게 설정하는 거야! 🚀
💡 이걸 가능하게 하는 핵심 기술 = Self-Attention (자기-어텐션)
Transformer 모델은 단어 하나하나를 독립적으로 해석하는 게 아니라, 문장 전체를 보고 단어의 관계를 학습해.
즉, 각 단어가 다른 단어들과 얼마나 관련이 있는지를 계산하는 과정이 들어가! 📊
✅ 1️⃣ "bank"라는 단어를 처리할 때 그 주변 단어들을 확인
✅ 2️⃣ 각 단어의 의미를 조정하기 위해 가중치(Attention Score)를 다르게 부여
✅ 3️⃣ 이 과정을 통해 "bank"의 벡터가 문맥에 따라 동적으로 변경됨! 🔄
🔥 즉, Transformer 모델은 같은 단어라도 문맥에 따라 다르게 벡터를 생성할 수 있는 거야! 🚀

기존 RNN 기반 Seq2Seq 모델과 Transformer 모델의 가장 큰 차이점은 어떻게 문장을 학습하고 디코딩하는지의 방식이야.
📌 기존 RNN 계열 모델(RNN, LSTM, GRU) → 문장의 마지막에 도달한 후 컨텍스트 벡터(Context Vector)를 통해 문장을 생성
📌 Transformer 모델 → 단어들의 의미를 학습하고 한 번에 모든 단어를 고려하면서 문장을 생성
✅ RNN, LSTM, GRU 등 순환 신경망(RNN 계열 모델)이 단어를 한 번에 하나씩 처리
✅ 단어를 순서대로 처리하면서, 이전 단어 정보를 현재 단어와 함께 사용하여 숨겨진 상태(hidden state)를 업데이트
✅ 문장을 한 단어씩 처리하면서 마지막 시점의 숨겨진 상태(hidden state)를 컨텍스트 벡터(Context Vector)로 만든다
✅ 마지막 단어까지 처리되면, 최종적으로 컨텍스트 벡터(Context Vector)가 만들어짐
✅ 이 컨텍스트 벡터는 문장의 전체 의미를 함축한 고정된 크기의 벡터
✅ 디코더는 이 벡터를 사용해 새로운 문장을 생성할 수 있음
| 입력 단어 | Hidden State |
|---|---|
| "I" | hidden state 1 |
| "love" | hidden state 2 |
| "you" | hidden state 3 (최종 컨텍스트 벡터) |
✅ 컨텍스트 벡터: h3 (고정된 크기의 벡터)
✅ 마지막 hidden state h3는 전체 문장의 의미를 담고 있는 벡터가 됨.
✅ 이 벡터 h3는 디코더에게 전달됨.
✅ 인코더의 마지막 hidden state(h3)가 됨됨
✅ 컨텍스트 벡터(h3)를 받아서 디코더가 문장을 생성하는 방식
✅ 한 번에 한 단어씩 생성하며, 이전에 생성한 단어를 입력으로 받아 다음 단어를 예측.
입력: 컨텍스트 벡터 (h3)
출력: "나는" → "너를" → "사랑해"
1️⃣ h3를 받아서, 디코더가 처음 단어 "나는"을 생성.
2️⃣ 그 후 "나는"을 다시 입력하여 "너를"을 생성.
3️⃣ "너를"을 다시 입력하여 "사랑해"를 생성.
📌 문제점: 긴 문장의 경우 정보 손실이 발생할 수 있음.
우리가 "I love you"라는 문장을 숫자로 변환한다고 가정하자.
(실제로는 Word2Vec, FastText 같은 단어 임베딩 기법을 사용하지만, 이해를 돕기 위해 단순한 숫자로 표현!)
| 단어 | 임베딩 벡터 |
|---|---|
| "I" | [0.1, 0.3, 0.5] |
| "love" | [0.4, 0.6, 0.2] |
| "you" | [0.7, 0.2, 0.8] |
✅ 이제 이 단어들을 RNN 인코더에 넣어보자!
📌 RNN(또는 LSTM, GRU)은 숨겨진 상태(hidden state, h)를 계속 업데이트하면서 단어를 처리한다.
1️⃣ 첫 번째 단어: "I"
h0 = [0, 0, 0]h1이 생성됨.h1 = tanh(W1 * "I" + b1) → 예: h1 = [0.2, 0.5, 0.7]2️⃣ 두 번째 단어: "love"
h1)와 현재 단어(love)를 조합하여 새로운 h2를 만듦.h2 = tanh(W2 * "love" + U2 * h1 + b2) → 예: h2 = [0.6, 0.4, 0.9]3️⃣ 세 번째 단어: "you"
h2와 "you"를 입력하여 h3을 만듦.h3 = tanh(W3 * "you" + U3 * h2 + b3) → 예: h3 = [0.9, 0.1, 0.4]✅ 마지막 hidden state = 컨텍스트 벡터(Context Vector)
📌 이제 h3 = [0.9, 0.1, 0.4]가 컨텍스트 벡터가 됨!
📌 이 벡터는 "I love you" 문장의 전체 의미를 포함한 고정된 크기의 벡터 표현!
🔹 입력 문장의 길이가 다르더라도 같은 크기의 벡터로 표현할 수 있음
🔹 예: "Hello"(1단어)와 "I really love programming"(4단어)도 모두 고정된 크기 벡터로 변환 가능
🔹 이렇게 변환하면 문장을 비교하거나 디코더에서 새로운 문장을 생성할 때 편리!
🔹 디코더가 문장 생성 시 참조할 핵심 정보 제공
✅ 디코더는 이 컨텍스트 벡터를 받아서 새로운 문장을 생성함 (예: 번역 결과).
📌 "인코더는 입력 문장을 고정된 크기의 벡터(Context Vector)로 변환하는 역할을 한다."
✅ 단어들을 순차적으로 처리하면서 hidden state를 업데이트
✅ 마지막 hidden state가 문장의 전체 의미를 담은 컨텍스트 벡터가 됨
📌 이제 Transformer는 이 컨텍스트 벡터 없이, 모든 단어의 관계를 직접 학습하는 방식으로 더 효율적인 NLP 모델을 만든 거야! 🚀
✅ 긴 문장을 하나의 벡터(h3)로 압축하면 중요한 정보가 손실될 수 있음.
✅ 예를 들어, 100개의 단어가 있는 문장을 1개의 벡터로 변환하면 앞부분의 정보가 소실될 수 있음.
✅ RNN 계열 모델은 단어를 순차적으로 처리해야 하므로 속도가 느림.
✅ GPU 병렬 처리가 어려움.
✅ 문장이 길어질수록 앞부분 단어의 영향을 뒷부분에서 받기 어려움.
✅ 예제:
The cat that lived in the house near the river was very happy.
➡ "happy"가 "cat"을 가리킨다는 걸 RNN이 기억하기 어려울 수 있음.
✅ 이를 보완하기 위해 어텐션만으로 인코더와 디코더를 구성하는 모델을 제안 🚀
✅ Transformer는 컨텍스트 벡터 없이 모든 단어 간의 관계를 Self-Attention으로 학습함.
✅ Multi-head self-attention을 이용한 병렬 처리가 특징!
✅ Transformer는 단어를 한 번에 입력받고, 단어들 간의 관계를 분석함.
✅ 이를 위해 Self-Attention 메커니즘을 사용해서 각 단어가 문장에서 어떤 단어와 관련이 있는지 학습함.
✅ "I"는 "love", "you"와 어떤 관계인지 학습.
✅ "love"는 "I", "you"와 어떤 관계인지 학습.
✅ "you"는 "I", "love"와 어떤 관계인지 학습.
📌 즉, Transformer는 단어별로 서로 얼마나 영향을 주고받는지를 계산해서 학습하는 거야!
✅ Transformer는 디코더에서 단어를 하나씩 순차적으로 출력하는 것이 아니라, 한 번에 여러 단어를 예측할 수 있음.
✅ 즉, "나는", "너를", "사랑해"를 동시에 예측할 수 있음.
✅ Transformer는 위 문제를 해결하기 위해 어텐션 메커니즘만을 이용한 모델을 제안했다.
✅ 즉, RNN 없이도 문장 내 단어 간의 관계를 효과적으로 학습할 수 있는 구조를 설계했다.
📌 각 단어가 문장 내 다른 단어들과 얼마나 관련이 있는지를 계산하는 기법.
📌 예제:
The animal didn't cross the street because it was too tired.
➡ 여기서 "it"이 무엇을 가리키는지(= animal) 파악하기 위해 어텐션이 사용될 수 있다.
📌 Self-Attention을 여러 개 병렬로 수행하는 방식.
📌 문장에서 서로 다른 의미를 강조하는 여러 개의 "관점"을 동시에 학습할 수 있음.
📌 예제: "bank"라는 단어가 문맥에 따라 "은행"인지 "강둑"인지 구별해야 할 때, 다른 헤드들이 각각 다른 문맥을 학습할 수 있음.
📌 RNN은 입력 순서를 자연스럽게 반영하지만, Transformer는 병렬 연산을 위해 순서를 무시한다.
📌 이를 보완하기 위해, 입력 단어의 위치 정보를 추가적으로 학습하도록 함.


📌 인코더(Encoder)에 문장을 넣어 학습하는 과정(Train)과, 디코더(Decoder)를 통해 문장을 생성하는 과정(Inference)은 별개로 진행돼!
하지만 Seq2Seq 모델을 설명할 때는 훈련 과정과 추론 과정이 연결되어 있기 때문에 한 번에 설명한 것이야.
1️⃣ 인코더(Encoder)가 문장을 입력받아 hidden state(Context Vector)를 생성
2️⃣ 디코더(Decoder)가 정답 문장을 입력받아 학습하면서, 다음 단어를 예측하도록 손실 함수를 줄임
3️⃣ 모델이 학습되면서 점점 더 정확하게 예측할 수 있도록 가중치 업데이트
📌 즉, 훈련(train) 과정에서는 모델이 학습하는 단계이므로 "정답 문장"을 함께 사용함!
1️⃣ 학습된 인코더 모델이 입력 문장을 받아 hidden state를 생성
2️⃣ 학습된 디코더 모델이 하나씩 단어를 예측하며 문장을 생성
3️⃣ 디코더가 멈출 때까지 단어를 반복해서 생성
📌 즉, 추론 과정에서는 정답 문장이 없고, 모델이 스스로 문장을 만들어내는 과정!
💡 예제: "I love you" → "나는 너를 사랑해" 번역 모델 학습
훈련 과정에서는 디코더가 정답을 알고 있는 상태에서 학습함.
1️⃣ 인코더에 입력 문장을 넣음 ("I love you")
| 입력 단어 | Hidden State |
|---|---|
| "I" | hidden state h1 |
| "love" | hidden state h2 |
| "you" | hidden state h3 (컨텍스트 벡터) |
2️⃣ 컨텍스트 벡터(h3)를 디코더에 전달
3️⃣ 디코더에 정답 문장을 입력하여 다음 단어 예측을 학습
| 입력 | 예측 |
|---|---|
| START | "나는" |
| "나는" | "너를" |
| "너를" | "사랑해" |
4️⃣ 예측 결과와 실제 정답을 비교하여 손실(loss) 계산
5️⃣ 손실을 최소화하도록 가중치 업데이트 → 모델이 점점 똑똑해짐!
💡 학습된 모델을 이용해서 새로운 문장을 번역하는 과정!
훈련 때는 정답 문장을 제공했지만, 추론 과정에서는 디코더가 하나씩 예측하면서 문장을 생성해야 함.
1️⃣ 인코더에 입력 문장을 넣음 ("I love you")
2️⃣ 컨텍스트 벡터 h3를 디코더에 전달
3️⃣ 디코더가 하나씩 단어를 예측하며 문장을 생성
| Hidden State | 예측된 단어 |
|---|---|
| h3 | "나는" |
| "나는" | "너를" |
| "너를" | "사랑해" |
4️⃣ 디코더가 END 토큰을 예측하면 문장 생성을 멈춤 🚀
✅ Transformer에서도 훈련 과정에서는 정답 문장을 이용하여 디코더를 학습함.
1️⃣ 입력 문장을 인코더에 넣음
"I love you" → Self-Attention 학습2️⃣ 출력 문장의 일부를 디코더에 넣어 학습
| 입력 | 예측 |
|---|---|
| START | "나는" |
| "나는" | "너를" |
| "너를" | "사랑해" |
3️⃣ 예측 결과와 실제 정답을 비교하여 손실을 줄이도록 학습
✅ 학습된 모델을 이용하여 새로운 문장을 생성하는 과정
1️⃣ 인코더에 입력 문장을 넣어 문맥을 이해함
2️⃣ 디코더가 START를 입력받아 첫 번째 단어 예측
3️⃣ 이전까지 생성된 단어들을 기반으로 다음 단어 예측을 반복
4️⃣ 예측된 문장이 끝날 때까지 반복해서 단어를 생성
📌 즉, Transformer도 훈련(train)과 추론(inference)이 분리되어 있음!
✔ 훈련(train)과 추론(inference)은 분리된 과정이 맞음!
✔ 훈련 과정에서는 정답 문장을 제공하여 학습, 추론 과정에서는 모델이 스스로 단어를 생성함.
✔ Seq2Seq 모델(RNN)과 Transformer 모두 이 원리를 따름.
✔ 하지만 Transformer는 전체 문맥을 동시에 학습할 수 있어서 더 효율적! 🚀
✅ 병렬 연산 가능 (속도 향상)
✅ 장기 의존성 문제 해결
✅ 더 좋은 성능
✅ 입력 단어를 벡터로 변환한 후, Self-Attention과 Multi-Head Attention을 이용해 관계를 학습.
✅ 포지셔널 인코딩을 추가하여 단어 순서 정보를 보존.
✅ 인코더-디코더 구조를 사용하여 입력 시퀀스를 이해하고 출력 시퀀스를 생성.

✅ Encoding은 여러 개의 Encoder를 쌓아 올려 만든 것, 논문에서는 6개를 쌓아올림.
✅ Decoding은 Encoding과 동일한 개수만큼의 Decoder를 쌓은 것.

📌 꼭 인코더 개수만큼 디코더를 써야 하는 건 아니지만, 논문에서는 6개씩 사용한 이유가 있어!
✅ Transformer 구조에서 인코더 개수(Encoder Layers)와 디코더 개수(Decoder Layers)는 반드시 동일할 필요는 없지만, 일반적으로 같게 설정하는 것이 성능적으로 좋기 때문이야.
✅ 인코더는 입력 문장을 점점 더 고차원적인 특징으로 변환하면서 정보를 압축해.
✅ 디코더는 그 정보를 다시 풀어서(디코딩) 문장을 생성해야 함.
✅ 만약 인코더가 6개인데, 디코더가 2개만 있다면?
📌 Transformer 모델을 적용하는 작업에 따라, 인코더 개수와 디코더 개수를 다르게 설정할 수도 있어!
✅ BERT (Bidirectional Encoder Representations from Transformers) → 인코더만 사용 (디코더 없음)
✅ GPT (Generative Pre-trained Transformer) → 디코더만 사용 (인코더 없음)
✅ T5 (Text-To-Text Transfer Transformer) → 인코더와 디코더 사용 (개수 동일)
✅ Whisper (OpenAI의 음성 모델) → 인코더와 디코더 개수 다르게 설정
📌 예를 들어,
✅ Encoder들은 모두 같은 구조를 가지나 동일한 Weight을 공유하지 않음.
✅ 2개의 Sub-layer를 가짐:

✅ Decoder는 3개의 Sub-layer를 가짐:

Transformer의 인코더는 입력 문장을 벡터로 변환하는 역할을 해.
각 인코더 블록(Encoder Layer)은 2개의 Sub-layer로 구성됨.
🔹 (1) Self-Attention Layer
🔹 (2) Feed Forward Neural Network (FFN) Layer
📌 역할:
📌 어떻게 동작할까?
1️⃣ 각 단어를 Query(Q), Key(K), Value(V) 세 가지 벡터로 변환
2️⃣ Query와 Key의 내적(dot product)을 계산하여 각 단어가 다른 단어들과 얼마나 관련이 있는지 점수(Attention Score)를 매김
3️⃣ 이 점수를 확률로 변환하여(Value) 각 단어의 정보를 가중 평균
4️⃣ 최종적으로 각 단어의 새로운 벡터 표현을 생성
Transformer에서 Query(Q), Key(K), Value(V)는 Self-Attention과 Encoder-Decoder Attention에서 핵심적인 역할을 해!
즉, 각 단어가 다른 단어들과 얼마나 관련이 있는지(어텐션 스코어)를 계산하기 위해 사용되는 벡터들이야.
📌 Self-Attention에서 Query(Q), Key(K), Value(V) 역할
📌 예제:
"I love NLP."
Self-Attention을 적용할 때,
📌 이제 Query(Q)와 Key(K)를 어떻게 설정하는지 수식으로 알아보자! 🔥
Transformer에서 Query(Q), Key(K), Value(V)는 학습된 가중치 행렬을 곱해서 생성됨.
📌 1) 입력 벡터 설정
먼저 각 단어를 벡터(Word Embedding)로 변환한다고 가정하자.
📌 예제 문장: "I love NLP."
| 단어 | 벡터 값 |
|---|---|
| "I" | [0.1, 0.3, 0.5] |
| "love" | [0.4, 0.6, 0.2] |
| "NLP" | [0.7, 0.2, 0.8] |
✅ 이제 각 단어 벡터(입력 벡터)를 Query, Key, Value로 변환해야 해!
📌 2) Query(Q), Key(K), Value(V) 만들기
각 입력 벡터(단어 벡터)에 학습 가능한 가중치 행렬

을 곱해서 Query, Key, Value를 생성해.
💡 가중치 행렬은 학습(train) 과정에서 자동으로 최적의 값이 결정됨!
✅ 즉, 우리가 직접 정하는 게 아니라 모델이 학습하면서 자동으로 최적의 값으로 업데이트됨!
📌 2) 가중치 행렬의 초기 값은 어떻게 정할까?
💡 초기에는 랜덤 값으로 설정하고, 학습하면서 최적의 값으로 조정함.
✅ 훈련이 시작될 때는 가중치 행렬은 작은 랜덤 값으로 초기화됨.
✅ 이후, 모델이 데이터를 학습하면서 손실 함수(loss function)를 최소화하는 방향으로 가중치가 조정됨.
📌 학습 과정
1️⃣ 처음에는 랜덤한 값으로 설정
2️⃣ Query(Q), Key(K), Value(V)를 생성하여 Self-Attention 연산 수행
3️⃣ 예측 결과와 정답을 비교하여 손실(loss)을 계산
4️⃣ 역전파(Backpropagation) + 경사 하강법(Gradient Descent)으로 가중치를 업데이트
5️⃣ 반복해서 학습하면서 점점 더 좋은 값을 가지게 됨
📌 3) 왜 가중치 행렬이 필요할까?
💡 각 단어의 의미를 다른 관점에서 해석할 수 있도록 하기 위해!
📌 예제: "I love NLP"라는 문장에서,
✅ Query("love")는 "I"와 "NLP" 중 어느 쪽과 더 관련이 있는지를 결정해야 함.
✅ Key("I", "NLP")는 자신과 Query가 얼마나 관련 있는지를 평가해야 함.
✅ Value("I", "NLP")는 관련 있는 정보를 넘겨줘야 함.
➡ 가중치 행렬을 학습하면서, 모델이 각 단어가 다른 단어들과의 관계를 더 잘 파악할 수 있게 됨!
🔥 즉, 가중치 행렬은 모델이 문맥을 학습할 수 있도록 돕는 역할을 함! 🚀
📌 Query, Key, Value 수식 정리:

X = 단어 임베딩 벡터 (예: "I", "love", "NLP")
Query(Q) = 입력 벡터 * W_Q
Key(K) = 입력 벡터 * W_K
Value(V) = 입력 벡터 * W_V
✅ 즉, Query, Key, Value는 입력 벡터에 학습된 가중치 행렬을 곱해서 생성하는 것! 🚀
📌 Query(Q)와 Key(K)로 어텐션 스코어 계산하기

📌 즉, Self-Attention의 핵심 과정:
1️⃣ Query 벡터와 Key 벡터를 내적(dot product) 해서 유사도를 계산
2️⃣ Softmax 함수를 적용하여 확률값으로 변환
3️⃣ Value 벡터와 곱해서 최종적인 문맥 정보를 얻음 🚀
💡 내적(Dot Product)은 벡터의 방향이 얼마나 비슷한지를 측정하는 연산이야!
즉, 두 벡터를 내적하면 서로 얼마나 비슷한지를 수치로 나타낼 수 있음.

✅ 벡터의 방향이 같을수록(각도가 0도에 가까울수록) 내적 값이 커지고, 방향이 다르면(각도가 90도 이상이면) 내적 값이 작아짐.
✅ 즉, 내적이 크다는 건 두 벡터가 비슷한 방향을 가진다는 의미야!
➡ Self-Attention에서 내적을 사용하면, 두 단어가 얼마나 유사한지를 측정할 수 있음!
Self-Attention에서는 Query(Q)와 Key(K)를 내적하여 두 단어가 얼마나 관련이 있는지를 측정함.
"The cat sat on the mat."
여기서, "cat"과 "sat"의 관계를 분석한다고 가정하자.
1️⃣ 각 단어 벡터를 Query(Q)와 Key(K)로 변환
Query("cat") = [0.5, 0.2, 0.1]
Key("sat") = [0.4, 0.3, 0.2]
2️⃣ 내적(dot product) 계산
Attention Score = Q("cat") · K("sat")
= (0.5 * 0.4) + (0.2 * 0.3) + (0.1 * 0.2)
= 0.2 + 0.06 + 0.02
= 0.28
👉 0.28이라는 값이 나왔는데, 이 값이 클수록 "cat"과 "sat"이 더 관련 있다는 의미!
💡 즉, Query와 Key의 내적 결과가 높으면 두 단어가 서로 연관성이 높다는 뜻!
Self-Attention에서는 Query와 Key의 내적 결과(Attention Score)를 Softmax를 적용해 확률 값으로 변환합니다.
각 단어의 Query와 문장의 모든 단어 Key를 내적하여 Attention Score를 계산합니다.
Attention Score("cat", "cat") = 0.50
Attention Score("cat", "sat") = 0.28
Attention Score("cat", "mat") = 0.10


📌 exp(지수 함수)는 Attention Score를 확률값으로 변환하는 Softmax 함수에서 사용됨.

📌 exp()를 사용하지 않으면, 값이 비슷한 경우 확률 차이가 크지 않음.
📌 exp()를 사용하면 큰 값과 작은 값의 차이가 더 커져서, 중요한 단어에 더 많은 가중치를 줄 수 있음!
exp(0.50) = 1.6487
exp(0.28) = 1.3231
exp(0.10) = 1.1052
| 단어 | 계산식 | 확률값 |
|---|---|---|
| cat | 1.6487 / (1.6487 + 1.3231 + 1.1052) | 0.39 |
| sat | 1.3231 / (1.6487 + 1.3231 + 1.1052) | 0.31 |
| mat | 1.1052 / (1.6487 + 1.3231 + 1.1052) | 0.26 |
💡 Softmax를 적용하면 모든 Attention Score가 0~1 사이의 확률 값이 되고, 확률의 합이 1이 됩니다!
Softmax를 사용하지 않고 Attention Score를 그대로 사용하면:
🔹 값이 음수이거나 너무 작은 값이 나올 수 있음.
🔹 확률처럼 해석하기 어려움.
🔹 학습이 안정적으로 이루어지지 않을 가능성이 높음.
🔥 Softmax를 사용하면 Attention Score를 확률 값으로 변환할 수 있어 학습이 더 안정적임! 🚀
Softmax 결과를 Value(V) 벡터와 곱하면, 문장에서 중요한 단어들만 강조된 벡터를 만들 수 있음! 즉, 문맥(Context)에 맞게 정보가 조정됨!
Value("cat") = [0.2, 0.4, 0.6]
Value("sat") = [0.3, 0.5, 0.7]
Value("mat") = [0.1, 0.3, 0.2]
최종 벡터 = (0.39 * Value("cat")) + (0.31 * Value("sat")) + (0.26 * Value("mat"))
= (0.39 * [0.2, 0.4, 0.6]) + (0.31 * [0.3, 0.5, 0.7]) + (0.26 * [0.1, 0.3, 0.2])
= [0.078, 0.156, 0.234] + [0.093, 0.155, 0.217] + [0.026, 0.078, 0.052]
= [0.197, 0.389, 0.503]
💡 "cat"의 최종 벡터는 [0.197, 0.389, 0.503]이 됨!
➡ 즉, "cat"이 문장에서 "sat"과 "mat"과 어떻게 연결되는지를 반영한 벡터가 생성됨.
🔥 이 과정이 바로 "Self-Attention을 통해 문맥(Context)이 반영된 벡터를 만드는 과정"! 🚀
💡 Query(Key와 내적하여 얻은 어텐션 확률)와 Value를 곱하는 이유는 "문장에서 중요한 정보를 강조하고, 불필요한 정보를 억제하기 위해서입니다."
Query와 Key를 통해 얻은 어텐션 확률(Softmax 값)을 Value 벡터에 곱하면:
✔ 중요한 단어의 정보를 더 강조하고,
✔ 중요하지 않은 단어의 정보는 덜 반영할 수 있음!
➡ 따라서 "sat"의 Value 벡터를 더 많이 반영하고, "on"의 Value 벡터는 거의 반영하지 않도록 조정함.
🔹 즉, Query-Key를 통해 구한 어텐션 확률을 Value 벡터와 곱하면, "문맥을 반영한 단어 표현"이 생성됨!

1️⃣ Query와 Key의 내적 → "단어 간의 연관성(어텐션 점수)"을 계산.
2️⃣ Softmax 적용 → 연관성을 확률 값(0~1)으로 변환하여 중요한 단어에 높은 가중치를 부여.
3️⃣ Value 벡터와 곱하기 → "문맥을 반영한 최종 단어 벡터" 생성.
🔥 즉, Self-Attention의 최종 목표는 각 단어의 의미를 문맥(Context) 기반으로 변환하는 것! 🚀
Value 벡터도 Query, Key와 마찬가지로, 입력 단어 벡터(Word Embedding)에 가중치 행렬을 곱해서 생성됨!


즉, 처음에는 랜덤한 값을 가지지만, 학습이 진행되면서 점점 더 문맥을 반영할 수 있도록 조정됨! 🎯
Value 벡터를 그냥 단어 벡터로 사용하지 않고, 학습 가능한 가중치 행렬을 곱해서 변환하는 이유는?
✅ Value 벡터를 조정하면 모델이 더 유연하게 단어 관계를 학습할 수 있기 때문!
[0.1, 0.2, 0.3]이면, "cat"이 어떤 문장에서든 같은 정보만 유지됨.📌 "The cat sat"에서는 "sat"과 더 연관된 벡터로 조정됨.
📌 "The cat chased the mouse"에서는 "chased"와 더 연관된 벡터로 조정됨.
🔥 즉, Value 벡터는 문맥에 맞게 조정될 수 있도록 학습 가능해야 하고, 그래서 학습 가능한 가중치를 곱해서 생성하는 것! 🚀
✔ Query-Key로 계산한 유사도를 Softmax를 통해 확률값으로 변환한 후, 이를 Value 벡터에 곱하면 문맥이 반영된 최종 벡터가 생성됨!
✔ Value 벡터는 학습 가능한 가중치 행렬을 곱해서 생성되며, 처음에는 랜덤 값이지만 학습을 통해 최적화됨!

🔥 즉, Query-Key는 "어떤 단어가 중요한가"를 찾는 과정이고, Value는 "그 중요한 정보를 반영하는 과정"이야! 🚀
✅ Self-Attention을 통해 문장 내에서 중요한 단어들을 학습하고 연결함.
✅ 기존 RNN처럼 한 방향으로 순서대로 학습하는 것이 아니라, 모든 단어들이 동시에 서로의 관계를 학습할 수 있음!
💡 이 과정이 Transformer의 핵심이며, 이를 통해 문맥을 효과적으로 반영할 수 있음!
각 단어의 표현을 더 복잡한 형태로 변환하는 비선형 변환 역할을 합니다. 즉, Self-Attention을 거친 단어 벡터를 더 의미 있게 조정하는 과정입니다.
➡ 더 복잡한 관계를 학습할 수 있도록 비선형 변환을 적용하기 위해서! 🚀
Self-Attention을 거친 벡터는 단어 간의 관계를 반영한 값이지만, 연산 과정이 선형적인 연산(내적, Softmax, Value 곱하기)만 포함되어 있습니다.
벡터를 만들긴 했지만, 이 벡터가 충분히 복잡한 패턴을 학습하지 못할 수도 있습니다.
그러므로, 추가적인 비선형 변환을 적용하여 더 풍부한 의미를 학습할 필요가 있습니다! 이를 위해 두 번의 선형 변환과 ReLU 활성화 함수를 사용합니다. 🔥
X' = W_1 X + b_1
📌 X: Self-Attention 결과 벡터
📌 W, b: 학습 가능한 가중치 행렬과 편향(Bias)
✅ 이 과정에서 벡터 차원이 증가합니다. (보통 d→4d)
✅ 차원을 확장함으로써 더 많은 정보를 저장할 수 있도록 합니다.
X'' = ReLU(X')
✅ ReLU(Rectified Linear Unit)라는 비선형성을 추가하는 활성화 함수 적용 ✅ 음수 값은 0으로 만들고, 양수 값은 그대로 유지
✅ 이를 통해 비선형적인 특징을 학습할 수 있게 됨!
📌 ReLU 적용 이유 💡 (왜 비선형 변환이 필요할까?)
Y = W_2 X'' + b_2
✅ ReLU를 적용한 벡터를 다시 원래 차원으로 축소하는 과정입니다. 즉, 4d→d로 차원을 다시 축소 ✅ 차원을 다시 줄이면서 비선형 변환이 적용된 문맥 정보가 최종 벡터로 반환됩니다.
Self-Attention을 거친 후, 더 깊은 의미를 학습하기 위해 다음 단계를 추가합니다!
1️⃣ Self-Attention 수행
2️⃣ 첫 번째 선형 변환: 벡터 차원을 확장하여 더 많은 정보 저장
3️⃣ ReLU 활성화 함수 적용: 비선형성을 추가하여 더 복잡한 관계 학습
4️⃣ 두 번째 선형 변환: 벡터 차원을 다시 원래 크기로 줄이면서 최종 벡터 출력
➡ 인코더는 입력 문장을 이해하는 역할을 하고, 디코더는 새 문장을 생성하는 역할을 하기 때문!
즉, Transformer에서 인코더와 디코더는 서로 다른 목적을 가지고 있음. 🚀
이제 인코더와 디코더의 차이점을 자세히 알아보자!
📌 인코더는 입력 문장을 하나의 의미 있는 벡터 표현으로 변환하는 역할!
인코더는 다음과 같은 과정으로 입력 문장을 처리합니다.
1️⃣ 입력 문장을 벡터로 변환 (Word Embedding + Positional Encoding 적용)
2️⃣ Self-Attention을 통해 단어들 간의 관계를 학습
3️⃣ Feed Forward Network를 적용하여 비선형 변환 수행
4️⃣ N개(논문에서는 6개)의 인코더 블록을 통과하면서 정보를 점점 더 압축
5️⃣ 최종적으로, 문장 전체를 표현하는 벡터(고차원 의미 벡터)를 생성하여 디코더로 전달
💡 즉, 인코더의 목표는 "입력 문장의 의미를 벡터로 변환하는 것"!
➡ 하지만, 이 벡터를 바로 디코더에서 사용할 수 없는 이유가 있음!
💡 인코더가 만든 벡터는 "입력 문장의 의미"를 담고 있지만, "출력 문장을 생성"하는 과정과는 다름!
즉, 디코더는 새로운 문장을 만들어야 하기 때문에, "입력 문장을 이해한 벡터"를 "출력 문장을 만드는 벡터"로 변환하는 과정이 필요합니다!
➡ 디코더는 "출력 문장이 자연스럽게 생성될 수 있도록" 인코더 벡터를 변환해야 함.
📌 디코더는 인코더가 만든 의미 벡터를 받아, 올바른 출력을 생성하는 역할!
디코더는 인코더의 출력 벡터를 받아서 새로운 문장을 생성하는 과정을 수행합니다.
1️⃣ 디코더의 Self-Attention을 통해, 현재까지 생성된 단어들 사이의 관계를 학습
2️⃣ Encoder-Decoder Attention을 통해, 입력 문장과 생성 중인 문장을 연결
3️⃣ Feed Forward Network를 적용하여 최종적인 벡터를 생성
4️⃣ Softmax를 사용하여 최종적으로 확률 분포를 계산 → 다음 단어를 생성
5️⃣ 이 과정을 반복하여 최종적으로 문장을 완성
💡 즉, 디코더는 "입력 문장"을 기반으로 "출력 문장"을 한 단어씩 생성하는 과정!
💡 디코더는 이전에 생성된 단어들과의 관계를 학습해야 하기 때문!
➡ 출력 문장을 생성할 때, 앞에서 나온 단어들을 참고해서 자연스럽게 문장을 만들어야 함.
📌 예제: 영어 → 한국어 번역
❗ 만약 디코더가 Self-Attention을 사용하지 않으면, 각 단어를 독립적으로 생성해서 문맥이 깨질 수 있음!
🔥 즉, 디코더의 Self-Attention은 "출력 문장 내부에서 단어들의 관계를 학습하는 과정"! 🚀
💡 Encoder-Decoder Attention은 인코더에서 만든 의미 벡터를 활용하여, 출력 문장을 더 자연스럽게 만들기 위해 필요함!
즉, 입력 문장과 출력 문장을 연결하는 과정!
📌 Encoder-Decoder Attention의 역할
🔥 즉, Encoder-Decoder Attention은 입력과 출력을 연결하는 핵심적인 과정!

✔ 인코더는 입력 문장을 이해하는 역할 → 문장 전체를 벡터로 압축하여 의미를 학습
✔ 디코더는 입력 문장을 기반으로 새로운 문장을 생성하는 역할 → 인코더 벡터를 활용하여 단어를 하나씩 생성
✔ 인코더의 정보를 그대로 사용하면 "출력 문장 생성"에 필요한 문맥이 부족할 수 있어서, 디코더에서 추가적인 변환 과정이 필요함
✔ 디코더가 Self-Attention을 하는 이유 → 이전에 생성된 단어들과의 관계를 학습하기 위해!
✔ 디코더의 Encoder-Decoder Attention이 중요한 이유 → 인코더가 이해한 내용을 활용하여 올바른 출력을 만들기 위해!
🔥 즉, Transformer의 디코더는 단순히 인코더 벡터를 그대로 쓰는 게 아니라, "출력 문장을 만들 수 있도록" 추가적인 변환을 수행하는 거야! 🚀
Transformer의 디코더는 인코더에서 받은 정보를 바탕으로 문장을 생성하는 역할을 합니다.
각 디코더 블록(Decoder Layer)은 3개의 Sub-layer로 구성됩니다.
🔹 (1) Self-Attention Layer
🔹 (2) Encoder-Decoder Attention Layer
🔹 (3) Feed Forward Neural Network (FFN) Layer
1️⃣ 인코더의 Self-Attention과 동일한 방식으로 각 단어의 관계를 학습
2️⃣ 하지만 미래 단어를 참고하지 않도록 Masking을 적용
3️⃣ 생성된 단어들끼리의 관계를 반영하여 새로운 벡터를 생성
🔥 디코더의 학습 과정에서는 정답 문장(출력 문장)이 주어짐
만약 디코더가 "나는 너를 사랑해" 전체를 한 번에 본다면?
즉, 학습이 제대로 되지 않고 단어를 보고 그대로 따라 쓰는 방식으로 학습될 위험이 있음! ❌
➡ 디코더가 "현재 단어까지"의 정보만 사용해서 다음 단어를 예측하도록 제한해야 함!
💡 마스킹은 디코더가 미래 단어를 보지 못하도록 가리는 역할을 함
➡ 현재까지 생성된 단어만 참고하여 예측할 수 있도록 제한함!
| 디코더 입력 (Self-Attention) | 마스킹 적용 후 보이는 단어 |
|---|---|
| START 나는 너를 사랑해 | START |
| START 나는 너를 사랑해 | START 나는 |
| START 나는 너를 사랑해 | START 나는 너를 |
| START 나는 너를 사랑해 | START 나는 너를 사랑해 |
✅ 즉, "나는"을 예측할 때 "너를 사랑해"를 미리 보면 안 되고,
✅ "너를"을 예측할 때 "사랑해"를 미리 보면 안 됨!
➡ 그래서 마스킹을 적용해서 디코더가 미래 단어를 볼 수 없도록 함! 🚀
💡 디코더에서 Self-Attention을 적용할 때, 학습할 때와 추론할 때 방식이 같은지?
➡ 기본적인 구조는 같지만, 실행 방식은 다름! 🚀
➡ 특히 Masking(미래 단어 가리기) 방식이 학습과 추론에서 차이가 있음.
1️⃣ 입력 문장 → 인코더에 전달 → 인코더의 출력 생성
2️⃣ 디코더의 Self-Attention 수행 (미래 단어 Masking 적용)
3️⃣ Encoder-Decoder Attention 수행 (인코더 출력과 결합)
4️⃣ Feed Forward Network 적용 → 최종 출력 단어 예측
5️⃣ 예측된 단어와 정답 비교 → 손실(loss) 계산 → 가중치 업데이트
1️⃣ 입력 문장 → 인코더에 전달 → 인코더의 출력 생성
2️⃣ 디코더의 입력으로 START 토큰을 제공 → 첫 번째 단어 예측
3️⃣ 예측된 첫 번째 단어를 다시 디코더 입력으로 사용 → 두 번째 단어 예측
4️⃣ 이 과정을 반복하면서 문장을 생성
5️⃣ END 토큰이 나올 때까지 반복
💡 즉, 학습할 때는 정답 문장이 있어 한 번에 연산하지만, 추론할 때는 한 단어씩 예측하면서 진행해야 함!
💡 Masking을 적용해서 현재 단어까지의 정보만 보고 학습하도록 만듦!
💡 결과:
디코더가 단어를 하나씩 순차적으로 생성하도록 학습함.
이전 단어들만 참고하여 문장을 만들어 나갈 수 있도록 함.
추론(Inference)할 때는 인코더가 입력 문장을 벡터로 변환하고, 디코더가 그 벡터를 이용해 학습된 내용을 바탕으로 단어를 하나씩 생성하는 방식이야.
하지만, 그동안 학습한 문장을 단순히 "찾아"서 출력하는 게 아니라, 학습된 확률 모델을 기반으로 "새로운 문장을 생성"하는 방식이야! 🚀
📌 Transformer의 동작 흐름
1️⃣ 사용자가 입력 문장을 인코더에 넣음
2️⃣ 인코더가 입력 문장을 벡터로 변환 (Self-Attention 수행)
3️⃣ 디코더가 하나씩 단어를 생성 (처음에는 START 토큰 입력)
4️⃣ 생성된 단어를 다시 디코더에 넣고 다음 단어를 예측 (반복)
5️⃣ END 토큰이 나오면 문장 생성을 멈춤
🔥 즉, Transformer는 학습 데이터에서 가장 적절한 문장을 찾아 출력하는 게 아니라, "확률적으로 가장 적절한 단어들을 하나씩 생성"하는 방식! 🚀
💡 Transformer는 학습할 때 단어들의 관계를 확률 모델로 학습함!
즉, 이전에 본 문장을 그대로 출력하는 게 아니라, 확률적으로 가장 적절한 단어를 하나씩 생성하는 것!
이 문장을 학습 데이터에서 본 적이 있을 수도 있지만,
Transformer는 단순히 "I love you"라는 문장이 등장했던 기존 문장을 찾아서 복사(copy)하는 게 아님!
➡ "I love you"라는 입력이 주어졌을 때, 확률적으로 가장 적절한 단어를 생성하는 것!
즉, 학습할 때 "love" 다음에 "you"가 나올 확률이 높다는 걸 배운 것처럼,
추론할 때 "나는" 다음에는 "너를"이 나올 확률이 높다고 판단하여 확률적으로 가장 적절한 단어를 생성하는 것!
💡 즉, Transformer는 학습한 문장을 "찾는 것"이 아니라, 학습된 확률 모델을 기반으로 "새로운 문장을 생성"하는 것! 🚀
🔥 Transformer가 단어를 하나씩 생성할 때, 각 단어가 올 확률을 계산하고 가장 확률이 높은 단어를 선택!
➡ 즉, 가장 확률이 높은 단어를 하나씩 예측하면서 문장을 생성하는 것!
input_sentence = "I love you"
1️⃣ "I love you"를 Word Embedding과 Positional Encoding을 거쳐 벡터로 변환
2️⃣ Self-Attention을 통해 단어 간 관계를 학습
3️⃣ 최종적으로 인코더는 입력 문장의 의미를 담은 벡터를 생성하여 디코더에 전달
1️⃣ 첫 번째 입력으로 START를 디코더에 넣음
2️⃣ 디코더가 START 다음 단어를 예측 → "나는"을 생성
3️⃣ "나는"을 다시 디코더에 입력하여 다음 단어 예측 → "너를"을 생성
4️⃣ "나는 너를"을 입력하여 다음 단어 예측 → "사랑해"를 생성
5️⃣ END 토큰이 나오면 종료
✅ Transformer가 START 토큰에서 어떻게 첫 번째 단어(예: "나는")를 뽑아내는지?
💡 디코더는 처음에는 START 토큰 하나만 입력으로 받는데, 어떻게 "나는"을 뽑아낼까?
➡ "나는"을 뽑아내는 과정도 확률 기반으로 이루어짐!
즉, 디코더는 학습 과정에서 배운 확률 분포를 바탕으로 첫 번째 단어를 생성하는 것! 🚀
🔥 디코더는 단순히 START 라는 단어를 기억해서 "나는"을 내뱉는 게 아니라, 확률적으로 가장 적절한 단어를 선택하는 방식으로 동작!
1️⃣ 디코더는 첫 입력으로 START 토큰을 받음
2️⃣ 디코더 내부에서 Self-Attention과 Encoder-Decoder Attention을 수행
3️⃣ 디코더는 Softmax를 사용하여 첫 번째 단어의 확률 분포를 계산
디코더는 START를 입력받아 다음 단어로 나올 확률이 높은 단어들을 계산함.
(예: "나는", "저는", "그는" 등)

📌 확률이 가장 높은 "나는"(0.75)이 선택됨!
➡ 즉, 디코더는 "나는"을 선택해서 첫 번째 단어로 출력하는 것! 🚀
1️⃣ "나는"이 첫 번째 단어로 선택되면,
2️⃣ 이제 디코더의 입력이 START → "나는"이 됨.
3️⃣ 디코더는 "나는"을 입력으로 받아 다음 단어 "너를"을 예측.
4️⃣ 이 과정을 반복해서 "나는 너를 사랑해"가 완성됨!
🔥 즉, Transformer는 학습된 확률 모델을 기반으로 가장 적절한 단어를 예측하면서 문장을 생성하는 방식! 🚀
1️⃣ 인코더에서 나온 hidden state를 Key(K), Value(V)로 사용
2️⃣ 디코더에서 Query(Q)를 만들고, 인코더의 Key와 Attention Score를 계산
3️⃣ 인코더에서 나온 정보를 활용하여 디코더가 다음 단어를 예측할 수 있도록 도와줌
🔥 Encoder-Decoder Attention는 디코더가 인코더의 정보를 활용하여 올바른 문장을 생성할 수 있도록 도와주는 역할을 해!
즉, 입력 문장(영어)과 출력 문장(한국어)의 관계를 연결해주는 과정이야! 🚀
🔥 Encoder-Decoder Attention은 입력 문장의 의미를 참고하여, 디코더가 올바른 문장을 생성하도록 도와주는 역할! 🚀
Encoder-Decoder Attention의 핵심 개념은 "입력 문장과 출력 문장을 연결하는 것"!
➡ 즉, 입력 문장("I love you")의 의미를 잘 반영하여 출력 문장("나는 너를 사랑해")을 만들 수 있도록 도와주는 역할!
| 단어 | 인코더의 최종 벡터 (예제 값) |
|---|---|
| "I" | [0.5, 0.2, 0.7] |
| "love" | [0.8, 0.3, 0.5] |
| "you" | [0.6, 0.4, 0.9] |
➡ 이 벡터들은 Encoder-Decoder Attention에서 Key(K)와 Value(V)로 사용됨!
| 단어 | 디코더의 Query(Q) 벡터 (예제 값) |
|---|---|
| "나는" | [0.4, 0.1, 0.6] |
➡ 디코더는 "나는"이라는 단어가 입력 문장의 어떤 부분과 관련이 있는지 판단해야 함.
➡ 이를 위해 Query(Q)와 Key(K)의 내적을 계산함.
Attention Score("나는", "I") = (0.4 * 0.5) + (0.1 * 0.2) + (0.6 * 0.7) = 0.64
Attention Score("나는", "love") = (0.4 * 0.8) + (0.1 * 0.3) + (0.6 * 0.5) = 0.65
Attention Score("나는", "you") = (0.4 * 0.6) + (0.1 * 0.4) + (0.6 * 0.9) = 0.82
📌 즉, "나는"이라는 단어는 "you"와 가장 연관이 높다고 계산됨!
➡ 하지만 번역을 위해선 "I"와 더 강한 연결을 만들어야 함.
➡ Transformer는 학습을 통해 이러한 관계를 조정함.
| 단어 | Attention Score | Softmax 확률 |
|---|---|---|
| "I" | 0.64 | 0.30 |
| "love" | 0.65 | 0.31 |
| "you" | 0.82 | 0.39 |
➡ 확률이 가장 높은 단어가 출력 문장에 가장 많이 반영됨.
➡ 이 확률 값을 이용하여 Value 벡터와 곱해서 최종 벡터를 생성!
Context Vector = (0.30 * Value("I")) + (0.31 * Value("love")) + (0.39 * Value("you"))
➡ 즉, 입력 문장의 정보를 반영한 최종 벡터가 만들어짐!
➡ 이 벡터를 기반으로 디코더는 "나는" 이후에 올 단어를 예측함. 🚀
1️⃣ 선형 변환(Linear Transformation) + 활성화 함수(ReLU) 적용
2️⃣ 다시 선형 변환하여 최종 출력
📌 Self-Attention과 Encoder-Decoder Attention은 "단어 간의 관계"를 학습하는 과정!
📌 하지만, 각 단어의 의미 자체를 더욱 풍부하게 만들기 위해 추가적인 비선형 변환이 필요!
📌 FFN Layer는 "각 단어의 의미를 더욱 정교하게 조정"하는 역할!
🔥 Self-Attention과 Encoder-Decoder Attention이 하는 일은 "단어 간의 관계"를 학습하는 것!
➡ 하지만, 각 단어 자체의 표현(의미)을 더욱 풍부하게 만들기 위해 추가적인 변환이 필요!
➡ 즉, 단어 간 관계를 학습하는 과정과, 개별 단어 벡터를 최적화하는 과정은 다름!
➡ 그래서 최종적으로 FFN을 통해 단어 벡터를 비선형 변환하여 의미를 더욱 풍부하게 만드는 것! 🚀
📌 만약 FFN Layer가 없으면?
❌ Self-Attention과 Encoder-Decoder Attention이 단어 간 관계를 학습하는 것은 가능하지만, 각 단어의 의미를 더 정교하게 조정할 수 없음.
❌ 단어 자체의 표현력을 충분히 강화하지 못하기 때문에, 더 깊고 풍부한 의미를 학습하는 데 한계가 생김!
❌ 모델이 복잡한 의미를 학습하지 못하고, 단순한 번역 패턴만 학습할 가능성이 높음.
🔥 즉, FFN이 없으면 단어 간 관계는 학습할 수 있지만, 단어 자체의 표현력이 부족할 수 있음! 🚀
✔ 디코더의 FFN은 번역된 한국어 문장에서 "각 단어의 의미를 더 깊게 학습"하는 과정!
✔ Self-Attention과 Encoder-Decoder Attention이 단어 간 관계를 학습하는 과정이라면, FFN은 개별 단어를 최적화하는 과정!
✔ 두 번의 선형 변환(차원 확장 → 차원 축소)과 ReLU를 통해 더 복잡한 의미를 학습할 수 있도록 도와줌!
✔ FFN이 없으면 단어 간 관계는 학습할 수 있지만, 개별 단어의 의미를 세밀하게 조정하지 못할 가능성이 높음.
🔥 즉, 디코더의 FFN은 번역된 문장의 단어를 최적의 표현으로 변환하여 더 자연스럽고 정확한 번역이 나오도록 도와주는 역할을 하는 거야! 🚀
✅ 최종적으로 각 단어가 적절한 형태로 변환되어 출력될 준비가 됨.
✅ 디코더에서 예측한 단어를 다음 예측 과정에 활용함.

💡 기존 RNN 구조에서는 단어를 순차적으로 입력받았기 때문에, 단어의 순서를 자연스럽게 학습할 수 있었음!
"I love NLP."
➡ RNN은 "I" → "love" → "NLP" 순서대로 입력받음.
➡ 따라서 "I"가 먼저 입력되고, "NLP"가 마지막에 입력된다는 순서를 자연스럽게 인식할 수 있음!
➡ 즉, RNN은 단어의 순서를 자연스럽게 고려할 수 있음!
💡 트랜스포머는 병렬 처리를 위해 단어를 한꺼번에 입력받기 때문에, 단어의 순서를 직접 알 수 없음.
["I", "love", "NLP"]
➡ 트랜스포머는 한 번에 모든 단어를 입력받기 때문에, 어떤 단어가 먼저 등장했는지 직접 알 수 없음!
➡ 따라서, 단어의 위치 정보를 따로 제공해야 함!
왼쪽 행렬: 각 단어의 임베딩 벡터(Word Embedding)
오른쪽 행렬: 포지셔널 인코딩(Positional Encoding)
중앙 화살표 (pos,i)
pos = 문장에서 단어의 위치 (예: "I"는 1번째 단어, "am"은 2번째 단어)
i = 벡터 차원의 특정 인덱스 (예: 512차원 벡터 중 3번째 차원)
->
그림에서는, 2번째 단어인 am 의 총 512개의 임베딩 벡터 중, 3번째 임베딩 벡터가 어떻게 변화할지 가리키는 것
그림에서 화살표가 의미하는 것
📌 화살표가 가리키는 위치는 단순히 "am" 전체를 의미하는 게 아니라, 특정 단어("am")의 특정 차원(예: 3번째 차원) 값이 어떻게 변하는지를 나타내는 것!
➡ 즉, 포지셔널 인코딩을 추가하면 단어의 순서 정보가 반영됨!
1️⃣ 각 단어는 벡터(예: 512차원)로 표현됨
| 단어 | 벡터 값 (예제) |
|---|---|
| "I" | [0.2, 0.3, ..., 0.5] |
| "am" | [0.4, 0.7, ..., 0.2] |
| "student" | [0.1, 0.8, ..., 0.3] |
2️⃣ 포지셔널 인코딩도 같은 차원의 벡터(512차원)를 가짐
| 단어 | 위치 정보 벡터 (예제) |
|---|---|
| "I" | [0.9, 0.1, ..., 0.3] |
| "am" | [0.5, 0.6, ..., 0.4] |
3️⃣ 각 단어의 벡터에 포지셔널 인코딩을 더함
최종 입력 벡터 = (단어 의미 벡터) + (위치 벡터)
➡ 즉, 포지셔널 인코딩을 더해주면, 트랜스포머는 단어의 순서를 고려할 수 있게 됨! 🚀
즉, 해당 차원의 값이 단어 위치에 따라 어떻게 조정되는지를 나타냄!
트랜스포머에서는 사인(Sin)과 코사인(Cosine) 함수를 이용해서 포지셔널 인코딩을 생성함.

📌 pos (위치) → 문장에서 단어가 몇 번째 위치인지
📌 i (차원 인덱스) → 임베딩 벡터의 특정 차원 인덱스
📌 d_model (임베딩 차원 수) → 트랜스포머의 모든 층의 출력 차원을 의미하는 하이퍼파라미터(논문에서는 512 값을 사용)
➡ 즉, 각 차원의 값이 단어의 위치에 따라 조정됨!
📌 포지셔널 인코딩 적용 방식
1️⃣ 각 단어를 임베딩 벡터로 변환
2️⃣ 각 단어의 위치(Positional Encoding) 값을 계산
3️⃣ 임베딩 벡터와 포지셔널 인코딩 값을 더해서 최종 입력 벡터를 만듦
📌 최종 입력 벡터 계산
입력 벡터=단어 임베딩+포지셔널 인코딩
🔥 즉, 포지셔널 인코딩을 더해주면, 트랜스포머는 단어의 순서를 고려할 수 있게 됨! 🚀

💡 인코더는 입력 문장을 벡터로 변환하는 역할!
1️⃣ Embedding & Positional Encoding (단어 임베딩 + 위치 정보 추가)
단어를 벡터로 변환하고(Positional Encoding 추가), 순서를 반영.
2️⃣ Multi-Head Self-Attention (멀티 헤드 자기 어텐션)
문장의 모든 단어가 서로를 참고하여 의미를 학습.
3️⃣ Add & Norm (잔차 연결 + 정규화)
네트워크의 안정성을 높이기 위해 정규화(Normalization) 적용.
4️⃣ Feed Forward Neural Network (FFN, 피드포워드 네트워크)
단어 벡터를 더 깊이 학습하기 위한 비선형 변환 수행.
➡ 즉, 인코더는 입력 문장의 의미를 벡터로 압축하여 디코더로 전달하는 역할을 함! 🚀
💡 디코더는 인코더에서 전달받은 정보를 기반으로 새로운 문장을 생성하는 역할!
1️⃣ Embedding & Positional Encoding (단어 임베딩 + 위치 정보 추가)
입력된 문장을 벡터로 변환하고, 위치 정보를 추가.
2️⃣ Masked Multi-Head Self-Attention (마스킹된 자기 어텐션)
미래 단어를 보지 못하도록 마스킹을 적용하여 문장을 순차적으로 생성.
3️⃣ Encoder-Decoder Attention (인코더-디코더 어텐션)
인코더의 정보를 참고하여 가장 적절한 단어를 선택.
4️⃣ Feed Forward Neural Network (FFN, 피드포워드 네트워크)
각 단어 벡터를 더 정교하게 다듬어서 최종적인 의미를 학습.
5️⃣ Softmax & Dense (출력 생성)
최종적으로 확률 분포를 계산하여 단어를 하나씩 생성.
➡ 즉, 디코더는 인코더의 정보를 활용하여 하나씩 단어를 생성하는 역할을 함! 🚀
📌 Encoder Self-Attention: 인코더를 구성하며 입력으로 들어간 문장 내 단어들이 서로 유사도를 구함.
📌 Decoder Self-Attention: 디코더를 구성하며 단어를 1개씩 생성하는 과정에서 앞 단어들과의 유사도를 구함.
➡ 즉, 디코더는 앞에서 나온 단어들이 서로 어떻게 관련되는지를 학습해야 함! 🚀
Self-Attention을 적용하되, 미래 단어를 보지 못하도록 마스킹을 적용한 것!
즉, 현재 단어까지만 참고하여 다음 단어를 예측하도록 제한함.
📌 디코더가 앞 단어들과 유사도를 구하는 이유는?

따라서, 디코더는 앞에서 생성된 단어들과의 유사도를 계산하여 가장 적절한 다음 단어를 선택하는 방식으로 동작함!
🔥 즉, 디코더는 단어를 하나씩 생성하면서, 앞 단어들과의 관계를 학습하여 다음 단어를 예측하는 것! 🚀

📌 "그 동물은 길을 건너지 않았다. 왜냐하면 그것은 너무 피곤했기 때문이다."
📌 유사도를 구하는 식

📌 Q (쿼리), K (키), V (값), X (입력 벡터 시퀀스)

📌 입력 벡터 시퀀스 예제

📌 쿼리(Query) 계산
좌변이 입력벡터 시퀀스이고 우변이 W_Q에 대응

📌 키(Key) 계산
좌변이 입력벡터 시퀀스이고 우변이 W_K에 대응

📌 밸류(Value) 계산
좌변이 입력벡터 시퀀스이고 우변이 W_V에 대응

📌 W_Q, W_K, W_V는 학습 과정에서 업데이트됨

📌 원래 Key 벡터는 세로 행렬(컬럼 벡터)이지만, 전치(transpose) 연산을 적용하여 가로 행렬(로우 벡터)로 변환
📌 Query(Q) × Key(K_t) 연산 (행렬 곱)
📌 결과 행렬의 의미
Self-Attention Score 행렬(오른쪽, 초록색)은 Query와 Key의 내적으로 계산되며, 단어 간의 유사도를 나타냅니다.
🔥 즉, 이 연산을 통해 트랜스포머는 문장에서 어떤 단어들이 서로 더 관련 있는지를 학습할 수 있습니다! 🚀

▪d_k 값은 d_model/num_heads라는 식에 따라 구하며 여기에 루트를 씌운 값으로 계산합니다.
트랜스포머의 멀티헤드 어텐션(Multi-Head Attention)에서는 하나의 큰 벡터(예: 512차원)를 여러 개의 작은 벡터(예: 8개로 나눠서 각 64차원)로 분할하여 어텐션을 수행합니다.
🔹 각 헤드의 차원 크기 = d_k
➡ 즉, 하나의 어텐션 헤드에서 처리하는 벡터 차원이 d_k로 설정됩니다.
로 나누는가?✅ 이유:
1. 값이 너무 커지거나 작아지는 문제 방지
2. Softmax의 출력이 안정적으로 나오도록 하기 위함 🚀
✅ 추가 개념:
💡 Softmax를 사용하는 이유:
➡ 유사도를 0과 1 사이 값으로 Normalize 하기 위함
📌 위와 같은 방식으로 Q와 K의 유사도를 구했기 때문에 Scaled Dot Product Attention이라 불립니다.
📌 특정 값을 분모로 나누지 않은 어텐션은 Dot Product Attention이라고 합니다.

🔥 즉, Scaled Dot Product Attention은 기존 Dot Product Attention의 문제점을 보완하여 Softmax 출력을 더 안정적으로 만드는 개선된 방식입니다! 🚀
Self-Attention Layer에 "Multi-Head Attention" 메커니즘을 추가하여 Attention Layer의 성능을 향상시킵니다.
기존 Self-Attention을 확장하여, 여러 개의 시각에서 문장을 해석할 수 있도록 만든 기법입니다!
➡ 하나의 어텐션이 아닌, 여러 개의 어텐션을 병렬로 수행하여 더 풍부한 정보를 학습하는 방식입니다. 🚀
기본적인 Self-Attention은 문장 내 단어들 간의 관계를 학습하지만, 한 번의 어텐션으로는 모든 관계를 고려하기 어렵습니다.
📌 그리스 로마 신화에 등장하는 괴물 히드라나 케로베로스는 머리가 여러 개라 상대방을 여러 시점에서 볼 수 있습니다. 멀티 헤드 어텐션도 어텐션을 병렬로 수행해 다양한 시각으로 정보를 수집합니다.
예를 들어,
"그 동물은 길을 건너지 않았다. 왜냐하면 그것은 너무 피곤하였기 때문이다."
➡ 여기서 "it"이 "the animal"을 가리키는지, "the road"를 가리키는지 한 번의 Self-Attention만으로 판단하기 어렵습니다.
🔥 그래서 여러 개의 어텐션(멀티 헤드 어텐션)을 병렬로 수행하여, 문맥을 다양한 시각에서 해석합니다! 🚀
📌 멀티 헤드 어텐션의 핵심
멀티 헤드 어텐션은 하나의 큰 어텐션을 수행하는 대신, 여러 개의 작은 어텐션을 독립적으로 수행하고 이를 결합하는 방식입니다.
1️⃣ 입력 벡터를 d_model 차원의 벡터로 임베딩
2️⃣ d_model을 num_heads 개의 작은 차원으로 나눔
3️⃣ 각 부분 벡터에 대해 독립적으로 Self-Attention 수행
4️⃣ 각 어텐션 결과를 결합하여 최종 벡터 생성
만약 Self-Attention을 한 번만 수행한다면, 모든 단어들 간의 관계를 단 하나의 시각에서만 학습해야 합니다.
즉, "it"이 "animal"과 관련이 있는지, "road"와 관련이 있는지 구분하는 것이 어려울 수 있습니다.
➡ 단 하나의 시각에서 문장을 해석해야 하므로 문맥 이해가 부족할 수 있습니다.
💡 멀티 헤드 어텐션을 사용하면, 여러 개의 다른 어텐션이 서로 다른 관계를 학습할 수 있습니다!
| 어텐션 헤드 | "it"과 강하게 연결된 단어 |
|---|---|
| 헤드 1 | "animal" (명시적 참조) |
| 헤드 2 | "tired" (의미적 연관) |
| 헤드 3 | "road" (다른 가능성 탐색) |
🔥 즉, 하나의 어텐션이 하나의 해석만 하는 것이 아니라, 여러 개의 어텐션이 서로 다른 시각에서 문장을 분석할 수 있도록 합니다! 🚀
1️⃣ 입력 벡터(Embedding)를 여러 개의 작은 벡터로 분할
2️⃣ 각 헤드에서 독립적인 Query(Q), Key(K), Value(V) 행렬을 생성
3️⃣ 각 헤드에서 개별적으로 Self-Attention 수행
4️⃣ 각 어텐션 결과를 결합 (Concat)하여 최종 출력 벡터 생성
📌 병렬 어텐션을 모두 수행하였다면 모든 어텐션 헤드를 연결(Concatenate) 합니다.


✅ 멀티 헤드 어텐션에서 최종 출력을 어떻게 선택하는가?
💡 각 헤드에서 병렬로 어텐션을 수행한 후, 마지막에 합쳐진 차원에서 가장 확률이 높은 것을 선택하는 방식인가?
💡 최종 선택은 단순히 "가장 확률이 높은 헤드"를 선택하는 방식이 아니라, "모든 헤드의 정보를 결합"하는 방식! 🚀
📌 최종 출력 과정
1️⃣ 각 헤드에서 독립적으로 Self-Attention 수행 → Query(Q), Key(K), Value(V) 생성
2️⃣ 각 헤드에서 Self-Attention 연산 수행하여 결과 벡터 생성
3️⃣ 각 헤드에서 나온 결과를 합쳐(Concatenate) 큰 벡터로 변환
4️⃣ 최종적으로 하나의 벡터로 변환하기 위해 추가적인 가중치 행렬을 곱함

🔥 즉, 각 헤드에서 얻은 정보들을 모두 결합한 후 새로운 가중치를 학습하여 최종 출력을 생성합니다! 🚀
📌 최종 출력 벡터는 무엇을 의미하는가?
➡ 최종 벡터는 단순한 해석이 아니라 문맥적 정보를 풍부하게 포함한 벡터입니다.
🔥 즉, 멀티 헤드 어텐션은 여러 개의 시각에서 정보를 해석하고 이를 종합하여 최적의 문맥 정보를 제공하는 역할을 합니다! 🚀
각 헤드는 서로 다른 시각에서 정보를 학습하기 때문에, 모든 헤드의 정보를 결합하면 더 풍부한 문맥 정보를 학습할 수 있습니다.
🔥 즉, "가장 높은 확률을 선택하는 방식"이 아니라, "모든 헤드의 정보를 결합한 후 변환하는 방식"입니다! 🚀
🔥 최종 벡터는 단순한 정보만 포함하는 것이 아니라, 여러 개의 어텐션 헤드가 학습한 정보를 반영한 최적의 표현 벡터입니다! 🚀
The animal did not cross the road because it was too tired.
(그 동물은 길을 건너지 않았다. 왜냐하면 그것은 너무 피곤했기 때문이다.)
➡ 여기서 "it"이 "animal"을 뜻하는지, "road"를 뜻하는지 헷갈릴 수 있습니다.
| 어텐션 헤드 | "it"과 강하게 연결된 단어 |
|---|---|
| 헤드 1 | "animal" (명시적 참조) |
| 헤드 2 | "tired" (의미적 연관) |
| 헤드 3 | "road" (다른 가능성 탐색) |
🔥 즉, 멀티 헤드 어텐션은 "it"의 다양한 해석을 제공하고, 최종적으로 모델이 문맥을 이해할 수 있도록 정보를 풍부하게 전달하는 역할을 합니다! 🚀
🔥 즉, 최종 출력 벡터는 "이중에서 상황에 따라 알맞게 판단하세요"라는 느낌이 맞습니다! 🚀
➡ 모델이 다음 레이어에서 더 깊이 있는 해석을 할 수 있도록 여러 시각에서 분석한 정보를 제공하는 것입니다!
특정 값들을 가려서 실제 연산에 방해가 되지 않도록 하는 기법으로, 트랜스포머에서는 패딩 마스킹(Padding Masking)과 룩 어헤드 마스킹(Look-ahead Masking, 다음 단어 가리기)을 사용합니다.
입력 문장에 padding 이 있을 경우 어텐션에서 제외하기 위한 연산
padding 은 실질적인 의미를 가진 단어가 아니기 때문에 토큰이 존재한다면 이에 대해서는 유사도를 구하지 않도록 마스킹(Masking) 해줌
💡 패딩 마스킹은 의미 없는 패딩(Padding) 토큰이 어텐션 연산에 영향을 주지 않도록 제외하는 과정입니다.
➡ 즉, 트랜스포머가 의미 없는 토큰을 고려하지 않고 실제 단어만을 학습하도록 하기 위한 기술입니다! 🚀
💡 문장의 길이가 다를 때, 신경망에서 연산을 수행하기 위해 모든 문장을 같은 길이로 맞춰야 합니다.
➡ 이때 짧은 문장에는 의미 없는 토큰(패딩, [PAD])을 추가하여 길이를 맞춥니다.
| 원본 문장 | 패딩 적용 후 |
|---|---|
| "I love NLP" | "I love NLP [PAD][PAD]" |
| "Transformers are amazing" | "Transformers are amazing" |
➡ 이제 두 문장의 길이가 동일해졌지만, [PAD]는 의미 없는 단어이므로 학습할 필요가 없습니다.
Self-Attention 연산에서는 모든 토큰을 서로 연관 지으려 하기 때문에, [PAD]까지 학습하려고 합니다. 그러면 의미 없는 [PAD] 토큰까지 고려하게 되어 모델의 성능이 저하될 수 있습니다.
➡ 따라서 패딩 마스킹을 적용하여 [PAD] 토큰을 연산에서 제외합니다! 🚀
📌 패딩 마스킹은 [PAD] 토큰이 Attention Score에 영향을 미치지 않도록 제거하는 방식입니다.
➡ 즉, 패딩 토큰을 어텐션 연산에서 제외하기 위해 Attention Score를 0 또는 매우 작은 값(음수 무한대)으로 만들어서 무시하는 것!
1️⃣ Self-Attention 수행 전, 마스킹 적용
[PAD]가 있는 위치를 찾아서 마스킹 벡터를 생성합니다.[1, 1, 1, 0, 0] (1은 유효한 단어, 0은 [PAD] 위치)2️⃣ 어텐션 연산에서 [PAD] 부분을 제외
[PAD]가 있는 부분을 -∞(음의 무한대)로 설정합니다.0이 되어, 해당 위치는 학습되지 않습니다.📌 패딩 마스킹 적용 전후 비교

🔥 즉, 패딩 마스킹을 적용하면 [PAD] 토큰이 어텐션 연산에서 제외되어 모델이 불필요한 연산을 수행하지 않도록 합니다! 🚀
💡 룩 어헤드 마스킹(Look-ahead Masking)은 트랜스포머 디코더에서 "미래 단어를 보지 못하도록" 제한하는 마스킹 기법입니다!
➡ 즉, 트랜스포머는 한꺼번에 문장을 입력받기 때문에, 훈련 시 미래 단어를 미리 보는 문제를 방지하기 위해 마스킹이 필요합니다! 🚀
💡 기존 RNN 기반 모델과 트랜스포머의 입력 방식이 다르기 때문!
🔥 즉, RNN처럼 순차적인 구조가 아닌 트랜스포머에서는, 디코더가 미래 단어를 보지 못하도록 "룩 어헤드 마스킹"을 적용해야 합니다! 🚀
📌 룩 어헤드 마스킹을 적용하면, 트랜스포머 디코더가 아직 예측하지 않은 미래 단어를 참조하지 못하도록 제한할 수 있습니다.
1️⃣ 문장을 행렬(Matrix) 형태로 입력받음
2️⃣ 현재까지의 단어까지만 사용하고, 이후 단어는 마스킹 처리 (-∞ 값 할당)
3️⃣ Softmax를 적용하면 마스킹된 단어는 확률이 0이 되어, 모델이 참고할 수 없음
📌 룩 어헤드 마스킹 적용 전

➡ 이 상태에서는 모든 단어를 참고할 수 있음 → 미래 단어를 미리 볼 수 있음!
📌 룩 어헤드 마스킹 적용 후

➡ 이제, 디코더는 아직 생성되지 않은 단어(미래 단어)를 참조하지 못함!
➡ Softmax를 적용하면 -∞ 값은 0이 되어 완전히 무시됨.
🔥 즉, 룩 어헤드 마스킹을 사용하면, 트랜스포머 디코더가 훈련 중에 미래 단어를 미리 참조하지 못하도록 만들 수 있습니다! 🚀
RNN은 순차적으로 단어를 입력받고, 이전 단어를 기반으로 다음 단어를 예측하는 방식입니다.
| Step | 현재까지의 입력 | 출력 |
|---|---|---|
| 1️⃣ | what | is |
| 2️⃣ | what is | the |
| 3️⃣ | what is the | problem |

➡ RNN은 한 번에 하나의 단어씩 입력받으며, 자연스럽게 미래 단어를 볼 수 없습니다.
트랜스포머는 전체 문장을 한꺼번에 입력받아 병렬 연산을 수행합니다. 하지만, 이렇게 되면 미래 단어를 미리 참조하는 문제가 발생할 수 있습니다.
➡ 이를 방지하기 위해 룩 어헤드 마스킹을 적용합니다.

트랜스포머에서는 문장 속 단어들이 서로 얼마나 관련이 있는지를 계산하기 위해 Query, Key, Value를 사용합니다.
💡 이 개념은 정보 검색 시스템에서 "질문(Query)"과 "데이터베이스(Key-Value)" 관계와 비슷합니다.
📌 예제: "나는 행복을 찾고 있다." 문장에서 각 단어가 서로 얼마나 연관이 있는지 계산한다고 가정하자.
Query(Q)는 특정 단어가 다른 단어들과 얼마나 관련이 있는지 질문하는 벡터입니다.
예를 들어, Query가 "나는"이라면:
"나는"이 문장 속에서 "행복을", "찾고", "있다"와 얼마나 관련이 있는지 알고 싶어!
💡 즉, Query는 "이 단어가 다른 단어들과 얼마나 연관이 있는지 물어보는 벡터"야.
Key(K)는 각 단어의 특성을 담고 있는 벡터입니다.
Query가 특정 단어를 찾을 때, Key를 이용해서 비교함.
예를 들어:
Query가 "나는"이라면,
Key는 "행복을", "찾고", "있다" 등의 단어들을 포함하는 행렬이야.
"나는"과 "행복을"의 관계가 얼마나 가까운지 판단하기 위해 Key를 사용해.
💡 즉, Key는 Query가 찾고자 하는 단어들을 평가할 수 있도록 하는 기준이 되는 벡터야.
Value(V)는 최종적으로 선택된 단어의 문맥 정보를 담고 있는 벡터.
Query와 Key를 비교한 후, 가장 연관이 높은 Key를 선택하고, 그에 해당하는 Value를 가져와 최종 결과로 사용합니다.
예를 들어:
"나는"이라는 Query가 "행복을"과 가장 높은 연관성을 가진다면,
"행복을"이라는 Key에 대응하는 Value가 최종적으로 사용됨.
💡 즉, Value는 Query와 Key의 연관성을 계산한 후, 최종적으로 적용할 문맥 정보를 담고 있어.
📌 트랜스포머에서는 Self-Attention을 계산할 때 Query와 Key를 내적(dot product)하여 연관성(유사도)을 계산합니다.

➡ Query와 Key를 비교하여 유사도를 구하고, 그 유사도에 따라 Value를 가중합해서 최종 벡터를 결정하는 방식입니다.
💡 즉, Query와 Key를 비교하여 연관도가 높은 단어를 찾고, 그 단어의 Value 정보를 최종적으로 반영하는 방식이야! 🚀
📌 (1) Query (왼쪽, 입력 문장 열)
현재까지 생성된 단어들을 기준으로, 다음 단어 예측을 위한 질문을 던지는 벡터.
즉, "이 단어가 문장에서 어떤 단어들과 가장 연관이 있는지 알고 싶다!"
💡 Query의 역할:
"나는"이 등장했을 때, "행복을"과 "찾고"와 얼마나 관련이 있는지 알고 싶어!
📌 (2) Key (위쪽, 입력 문장 행)
입력 문장에서 등장한 단어들의 특성을 담고 있는 벡터.
Query와 비교하여 각 단어가 얼마나 관련이 있는지 계산하는 기준.
💡 Key의 역할:
Query("나는")가 Key("행복을")과 비교하여 얼마나 관련이 있는지를 판단하는 기준.
📌 (3) Value (가운데, 입력 문장과 동일한 형태)
Query와 Key를 비교하여 가장 연관성이 높은 단어를 찾은 뒤, 그 단어의 문맥 정보를 반영.
💡 Value의 역할:
Query("나는")가 Key("행복을")과 높은 연관이 있다고 판단되면,
→ Value("행복을")을 최종 결과에 반영!
📌 (2) Query-Key Attention Score 행렬 (왼쪽)
📌 Query와 Key를 내적하여 유사도를 계산하는 과정
그림에서 보이는 왼쪽의 주황색/빨간색 행렬이 바로 Query와 Key를 내적한 "Attention Score 행렬"이야.
각 단어가 다른 단어와 얼마나 관련이 있는지 점수를 계산한 후, Softmax를 적용해서 확률 값으로 변환함.
그런데 여기서 룩 어헤드 마스킹을 적용하여, 미래 단어를 가려버려야 함!
룩 어헤드 마스킹은 "현재까지 예측한 단어까지만 참고하도록, 미래 단어를 Softmax에서 제외하는 기법"입니다.
📌 룩 어헤드 마스킹이 적용된 Attention Score 행렬의 모습 (왼쪽 행렬)
빨간색 부분 = 마스킹된 부분 (Softmax 확률이 0이 되어 무시됨)
연한색 부분 = 미래 단어를 볼 수 없는 곳, 현재 단계의 단어 (음수 무한대 값을 넣어 Softmax 적용 후 0이 됨)
분홍색 부분 = 현재까지의 단어들 간의 관계를 학습하는 부분
📌 룩 어헤드 마스킹이 적용된 Attention Score 행렬

📌 룩 어헤드 마스킹의 의미
첫 번째 단어 (s)는 아무 문제 없이 모든 단어와 연관됨.
두 번째 단어 (나는)는 자기 자신까지만 보이고, 이후 단어들은 가려짐.
세 번째 단어 (행복을)는 "나는"과 "행복을"만 보고, "찾고", "있다" 같은 미래 단어는 못 봄.
네 번째 단어 (찾고)는 "나는", "행복을", "찾고"까지만 볼 수 있음.
다섯 번째 단어 (있다)는 "나는", "행복을", "찾고", "있다"까지만 볼 수 있음.
🔥 즉, 룩 어헤드 마스킹이 적용되어, 현재까지의 단어까지만 참고할 수 있도록 제한하는 구조야! 🚀
🔥 즉, 룩 어헤드 마스킹 덕분에 디코더는 훈련 과정에서 미래 단어를 미리 참조하지 않고, 자연스럽게 다음 단어를 예측하는 방식으로 학습할 수 있습니다! 🚀
마스킹된 Attention Score 행렬과 Value 행렬을 곱하여 최종적인 Self-Attended Decoder Output을 생성함.
이제 디코더는 현재까지의 단어까지만 참고하면서 다음 단어를 예측할 수 있음.
🔥 즉, 룩 어헤드 마스킹 덕분에 디코더는 훈련 과정에서 미래 단어를 미리 참조하지 않고, 자연스럽게 다음 단어를 예측하는 방식으로 학습할 수 있어! 🚀
트랜스포머의 인코더(Encoder) 내의 각 Sub-layer(층)는 Residual Connection(잔차 연결)을 사용하여 연결되며, 이후 Layer Normalization(층 정규화)을 적용하는 구조입니다.
➡ 즉, 정보 손실을 줄이고 학습을 안정적으로 만들기 위해 이 과정을 거치는 것입니다. 🚀
💡 Residual Connection(잔차 연결)은 입력값을 변형하지 않고 그대로 다음 레이어에 더하는 방식입니다.
➡ 즉, 원래 입력값을 유지하면서도 추가적인 변환을 적용할 수 있도록 합니다! 🚀
Output = LayerNorm(Input + Sub-layer(Input))
✅ Gradient Vanishing 문제 완화
🔥 즉, Residual Connection을 사용하면 입력 정보를 보존하면서도 새로운 정보를 추가할 수 있습니다! 🚀
💡 Layer Normalization(층 정규화)은 신경망의 각 층에서 출력을 정규화하여 안정적인 학습을 가능하게 하는 기법입니다.
➡ 즉, 모델이 더 빠르게 수렴하고, Gradient Explosion(기울기 폭발)이나 Overfitting(과적합)을 방지하는 역할을 합니다! 🚀

✅ 모델 학습 안정성 향상
✅ Gradient Vanishing & Gradient Explosion 방지
✅ Batch 크기와 무관하게 동작 (BN과의 차이점!)
🔥 즉, Layer Normalization을 적용하면 신경망의 출력을 안정적으로 유지할 수 있습니다! 🚀


배치 정규화(Batch Normalization, BN)는 "미니배치(batch) 단위로 정규화하는 방법"이다.
즉, 배치 내의 모든 샘플을 기준으로 평균(mean)과 표준편차(std)를 계산하고, 이를 사용해 정규화한다.
1️⃣ 배치(batch)에서 각 feature(특징)마다 평균(mean)과 표준편차(std)를 계산
2️⃣ 해당 평균과 표준편차를 사용하여 정규화 수행
3️⃣ 각 미니배치마다 다른 정규화 값이 적용됨
💡 즉, 배치 정규화는 같은 특성을 가지는 값들끼리 정규화하며, 배치 단위로 동작하는 기법!
배치 정규화(BN)는 배치 내(feature별) 평균과 표준편차를 계산하여 정규화하는 방식이다. 그러나 트랜스포머와 같은 모델에서는 BN을 사용하기 어렵거나 비효율적일 수 있다!
🔥 즉, 배치 정규화는 시퀀스 데이터(문장) 처리에는 적절하지 않으며, 트랜스포머 같은 모델에서는 사용하기 어려워! 🚀
층 정규화(Layer Normalization, LN)는 "각 샘플(데이터 포인트) 단위로 정규화하는 방법"이다.
즉, 각 데이터 포인트(샘플)의 모든 feature 값들을 기준으로 평균(mean)과 표준편차(std)를 계산하여 정규화한다.
1️⃣ 각 샘플(한 데이터 포인트)에서 평균(mean)과 표준편차(std)를 계산
2️⃣ 해당 평균과 표준편차를 사용하여 정규화 수행
3️⃣ 모든 데이터 포인트에서 동일한 방식으로 정규화됨 (배치와 무관함)
💡 즉, 층 정규화는 샘플 자체를 기준으로 정규화하며, 배치 크기에 영향을 받지 않는 기법!
층 정규화(LN)는 배치 크기에 영향을 받지 않고, 문장을 구성하는 각 단어의 표현(Embedding)을 정규화할 수 있다.
따라서 트랜스포머와 같은 자연어 처리(NLP) 모델에서 더 적합함.
🔥 즉, 층 정규화는 배치 크기에 영향을 받지 않으면서, 트랜스포머가 문장 내 단어를 처리하는 방식과 더 잘 맞기 때문에 사용되는 거야! 🚀

인코더(Encoder)는 입력 문장을 벡터로 변환하는 역할을 합니다.
트랜스포머의 인코더는 입력 문장의 모든 단어를 벡터로 변환하고, 단어 간의 관계를 학습하여 최종 벡터 시퀀스를 생성합니다.
마지막 인코더 블록에서 나온 벡터는 입력 문장의 의미를 압축한 표현(고유한 의미 벡터)이라고 볼 수 있습니다.
"I love NLP"
| 단어 | 벡터 변환 |
|---|---|
| I | → h1 |
| love | → h2 |
| NLP | → h3 |
디코더는 이 벡터 시퀀스를 참조하여 번역할 문장을 생성할 때 활용합니다.
🔥 즉, 인코더가 입력 문장의 의미를 벡터로 변환하고, 디코더는 이 정보를 기반으로 문장을 생성하는 것입니다! 🚀
디코더는 문장을 한꺼번에 생성하는 것이 아니라, 단어를 하나씩 예측하면서 문장을 만들어갑니다.
현재까지 생성된 단어들을 바탕으로 다음 단어를 예측해야 하므로, 이전 블록의 출력이 다음 블록의 입력으로 사용됩니다.
이는 RNN의 "시퀀스 기반 학습 방식"과 유사하지만, 트랜스포머는 병렬 연산을 지원하므로 훨씬 빠릅니다.
타깃 문장: "나는 NLP를 사랑해."
1️⃣ 디코더가 처음에는 시작 토큰(s)을 입력받음.
2️⃣ 이전 디코더 블록에서 예측된 단어를 다음 블록의 입력으로 사용하여 점점 더 문장을 확장해 나감.
🔥 즉, 디코더는 이전에 예측된 단어들을 입력으로 받아, 점진적으로 문장을 만들어 가는 방식입니다! 🚀
디코더는 "입력 문장의 의미" + "현재까지 생성된 문장"을 조합하여 다음 단어를 예측해야 합니다.
✔ ① 인코더에서 얻은 정보(입력 문장의 의미)를 참고하여 번역 방향을 설정
✔ ② 이전에 생성된 단어들을 사용하여 문장의 흐름을 유지하면서 다음 단어를 예측
1️⃣ 인코더가 "I love NLP"를 벡터로 변환하여 디코더에게 전달
2️⃣ 디코더는 시작 토큰 s을 입력받아 "나는"을 예측
3️⃣ 디코더는 "나는"을 입력받아 "NLP를"을 예측
4️⃣ 디코더는 "나는 NLP를"을 입력받아 "사랑해."을 예측
🔥 즉, 디코더는 "입력 문장의 의미"와 "현재까지의 예측 결과"를 함께 참고하여 문장을 만들어 가는 것입니다! 🚀
번역하려는 언어(예: 한국어 → 영어 번역 시 영어)의 단어 벡터 시퀀스를 디코더 셀프 어텐션을 통해 계산합니다.
예를 들어, "I went to the cafe there." 문장에서 ‘cafe’ 다음으로 올 단어가 ‘there’임을 맞추는 과정입니다.
| 단어 | 어텐션 값 |
|---|---|
| I | 0.01 |
| went | 0.01 |
| to | 0.02 |
| the | 0.03 |
| cafe | 0.05 |
| there | 0.80 |
소스 언어 문장(예: "어제 카페 갔었어 거기 사람 많더라")의 단어 벡터 시퀀스를 Key로 삼고, 타깃 언어 문장(예: "I went to the cafe yesterday. There...")의 단어 벡터 시퀀스를 Query로 삼아 셀프 어텐션 계산을 수행합니다.
💡 쿼리는 질문이고, 답을 찾기 위해 참조하는 것이 키(Key)라는 점을 기억하세요!
예를 들어, 쿼리(Query) 안의 'cafe'에 대응하여 Key 요소들은 셀프 어텐션을 통하여 확률값을 갖고 그중 가장 높은 확률을 갖는 '카페'를 맞추는 것입니다.

학습시 디코더에서 수행되는 셀프 어텐션에는 단어 벡터 시퀀스에 마스킹이 적용됩니다.
✅ 목적:
미래 정보를 참고하는 것을 방지하여, 정답을 포함한 미래 정보를 셀프 어텐션 계산에서 제외하도록 하기 위함입니다.
✅ 방법:
마스킹이 적용된 단어 정보는 확률값이 0이 되게 하여 해당 단어 정보가 무시되도록 합니다.
Decoder Self-Attention과 Encoder-Decoder Attention 모두 스케일드 닷 프로덕트 어텐션(Scaled Dot-Product Attention)을 멀티-헤드 어텐션(Multi-Head Attention)으로 병렬 수행합니다.
🚀 이를 통해 병렬 연산이 가능해지고, 더욱 강력한 문맥 이해가 가능합니다!
1️⃣ 각 스텝마다 출력된 단어가 다음 스텝의 디코더 입력이 됨
2️⃣ 여러 디코더 레이어를 통과하며 문장이 생성됨
3️⃣ 출력할 문장이 완성될 때까지 반복
🔥 즉, 디코더는 "입력 문장의 의미" + "현재까지의 예측 단어"를 바탕으로 번역을 수행하는 것입니다! 🚀
➡ 이를 위해 Linear Layer(선형 변환) 와 Softmax Layer(확률 변환) 를 사용해서 단어를 예측하는 거야! 🚀
📌 Linear Layer: fully-connected 신경망으로 디코더의 출력 벡터를 훨씬 더 큰 사이즈인 logits 벡터로 투영시킴. 예를 들어 10,000개의 영어 단어를 학습하였다고 가정하면 logits vector의 크기는 10,000이 됨. 벡터의 각 요소는 각 단어에 대한 점수
📌 softmax layer: logits vector의 각 셀들의 점수를 확률로 변환해주는 역할. 각 셀값들을 모두 더하면 1이 되고 가장 높은 확률 값을 가지는 셀의 단어가 최종 출력됨.
➡ 따라서 이 벡터를 실제 단어로 변환해야 함!
"I love NLP"[0.3, 1.5, -0.2, 0.8, ...] (숫자 벡터)➡ Fully-connected 신경망(FC layer, 선형 변환)을 사용하여, 벡터를 logits 벡터 로 변환함.
logits=W×output_vector+b

🔥 즉, 디코더의 출력 벡터(512차원)를 곱해서 10,000차원의 logits 벡터로 변환하는 과정이야! 🚀
🔥 즉, Linear Layer는 "디코더의 벡터"를 "단어별 점수 벡터(logits)"로 변환하는 역할을 함! 🚀
➡ 따라서 Softmax를 적용해서 "확률 분포"로 변환해야 함.

📌 예제: "나는 NLP를" 다음 단어를 예측하는 과정
디코더의 최종 출력 벡터가 아래와 같은 logits 벡터로 변환된다고 가정해 보자:
logits = [ -0.3, 2.5, 0.8, 1.7, -1.1, ... ] (총 10,000개)

🔥 즉, logits 벡터의 값은 "각 단어가 현재 문장에서 등장할 가능성(적절성)"을 나타내는 점수야! 🚀
[0.2, 2.5, -1.3, 1.7, 0.9, ...] (10,000개)
[0.01, 0.60, 0.02, 0.20, 0.05, ...] (10,000개)
✅ 확률이 가장 높은 단어 선택!
➡ 2번째 값(0.60)이 가장 크므로, 해당 단어가 최종 출력됨!
🔥 즉, Softmax는 "logits 벡터"를 "확률 분포"로 변환하고, 가장 확률이 높은 단어를 선택하는 역할을 함! 🚀
