
KV Cache를 10분의 1로 줄인 MLA의 트릭
- 6Transformer 블록 뜯어보기
- 7FlashAttention은 왜 더 많이 계산하면서 더 빠를까
- 8MoE는 전문가를 어떻게 고를까
- 9KV Cache를 10분의 1로 줄인 MLA의 트릭읽는 중
- 10Sparse Attention, 블록으로 묶으면 달라지는 것
GQA(Grouped Query Attention)는 KV head를 줄여 KV Cache를 아꼈습니다. 64개이던 KV head를 8개로 줄이면 캐시가 8분의 1이 되죠. 그런데 GQA가 줄인 것은 K, V의 벌 수이지 각 벡터의 크기(head_dim)는 128차원 그대로입니다. KV head를 극단까지 줄여 1개만 남겨도(MQA, Multi-Query Attention) 토큰당 캐시는 아래로 내려가지 않습니다.
벡터 자체를 줄이면 되지 않을까요? 128차원을 64차원으로 줄이면 어텐션이 구분할 수 있는 패턴의 해상도가 떨어져 품질에 영향을 줍니다. 벌 수를 줄이든 차원을 줄이든 어딘가에서 품질을 희생하는 구조입니다.
2024년, DeepSeek-V2가 완전히 다른 길을 제안했습니다. K, V를 나눠 쓰지 않고 압축합니다. head_dim을 직접 줄이는 것이 아니라 K, V 전체를 저차원 잠재 벡터로 압축한 뒤 필요할 때 복원하는 방식입니다. 이것이 MLA(Multi-head Latent Attention)입니다.
공유의 한계
MQA를 제안한 Shazeer(2019)의 논문 제목은 “Fast Transformer Decoding”입니다. 품질 논문이 아니라 속도 논문이죠. 디코더가 토큰을 생성할 때마다 KV Cache 전체를 메모리에서 읽어야 하는데 연산량보다 이 전송이 병목입니다. K, V를 모든 헤드가 하나씩만 공유하면 읽는 양이 로 줄어듭니다.
대가는 표현력입니다. 같은 K, V로 개의 서로 다른 질문에 답해야 하니 주어를 찾는 헤드와 목적어를 찾는 헤드가 같은 간판을 보게 됩니다.
GQA(Ainslie et al., 2023)는 이 타협의 정도를 조절합니다. Q 헤드를 개 그룹으로 묶고 그룹마다 K, V 한 벌을 공유하는 방식으로 이면 MQA, 이면 MHA입니다.
| 방식 | KV head 수 | 토큰당 캐시 () |
|---|---|---|
| MHA | (예: 64) | |
| GQA-8 | 8 | |
| MQA | 1 |
GQA 논문의 ablation에서 GQA-8의 품질은 MHA와 거의 같았고(평균 47.1 vs 47.2) 속도는 MHA의 5.4배였습니다. 기존 MHA 체크포인트를 원래 학습량의 5%만으로 변환할 수 있다는 이점까지 갖추고 있어서 Llama 2 70B 이후 오픈 모델의 기본값이 됐습니다.
다만 공유에는 구조적 바닥이 있습니다. KV head를 아무리 줄여도 각 K, V 벡터의 차원 는 건드리지 못합니다. 이면 MQA라도 토큰당 차원을 레이어마다 저장해야 하고 자체를 줄이면 어텐션 패턴의 해상도가 떨어져 품질이 내려가죠. 공유만으로는 이 바닥 아래로 내려갈 수 없습니다.
MLA, 압축이라는 다른 길
DeepSeek-V2(2024)는 K, V를 공유하지 않고 압축합니다. 토큰의 hidden state 를 작은 잠재 벡터(latent vector) 로 다운프로젝션하고 캐시에는 만 저장합니다. K와 V가 필요한 시점에 에서 업프로젝션으로 복원하는 구조입니다.
는 토큰 의 hidden state(차원), 는 차원으로 줄이는 다운프로젝션 행렬, 와 가 K와 V를 복원하는 업프로젝션 행렬입니다.
캐시에 저장하는 것은 뿐이고 차원은 입니다. 추론 시에는 를 캐시에서 읽고 , 를 실시간으로 복원합니다. 행렬 곱이 추가되지만 메모리에서 읽는 양이 줄어들고 디코딩은 메모리 대역폭에 묶여 있으니 총 시간은 오히려 단축됩니다.
10분의 1로 압축하는데 품질은 왜 유지될까요? MHA에서 128개 헤드의 K, V는 모두 같은 에서 나옵니다. 헤드마다 다른 투영 행렬을 쓸 뿐 원본은 하나이므로 K, V 사이에 상당한 중복이 있죠. MLA는 이 중복을 하나에 담고 헤드별 차이는 업프로젝션 행렬이 만들어냅니다. GQA가 같은 K, V를 여러 Q에 그대로 복사해 쓰는 것과 달리 MLA는 하나의 압축 표현에서 헤드마다 다른 K, V를 생성하는 구조입니다.
DeepSeek-V2의 구체적인 값은 , 입니다. 5,120차원을 512차원으로 압축하고 이 512차원짜리 하나로 128개 헤드의 K와 V를 모두 복원합니다.
| 방식 | 토큰당 캐시 (레이어 1개) | DeepSeek-V2 기준 |
|---|---|---|
| MHA (128 KV head) | 32,768 | |
| GQA-8 (8 KV head) | 2,048 | |
| MLA | 576 |
MLA의 576은 MHA 대비 93% 이상 줄어든 수치입니다. DeepSeek-V2 논문은 이것이 GQA-2.25(KV head 2.25개 분량)에 해당한다고 밝혔습니다. 실제 메모리로 환산하면 128K 컨텍스트, 60 레이어, fp16 기준으로 이렇습니다.
MHA: 32,768 × 60 × 131,072 × 2바이트 ≈ 480 GB
GQA-8: 2,048 × 60 × 131,072 × 2바이트 ≈ 30 GB
MLA: 576 × 60 × 131,072 × 2바이트 ≈ 8.5 GBMHA라면 요청 하나의 캐시만으로 A100 80GB 6장이 필요하지만 MLA는 1장이면 충분합니다.
표에서 MLA의 캐시가 가 아니라 인 이유가 있습니다. 위치 인코딩 때문입니다.
위치 정보와 압축의 충돌
RoPE(Rotary Position Embedding)는 K 벡터에 위치에 따른 회전을 적용합니다. 같은 단어라도 위치가 다르면 K 값이 달라지고 이 덕분에 Q와 K의 내적에 상대 위치 정보가 반영되죠. 2026년 기준 주요 모델이 모두 RoPE를 쓰고 있으니 MLA가 RoPE를 피할 수는 없습니다.
문제는 이렇습니다. 를 캐시하고 추론 시 를 복원한 뒤 RoPE를 적용해야 합니다. 그런데 RoPE가 적용된 는 위치마다 값이 다르므로 만으로는 복원이 불가능합니다. RoPE 적용된 K 전체를 캐시해야 하니 압축의 의미가 사라지죠.
DeepSeek-V2의 해법은 K를 내용 부분()과 위치 부분()으로 나누는 것입니다. 내용 부분은 에서 업프로젝션()으로 복원하되 RoPE를 적용하지 않습니다. 위치 부분은 별도의 작은 벡터 (, head_dim의 절반)에 RoPE를 적용합니다. 캐시에는 (512차원)와 (64차원)만 저장하면 되죠.
여기서 핵심 트릭이 등장합니다. 내용 부분의 어텐션 스코어를 계산할 때 행렬 곱의 결합법칙을 쓰면 를 Q 쪽으로 옮길 수 있습니다.
를 한 번만 계산해 두면 이후에는 캐시의 와 직접 내적합니다. K를 복원하는 연산이 사라지는 셈이죠. 이것이 흡수(absorption)입니다. V 쪽에서도 같은 원리로 를 출력 프로젝션 에 흡수시킵니다. 와 는 모델 로드 시 한 번 흡수시키면 되고 추론 중에는 등장하지 않습니다.
최종 어텐션 스코어는 두 부분의 합입니다. 내용 점수()와 위치 점수(, RoPE 적용)를 더해 softmax를 취하면 어텐션 가중치가 나옵니다. 캐시에서 읽는 것은 (512)와 (64)뿐이고 이 두 값의 합 576이 앞 섹션 표의 MLA 캐시 크기입니다.
마치며
MQA와 GQA는 K, V의 벌 수를 줄여 캐시를 아꼈고 MLA는 K, V 자체를 압축해 같은 목표를 다른 경로로 해결했습니다. GQA는 2026년 현재 거의 모든 오픈 모델의 기본값이고 MLA는 DeepSeek-V2/V3와 Kimi K2 등 일부 모델에서 쓰입니다.
MLA에도 대가는 있습니다. 텐서 병렬(TP)로 여러 GPU에 나눌 때 GQA는 KV head를 GPU 수로 나눌 수 있지만 MLA의 잠재 벡터 는 헤드 단위가 아니라 분할이 불가능합니다. TP=4일 때 GQA-8의 GPU당 캐시는 인데 MLA는 576 그대로이니 GPU를 늘릴수록 오히려 GQA보다 불리해집니다.
DeepSeek-V4(2026)는 MLA를 제거하고 시퀀스 축을 압축하는 방식(CSA, HCA)으로 전환했습니다. MLA를 만든 팀이 2년 만에 MLA를 대체한 셈이니 캐시를 줄이는 최적의 경로는 아직 열려 있습니다.
다음 글에서는 어떤 위치를 볼지를 줄이는 문제를 다룹니다. GQA와 MLA가 캐시에 무엇을 저장할지의 문제였다면 희소 어텐션은 어떤 위치를 아예 보지 않을지를 정합니다.