콘텐츠로 이동

트랜스포머와 Attention

분류: Layer 11 - AI 기초 & 머신러닝 | 선수지식: L11-10 (ML 수학 토대), L11-40 (신경망과 역전파)

트랜스포머와 Attention — Self-Attention, KV Cache, Long-Context

섹션 제목: “트랜스포머와 Attention — Self-Attention, KV Cache, Long-Context”

트랜스포머는 attention을 중심으로 sequence를 처리하는 신경망 구조이고, attention은 query·key·value를 이용해 토큰이 참고할 다른 토큰을 동적으로 고르는 가중 합 메커니즘이다.

조금 더 풀면, 입력 토큰마다 “내가 지금 찾는 단서”인 query, “내가 가진 단서 표지”인 key, “실제로 전달할 정보”인 value를 만든다. 그런 다음 query와 key의 내적 점수를 sqrt(d_k)로 나누어 스케일을 안정화하고, softmax로 정규화한 뒤, 그 가중치로 value를 섞어 각 토큰의 새 표현을 만든다. 이 흐름이 softmax(QK^T/sqrt(d_k))V다.

트랜스포머를 모르면 LLM의 품질·속도·메모리 문제가 모두 개별 팁처럼 보인다. 반대로 attention의 shape와 비용을 잡으면 다음 현상을 같은 언어로 읽을 수 있다.

  • 현대 LLM의 기본 구조: GPT·LLaMA류 텍스트 LLM은 대체로 decoder-only transformer를 기반으로 한다.
  • context length 비용 직관: 긴 입력이 비싼 이유는 모든 토큰 쌍 비교와 KV cache 메모리에서 나온다.
  • KV cache와 batch 한계: output 토큰을 빠르게 생성하려면 K,V를 저장해야 하고, 이 저장량은 batch × seq_len에 비례한다.
  • KV cache 공유: GQA(Grouped-Query Attention)는 query head를 여러 group으로 묶어 group마다 K,V를 공유하고, MQA(Multi-Query Attention)는 모든 query head가 K,V 한 쌍을 공유해 KV cache를 줄인다.
  • 메모리 이동 최적화: FlashAttention은 HBM(High Bandwidth Memory, GPU의 크고 상대적으로 느린 외부 메모리)과 on-chip SRAM(Static Random-Access Memory, GPU 칩 안의 작고 빠른 메모리) 사이의 I/O(Input/Output, 메모리 읽기·쓰기)를 줄이는 정확한 attention 구현이다.
  • 조건부 계산: MoE(Mixture of Experts)는 router가 token마다 일부 expert만 골라 계산량을 줄이는 구조다. Sliding window와 speculative decoding까지 포함해 각 신기법을 “무엇을 줄이고 무엇을 포기하는가”로 비교한다.
  • 장애 신호 해석: long-context 품질 폭락, cache OOM, prefix cache miss, draft rejection 같은 증상을 attention 구조와 연결할 수 있다.

처음 읽을 때 모든 모델 이름을 외울 필요는 없다. 이 문서의 목표는 “토큰이 서로를 어떻게 참고하는가”, “왜 길이가 늘면 비용이 커지는가”, “어떤 최적화가 정확한 attention을 유지하고 어떤 최적화가 근사로 바꾸는가”를 설명할 수 있게 만드는 것이다.

2.5 선행 기술의 한계 — RNN 병목에서 Self-Attention으로

섹션 제목: “2.5 선행 기술의 한계 — RNN 병목에서 Self-Attention으로”

트랜스포머 이전의 대표 sequence 모델은 RNN, LSTM, GRU였다. 이들은 토큰을 왼쪽에서 오른쪽으로 하나씩 읽고 hidden state를 갱신한다.

h_1 = f(x_1, h_0)
h_2 = f(x_2, h_1)
h_3 = f(x_3, h_2)
...

이 구조는 순서를 자연스럽게 다루지만 세 병목이 생긴다.

  1. 순차 처리 병목: h_3을 계산하려면 h_2가 필요하고, h_2를 계산하려면 h_1이 필요하다. 긴 문장을 GPU에서 한꺼번에 병렬 처리하기 어렵다.
  2. state bottleneck: 과거 전체를 하나의 hidden state에 계속 압축한다. 앞쪽 정보가 뒤쪽까지 살아남으려면 매 단계에서 손실 없이 전달되어야 한다.
  3. long-range dependency 약화: 멀리 떨어진 토큰 사이 정보가 여러 step을 지나며 희미해진다. L11-40에서 본 vanishing gradient가 시간축으로 길어진 형태라고 볼 수 있다.

Attention의 철학은 이 병목을 다르게 푼다. “과거를 하나의 state에 압축해서 들고 오자”가 아니라, 필요할 때 모든 토큰을 직접 다시 보자에 가깝다. 어떤 토큰이 다른 토큰을 얼마나 참고할지 매번 점수화하고, 그 점수로 정보를 섞는다.

Vaswani et al.의 “Attention Is All You Need”는 RNN 없이 attention과 feed-forward layer만으로 번역 모델을 만들 수 있음을 보였다. 핵심 전환은 단순하다.

RNN 계열Transformer 계열
토큰을 순서대로 갱신학습 시 모든 토큰 위치를 병렬 계산
과거를 hidden state 하나에 압축모든 토큰 쌍의 관련도를 attention score로 직접 계산
먼 정보는 여러 step을 통과해야 함한 layer 안에서 먼 토큰도 직접 연결 가능
순서 정보가 구조 안에 자연히 들어감위치 정보는 positional encoding으로 별도 주입해야 함

여기서 trade-off도 생긴다. 모든 토큰 쌍을 직접 비교하면 정보 접근은 쉬워지지만, 길이가 n인 sequence에 대해 attention score 표가 n × n이 된다. 병렬화는 쉬워졌지만 long-context 비용은 attention의 중심 문제가 되었다.

이 문서의 수식은 L11-10의 행렬 곱과 softmax만 알면 따라갈 수 있다. 기호를 먼저 정리한다.

기호
token모델이 읽는 최소 조각. 단어, 단어 일부, 기호일 수 있다
sequence length한 번에 보는 token 수. 보통 n 또는 seq_len
hidden dimensiontoken 하나를 표현하는 벡터 칸 수. 보통 d_model
headattention을 여러 관점으로 나누어 병렬 계산하는 작은 단위
d_k, d_headhead 하나의 query/key 차원
context length모델이 한 요청에서 볼 수 있는 최대 token window
prefill입력 prompt 전체의 KV를 한 번에 만드는 단계
decodeoutput token을 한 개씩 이어 생성하는 단계

입력 embedding 행렬을 X라고 하자.

X: n × d_model

n은 토큰 수, d_model은 토큰 하나의 벡터 길이다. Self-attention은 X에서 Q, K, V를 만들고, 토큰 간 관련도 표를 만든 뒤, value를 가중합한다.

4. Attention의 철학 — 검색하고, 점수화하고, 섞는다

섹션 제목: “4. Attention의 철학 — 검색하고, 점수화하고, 섞는다”

Attention은 짧게 말하면 soft retrieval이다. 데이터베이스나 검색처럼 “query가 key를 보고 관련 value를 가져온다”는 구조와 닮았다. 다만 딱 하나를 고르는 hard lookup이 아니라, 여러 value를 확률 가중치로 섞는 soft selection이다.

이 비유는 여기까지만 쓰면 충분하다. 실제 attention의 key는 사람이 만든 인덱스가 아니라 모델이 학습한 벡터이고, softmax 결과도 사람이 해석하기 쉬운 확률 설명이 아니라 다음 layer가 쓰기 좋은 가중치다.

Attention을 손으로 읽을 때는 네 단계만 기억한다.

  1. Projection: 입력 토큰 벡터에서 Q, K, V를 만든다.
  2. Scoring: QK^T로 모든 query-key 쌍의 점수를 만든다.
  3. Normalization: 점수를 sqrt(d_k)로 나누고 softmax로 attention weight를 만든다.
  4. Weighted sum: weight로 V를 섞어 각 토큰의 새 표현을 만든다.
Self-Attention 계산 흐름
flowchart LR
A["입력 토큰 벡터 X"] --> B["Q, K, V projection"]
B --> C["QK^T 점수 행렬"]
C --> D["sqrt(d_k)로 스케일링"]
D --> E["mask 적용 후 softmax"]
E --> F["V 가중 합"]
F --> G["문맥화된 token 표현"]

QK^T와 softmax는 토큰 쌍별 관련도 표를 만들고, V 가중 합은 그 관련도를 실제 정보로 바꾼다.

Self-attention에서는 같은 입력 X에서 세 행렬을 만든다.

Q = X W_Q
K = X W_K
V = X W_V

각 projection의 의미는 다음처럼 잡으면 된다.

  • Query(Q): 현재 위치가 찾고 싶은 단서다.
  • Key(K): 각 위치가 가진 단서의 표지다.
  • Value(V): attention이 실제로 가져와 섞을 내용이다.

왜 Q와 K를 나눌까? “무엇을 찾는가”와 “무엇으로 매칭되는가”를 서로 다른 공간에서 학습할 수 있게 하기 위해서다. 예를 들어 어떤 토큰은 앞의 주어를 찾는 query를 만들고, 다른 토큰은 주어라는 key 성분을 강하게 가질 수 있다. value는 그 토큰의 의미 정보, 문법 정보, 후속 layer에 필요한 여러 성분을 담는다.

5.2 QK^T — 모든 토큰 쌍의 점수 표

섹션 제목: “5.2 QK^T — 모든 토큰 쌍의 점수 표”

토큰이 3개이고 head 차원이 2라고 하자. 작은 숫자로 직접 계산해 보자.

Q =
q1 [1, 0]
q2 [0, 1]
q3 [1, 1]
K =
k1 [1, 0]
k2 [1, 1]
k3 [0, 1]

QK^T는 모든 query와 모든 key의 내적 표다.

k1 k2 k3
q1 1 1 0
q2 0 1 1
q3 1 2 1

해석:

  • 1번 토큰의 query q1=[1,0]k1, k2와 잘 맞고 k3와 덜 맞는다.
  • 2번 토큰은 k2, k3와 잘 맞는다.
  • 3번 토큰은 k2를 가장 강하게 본다.

이 표가 attention의 중심이다. 모든 토큰이 모든 토큰을 한 번씩 비교하므로 n × n 칸이 생긴다. 토큰이 4개면 16칸, 8개면 64칸, 32k면 약 10억 칸이다. 실제 구현은 여러 최적화를 쓰지만, long-context 비용의 기본 감각은 이 표에서 출발한다.

내적은 차원이 커질수록 값의 분산이 커지기 쉽다. d_k가 큰데 점수를 그대로 softmax에 넣으면 가장 큰 점수 하나가 지나치게 커져 softmax가 거의 one-hot처럼 굳을 수 있다.

Attention score = QK^T / sqrt(d_k)

sqrt(d_k)로 나누는 이유는 점수 스케일을 안정화하기 위해서다. L11-10의 softmax에서 본 것처럼 logit 차이가 너무 커지면 확률 분포가 뾰족해지고 gradient가 약해진다. attention에서도 같은 문제가 생긴다. scaling은 attention weight가 초반부터 포화되는 것을 줄인다.

실패 신호는 “attention weight가 항상 한 위치에만 몰린다”이다. 물론 어떤 head가 특정 위치를 강하게 보는 것은 정상일 수 있다. 문제는 대부분의 head와 대부분의 layer가 초반부터 거의 one-hot이 되고 학습이 흔들리는 경우다.

방금 점수 표의 3번 query 행 [1, 2, 1]만 보자. sqrt(d_k)와 mask는 잠시 생략하면 softmax는 대략 다음처럼 된다.

softmax([1, 2, 1]) ≈ [0.212, 0.576, 0.212]

value가 다음과 같다고 하자.

V =
v1 [10, 0]
v2 [0, 20]
v3 [10, 10]

3번 토큰의 새 표현은 value의 가중합이다.

0.212*v1 + 0.576*v2 + 0.212*v3
= 0.212*[10,0] + 0.576*[0,20] + 0.212*[10,10]
= [4.24, 13.64]

중요한 점은 attention이 “가장 비슷한 토큰 하나를 복사”하는 것이 아니라는 점이다. 여러 토큰의 value를 비율대로 섞는다. 그래서 attention weight를 사람이 해석할 때도 조심해야 한다. 높은 weight는 “이 위치의 value가 현재 표현에 많이 섞였다”는 신호이지, 항상 인간 언어의 설명이나 근거를 뜻하지는 않는다.

5.5 Multi-Head Attention — 한 종류의 관련도만 보지 않는다

섹션 제목: “5.5 Multi-Head Attention — 한 종류의 관련도만 보지 않는다”

Single-head attention은 하나의 Q/K/V 공간에서 관련도를 본다. Multi-head attention은 hidden dimension을 여러 head로 나누어 서로 다른 관련도를 병렬로 학습한다.

head_i = Attention(XW_Q^i, XW_K^i, XW_V^i)
MultiHead(X) = Concat(head_1, ..., head_h) W_O

예를 들어 한 head는 가까운 구문 관계를, 다른 head는 먼 위치의 지시 관계를, 또 다른 head는 특정 형식 패턴을 볼 수 있다. 이 해석은 관찰 결과에 따라 달라지므로 “head 하나가 반드시 문법 하나를 담당한다”처럼 단정하면 안 된다. 학습 관점에서 중요한 것은 여러 작은 attention 공간을 병렬로 두면 단일 큰 attention보다 다양한 matching 패턴을 표현하기 쉽다는 점이다.

운영에서 head 수를 읽을 때 특히 중요한 구분이 있다.

num_heads: query head 수
num_kv_heads: K,V를 실제로 저장하는 head 수
d_head: head 하나의 차원
hidden = num_heads × d_head

공식 128k context와 GQA가 명시된 Meta Llama 3.1 8B 예시는 다음과 같다. 이후 32k 계산은 이 모델의 지원 한도 안에서 KV cache 산식을 익히는 workload 예시다.

num_heads=32
num_kv_heads=8 # GQA
d_head=128
hidden=4096 # 32 × 128

query head는 32개지만 KV cache는 8개 KV head 기준으로 계산한다. 이 차이를 놓치면 메모리 견적이 4배 틀릴 수 있다.

6.1 Self-attention에는 순서가 저절로 들어 있지 않다

섹션 제목: “6.1 Self-attention에는 순서가 저절로 들어 있지 않다”

Self-attention은 기본적으로 토큰 집합을 비교한다. 행렬 곱 QK^T 자체에는 “이 토큰이 몇 번째였는가”라는 순서 정보가 없다. 그래서 트랜스포머는 위치 정보를 따로 주입한다.

방식핵심 아이디어주로 보는 곳
Sinusoidalsin/cos 함수로 위치별 고정 벡터를 만든다Original Transformer
Learned positional위치 embedding을 파라미터로 학습한다BERT, GPT-2
RoPE(Rotary)Q,K를 위치에 따라 회전시켜 상대 위치 정보를 담는다LLaMA, Mistral, Qwen 계열
ALiBiattention score에 거리 기반 bias를 더한다BLOOM, MPT
RoPE scaling, YaRN 등학습된 위치 범위보다 긴 context로 확장하려 시도long-context 확장에서 자주 등장

처음에는 RoPE의 회전 행렬을 모두 외우지 않아도 된다. 핵심은 위치 정보가 Q,K의 matching 방식에 들어간다는 점이다. long-context 확장은 이 위치 규칙을 훈련 때보다 먼 거리로 밀어붙이는 작업이므로, 무리한 확장은 품질 폭락으로 이어질 수 있다.

6.2 Causal mask — 미래를 보지 못하게 막기

섹션 제목: “6.2 Causal mask — 미래를 보지 못하게 막기”

Decoder-only LLM은 next-token prediction으로 학습한다. i번째 위치가 i+1 이후의 정답 토큰을 보면 cheating이 된다. 그래서 attention score에서 미래 위치를 -inf로 막고, softmax 후 가중치가 0이 되게 한다.

attention scores (n=4):
t1 t2 t3 t4
t1 A -inf -inf -inf
t2 B C -inf -inf
t3 D E F -inf
t4 G H I J

softmax 후 각 행은 이렇게 읽는다.

t1은 t1만 참고
t2는 t1, t2 참고
t3는 t1, t2, t3 참고
t4는 t1, t2, t3, t4 참고

이 구조 덕분에 학습 시에는 모든 위치의 다음 토큰 예측을 한 번에 계산할 수 있다. 미래를 mask했기 때문에 병렬 계산을 해도 정답을 훔쳐보지 않는다. 반대로 추론 시에는 아직 미래 토큰이 없으므로 한 토큰씩 생성해야 한다.

6.3 Encoder-only, Decoder-only, Encoder-Decoder

섹션 제목: “6.3 Encoder-only, Decoder-only, Encoder-Decoder”

Transformer 계열은 mask와 attention 방향에 따라 다르게 쓰인다.

Transformer 계열 선택 감각

Encoder-only

입력 전체를 양방향으로 읽고 각 토큰·문장의 표현을 만든다. 생성보다 이해와 분류에 강하다.

분류, 임베딩, NER처럼 입력 전체를 보고 판단할 때

Decoder-only

causal mask로 과거와 현재만 보고 다음 토큰을 예측한다. prompt 기반 생성 작업에 맞다.

chat, completion, tool call처럼 텍스트를 계속 생성할 때

Encoder-Decoder

입력 이해 encoder와 출력 생성 decoder를 분리하고 cross-attention으로 연결한다.

번역·요약처럼 입력과 출력의 역할이 명확히 나뉠 때

Decoder-only가 LLM의 기본형이 된 이유는 학습 목표가 단순하기 때문이다. 인터넷 텍스트에서 “지금까지 토큰을 보고 다음 토큰을 맞힌다”는 자기지도 학습을 대규모로 적용할 수 있고, 추론 때는 prompt 안에 지시·예시·도구 호출 형식을 모두 넣을 수 있다.

LLM의 한 layer는 대체로 attention sub-layer와 feed-forward network(FFN) sub-layer로 구성된다. 현대 decoder-only LLM은 pre-norm 구조를 자주 쓴다.

x' = x + Attention(Norm(x))
y = x' + FFN(Norm(x'))

구성요소를 L11-40의 신경망 언어로 다시 읽으면 다음과 같다.

  • Residual connection: x + f(x) 형태로 gradient 경로를 보존한다.
  • Norm: LayerNorm 또는 RMSNorm으로 hidden dimension의 스케일을 안정화한다.
  • Attention: 토큰 간 정보를 섞는다.
  • FFN: 각 토큰 위치에서 독립적으로 비선형 변환을 한다. 보통 hidden dimension을 넓혔다가 다시 줄인다.
  • Stack: 이 block을 수십 층 쌓아 얕은 pattern부터 추상 pattern까지 반복적으로 갱신한다.

Attention만 있어서는 충분하지 않다. Attention은 “어떤 token 정보를 섞을지”를 담당하고, FFN은 “섞인 정보를 각 위치에서 어떻게 변환할지”를 담당한다. residual과 norm은 깊게 쌓을 때 학습이 무너지지 않게 하는 안정화 장치다.

8. KV cache — inference 비용의 중심

섹션 제목: “8. KV cache — inference 비용의 중심”

학습 시에는 정답 sequence가 모두 있으므로 n개 위치를 한꺼번에 계산한다. 하지만 추론 시에는 output token을 한 개씩 생성한다.

prompt -> token_1 -> token_2 -> token_3 -> ...

매번 과거 모든 토큰의 K,V를 다시 계산하면 이미 계산한 prefix를 계속 반복하게 된다. 그래서 decoder inference는 각 layer의 K,V를 저장해 둔다. 새 토큰이 들어오면 새 Q는 과거 K,V cache를 보고 attention을 계산하고, 새 K,V만 cache에 추가한다.

중요한 경계:

  • cache에 저장하는 것은 Q가 아니라 K와 V다.
  • cache는 inference용이다. 학습의 activation memory와 다르다.
  • cache는 context가 길어질수록 선형으로 늘고, batch가 커지면 batch만큼 다시 곱해진다.

단일 요청, 단일 sequence의 KV cache 메모리는 대략 다음과 같이 잡는다.

KV cache 메모리 =
2 × num_layers × num_kv_heads × seq_len × d_head × bytes_per_param
2 = K와 V
num_kv_heads = K,V를 저장하는 head 수

Meta Llama 3.1 8B 예시를 보자. 기존 문서의 운영 숫자를 그대로 학습용 산식으로 풀면 다음과 같다.

num_layers = 32
num_kv_heads = 8 # GQA
d_head = 128
bytes_per_param = 2 # fp16 또는 bf16
2 × 32 × 8 × seq_len × 128 × 2
= 131,072 × seq_len bytes
≈ seq_len × 0.125 MB

따라서 요청 1개의 KV cache는 대략 다음과 같다.

context lengthKV cache 대략값
2k0.25 GB
4k0.5 GB
32k4 GB
128k16 GB

여기에는 모델 weight, activation/workspace, allocator overhead, batch padding, fragmentation은 빠져 있다. 그래도 “긴 context 요청 하나가 몇 GB cache를 잡을 수 있다”는 1차 감각을 주기에는 충분하다.

가장 흔한 실수는 GQA 모델에서 num_heads로 cache를 계산하는 것이다.

잘못된 계산: num_heads=32 사용
올바른 계산: num_kv_heads=8 사용
오차: 4배

퀴즈

Meta Llama 3.1 계열 KV cache 견적에서 num_heads 대신 num_kv_heads를 봐야 하는 이유는?

힌트: 캐시에 저장되는 것은 Q가 아니라 K와 V다.

정답 보기

GQA/MQA에서는 여러 query head가 같은 K,V를 공유하므로 cache는 query head 수가 아니라 K,V head 수에 비례한다. query head로 계산하면 메모리 견적이 몇 배 부풀거나 운영 판단이 틀어진다.

KV cache를 줄이는 attention 변형은 대체로 “K,V head를 얼마나 공유하는가”의 문제다.

방식K,V 공유 방식장점경계
MHA(Multi-Head Attention)query head마다 K,V를 따로 둔다표현력 기준선KV cache가 head 수만큼 커진다
MQA(Multi-Query Attention)모든 query head가 K,V 하나를 공유KV cache를 크게 줄인다품질 손실이 생길 수 있다
GQA(Grouped-Query Attention)query head 여러 개가 K,V group 하나를 공유MQA와 MHA 사이 절충group 수를 착각하면 메모리 견적이 틀린다
MLA(Multi-head Latent Attention)K,V를 저차원 latent로 압축해 저장KV cache를 더 줄일 수 있다구조 이해와 구현 복잡도가 높다
Quantized KV cache저장된 K,V의 숫자 정밀도를 낮춘다cache 메모리를 줄인다품질·속도·커널 지원을 함께 봐야 한다

선택 기준은 단순히 “가장 많이 줄이는 방식”이 아니다. 짧은 context, 작은 batch에서는 KV cache가 병목이 아닐 수 있다. 긴 context와 큰 동시성이 동시에 오면 GQA/MQA/MLA/quantized KV가 비용 결정에 직접 들어온다.

9. Attention 비용과 long-context trade-off

섹션 제목: “9. Attention 비용과 long-context trade-off”

9.1 연산과 메모리를 분리해서 봐야 한다

섹션 제목: “9.1 연산과 메모리를 분리해서 봐야 한다”

Attention의 기본 점수 표는 n × n이다. 그래서 sequence length가 2배가 되면 attention score 칸은 4배가 된다.

n=4 -> 16칸
n=8 -> 64칸
n=32k -> 약 1,000,000,000칸

하지만 실제 병목은 상황에 따라 다르다.

  • 학습에서는 attention activation, backward, optimizer state까지 함께 본다.
  • prefill에서는 prompt 전체를 병렬로 처리하므로 QK^T 비용이 크게 보인다.
  • decode에서는 새 token 하나가 과거 K,V 전체를 보므로 KV cache 읽기와 batch 스케줄링이 중요해진다.
  • serving에서는 요청별 context 길이가 달라 cache fragmentation과 padding 낭비가 생긴다.

따라서 “attention은 O(n²)이므로 무조건 느리다”도 틀리고, “FlashAttention을 쓰면 long-context 문제가 사라진다”도 틀리다. 어떤 단계의 어떤 병목을 줄이는지 따로 읽어야 한다.

9.2 FlashAttention vs Sparse/Linear Attention

섹션 제목: “9.2 FlashAttention vs Sparse/Linear Attention”

FlashAttention은 attention을 근사하지 않는다. 정확한 attention을 유지하면서 attention 행렬을 통째로 HBM에 저장하지 않고, SRAM-friendly chunk로 streaming해 I/O를 줄인다. log-sum-exp trick으로 chunk별 softmax를 정확하게 결합한다. 여기서 FLOPs(Floating-Point Operations) 는 부동소수점 연산 횟수이고, 메모리 이동량과는 다른 비용 축이다.

FlashAttention:
정확한 attention 유지
FLOPs 복잡도는 여전히 O(n²)
activation 메모리 사용을 O(n²)에서 O(n) 쪽으로 낮춤
핵심 병목은 HBM <-> SRAM 데이터 이동

Sparse attention과 linear attention은 성격이 다르다.

기법무엇을 바꾸는가얻는 것포기하거나 조심할 것
FlashAttention계산 순서와 메모리 I/O정확한 attention + 메모리 절감모든 쌍 비교 FLOPs 자체는 남는다
Sliding window가까운 window 안의 토큰만 본다local context 비용 절감먼 token dependency가 약해질 수 있다
Sparse attention일부 token pair만 선택적으로 계산긴 sequence 비용 절감선택하지 않은 pair의 정보 손실 가능
Linear attentionkernel trick 등으로 attention 계산식을 바꾼다이론상 O(n) 계열 비용품질·안정성·task 적합성 trade-off
SSM/Mamba 계열attention 대신 state space 방식으로 sequence를 처리긴 sequence를 선형 비용으로 처리transformer와 다른 inductive bias를 가진다

이 구분이 중요하다. FlashAttention은 “정확한 attention의 메모리·IO 구현 최적화”이고, sparse/linear attention은 “계산할 관계 자체를 줄이거나 바꾸는 모델링 선택”이다.

Long-context를 늘리는 방법은 하나가 아니다. 무엇을 병목으로 보는지에 따라 선택지가 달라진다.

문제 상황먼저 떠올릴 선택지경계 신호
학습 또는 prefill에서 attention 메모리 큼FlashAttention, sequence parallelismFLOPs 자체는 줄지 않으므로 latency는 남을 수 있음
가까운 문맥이 대부분이고 먼 의존이 적음sliding windowlong-range QA, 법률·계약 분석에서 품질 하락 가능
모델이 학습한 위치 범위보다 길게 쓰고 싶음RoPE scaling, YaRN, short fine-tunefactor가 커질수록 perplexity와 retrieval 품질 확인
serving에서 긴 요청이 batch를 밀어냄paged attention, chunked prefill, cache capcache fragmentation과 tail latency 확인
매우 긴 sequence를 구조적으로 다루고 싶음sparse/linear attention, SSM, hybrid정확한 attention과 같은 품질을 기대하면 안 됨

RoPE scaling은 특히 오해가 많다. 위치 규칙을 늘린다고 모델이 긴 문서 추론 능력을 자동으로 얻는 것은 아니다. needle-in-a-haystack 같은 검색형 평가는 좋아도, 중간 정보가 묻히는 lost-in-middle이나 여러 문단을 종합하는 reasoning은 따로 깨질 수 있다.

10. MoE — active parameter와 total parameter를 분리해서 읽기

섹션 제목: “10. MoE — active parameter와 total parameter를 분리해서 읽기”

MoE(Mixture of Experts)는 모든 FFN 파라미터를 매 token마다 쓰지 않고, router가 일부 expert만 고르는 구조다.

total parameters: 모델 파일에 들어 있는 전체 expert 파라미터
active parameters: 한 token을 처리할 때 실제로 계산에 참여하는 파라미터

Mixtral 8x7B 예시는 자주 쓰이는 감각이다. expert가 8개 있고 top-2만 활성화되면 total parameter는 큰데, token당 계산량은 일부 expert 기준이 된다. DeepSeek-V3의 total 671B / active 37B 예시도 같은 원리를 보여준다. 이 숫자는 “저장·배치·분산은 total을 보고, token당 계산 비용은 active를 본다”는 구분을 만들기 위한 anchor다.

운영 영향은 세 갈래다.

  • 메모리: 전체 expert weight를 어디엔가 올리거나 분산해야 한다. active가 작아도 total이 사라지지 않는다.
  • 계산량: token당 forward는 선택된 expert만 계산하므로 dense model보다 싸질 수 있다.
  • 라우팅 품질: 일부 expert에 token이 몰리면 load imbalance가 생기고, batch 1 또는 작은 batch에서는 expert parallelism 이득이 작을 수 있다.

MoE를 “큰 모델인데 공짜로 싸다”라고 읽으면 틀린다. 더 정확한 문장은 “total capacity는 크게 두고 token당 active compute를 줄이려는 구조이며, 메모리·라우팅·분산 비용을 따로 낸다”이다.

11. 추론 최적화는 runbook보다 결정 신호로 읽기

섹션 제목: “11. 추론 최적화는 runbook보다 결정 신호로 읽기”

LLM serving 최적화는 도구 이름이 빠르게 바뀐다. 처음 공부할 때는 특정 커맨드를 외우기보다 어떤 단계의 병목을 줄이는지로 분류한다.

기법줄이는 병목잘 맞는 상황효과가 약한 신호
Continuous batchingdecode GPU 유휴 시간동시 요청이 많고 output 길이가 들쭉날쭉함요청 수가 적거나 latency isolation이 더 중요함
PagedAttentionKV cache fragmentation긴 context와 많은 동시 요청context가 짧고 batch가 작아 cache 낭비가 작음
Prefix caching반복 prefix prefill 비용시스템 프롬프트, few-shot, RAG prefix가 반복됨prefix가 매번 바뀌어 hit ratio가 낮음
Speculative decodingtarget model decode step 수 체감output이 길고 draft token acceptance가 높음output이 짧거나 draft 거부율이 높음
FlashDecoding 계열decode 단계의 memory accessbatch가 작고 context가 긴 single-stream decode짧은 context 또는 prefill 병목
Quantizationweight 또는 KV 메모리, bandwidth품질 여유가 있고 kernel 지원이 충분함작은 품질 하락도 치명적인 task

예를 들어 사내 챗봇이 P95 TTFT < 1s, 동시 100 요청, Meta Llama 3.1 8B, 32k context를 목표로 한다고 하자. P95는 요청의 95%가 그 시간 안에 끝나는 지연 백분위이고, TTFT(Time To First Token)는 요청 후 첫 출력 token이 도착할 때까지의 시간이다. Llama 3.1 8B의 공식 context는 128k이므로 32k는 지원 범위 안의 workload다. 위 KV cache 산식만 적용해도 요청 1개당 약 4GB cache가 필요하다.

32k context: 요청 1개 KV cache ≈ 4GB
동시 100 요청: 4GB × 100 = 400GB

단일 80GB GPU에 그대로 올릴 수 없다. context를 4k로 제한하면 요청 1개당 약 0.5GB이고, 100 요청은 cache만 약 50GB다. 여기에 weight와 overhead가 붙는다. 이때의 판단은 “vLLM 명령어를 무엇으로 치나”가 아니라 다음 순서다.

  1. context cap을 낮출 수 있는가?
  2. 요청 prefix가 반복되어 prefix caching 이득이 있는가?
  3. batch를 키울수록 KV cache가 얼마나 늘어나는가?
  4. output이 길어 speculative decoding의 acceptance 이득이 있는가?
  5. PagedAttention처럼 fragmentation을 줄이는 serving engine이 필요한가?

도구는 이 질문에 답한 뒤 고른다. 같은 도구라도 workload가 짧은 Q&A인지, 긴 문서 요약인지, agent loop인지에 따라 효과가 달라진다.

트랜스포머는 LLM 전용 구조가 아니다. “token처럼 쪼갤 수 있고, 각 조각 사이의 관계를 계산할 수 있는 데이터”라면 여러 도메인에 적용된다.

  • ViT(Vision Transformer): 이미지를 patch token으로 쪼개 transformer에 넣는다.
  • CLIP: 이미지 encoder와 텍스트 encoder를 contrastive learning으로 맞춘다.
  • Whisper: 오디오 입력을 encoder-decoder 구조로 텍스트에 맞춘다.
  • AlphaFold 2: 단백질 구조 예측에서 attention 변형을 사용한다.

공통점은 “sequence 또는 set의 각 요소가 서로를 참고한다”는 점이다. 차이는 token을 무엇으로 정의하고, 위치나 구조 정보를 어떻게 넣고, 어떤 손실로 학습하느냐다.

13.1 Attention weight는 항상 설명 가능성이 아니다

섹션 제목: “13.1 Attention weight는 항상 설명 가능성이 아니다”

Attention weight가 높다고 해서 “모델이 인간적으로 그 단어를 근거로 삼았다”고 단정할 수 없다. Attention은 다음 layer를 위한 표현을 만드는 내부 가중치다. 특정 분석에서는 유용한 힌트가 될 수 있지만, 설명 가능성의 완전한 증거는 아니다.

13.2 Transformer가 RNN을 모든 문제에서 지운 것은 아니다

섹션 제목: “13.2 Transformer가 RNN을 모든 문제에서 지운 것은 아니다”

Transformer는 병렬화와 long-range 접근에서 강하지만 비용을 가진다. streaming, 매우 긴 sequence, 낮은 latency 제약에서는 RNN 계열, SSM, hybrid 구조가 여전히 후보가 될 수 있다. “최신이면 transformer”가 아니라 “sequence 길이, 필요한 전역 관계, latency, 메모리”를 같이 본다.

13.3 FlashAttention은 sparse attention이 아니다

섹션 제목: “13.3 FlashAttention은 sparse attention이 아니다”

FlashAttention은 모든 토큰 쌍을 계산하는 정확한 attention이다. sparse attention은 일부 쌍을 계산하지 않는다. 둘 다 long-context와 관련 있지만 trade-off가 다르다.

13.4 KV cache는 공짜 속도 향상이 아니다

섹션 제목: “13.4 KV cache는 공짜 속도 향상이 아니다”

KV cache는 중복 계산을 줄이지만 메모리를 쓴다. 짧은 prompt와 짧은 output에서는 cache 관리 overhead가 더 커 보일 수 있고, 긴 context와 큰 batch에서는 cache가 GPU 메모리를 잠식한다.

13.5 MoE의 active parameter만 보고 메모리를 추정하면 안 된다

섹션 제목: “13.5 MoE의 active parameter만 보고 메모리를 추정하면 안 된다”

MoE 추론 비용은 active parameter에 가깝지만, 모델을 올리고 expert를 분산하는 메모리·네트워크 비용은 total parameter를 본다. active와 total을 섞어 읽으면 비용 견적이 깨진다.

14. 실패 신호를 Attention 언어로 읽기

섹션 제목: “14. 실패 신호를 Attention 언어로 읽기”

아래 표는 응급 복구 runbook이 아니라, 증상을 attention 구조의 어느 부분과 연결할지 좁히는 지도다.

증상attention 언어로 번역먼저 의심할 것
긴 context에서 답이 중간 정보를 놓침먼 위치의 정보가 효과적으로 섞이지 않음lost-in-middle, RoPE scaling 한계, retrieval ordering
KV cache OOMbatch × seq_len × layers × kv_heads가 한도 초과context cap, batch, GQA/MQA 여부, paged attention
GQA 모델인데 cache가 예상보다 큼query head 기준으로 계산했거나 overhead가 큼num_kv_heads, dtype, batch padding, allocator
FlashAttention을 켰는데 느림IO 병목보다 다른 병목이 큼짧은 seq_len, kernel fallback, prefill/decode 구분
Prefix cache hit ratio가 낮음같은 K,V prefix가 재사용되지 않음system prompt 변동, RAG 문서 순서, 동적 metadata
Speculative decoding 이득이 없음draft token이 target에 자주 거부됨acceptance rate, output length, draft model 품질
Sliding window 모델이 문서 QA에 약함window 밖 먼 근거를 직접 보지 못함long-range dependency, RAG chunk 순서
RoPE scaling 후 품질이 급락위치 외삽이 모델 능력을 넘어섬scaling factor, long-context eval, short fine-tune
MoE 일부 expert만 과사용router load가 불균형routing loss, batch size, expert parallelism

정량 신호는 절대 기준이 아니라 workload 기준선과 비교한다. 예를 들어 speculative decoding의 acceptance rate가 낮으면 이득이 줄어드는 것은 맞지만, “몇 퍼센트면 실패”는 draft/target 조합과 output 길이에 따라 달라진다. 반대로 KV cache는 산식이 비교적 직접적이므로, context와 batch를 바꿨을 때 메모리가 선형으로 늘지 않으면 dtype·head 수·overhead를 다시 본다.

  • LLM 추론: chat, completion, tool call, agent loop는 대부분 decoder-only transformer serving 문제다.
  • 임베딩 모델: encoder-only 또는 decoder 기반 embedding 모델이 문장을 벡터로 바꾼다.
  • 번역·요약: encoder-decoder 또는 decoder-only prompting으로 처리한다.
  • 코드 모델: 긴 context, 구조적 token, retrieval과 attention 비용이 같이 중요해진다.
  • 멀티모달: 이미지 patch, audio frame, text token을 같은 sequence 처리 관점으로 묶는다.
  • RAG 시스템: “모델 context에 넣을 것인가, 외부 검색으로 줄일 것인가”가 long-context 비용과 직접 연결된다.

엔지니어링 판단은 보통 다음 네 질문으로 시작한다.

  1. 입력 길이와 출력 길이 중 무엇이 비용을 지배하는가?
  2. batch를 키우면 throughput 이득보다 KV cache 메모리 증가가 더 큰가?
  3. long-context가 정말 필요한가, 아니면 retrieval과 chunk 재배치로 줄일 수 있는가?
  4. 정확한 attention이 필요한가, sparse/linear/SSM 계열 근사를 받아들일 수 있는가?
개념 A개념 B차이점
Self-attentionCross-attention같은 sequence 안에서 참고 vs 다른 sequence를 참고
QueryKey찾는 단서 vs 매칭될 표지
KeyValue점수 계산에 쓰는 벡터 vs 실제로 가중합되는 정보
Multi-headSingle-head여러 matching 공간을 병렬로 둠 vs 하나의 matching 공간
Encoder-onlyDecoder-only양방향 이해 vs causal mask 기반 생성
MHA / MQA / GQAhead별 KV 분리 / 모두 공유 / group 공유
KV cacheactivation memoryinference K,V 저장 vs 학습 backward용 forward 결과 저장
FlashAttentionSparse Attention정확한 attention의 IO 최적화 vs 일부 attention pair 생략
Sliding windowLong-context RoPE볼 수 있는 pair를 제한 vs 위치 규칙을 더 긴 범위로 확장
PrefillDecodeinput prompt 병렬 처리 vs output 1토큰씩 순차 생성
DenseMoE모든 parameter 활성화 vs 일부 expert만 활성화
Total parameterActive parameter모델 전체 크기 vs token당 실제 계산에 참여하는 크기
TransformerMamba / SSMattention 기반 비교 vs state space 기반 선형 처리 후보
  1. §5.2의 Q,K로 QK^T를 직접 다시 계산한다.
  2. 3번 query 행 [1, 2, 1]의 softmax가 [0.212, 0.576, 0.212] 근처인지 확인한다.
  3. §5.4의 V를 가중합해 [4.24, 13.64] 근처가 나오는지 확인한다.
  4. 점수 [1, 10, 1]처럼 차이를 크게 만들면 softmax가 얼마나 뾰족해지는지 비교한다.

다음 4x4 attention score에서 미래 위치를 -inf로 바꾼 뒤 각 행의 softmax가 미래 위치 0이 되는지 확인한다.

raw scores =
[
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
]
causal masked =
[
[1, -inf, -inf, -inf],
[1, 2, -inf, -inf],
[1, 2, 3, -inf],
[1, 2, 3, 4],
]

Meta Llama 3.1 8B의 산식을 사용해 다음을 손으로 계산한다.

per-token KV cache ≈ 0.125 MB
  1. 8k context 요청 1개의 KV cache는 얼마인가?
  2. 8k context 요청 32개를 동시에 올리면 cache만 얼마인가?
  3. num_kv_heads=8 대신 num_heads=32로 계산하면 얼마가 되는가?

예상 감각:

8k × 0.125 MB ≈ 1 GB
32 requests × 1 GB ≈ 32 GB
query head로 잘못 계산하면 ≈ 128 GB

아래는 학습용 skeleton이다. 목표는 라이브러리 최적화가 아니라 shape를 눈으로 확인하는 것이다.

import torch
import torch.nn.functional as F
Q = torch.tensor([[1., 0.], [0., 1.], [1., 1.]])
K = torch.tensor([[1., 0.], [1., 1.], [0., 1.]])
V = torch.tensor([[10., 0.], [0., 20.], [10., 10.]])
scores = Q @ K.T
weights = F.softmax(scores / (Q.shape[-1] ** 0.5), dim=-1)
out = weights @ V
print(scores)
print(weights)
print(out)

확인할 것:

  • scores 모양이 3 × 3인지
  • weights의 각 행 합이 1인지
  • sqrt(d_k)를 제거하면 weight가 더 뾰족해지는지
  • causal mask를 추가하면 미래 위치 weight가 0이 되는지
  • softmax 행 합이 1이 아니다 → dim=-1이 맞는지 확인한다.
  • causal mask 후 미래 위치가 0이 아니다 → -inf 또는 충분히 작은 음수를 softmax 전에 더했는지 확인한다.
  • KV cache 측정이 산식보다 훨씬 크다 → weight memory, allocator overhead, batch padding, workspace가 포함됐는지 확인한다.
  • GQA 메모리 차이가 안 보인다 → 짧은 seq_len에서는 KV cache보다 weight·workspace가 더 커서 차이가 묻힐 수 있다.

트랜스포머와 Attention 체크

  • RNN의 순차 처리, state bottleneck, long-range dependency 약화를 설명할 수 있다
  • Self-attention을 projection, QK^T score, scaling, mask, softmax, V weighted sum으로 나눠 설명할 수 있다
  • Q, K, V의 역할을 각각 찾는 단서, 매칭 표지, 전달할 정보로 구분할 수 있다
  • sqrt(d_k) scaling이 softmax 포화를 줄이는 이유를 설명할 수 있다
  • causal mask가 next-token prediction에서 미래 token을 막는 방식을 작은 행렬로 설명할 수 있다
  • Multi-head attention과 GQA에서 num_heads와 num_kv_heads를 구분할 수 있다
  • KV cache 메모리 식을 사용해 context length와 batch 변화의 자릿수를 추정할 수 있다
  • FlashAttention이 정확한 attention의 IO 최적화이고 sparse/linear attention과 다르다는 점을 설명할 수 있다
  • long-context 확장에서 FlashAttention, sliding window, RoPE scaling, paged attention이 각각 다른 병목을 줄인다는 점을 구분할 수 있다
  • MoE의 active parameter와 total parameter가 메모리·계산 비용에 다르게 작용함을 설명할 수 있다
  • 추론 최적화 기법을 prefill, decode, KV fragmentation, prefix reuse, draft acceptance 관점으로 분류할 수 있다
  • long-context 품질 폭락, KV cache OOM, prefix cache miss 같은 실패 신호를 attention 구조와 연결할 수 있다
  • Attention 변형: MHA, MQA, GQA, MLA, Linear Attention, Sparse Attention, Sliding Window
  • Positional: Sinusoidal, RoPE, ALiBi, NoPE, NTK-aware scaling, YaRN
  • 블록 구조: Pre-norm, RMSNorm, SwiGLU, GeGLU, residual stream
  • Long-context 인프라: Ring Attention, sequence parallelism, paged attention, chunked prefill
  • 추론 최적화: continuous batching, speculative decoding, prefix caching, FlashDecoding
  • MoE: router, top-k routing, load balancing, expert parallelism
  • 대안 sequence 모델: Mamba, SSM, Hyena, RWKV, hybrid transformer

처음에는 모든 키워드를 깊게 공부하지 않아도 된다. Q/K/V와 KV cache 산식이 편해진 뒤, long-context나 serving 병목을 만났을 때 필요한 키워드부터 붙이면 된다.

  1. 트랜스포머는 RNN의 순차 처리와 hidden-state 병목을 줄이기 위해, 모든 토큰 쌍을 attention score로 직접 비교한다.
  2. Self-attention은 QK^T -> scaling/mask -> softmax -> V 가중합이고, 이 흐름이 토큰 간 정보를 동적으로 섞는다.
  3. Decoder-only LLM은 causal mask로 미래를 막고, inference에서는 K,V를 cache해 output token을 한 개씩 생성한다.
  4. KV cache는 2 × layers × kv_heads × seq_len × d_head × bytes로 추정하며, GQA 모델에서는 num_heads가 아니라 num_kv_heads를 봐야 한다.
  5. FlashAttention은 정확한 attention의 IO 최적화이고, sparse/linear attention·SSM·MoE·speculative decoding은 각기 다른 비용 축을 줄이는 별도 trade-off다.

최종 수정: 2026-07-14