Post

Stanford CME295: Lecture 0 - Transformer 개요

Stanford CME295: Lecture 0 - Transformer 개요

강의 출처: Stanford CME295 - Transformers & LLMs (Autumn 2025)


1. NLP (자연어 처리) 기초

1.1 NLP의 주요 태스크

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
┌─────────────────────────────────────────────────────────────────┐
│ NLP의 3가지 주요 태스크                                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐    │
│ │ Classification  │ │Multi-Classification│ │ Generation    │    │
│ │ (분류)          │ │ (다중 분류)       │ │ (생성)         │    │
│ ├─────────────────┤ ├─────────────────┤ ├─────────────────┤    │
│ │ • 감정 분석     │ │ • 품사 태깅      │ │ • 텍스트 생성   │    │
│ │ • 스팸 탐지     │ │ • 개체명 인식    │ │ • 기계 번역     │    │
│ │ • 의도 파악     │ │   (NER)         │ │ • 요약          │    │
│ │                 │ │ • 주제 분류      │ │ • 질의응답      │    │
│ └─────────────────┘ └─────────────────┘ └─────────────────┘    │
│                                                                 │
│ 입력 → 단일 레이블   입력 → 시퀀스별 레이블   입력 → 텍스트 시퀀스│
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

1.2 NLP 파이프라인

1
텍스트 → 토큰화 → 임베딩 → 모델 처리 → 출력

2. 토큰화 (Tokenization)

텍스트를 모델이 처리할 수 있는 단위로 분할하는 과정

2.1 토큰화 방법 비교

방법설명장점단점
Word-level단어 단위 분리직관적, 의미 보존OOV 문제, 큰 어휘집
Sub-word단어를 더 작은 단위로OOV 해결, 적정 어휘 크기학습 필요
Character-level문자 단위 분리OOV 없음, 작은 어휘집긴 시퀀스, 의미 손실

2.2 Sub-word 토큰화 알고리즘

1
2
3
4
5
6
7
8
9
# BPE (Byte Pair Encoding) 예시
원본: "lowest", "lower", "newer", "wider"
Step 1: 문자 단위 분리
l o w e s t, l o w e r, n e w e r, w i d e r
Step 2: 가장 빈번한  병합 ("e" + "r"  "er")
l o w e s t, l o w er, n e w er, w i d er
Step 3: 다음 빈번한  병합 ("l" + "o"  "lo")
lo w e s t, lo w er, n e w er, w i d er
... 반복하여 적정 어휘 크기에 도달

2.3 주요 토큰화 방식

모델토큰화 방식
GPT-2/3/4BPE (Byte Pair Encoding)
BERTWordPiece
T5, LLaMASentencePiece

3. 단어 표현 (Word Representation)

3.1 One-Hot Encoding

1
2
3
4
5
어휘집: [cat, dog, bird, fish]
"cat"  → [1, 0, 0, 0]
"dog"  → [0, 1, 0, 0]
"bird" → [0, 0, 1, 0]
"fish" → [0, 0, 0, 1]

문제점:

  • 단어 간 유사도 표현 불가 (모든 벡터가 직교)
  • 어휘 크기에 따라 차원이 폭발적 증가
  • 희소 벡터 (sparse vector)

3.2 Word2Vec (분산 표현)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
핵심 아이디어: "비슷한 맥락에 나타나는 단어는 비슷한 의미"

벡터 공간에서의 단어 관계:
  king ─────────────────→ queen
    ↓                       ↓
    │ - man + woman         │
    ↓                       ↓
  man ──────────────────→ woman

vec(king) - vec(man) + vec(woman) ≈ vec(queen)

특징:
  • 밀집 벡터 (dense vector): 보통 100-300 차원
  • 유사한 단어 → 유사한 벡터 (코사인 유사도 높음)
  • 의미적, 문법적 관계 포착

3.3 코사인 유사도

두 토큰 $t_1$, $t_2$의 유사도:

\[\text{similarity}(t_1, t_2) = \frac{t_1 \cdot t_2}{\|t_1\| \cdot \|t_2\|} = \cos(\theta)\]
  • 값 범위: [-1, 1]
  • 1에 가까울수록 유사
  • -1에 가까울수록 반대

4. RNN의 한계와 Transformer의 등장

4.1 RNN (Recurrent Neural Network)의 문제점

1
2
3
4
5
6
7
8
9
x₁ ──→ [h₁] ──→ x₂ ──→ [h₂] ──→ x₃ ──→ [h₃] ──→ ...
         │               │               │
         ↓               ↓               ↓
         y₁              y₂              y₃

문제점:
  1. 순차적 처리 → 병렬화 불가능
  2. Vanishing/Exploding Gradient
  3. 긴 문장에서 장거리 의존성 학습 어려움

4.2 장거리 의존성 문제

1
2
3
4
예시: "The cat, which was sitting on the mat, was black."
                                                   ↑
주어 "cat"과 동사 "was"의 거리가 멀다
RNN에서는 이 정보가 여러 스텝을 거치면서 희석됨

4.3 LSTM/GRU의 개선과 한계

  • LSTM: 게이트 메커니즘으로 장기 의존성 일부 해결
  • 한계: 여전히 순차적 처리 → 학습 시간 오래 걸림

5. Self-Attention 메커니즘

5.1 Self-Attention의 핵심 개념

1
2
3
4
5
6
문장: "The animal didn't cross the street because it was tired"

"it"이 무엇을 의미하는가?

Self-Attention: 각 토큰이 문장 내 모든 토큰과의 관계를 계산
→ "it"은 "animal"에 높은 attention 가중치를 가짐

5.2 Query, Key, Value (Q, K, V)

정보 검색(Information Retrieval) 시스템에서 영감을 받은 개념:

1
2
3
4
5
6
7
8
9
10
11
12
데이터베이스 비유:
  검색어(Query): "무엇을 찾고 싶은가?"
  키(Key):      "각 데이터의 인덱스/제목"
  값(Value):    "실제 데이터 내용"

Self-Attention에서:
  Query (Q): "현재 토큰이 어떤 정보를 원하는가?"
  Key (K):   "각 토큰이 어떤 정보를 가지고 있는가?"
  Value (V): "각 토큰의 실제 정보/특징"

Q와 K의 내적 → 유사도 → 어디에 attention할지 결정
그 가중치로 V를 조합 → 최종 출력

5.3 Scaled Dot-Product Attention

공식:

\[\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V\]

단계별 계산:

1
2
3
4
5
6
7
8
9
Step 1: Q × K^T 계산 (유사도 점수)
  → 각 쿼리와 모든 키 간의 내적
Step 2: √d_k로 스케일링
  → 내적 값이 너무 커지는 것을 방지
  → d_k가 클수록 내적 값의 분산이 커짐
Step 3: Softmax 적용
  → 확률 분포로 변환 (합이 1)
Step 4: V와 곱셈
  → 가중 평균으로 최종 출력 생성

5.4 스케일링이 필요한 이유

1
2
3
4
5
6
7
8
9
# d_k가 클 때의 문제
d_k = 64  # key dimension
# Q, K의 각 원소가 평균 0, 분산 1이라면
# Q·K의 분산 = d_k (내적의 분산)
# d_k가 커지면 내적 값도 커짐
# → softmax에서 큰 값은 1에 가깝게, 작은 값은 0에 가깝게
# → gradient가 매우 작아짐 (vanishing gradient)
# 해결: √d_k로 나눔
score = (Q @ K.T) / math.sqrt(d_k)  # 분산을 1로 정규화

스케일링이 필요한 이유 상세 (수식 포함)

$q$와 $k$의 각 성분이 독립적이고 평균 0, 분산 1인 확률변수라고 가정하면:

\[q \cdot k = \sum_{i=1}^{d_k} q_i \cdot k_i\]

각 $q_i \cdot k_i$의 기댓값과 분산:

\[E[q_i \cdot k_i] = E[q_i] \cdot E[k_i] = 0\] \[\text{Var}(q_i \cdot k_i) = E[q_i^2] \cdot E[k_i^2] = 1 \cdot 1 = 1\]

$d_k$개를 합산하면:

\[\text{Var}(q \cdot k) = d_k\]

따라서 dot product의 표준편차는 $\sqrt{d_k}$에 비례합니다. $d_k$가 크면 dot product 값이 매우 커져 softmax의 gradient가 소실됩니다.

\[\text{Var}\left(\frac{q \cdot k}{\sqrt{d_k}}\right) = \frac{d_k}{d_k} = 1\]

$\sqrt{d_k}$로 나누면 분산이 1로 정규화되어 안정적인 softmax 분포를 얻습니다.

분산의 기본 성질

독립 확률변수의 분산 성질:

\[\text{Var}(aX) = a^2 \text{Var}(X)\] \[\text{Var}(X + Y) = \text{Var}(X) + \text{Var}(Y) \quad \text{(X, Y 독립)}\] \[\text{Var}(XY) = E[X^2]E[Y^2] - (E[X])^2(E[Y])^2\]

$X, Y$가 평균 0, 분산 1이면:

\[\text{Var}(XY) = E[X^2] \cdot E[Y^2] = 1 \cdot 1 = 1\]

이를 $d_k$개 합산하면: $\text{Var}\left(\sum_{i=1}^{d_k} q_i k_i\right) = d_k$


6. Multi-Head Attention (MHA)

6.1 MHA의 필요성

단일 attention head의 한계:

  • 하나의 관점에서만 관계를 파악
  • 다양한 유형의 의존성을 동시에 포착하기 어려움

6.2 Multi-Head Attention 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
입력 X
  │
  ┌───────────────┼───────────────┐
  ↓               ↓               ↓
┌──────────┐ ┌──────────┐ ┌──────────┐
│  Head 1  │ │  Head 2  │ │  Head h  │
│ Q₁=X·W^Q₁│ │ Q₂=X·W^Q₂│ │ Qₕ=X·W^Qₕ│
│ K₁=X·W^K₁│ │ K₂=X·W^K₂│ │ Kₕ=X·W^Kₕ│
│ V₁=X·W^V₁│ │ V₂=X·W^V₂│ │ Vₕ=X·W^Vₕ│
│ Attention │ │ Attention │ │ Attention │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
      └───────────────┼───────────────┘
                      ↓
                   Concat
                      ↓
                 Linear (W^O)
                      ↓
                     출력

6.3 MHA 공식

\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, ..., \text{head}_h)W^O\] \[\text{where } \text{head}_i = \text{Attention}(QW_i^Q, KW_i^K, VW_i^V)\]

6.4 원논문의 설정

파라미터설명
h8attention head 수
$d_{model}$512모델 차원
$d_k = d_v$64head당 차원 (512/8)

계산 효율성: 각 head의 차원을 줄여서 총 계산량은 single-head와 유사


7. Transformer 아키텍처

7.1 전체 구조

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌─────────────────────────────────────────────────────────────────┐
│ Transformer 아키텍처                                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ENCODER                          DECODER                       │
│  ─────────                        ──────────────                │
│  ┌───────────────┐                ┌───────────────┐             │
│  │ Multi-Head    │                │ Masked        │             │
│  │ Self-Attention│           ┌───│ Self-Attention│             │
│  └───────┬───────┘           │    └───────┬───────┘             │
│          ↓                   │            ↓                     │
│  ┌───────────────┐           │    ┌───────────────┐             │
│  │ Add & Norm    │           │    │ Add & Norm    │             │
│  └───────┬───────┘           │    └───────┬───────┘             │
│          ↓                   │            ↓                     │
│  ┌───────────────┐           │    ┌───────────────┐             │
│  │ Feed Forward  │           │    │ Cross-        │             │
│  │ Network       │           │    │ Attention     │◀────────┤   │
│  └───────┬───────┘           │    └───────┬───────┘             │
│          ↓                   │            ↓                     │
│  ┌───────────────┐           │    ┌───────────────┐             │
│  │ Add & Norm    │           │    │ Feed Forward  │             │
│  └───────┬───────┘           │    └───────┬───────┘             │
│          │ ×N                │            │ ×N                  │
│          └────────────────────┘                                  │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

7.2 Encoder 구조

N = 6개의 동일한 레이어 스택

각 레이어 구성:

  1. Multi-Head Self-Attention
  2. Position-wise Feed-Forward Network

각 서브레이어 후:

  • Residual Connection
  • Layer Normalization
1
출력 = LayerNorm(x + Sublayer(x))

Encoder 단계별 동작 상세

Step 1: Input Embedding + Position Encoding

\[\text{Input}_i = \text{Embed}(x_i) + \text{PE}(i) \in \mathbb{R}^{d_{model}}\]

입력 시퀀스의 각 토큰을 $d_{model}$ 차원 벡터로 변환하고 위치 정보를 더합니다.

Step 2: Multi-Head Self-Attention

각 토큰이 다른 모든 토큰을 참조하여 문맥 정보를 수집합니다.

\[\text{Attn}(X) = \text{MultiHead}(X, X, X)\]

Q, K, V 모두 같은 입력 $X$에서 생성되므로 “Self”-Attention입니다.

Step 3: Add & Norm (첫 번째)

\[\text{Out}_1 = \text{LayerNorm}(X + \text{Attn}(X))\]

잔차 연결로 원래 입력 정보를 보존하면서 Attention 결과를 더합니다.

Step 4: Feed-Forward Network

\[\text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2\]

각 토큰 위치에 독립적으로 적용됩니다 (토큰 간 상호작용 없음).

Step 5: Add & Norm (두 번째)

\[\text{Out}_2 = \text{LayerNorm}(\text{Out}_1 + \text{FFN}(\text{Out}_1))\]

이 과정이 $N$번 반복되어 점점 더 풍부한 표현을 생성합니다.

7.3 Decoder 구조

N = 6개의 동일한 레이어 스택

각 레이어 구성:

  1. Masked Multi-Head Self-Attention (미래 토큰 마스킹)
  2. Multi-Head Cross-Attention (Encoder 출력에 attention)
  3. Position-wise Feed-Forward Network

7.4 Attention의 3가지 유형

1
2
3
4
5
6
7
8
9
10
11
12
13
1. Self-Attention (Encoder)
   Q, K, V = 모두 같은 소스 (이전 인코더 레이어 출력)
   모든 위치가 모든 위치에 attention 가능

2. Masked Self-Attention (Decoder)
   Q, K, V = 모두 같은 소스 (이전 디코더 레이어 출력)
   현재 위치는 이전 위치들에만 attention 가능
   → 미래 토큰 정보 유출 방지 (auto-regressive)

3. Cross-Attention (Encoder-Decoder)
   Q = 디코더 이전 레이어 출력
   K, V = 인코더 최종 출력
   디코더가 인코더의 모든 위치에 attention 가능

8. Position-wise Feed-Forward Network (FFN)

8.1 구조

\[\text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2 = \text{ReLU}(xW_1 + b_1)W_2 + b_2\]

또는 현대 LLM에서: SwiGLU, GeGLU, GELU 등 사용

8.2 차원 설정 (원논문)

파라미터
$d_{model}$ (입력/출력)512
$d_{ff}$ (hidden)2048

특징:

  • 위치별 독립적으로 적용 (동일 가중치)
  • 비선형성 제공
  • “채널 믹싱” 역할

FFN 적용 이유 상세

왜 Self-Attention 후에 FFN이 필요한가?

Self-Attention은 토큰 간의 관계를 학습하지만, 각 토큰의 표현을 개별적으로 변환하는 능력이 제한됩니다. FFN이 이를 보완합니다.

역할 분담:

구성요소역할
Self-Attention토큰 상호작용 (어떤 토큰이 중요한가?)
FFN토큰 변환 (수집한 정보를 어떻게 처리할 것인가?)

Expansion & Contraction:

\[x \in \mathbb{R}^{d_{model}} \xrightarrow{W_1} h \in \mathbb{R}^{d_{ff}} \xrightarrow{\text{ReLU}} h' \xrightarrow{W_2} y \in \mathbb{R}^{d_{model}}\]
  1. $W_1$: $d_{model} \rightarrow d_{ff}$ (확장, 보통 4배)
  2. ReLU: 비선형 활성화
  3. $W_2$: $d_{ff} \rightarrow d_{model}$ (축소)

확장하는 이유: 더 높은 차원에서 비선형 변환을 수행하면 더 복잡한 패턴을 학습할 수 있습니다. 이후 다시 축소하여 원래 차원으로 돌아옵니다.

Position-wise 적용: FFN은 각 토큰 위치에 동일한 가중치독립적으로 적용됩니다. 즉, 토큰 간 상호작용은 Attention에서만 일어납니다.

비유: Self-Attention이 “회의에서 정보 수집”이라면, FFN은 “수집한 정보를 개인적으로 정리하고 소화하는 단계”입니다.


9. Positional Encoding

Transformer는 순서 정보가 없으므로 위치 정보를 명시적으로 추가

9.1 Sinusoidal Positional Encoding (원논문)

\[PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)\] \[PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)\]
1
2
3
4
5
6
7
8
9
10
11
# PyTorch 구현
def sinusoidal_encoding(max_len, d_model):
    pe = torch.zeros(max_len, d_model)
    position = torch.arange(0, max_len).unsqueeze(1).float()
    div_term = torch.exp(
        torch.arange(0, d_model, 2).float() *
        -(math.log(10000.0) / d_model)
    )
    pe[:, 0::2] = torch.sin(position * div_term)  # 짝수 인덱스
    pe[:, 1::2] = torch.cos(position * div_term)  # 홀수 인덱스
    return pe

9.2 Sinusoidal PE의 장점

  1. 상대적 위치 표현: $PE(pos+k)$를 $PE(pos)$의 선형 함수로 표현 가능
  2. 길이 일반화: 학습 시 보지 못한 길이에도 적용 가능
  3. 학습 불필요: 미리 정의된 함수

9.3 현대 위치 인코딩 방식

방식설명사용 모델
Learned Absolute학습 가능한 위치 임베딩GPT-2, BERT
RoPE회전 위치 임베딩LLaMA, GPT-NeoX
ALiBiAttention에 위치 바이어스 추가MPT, BLOOM
T5 Relative Bias상대적 위치 바이어스T5

10. Layer Normalization & Residual Connections

10.1 Residual Connection (Skip Connection)

\[\text{output} = x + \text{Sublayer}(x)\]

효과:

  • Gradient 소실 문제 완화
  • 깊은 네트워크 학습 가능
  • 정보 흐름 개선

10.2 Layer Normalization

\[\text{LayerNorm}(x) = \gamma \cdot \frac{x - \mu}{\sigma + \epsilon} + \beta\]

여기서 $\mu = \text{mean}(x)$, $\sigma = \text{std}(x)$, $\gamma, \beta$는 학습 가능한 파라미터

10.3 Pre-Norm vs Post-Norm

1
2
3
4
5
6
7
Post-Norm (원논문):
  x → Sublayer → + → LayerNorm → 출력
       ↑___|

Pre-Norm (현대 LLM):
  x → LayerNorm → Sublayer → + → 출력
       ↑___|

Pre-Norm의 장점:

  • 학습 안정성 향상
  • 더 깊은 네트워크 학습 가능
  • 대부분의 현대 LLM에서 사용 (GPT-2+, LLaMA 등)

Residual Connection 적용 이유 상세

문제: 깊은 네트워크의 학습 어려움

네트워크가 깊어지면 gradient가 역전파될 때 점점 작아지거나 커져서 학습이 불안정해집니다.

Residual Connection의 해결:

\[y = F(x) + x\]

역전파 시:

\[\frac{\partial y}{\partial x} = \frac{\partial F(x)}{\partial x} + 1\]

항상 1이 더해지므로 gradient가 최소 1은 보장됩니다. 이는 “gradient highway”를 만들어 깊은 층까지 gradient가 잘 전달됩니다.

Identity Mapping 관점:

Sub-layer가 학습해야 할 것은 $F(x) = y - x$ (잔차, residual)입니다. “원래 입력에서 얼마나 변해야 하는가?”만 학습하면 되므로 최적화가 쉬워집니다.

LayerNorm 적용 이유 상세

왜 Normalization이 필요한가?

각 층을 거치면서 활성값의 분포가 변화(Internal Covariate Shift)하여 학습이 불안정해질 수 있습니다.

Layer Norm vs Batch Norm:

특성Batch NormLayer Norm
정규화 축배치 차원 (같은 feature, 다른 샘플)특성 차원 (같은 샘플, 다른 feature)
배치 크기 의존의존 (작은 배치에서 불안정)비의존
시퀀스 길이가변 길이 처리 어려움가변 길이 자연스럽게 처리
추론 시Running statistics 필요입력만으로 계산 가능

Layer Norm 계산:

각 토큰 벡터 $x \in \mathbb{R}^{d_{model}}$에 대해:

\[\mu = \frac{1}{d_{model}} \sum_{i=1}^{d_{model}} x_i, \quad \sigma = \sqrt{\frac{1}{d_{model}} \sum_{i=1}^{d_{model}} (x_i - \mu)^2}\] \[\text{LayerNorm}(x) = \gamma \odot \frac{x - \mu}{\sigma + \epsilon} + \beta\]

$\gamma, \beta$는 학습 가능한 파라미터로, 정규화 후 표현력을 복원합니다.

Transformer에서 Layer Norm을 쓰는 이유: NLP에서는 배치 내 시퀀스 길이가 다르고, 같은 위치의 feature가 배치 간 의미가 다를 수 있어 Batch Norm이 적합하지 않습니다.


11. Transformer 변형 아키텍처

11.1 Encoder-only (BERT류)

1
2
3
4
5
6
7
8
9
10
구조: Encoder 스택만 사용

특징:
  • 양방향 Self-Attention (모든 토큰 참조 가능)
  • [CLS] 토큰으로 문장 표현
  • [MASK] 토큰으로 MLM 학습

대표 모델: BERT, RoBERTa, ALBERT, ELECTRA

주요 태스크: 텍스트 분류, 토큰 분류 (NER), 질의응답 (추출형)

11.2 Decoder-only (GPT류)

1
2
3
4
5
6
7
8
9
10
구조: Decoder 스택만 사용 (Cross-Attention 제거)

특징:
  • Causal Self-Attention (이전 토큰만 참조)
  • Auto-regressive 생성
  • Next Token Prediction으로 학습

대표 모델: GPT 시리즈, LLaMA, Claude, Gemma, DeepSeek 등

※ 현재 대부분의 LLM이 Decoder-only 아키텍처 사용

11.3 Encoder-Decoder (T5류)

1
2
3
4
5
6
7
8
9
10
구조: 원본 Transformer 구조 유지

특징:
  • Encoder: 양방향 Self-Attention
  • Decoder: Causal Self-Attention + Cross-Attention
  • Seq2Seq 태스크에 적합

대표 모델: T5, BART, mT5, Flan-T5

주요 태스크: 기계 번역, 요약, 질의응답 (생성형)

12. Transformer End-to-End 예시

12.1 기계 번역 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
입력: "I love AI"
목표 출력: "나는 AI를 사랑한다"

Step 1: 토큰화
  입력: ["I", "love", "AI"]
  출력: ["<sos>", "나는", "AI를", "사랑한다", "<eos>"]

Step 2: 임베딩 + Positional Encoding
  각 토큰 → d_model 차원 벡터 + PE

Step 3: Encoder 처리
  ["I", "love", "AI"] → 6개 Encoder 레이어
  → contextual representations

Step 4: Decoder 처리 (auto-regressive)
  t=0: <sos> + Encoder출력 → "나는"
  t=1: <sos>, "나는" + Encoder출력 → "AI를"
  t=2: <sos>, "나는", "AI를" + Encoder출력 → "사랑한다"
  t=3: ... → <eos>

Step 5: 최종 출력
  "나는 AI를 사랑한다"

13. Transformer의 핵심 장점

13.1 RNN 대비 장점

측면RNNTransformer
병렬화불가능 (순차 처리)완전 병렬화 가능
장거리 의존성gradient 소실로 어려움직접 연결 (O(1) 경로)
학습 속도느림빠름 (GPU 활용)
메모리시퀀스 길이에 선형시퀀스 길이에 이차

13.2 Self-Attention의 계산 복잡도

복잡도 유형Self-AttentionRNN
시간 복잡도 (per layer)$O(n^2 \cdot d)$$O(n \cdot d^2)$
병렬화 가능 연산$O(1)$$O(n)$
최대 경로 길이$O(1)$$O(n)$
  • n: 시퀀스 길이
  • d: 표현 차원

14. 실습 코드: Self-Attention 구현

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
import torch
import torch.nn as nn
import math

class ScaledDotProductAttention(nn.Module):
    """Scaled Dot-Product Attention"""
    def __init__(self, dropout=0.1):
        super().__init__()
        self.dropout = nn.Dropout(dropout)

    def forward(self, Q, K, V, mask=None):
        """
        Args:
            Q: [batch, heads, seq_len, d_k]
            K: [batch, heads, seq_len, d_k]
            V: [batch, heads, seq_len, d_v]
            mask: [batch, 1, 1, seq_len] or [batch, 1, seq_len, seq_len]
        """
        d_k = Q.size(-1)

        # Step 1: Q @ K^T / sqrt(d_k)
        scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)

        # Step 2: 마스킹 (선택적)
        if mask is not None:
            scores = scores.masked_fill(mask == 0, float('-inf'))

        # Step 3: Softmax
        attention_weights = torch.softmax(scores, dim=-1)
        attention_weights = self.dropout(attention_weights)

        # Step 4: Attention @ V
        output = torch.matmul(attention_weights, V)
        return output, attention_weights


class MultiHeadAttention(nn.Module):
    """Multi-Head Attention"""
    def __init__(self, d_model, n_heads, dropout=0.1):
        super().__init__()
        assert d_model % n_heads == 0

        self.d_model = d_model
        self.n_heads = n_heads
        self.d_k = d_model // n_heads

        # Linear projections
        self.W_Q = nn.Linear(d_model, d_model)
        self.W_K = nn.Linear(d_model, d_model)
        self.W_V = nn.Linear(d_model, d_model)
        self.W_O = nn.Linear(d_model, d_model)

        self.attention = ScaledDotProductAttention(dropout)

    def forward(self, Q, K, V, mask=None):
        batch_size = Q.size(0)

        # Linear projection & reshape to [batch, heads, seq_len, d_k]
        Q = self.W_Q(Q).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        K = self.W_K(K).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)
        V = self.W_V(V).view(batch_size, -1, self.n_heads, self.d_k).transpose(1, 2)

        # Apply attention
        output, attention_weights = self.attention(Q, K, V, mask)

        # Concat heads & final projection
        output = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model)
        output = self.W_O(output)

        return output, attention_weights


# 사용 예시
d_model = 512
n_heads = 8
seq_len = 10
batch_size = 2

mha = MultiHeadAttention(d_model, n_heads)
x = torch.randn(batch_size, seq_len, d_model)

# Self-Attention
output, weights = mha(x, x, x)
print(f"Output shape: {output.shape}")            # [2, 10, 512]
print(f"Attention weights shape: {weights.shape}") # [2, 8, 10, 10]

15. 심화 학습 자료

15.1 필수 읽기 자료

  1. “Attention Is All You Need” - Vaswani et al., 2017
  2. The Annotated Transformer
  3. Stanford CS224N Lecture Notes

15.2 후속 강의 미리보기

강의주제
Lecture 2Advanced Transformer (RoPE, ALiBi, Sparse Attention, BERT)
Lecture 3LLMs & Inference (MoE, Decoding, Prompting, KV Cache)
Lecture 4LLM Training (Pretraining, Scaling Laws, LoRA, Flash Attention)
Lecture 5Preference Tuning (RLHF, DPO, Reward Model)
Lecture 6Applications (RAG, Agents, LLM-as-a-Judge)
Lecture 7Reasoning Models (DeepSeek-R1, Test-time Scaling)

16. 핵심 용어 정리

용어정의
Self-Attention시퀀스 내 모든 위치 간의 관계를 직접 계산하는 메커니즘
Query (Q)현재 토큰이 찾고자 하는 정보를 표현하는 벡터
Key (K)각 토큰이 가진 정보의 “주소”를 나타내는 벡터
Value (V)각 토큰의 실제 정보 내용을 담은 벡터
Multi-Head Attention여러 attention head를 병렬로 사용하여 다양한 관계 포착
Positional Encoding토큰의 순서 정보를 임베딩에 추가하는 방법
Residual Connection입력을 출력에 직접 더하는 skip connection
Layer Normalization레이어 내 활성화 값을 정규화하는 기법
Causal Masking미래 토큰을 가리는 attention 마스킹
Cross-AttentionEncoder 출력을 참조하는 Decoder의 attention

17. 연습 문제

Q1. Self-Attention의 계산 복잡도가 O(n²)인 이유는?

정답 보기

모든 토큰 쌍에 대해 attention score를 계산해야 하기 때문입니다.

  • n개의 Query × n개의 Key = n² 개의 점수
  • 따라서 시간 및 메모리 복잡도가 $O(n^2 \cdot d)$

Q2. $\sqrt{d_k}$로 스케일링하는 이유는?

정답 보기

내적 값의 분산이 $d_k$에 비례하여 커지기 때문입니다.

  • Q, K의 각 원소가 평균 0, 분산 1이면, 내적의 분산 $\approx d_k$
  • 큰 값이 softmax를 통과하면 gradient가 매우 작아짐
  • $\sqrt{d_k}$로 나누어 분산을 1로 정규화하여 안정적인 학습 유도

Q3. Encoder-only vs Decoder-only의 핵심 차이는?

정답 보기

Attention 방향이 다릅니다:

  • Encoder-only (BERT): 양방향 attention (모든 토큰 참조)
  • Decoder-only (GPT): 단방향 attention (이전 토큰만 참조)

용도:

  • Encoder-only: 분류, 표현 학습
  • Decoder-only: 텍스트 생성 (auto-regressive)

Based on Stanford CME295 Lecture 1 by Afshine & Shervine Amidi

This post is licensed under CC BY 4.0 by the author.