VRAM 계산기가 실제와 얼마나 맞는가 — RTX 3060 두 장으로 검증
계산기를 만들었으면 그 계산이 맞는지 확인해야 합니다. 로컬 LLM VRAM 계산기의 계산식을 실제 측정값과 대조했습니다.
먼저 이 측정이 무엇인지 정확히 밝힙니다. 아래 수치는 컨텍스트 설정(num_ctx)을 바꿨을 때 런타임이 예약한 VRAM의 증가분입니다. 실제로 수만 토큰을 채워 넣고 KV 캐시가 차오르는 과정을 측정한 것이 아닙니다. 따라서 이 증가분에는 KV 캐시 외에 컨텍스트 크기에 따라 함께 잡히는 다른 버퍼가 섞여 있을 수 있습니다.
측정 환경
| 항목 | 값 |
|---|---|
| GPU | RTX 3060 12GB × 2 (합계 24GB) |
| 전력 상한 | 각 170W |
| 드라이버 | 590.48.01 |
| 런타임 | Ollama 0.20.0 |
| KV 타입 | f16 (OLLAMA_* 환경변수 미설정, 기본값) |
| 오프로드 | 100% GPU, 두 장 분할 (ollama ps 확인) |
| 모델 | Qwen3-Coder-30B-A3B-Instruct Q4_K_M (MoE, 활성 3B) |
모델을 언로드한 상태의 기준값은 두 장 합계 35MiB였습니다. 아래 수치는 모두 두 GPU의 합계입니다.
측정 결과
| 컨텍스트 | VRAM 할당량 | 직전 대비 증가 | 증가 배율 |
|---|---|---|---|
| 4,096 | 18,529 MiB | — | — |
| 8,192 | 18,929 MiB | +400 MiB | — |
| 16,384 | 19,711 MiB | +782 MiB | 1.96× |
| 32,768 | 21,279 MiB | +1,568 MiB | 2.01× |
컨텍스트를 두 배로 늘리면 증가분도 거의 두 배가 됩니다. 정확히 두 배는 아니지만(1.96배, 2.01배) 컨텍스트 길이에 정비례한다는 전제는 성립합니다.
재현성을 확인했습니다. 8,192에서 3회 반복 측정한 결과가 18,929MiB로 모두 같았고, 32,768에서는 21,279 / 21,279 / 21,277MiB였습니다. 편차가 2MiB 이내라 측정 노이즈는 무시할 수준입니다.
이론값과의 대조
KV 캐시 크기는 다음 식으로 구합니다.
KV 바이트/토큰 = 2(K와 V) × 레이어 수 × KV 헤드 수 × head_dim × 요소당 바이트
Qwen3-Coder-30B-A3B-Instruct는 공식 설정 기준으로 레이어 48개, KV 헤드 4개, head_dim 128입니다. KV를 f16으로 두면 요소당 2바이트입니다.
2 × 48 × 4 × 128 × 2 = 98,304 바이트 = 96.0 KiB/토큰
측정한 할당 증가분을 토큰 수로 나눈 값은 다음과 같습니다.
| 구간 | 토큰당 할당 증가 | KV 이론값 대비 |
|---|---|---|
| 4k → 8k | 100.0 KiB | +4.2% |
| 8k → 16k | 97.8 KiB | +1.8% |
| 16k → 32k | 98.0 KiB | +2.1% |
| 4k ↔ 32k 양 끝 차분 | 98.2 KiB | +2.3% |
이론식이 실제 할당량을 2~4% 오차로 예측합니다. 계산기가 내놓는 숫자를 믿고 계획을 세워도 되는 수준입니다.
오차는 세 구간 모두 양수였습니다. KV 캐시 외에 컨텍스트에 비례해 함께 늘어나는 메모리가 포함되어 있다는 뜻입니다. 어텐션 연산 workspace, 할당 단위 정렬, 두 GPU에 각각 잡히는 버퍼 등이 후보입니다. 다만 이 측정만으로 원인을 특정할 수는 없습니다. 오차율이 4.2% → 1.8% → 2.1%로 움직여 단조롭게 수렴하지도 않으므로, 하나의 요인으로 설명하려는 시도는 근거가 부족합니다.
가중치 쪽은 어떤가
4,096 컨텍스트 측정값에서 언로드 기준값과 해당 컨텍스트의 KV 이론값을 빼면 다음이 남습니다.
18,529 − 35 − (4,096 × 96 KiB ÷ 1,024) = 18,110 MiB ≈ 17.69 GiB
이 모델의 GGUF 파일 크기는 18GB입니다. 양자화된 가중치는 압축을 풀지 않고 그대로 올라가므로 근접한 값이 나오는 것이 자연스럽습니다.
다만 이 잔차에는 가중치뿐 아니라 컨텍스트와 무관한 고정 오버헤드가 함께 들어 있습니다. 따라서 “파일 크기와 정확히 일치함을 검증했다”고 말할 수는 없고, 모델 파일 크기를 가중치 VRAM의 실용적인 근사치로 써도 된다는 정도가 이 측정이 뒷받침하는 결론입니다.
이 결과로 알 수 있는 것
계산기 예측에 10% 정도 여유를 두십시오. 이론값에 딱 맞춰 컨텍스트를 잡으면 2~4% 오차와 런타임 오버헤드 때문에 넘칠 수 있습니다.
모델이 지원하는 최대 컨텍스트와 내 하드웨어에서 쓸 수 있는 컨텍스트는 다릅니다. 이 모델의 최대 컨텍스트는 262,144입니다. 토큰당 96KiB로 단순 계산하면 KV만 24GiB이고, 가중치까지 더하면 42GiB 규모가 됩니다. 24GB 구성으로는 불가능합니다. 다만 이 수치는 실측 범위(32k)를 여덟 배 외삽한 값이므로 정확한 예측이 아니라 규모 감각으로만 받아들이십시오.
KV 양자화의 이득도 가늠할 수 있습니다. q8_0으로 두면 요소당 바이트가 절반이 되어 KV 캐시가 이론상 약 절반으로 줄어듭니다. 32k 기준으로 1.5GiB 안팎입니다. 블록 스케일 등 부가 정보가 있어 정확히 절반은 아니며, 이 항목은 이번에 실측하지 않았습니다.
같은 방법으로 확인하려면
특별한 도구가 필요하지 않습니다.
- 모델을 언로드한 상태에서
nvidia-smi로 기준값을 잡습니다 num_ctx를 지정해 모델을 올리고 몇 초 기다린 뒤 다시 측정합니다- 컨텍스트를 두 배씩 늘려가며 반복합니다
- 증가분을 토큰 수 차이로 나누면 토큰당 할당 바이트가 나옵니다
Ollama라면 API 요청에 "options": {"num_ctx": 8192} 를 넣으면 됩니다. 값이 안정되기까지 시간이 걸리므로 측정 직후보다 몇 초 뒤에 읽는 편이 낫습니다.
원본 데이터
측정 기록은 저장소에 공개해 두었습니다. 하드웨어, 드라이버, 런타임 설정, 구간별 수치, 반복 측정값이 들어 있습니다. 다른 GPU나 다른 모델에서 재현한 결과를 알려주시면 출처를 밝히고 반영하겠습니다.
한계
이 측정이 답하지 못하는 것들을 명확히 적어둡니다.
- KV만 분리해 잰 것이 아닙니다.
num_ctx를 바꾸면 KV 캐시 외의 버퍼도 함께 변할 수 있어, 증가분 전체를 KV로 귀속시킬 수 없습니다. - 실제로 채운 것이 아니라 예약된 용량입니다. 긴 프롬프트로 컨텍스트를 실제로 채운 상태의 측정이 아닙니다.
- 단일 환경입니다. 다른 런타임(llama.cpp 직접 실행, vLLM 등)은 메모리 할당 방식이 달라 결과가 다를 수 있습니다.
- 두 장 분할 구성입니다. 단일 GPU에서는 중복 버퍼가 없어 수치가 달라질 수 있습니다.
- MoE 모델 하나만 검증했습니다. dense 모델에서도 같은 식이 성립하는지는 별도로 확인할 계획입니다.
- 32k까지만 측정했습니다. 262k 관련 서술은 외삽입니다.
nvidia-smi값의 성격. 드라이버가 보고하는 할당·예약 메모리이며 할당 단위의 영향을 받습니다. 정확한 실사용 바이트가 아닙니다.- GPU별 원시 시계열을 보존하지 않았습니다. 컨텍스트별 합계값만 기록해, 장별 분할 양상을 독립적으로 재분석할 수 없습니다.