4단계 두 번째 논문. 이 글은 Joshua Ainslie 외의 GQA 원문을 직접 읽고 썼다. 확인한 판본은 arXiv v3, 2023-12-23이며 PDF SHA-256은
ba9094fe73db9bf515d47ae8b2d502fee9d8a6c7b1327e197ddb160f4c63b94a다. GQA(Grouped-Query Attention, 그룹 질의 어텐션)는 여러 query head가 K와 V를 전부 따로 갖는 MHA와 K·V 하나를 모두 공유하는 MQA 사이에서, query head 그룹마다 K·V 하나를 공유하는 추론 최적화 구조다.
이 글에서 얻을 답과 범위
LLM이 token을 한 개 생성할 때마다 과거 모든 token의 K(Key, 키)와 V(Value, 값)를 읽는다. 긴 context와 많은 동시 요청에서는 계산기보다 memory bandwidth(메모리 대역폭)가 병목이 된다. GQA는 cache에서 읽을 K·V head 수를 줄인다.
이 글 뒤에는 MHA(Multi-Head Attention, 다중 헤드 어텐션), MQA(Multi-Query Attention, 다중 질의 어텐션), GQA-G의 차이, KV cache 식, checkpoint conversion과 uptraining(추가 사전학습), 논문 benchmark 한계를 설명할 수 있어야 한다. 범위는 Ainslie 외의 T5 encoder-decoder 실험과 decoder inference다. FlashAttention, quantization, speculative decoding은 비슷한 목적의 다른 계층이다.
GQA는 query head 수는 유지하고 K·V head만 group 수 G개로 줄인다. 따라서 KV cache는 MHA보다 H/G배 작아지지만 head별 독립 K·V capacity도 일부 줄어든다.
왜 필요한가 — 생성 한 token이 과거 cache를 다시 읽는다
prefill(프리필)은 prompt 전체를 병렬 처리해 K·V를 만들고, decode(디코드)는 새 token 하나를 만든 뒤 과거 cache를 읽는다. decode는 다음 token을 모른 채 순서대로 생성하므로 작은 batch에서는 K·V memory read가 병목이 되기 쉽다.
head 수를 H, head dimension을 d_h, batch를 B, 현재 길이를 T라 하면 한 layer의 K와 V cache element 수는 다음이다.
[ N_{KV}=2BTHd_h \tag{1} ]
2는 K와 V 두 tensor다. FP16 또는 BF16은 element당 2 byte다. L layer model의 전체 cache는 다시 L배이며, weight memory와 별개로 request 길이와 concurrency에 따라 늘어난다. 원 논문은 autoregressive decoder inference에서 decoder weight와 attention K·V load의 memory bandwidth를 핵심 병목으로 둔다.원 논문 1절
무엇인가 — Query는 여러 개, K와 V는 그룹마다 하나
| 구조 | query head | K·V head | group G | MHA 대비 cache |
|---|---|---|---|---|
| MHA | H | H | H | 1 |
| GQA-G | H | G | 1<G<H | G/H |
| MQA | H | 1 | 1 | 1/H |
GQA는 H query head를 G group으로 나누고 같은 group query가 한 K head와 한 V head를 쓴다. r=H/G라면 query head h의 group은 floor(h/r)다. GQA-1은 MQA, GQA-H는 MHA다.
[ N_{KV}^{GQA}=2BTGd_h,\qquad \frac{N_{KV}^{MHA}}{N_{KV}^{GQA}}=\frac{H}{G} \tag{2} ]
GQA는 새 score 식이 아니다. 같은 scaled dot-product attention에서 K·V projection을 몇 query가 함께 참조하는지만 바꾼다.원 논문 2.2절
선행 개념 — Q는 찾고 K는 주소를 만들고 V는 내용을 보낸다
현재 query q_h와 과거 위치 j의 k_{g,j}, v_{g,j}에 대해 h의 group g를 쓰면 다음이다.
[ a_{h,j}=\operatorname{softmax}j\left(\frac{q_h k{g,j}^T}{\sqrt{d_h}}\right) \tag{3} ]
[ o_h=\sum_{j\le T}a_{h,j}v_{g,j} \tag{4} ]
같은 group이라도 query가 다르면 a가 달라진다. 공유하는 것은 K·V다. 따라서 “GQA는 H attention head를 G개로 줄인다”는 말은 틀리다. query H개는 그대로 있고, 그들이 읽는 memory bank K·V만 G개다.
밑바닥 원리 — cache 절감과 capacity 절감의 교환
B=1, T=1024, H=8, d_h=4를 넣으면 아래가 된다.
| 구조 | K·V head | element | FP16 byte | KiB |
|---|---|---|---|---|
| MHA | 8 | 65,536 | 131,072 | 128 |
| GQA-2 | 2 | 16,384 | 32,768 | 32 |
| MQA | 1 | 8,192 | 16,384 | 16 |
GQA-2가 MHA보다 4배 작은 이유는 H/G=8/2다. 실제 model은 B, T, L, d_h가 커 차이가 커진다. 반면 group 안에서 서로 다른 MHA K·V head를 하나로 공유하면 각 head가 가지던 독립 표현을 모두 유지하지 못한다. 이것이 품질과 bandwidth의 교환이다.
내부 구조와 실제 실행 흐름 — checkpoint를 바꾸고 적응시키기
기존 MHA checkpoint에서 GQA로 갈 때 논문은 group 안 K projection matrix와 V projection matrix를 **mean pooling(평균 풀링)**해 group당 하나로 만든다. 첫 head 선택이나 random initialization보다 mean pooling이 좋았다고 보고한다.원 논문 2.1–2.2절·Figure 4
MHA checkpoint
K_0 K_1 ... K_(r-1) → mean → group-0 K
V_0 V_1 ... V_(r-1) → mean → group-0 V
→ 각 group 반복
→ 원 recipe로 추가 pre-training
→ GQA checkpoint
평균은 lossless conversion이 아니다. 그래서 uptraining이 필요하다. 논문은 원 pre-training compute의 α=0.05, 즉 5%를 추가 학습했다. T5-XXL에서 약 600 TPUv3 chip-days였다고 썼다.원 논문 3.1절 이미 배포한 model의 config 값만 바꾸는 것은 tensor shape와 embedding 의미를 깨는 변경이다.
직접 검증과 재현 — cache 식과 head group mapping
직접 실행 확인이다. 2026-07-24, Python 3.9.6 표준 라이브러리로 식 (2)와 4 query·2 group attention을 실행했다. weight는 사람이 정한 작은 vector이며 trained model benchmark가 아니다.
MHA: KV heads=8, elements=65536, fp16 bytes=131072, KiB=128.0
GQA-2: KV heads=2, elements=16384, fp16 bytes=32768, KiB=32.0
MQA: KV heads=1, elements=8192, fp16 bytes=16384, KiB=16.0
head=0 group=0 output=[7.937395, 2.062605]
head=1 group=0 output=[7.764175, 2.235825]
head=2 group=1 output=[2.062605, 7.937395]
head=3 group=1 output=[2.235825, 7.764175]
checks passed
파일은 /tmp/gqa-research/verify_gqa.py다. 이 실행은 MHA K·V가 group 안에서 이미 동일하다면 GQA가 같은 output을 낸다는 것도 확인한다. 현실 MHA는 보통 다르므로 mean-pooling 뒤 output이 변하고 uptraining한다.
성능과 트레이드오프 — 논문 수치는 조건과 함께 읽기
논문 Table 1은 T5-XXL에서 MHA 1.51초·average 47.2, 5% uptrained MQA 0.24초·46.6, GQA-8 0.28초·47.1을 보고했다. 측정은 TPUv4 chip당 sample time, 8 TPU, 모델별 최대 fitting batch, 논문 지정 task와 greedy decoding이다.원 논문 Table 1
따라서 0.28초를 내 GPU와 serving batch의 약속으로 복사하면 안 된다. 속도는 context length, batch, cache dtype·layout, tensor parallelism, GPU bandwidth, attention kernel에 따라 달라진다. Figure 6도 G가 커져 MHA에 가까울수록 비용이 커진다고 보인다.
| 선택 | 이득 | 대가 |
|---|---|---|
| MHA | head별 K·V capacity 최대 | cache·bandwidth 최대 |
| MQA | cache 최소 | quality 저하와 training instability 가능 |
| 적은 G GQA | MQA에 가까운 절감 | group 공유 capacity 감소 |
| 큰 G GQA | MHA에 가까운 quality | cache 절감 작음 |
Appendix A는 scratch MQA long-input fine-tuning에서 loss spike와 divergence를 보고했고 uptrained GQA가 안정적으로 보였다고 한정한다. 이것은 모든 model의 안정성 정리가 아니다.
실패와 운영 기준 — GQA는 cache 운영을 없애지 않는다
- GQA에서도 cache는 T와 B에 선형 증가한다. OOM(Out Of Memory, 메모리 부족)은 G를 줄여도 남는다.
- prefill attention IO와 decode KV bandwidth는 다르다. FlashAttention은 score materialization IO를 줄이는 별도 방법이다.
num_key_value_heads, checkpoint tensor shape, RoPE(Rotary Position Embedding, 회전 위치 임베딩), cache layout, kernel 지원을 같이 확인한다.- TTFT(Time To First Token, 첫 token까지 시간), TPOT(Time Per Output Token, 출력 token당 시간), p95 latency, peak cache byte를 prompt 길이별로 잰다.
- conversion했다면 group mapping, mean-pooling, uptraining corpus·steps·seed·evaluation을 manifest에 남긴다.
GQA는 prompt injection, hallucination, retrieval quality를 고치는 security 기능이 아니다. 같은 LLM 계산을 더 적은 K·V head로 운영하는 architecture trade-off다.
대안과 선택 기준 — 병목의 위치부터 분리한다
| 병목 | 먼저 검토 | GQA와 관계 |
|---|---|---|
| decode KV cache | GQA, MQA, KV quantization | 직접 관련 |
| prefill attention IO | FlashAttention | 보완 가능 |
| weight memory | quantization, smaller model | 다른 memory |
| token 생성 순차성 | speculative decoding | 병행 가능 |
| MHA 품질 보존 | MHA 또는 충분한 G | 절감 작아짐 |
새 model pretraining이면 G 후보를 같은 corpus와 vocabulary budget에서 평가한다. 기존 pretrained model이면 공식 architecture를 바꾸지 않고 제공 tokenizer·cache format을 그대로 써야 한다.
흔한 오해와 최초 질문에 대한 답
GQA는 attention head 수를 줄이나
아니다. query head H는 유지한다. K·V head만 G개로 공유한다.
GQA-8은 query가 8개라는 뜻인가
아니다. K·V group이 8개라는 뜻이다. query H는 model config에 따로 있다.
GQA면 MHA output을 항상 그대로 재현하나
아니다. group 안 MHA K·V가 같을 때만 직접 실행처럼 같다. 현실 K·V는 달라 mean-pooling 후 output이 변한다.
내 RAG service가 느리면 GQA만 바꾸면 되나
아니다. input·output token 길이, concurrency, KV cache byte, TTFT·TPOT, GPU utilization을 먼저 측정한다. retrieval, reranker, network, prefill, decode 중 병목을 구분해야 한다.
운영 계산 예시와 배포 전 체크리스트
GQA가 실무에서 중요한 이유는 parameter 수보다 동시에 살아 있는 request의 cache가 먼저 GPU memory를 채우기 때문이다. 다음 가정만으로도 release 전 대략적인 상한을 계산할 수 있다.
한 request KV cache byte
= 2 × layer 수 × batch × 현재 token 수
× KV head 수 × head dimension × element byte
동시 request cache byte
= request별 cache byte의 합
예를 들어 layer가 32개, T=8,192, d_h=128, FP16, batch 1, H=32인 MHA라면 request 하나의 K·V cache는 약 4 GiB다. 같은 model family가 G=8 GQA이면 약 1 GiB다. 계산식의 batch는 serving engine의 continuous batching에서 단순 user 수와 같지 않을 수 있다. request가 종료된 token도 page 단위 allocator, prefix cache, swap 정책 때문에 즉시 물리 memory에서 사라지지 않을 수 있으므로 실제 peak는 profiler로 확인해야 한다.
다음 항목은 운영 change 전 최소 체크리스트다.
| 확인 | 이유 | 실패 신호 |
|---|---|---|
| model config와 checkpoint shape | G가 tensor 축과 맞아야 함 | load error 또는 조용한 잘못된 reshape |
| tokenizer와 max context | token T가 cache를 결정 | 문자 길이만 보고 OOM 발생 |
| cache dtype와 quantization | element byte가 식에 직접 들어감 | 품질 하락 또는 kernel fallback |
| prompt length별 TTFT·TPOT | prefill과 decode 병목 구분 | 평균만 좋아지고 p95 악화 |
| concurrency별 peak memory | cache는 합산됨 | 단일 request benchmark만 통과 |
| task 품질 regression | 공유 K·V의 capacity 손실 확인 | 짧은 demo만 좋고 long context 저하 |
GQA pretraining model을 serving할 때는 “MHA보다 cache가 작다”는 general claim보다, 실제 모델의 num_attention_heads, num_key_value_heads, hidden size, layer 수, cache dtype으로 위 식을 계산한다. vendor kernel이 GQA를 지원하지 않아 MHA layout으로 fallback하면 예상 대역폭 이득이 사라질 수도 있다. 따라서 config 검사와 실제 memory telemetry는 모두 필요하다.
논문 한계가 실무 판단에 주는 경계
이 논문은 encoder-decoder T5에서 decoder self-attention과 cross-attention에 MQA·GQA를 적용했고 encoder self-attention에는 적용하지 않았다. encoder는 token representation을 병렬 계산하므로 decoder autoregressive cache와 같은 bandwidth 병목이 일반적으로 중심이 아니기 때문이다.원 논문 2.2절 또한 XXL GQA를 scratch부터 학습한 model과 직접 비교하지 않았고, long input 품질 평가는 어려우며 ROUGE 같은 점수도 완전하지 않다고 Limitations에서 적었다. 그러므로 현재 decoder-only LLM에 대한 기대 이득은 architecture상 합리적인 추정일 뿐, 이 T5 benchmark가 증명한 사실은 아니다.
이 경계를 지키면 GQA는 만능 최적화가 아니라, 긴 생성과 높은 동시성에서 cache read 비용이 확인됐을 때 선택하는 정확한 도구가 된다.
장애를 재현할 때 바꾸는 값 하나
cache 식을 검증할 때는 한 번에 여러 parameter를 바꾸지 않는다. 먼저 T만 두 배로 바꾸면 cache byte도 정확히 두 배가 되어야 한다. 다음에는 G를 절반으로 바꾸면 같은 T에서 cache byte가 절반이 되어야 한다. 이 두 확인은 serving framework가 실제로 GQA layout을 사용하고 있는지 찾는 가장 작은 smoke test(스모크 테스트)다. 반대로 output quality 차이는 작은 random tensor에서 판단할 수 없다. fixed prompt set, long-context task, deterministic decode와 sampling decode를 분리해 측정하고, 특히 position이 길어질수록 retrieval recall과 answer faithfulness가 어떻게 변하는지 확인해야 한다.
출처 및 검증 경로
1차 자료
- Ainslie 외. GQA — Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints — 2절 method, 3절 setup·Table 1·Figures 3–6, 5절 limitation, Appendix A를 직접 확인했다.
- Shazeer. Fast Transformer Decoding — One Write-Head Is All You Need — MQA 원전이다.
- Dao 외. FlashAttention — 대비 대상인 attention IO 최적화 원전이다.
직접 실행 기록
- 환경 — macOS, Python 3.9.6, 외부 numerical library 없음.
- 파일 —
/tmp/gqa-research/verify_gqa.py. - 검증 — MHA·GQA-2·MQA KV element·FP16 byte 식, H=4와 G=2 mapping, group 안 K·V가 같은 MHA와 GQA output 동치.
- 한계 — 작은 수치 예제이며 T5-XXL 품질·TPU timing·실제 serving throughput을 재현하지 않았다.
댓글