1. Overview
Tokenization : ์
๋ ฅ ํ
์คํธ๋ฅผ Token ID๋ก ๋ณํ
Embedding : Token ID๋ฅผ ๊ณ ์ ์ฐจ์์ ๋ฒกํฐ๋ก ๋ณํ
QKV Projection : ๊ฐ์ค์น ํ๋ ฌ์ ์ฌ์ฉํ์ฌ Query, Key, Value ์์ฑ
Multi-Head Attention (MHA) : ์ฌ๋ฌ Head์์ ๋
๋ฆฝ์ ์ผ๋ก Attention ๊ณ์ฐ
Grouped-Query Attention (GQA) : ์ฌ๋ฌ Query Head๊ฐ Key/Value Head ๊ณต์
KV Cache : ์ด์ ํ ํฐ์ Key/Value๋ฅผ ์ ์ฅํ๊ณ ์ฌ์ฌ์ฉ
Processing Flow
flowchart TD
A["Input Text"] --> B["Tokenizer"]
B --> C["Token IDs"]
C --> D["Token Embedding"]
D --> E["Input Vector"]
E --> F["QKV Projection"]
F --> Q["Query"]
F --> K["Key"]
F --> V["Value"]
K --> CACHE["KV Cache"]
V --> CACHE
Q --> ATT["Multi-Head / Grouped-Query Attention"]
CACHE --> ATT
ATT --> O["Head Concatenation"]
O --> P["Output Projection"]
2. Tokenization & Embedding
Tokenization
์
๋ ฅ ํ
์คํธ๋ฅผ Vocabulary์ ์ ์๋ Token ID๋ก ๋ณํํ๋ค.
Input: "The cat sleeps"
โ
Tokens: ["The", "cat", "sleeps"]
โ
IDs: [101, 205, 309]
์ ํ ํฐ ๋ถํ ๊ณผ ID๋ ์ค๋ช
์ฉ ์์์ด๋ค.
run.c์์ Tokenization์ ์ํํ๋ ์ฝ๋:
encode(t, prompt, 1, 0, &prompt_tokens, &num_prompt_tokens);
Token Embedding
Token ID๋ฅผ ๋ชจ๋ธ์ Embedding Table์์ ์กฐํํ์ฌ ๋ฒกํฐ๋ก ๋ณํํ๋ค.
float* content_row = w->token_embedding_table + token * dim;
memcpy(x, content_row, dim * sizeof(*x));
์๋ฅผ ๋ค์ด dim = 288์ด๋ฉด ํ ํฐ ํ๋๊ฐ 288๊ฐ์ ์ค์๋ก ํํ๋๋ค.
x\in\mathbb{R}^{288}
]$$
```mermaid
flowchart LR
A["Token ID: 205"] --> B["Embedding Table"]
B --> C["Vector x"]
C --> D["288 Dimensions"]
```
- **Token**: ํ
์คํธ๋ฅผ ๋ถํ ํ ์ฒ๋ฆฌ ๋จ์
- **Dimension**: ํ ํฐ ํ๋๋ฅผ ํํํ๋ ๋ฒกํฐ์ ์ซ์ ๊ฐ์
- **Embedding**: ํ์ต๋ ๋ฒกํฐ ํํ
## 3. QKV Projection
์
๋ ฅ ๋ฒกํฐ๋ฅผ ํ์ต๋ ๊ฐ์ค์น ํ๋ ฌ๋ก ๋ณํํด Q, K, V๋ฅผ ์์ฑํ๋ค.
$$[
Q=W_Qx,\quad K=W_Kx,\quad V=W_Vx
]$$
|๋ฒกํฐ|์ญํ |
|---|---|
|Query (Q)|์ด๋ค ์ ๋ณด๋ฅผ ์ฐธ๊ณ ํ ์ง ํ๋จํ๋ ํํ|
|Key (K)|Query์ ๋น๊ตํ์ฌ Attention Score ๊ณ์ฐ|
|Value (V)|Attention ๊ฒฐ๊ณผ์ ๋ฐ์ํ ์ ๋ณด|
```mermaid
flowchart TD
X["Input Vector x"] --> WQ["Wq: Linear Projection"]
X --> WK["Wk: Linear Projection"]
X --> WV["Wv: Linear Projection"]
WQ --> Q["Query Vector"]
WK --> K["Key Vector"]
WV --> V["Value Vector"]
```
`run.c`์ ํต์ฌ ์ฐ์ฐ์ ๋จ์ํํ ์ฝ๋:
```
matmul(q, x, wq, dim, dim);
matmul(k, x, wk, dim, kv_dim);
matmul(v, x, wv, dim, kv_dim);
```
- `wq`, `wk`, `wv`: ํ์ต๋ ๊ฐ์ค์น
- `q`, `k`, `v`: ์
๋ ฅ์ผ๋ก๋ถํฐ ๊ณ์ฐ๋ ๋ฒกํฐ
- ์ค์ ๊ตฌํ์์๋ ์ ๊ทํ๋ ์
๋ ฅ๊ณผ ๋ ์ด์ด๋ณ ๊ฐ์ค์น ์คํ์
์ฌ์ฉ
## 4. Multi-Head Attention (MHA)
**Q, K, V๋ฅผ ์ฌ๋ฌ Head๋ก ๋๋์ด ๊ฐ๊ฐ Attention์ ๊ณ์ฐํ๋ ๊ตฌ์กฐ**
์์:
```
dim = 288;
n_heads = 6;
```
Head ํ๋์ ์ฐจ์:
$$[
head\_size=\frac{288}{6}=48
]$$
```mermaid
flowchart TD
Q["Query Vector: 288 Dimensions"]
Q --> H1["Head 1: 48"]
Q --> H2["Head 2: 48"]
Q --> H3["Head 3: 48"]
Q --> H4["Head 4: 48"]
Q --> H5["Head 5: 48"]
Q --> H6["Head 6: 48"]
H1 --> C["Concatenation: 288"]
H2 --> C
H3 --> C
H4 --> C
H5 --> C
H6 --> C
```
์ ๊ทธ๋ฆผ์ Query์ ์ฐจ์ ๋ถํ ์ ๋ณด์ฌ์ค๋ค. ์ค์ ๋ก๋ ๊ฐ Head์ ๋์ํ๋ K/V์ Attention์ ๊ณ์ฐํ **๊ฒฐ๊ณผ ๋ฒกํฐ**๋ฅผ ๊ฒฐํฉํ๋ค.
Head๋ ๋จ์ด ํ๋๋ฅผ ๋ด๋นํ๋ ๊ฒ์ด ์๋๋ผ, ํ ํฐ ๊ฐ ๊ด๊ณ๋ฅผ ๊ณ์ฐํ๋ ๋
๋ฆฝ์ ์ธ Attention ์ฐ์ฐ ๋จ์์ด๋ค.
### Attention Calculation
$$[
\operatorname{Attention}(Q,K,V)=
\operatorname{softmax}
\left(\frac{QK^T}{\sqrt{d_k}}\right)V
]$$
```mermaid
flowchart TD
Q["Query"] --> S["Q ร K Transpose"]
K["Key"] --> S
S --> SCALE["Scale by sqrt(d_k)"]
SCALE --> SM["Softmax"]
SM --> WS["Weighted Sum"]
V["Value"] --> WS
WS --> O["Attention Output"]
```
1. Query์ Key์ ๋ด์ ์ผ๋ก ์ ์ฌ๋ ๊ณ์ฐ
2. Head ์ฐจ์์ ์ ๊ณฑ๊ทผ์ผ๋ก ์ ์ ์กฐ์
3. Softmax๋ก Attention ๊ฐ์ค์น ๊ณ์ฐ
4. Value์ ๊ฐ์คํฉ์ผ๋ก ์ถ๋ ฅ ์์ฑ
`run.c`์์๋ Head๋ณ๋ก ๋ฐ๋ณตํ์ฌ Attention์ ๊ณ์ฐํ๋ค.
```
for (int h = 0; h < p->n_heads; h++) {
float* q = s->q + h * head_size;
}
```
## 5. Grouped-Query Attention (GQA)
**์ฌ๋ฌ Query Head๊ฐ ํ๋์ Key/Value Head๋ฅผ ๊ณต์ ํ๋ Attention ๊ตฌ์กฐ**
์์:
```
dim = 288;
n_heads = 6;
n_kv_heads = 2;
```
### MHA ๊ตฌ์กฐ
```mermaid
flowchart LR
Q1["Q1"] --> KV1["K1 / V1"]
Q2["Q2"] --> KV2["K2 / V2"]
Q3["Q3"] --> KV3["K3 / V3"]
Q4["Q4"] --> KV4["K4 / V4"]
Q5["Q5"] --> KV5["K5 / V5"]
Q6["Q6"] --> KV6["K6 / V6"]
```
- Query Head: 6๊ฐ
- Key/Value Head: ๊ฐ๊ฐ 6๊ฐ
- Query Head๋ง๋ค ๋ณ๋์ K/V Head ์ฌ์ฉ
### GQA ๊ตฌ์กฐ
```mermaid
flowchart LR
Q1["Q1"] --> KV1["K1 / V1"]
Q2["Q2"] --> KV1
Q3["Q3"] --> KV1
Q4["Q4"] --> KV2["K2 / V2"]
Q5["Q5"] --> KV2
Q6["Q6"] --> KV2
```
- Query Head: 6๊ฐ
- Key/Value Head: ๊ฐ๊ฐ 2๊ฐ
- Query Head 3๊ฐ๊ฐ ํ๋์ K/V Head ๊ณต์
### Dimension Calculation
$$[
head\_size=\frac{dim}{n_heads}=48
]$$
$$[
kv\_dim=dim\times\frac{n_kv_heads}{n_heads}=96
]$$
|๊ตฌ๋ถ|MHA|GQA|
|---|---|---|
|Query Heads|6|6|
|Key/Value Heads|6|2|
|Query Dimension|288|288|
|Key Dimension|288|96|
|Value Dimension|288|96|
|KV ๊ณต์ |์์|์์|
`run.c`์์ KV Head๋ฅผ ์ ํํ๋ ๊ณ์ฐ:
```
int kv_mul = p->n_heads / p->n_kv_heads;
int kv_head = h / kv_mul;
```
`kv_mul = 3`์ด๋ฏ๋ก Query Head 3๊ฐ๋ง๋ค ํ๋์ KV Head๋ฅผ ์ฌ์ฉํ๋ค.
GQA๋ KV Head ์๋ฅผ ์ค์ฌ Key/Value ์ ์ฅ ๊ณต๊ฐ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ์ ๊ทผ ๋ถ๋ด์ ๊ฐ์์ํจ๋ค.
## 6. KV Cache
**์ด์ ํ ํฐ์์ ๊ณ์ฐํ Key/Value๋ฅผ ์ ์ฅํ๊ณ ๋ค์ ํ ํฐ ์ฒ๋ฆฌ์ ์ฌ์ฌ์ฉํ๋ ๋ฉ๋ชจ๋ฆฌ**
LLM์ ํ ํฐ์ ์์ฐจ์ ์ผ๋ก ์์ฑํ๋ฏ๋ก ์ด์ ํ ํฐ์ K/V๋ฅผ ๋ฐ๋ณต ๊ณ์ฐํ ํ์๊ฐ ์๋ค.
### KV Cache Processing
```mermaid
flowchart TD
A["Token 1"] --> B["Compute K1, V1"]
B --> C["Store KV Cache"]
C --> D["Token 2"]
D --> E["Reuse K1, V1"]
D --> F["Compute K2, V2"]
E --> G["Attention for Token 2"]
F --> G
F --> H["Update KV Cache"]
H --> I["Token 3"]
I --> J["Reuse K1,V1 and K2,V2"]
I --> K["Compute K3,V3"]
J --> L["Attention for Token 3"]
K --> L
```
### Memory Allocation
`RunState` ๊ตฌ์กฐ์ฒด:
```
float* key_cache;
float* value_cache;
```
`malloc_run_state()`์์ ๋ฉ๋ชจ๋ฆฌ ํ ๋น:
```
int kv_dim = (p->dim * p->n_kv_heads) / p->n_heads;
s->key_cache = calloc(
p->n_layers * p->seq_len * kv_dim,
sizeof(float)
);
s->value_cache = calloc(
p->n_layers * p->seq_len * kv_dim,
sizeof(float)
);
```
- `n_layers`: Transformer Layer ๊ฐ์
- `seq_len`: ์ต๋ ์ํ์ค ๊ธธ์ด
- `kv_dim`: ํ ํฐ ํ๋์ Key ๋๋ Value ์ฐจ์
FP32 ๊ธฐ์ค ์ด KV Cache ๋ฉ๋ชจ๋ฆฌ:
$$[
M_{KV}=2\times n_{layers}\times seq_{len}\times kv_{dim}\times4
]$$
### GQA + KV Cache
```mermaid
flowchart TD
A["Current Token"] --> B["Generate Q Heads: 6"]
A --> C["Generate K/V Heads: 2"]
C --> D["Store Current K/V in Cache"]
E["Previous Token KV Cache"] --> F["Available K/V"]
D --> F
B --> G["Grouped-Query Attention"]
F --> G
G --> H["6 Head Outputs"]
H --> I["Concatenate: 288 Dimensions"]
```
- GQA: ์ฌ๋ฌ Query Head๊ฐ ๊ฐ์ KV Head๋ฅผ ๊ณต์
- KV Cache: ์ด์ ํ ํฐ์ K/V๋ฅผ ์ฌ์ฌ์ฉ
- ๋ ๊ธฐ๋ฒ์ ๊ฒฐํฉํ๋ฉด ์บ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ค์ด๋ฉด์ ์ค๋ณต K/V ๊ณ์ฐ์ ๋ฐฉ์งํ ์ ์๋ค.
## 7. Summary
```mermaid
flowchart TD
A["Input Text"] --> B["Tokenizer"]
B --> C["Token IDs"]
C --> D["Token Embedding: 288"]
D --> E["QKV Projection"]
E --> Q["Q: 6 Heads ร 48"]
E --> K["K: 2 Heads ร 48"]
E --> V["V: 2 Heads ร 48"]
K --> CACHE["KV Cache"]
V --> CACHE
Q --> GQA["Grouped-Query Attention"]
CACHE --> GQA
GQA --> H["6 Attention Outputs"]
H --> CONCAT["Concatenate: 288"]
CONCAT --> O["Output Projection"]
```
| ๊ฐ๋
| ํต์ฌ ์ญํ |
| ----------------------- | ---------------------- |
| Tokenizer | ํ
์คํธ โ Token ID |
| Embedding | Token ID โ ๋ฒกํฐ |
| QKV Projection | Q/K/V ๊ณ์ฐ |
| Multi-Head Attention | ์ฌ๋ฌ Head์์ Attention ์ํ |
| Grouped-Query Attention | ์ฌ๋ฌ Query Head๊ฐ K/V ๊ณต์ |
| KV Cache | ์ด์ K/V ์ ์ฅ ๋ฐ ์ฌ์ฌ์ฉ |