Dev.to AI 🤖 Ai 👁 0 📖 3 min read

111GB 모델 파일이 램 78.8GB로 도는 이유: POCKET GGUF를 비트 수·KV 캐시·토큰당 읽는 가중치로 분해한 램 예산표

TL;DR 로컬에서 모델을 돌릴 때 "파일이 몇 GB냐"만 보고 램을 정하면 두 방향으로 어긋납니다. 문맥이 길어지면 KV 캐시가 파일 밖에서 자라고, 반대로 전문가 혼합(MoE) 모델은 파일 전체를 램에 올리지 않아도 돕니다. 저희가 허깅페이스에 올린 POCKET GGUF 파일 8개의 크기와 파라미터 수, 그리고 26B·35B·180B 빌드의 헤더와 텐서 목록을 직접 읽어 계산한 결과는

111GB 모델 파일이 램 78.8GB로 도는 이유: POCKET GGUF를 비트 수·KV 캐시·토큰당 읽는 가중치로 분해한 램 예산표

TL;DR

로컬에서 모델을 돌릴 때 "파일이 몇 GB냐"만 보고 램을 정하면 두 방향으로 어긋납니다. 문맥이 길어지면 KV 캐시가 파일 밖에서 자라고, 반대로 전문가 혼합(MoE) 모델은 파일 전체를 램에 올리지 않아도 돕니다. 저희가 허깅페이스에 올린 POCKET GGUF 파일 8개의 크기와 파라미터 수, 그리고 26B·35B·180B 빌드의 헤더와 텐서 목록을 직접 읽어 계산한 결과는 이렇습니다.

  • 파일 크기를 전체 파라미터 수로 나누면 가중치 하나에 쓰인 비트는 1.90비트(35B IQ1_M)에서 6.57비트(27B Q6_K) 까지입니다. 파일 이름의 "Q2_K"는 평균 2비트가 아닙니다. 26B Q2_K는 3.53비트, 35B Q2_K는 2.99비트입니다.
  • 문맥 262,144토큰에서 KV 캐시는 26B 5.20GiB, 35B 5.00GiB, 180B 6.00GiB입니다. 모든 층이 문맥을 쌓는 표준 구조라면 각각 30, 20, 24GiB가 됩니다. 문맥을 쌓는 층이 5개, 10개, 12개뿐이기 때문입니다.
  • 180B(파일 111.33GB)의 텐서 목록을 합치면 라우팅 전문가가 77.02GB(69.2%), 층별 n-gram 임베딩 조회표가 28.80GB(25.9%)입니다. 모델카드에 적힌 램 정점 78.8GB는 파일에서 조회표를 뺀 약 82GB와 같은 규모입니다.
  • 토큰 하나가 실제로 읽는 가중치는 26B Q2_K 1.80GB, 35B Q2_K 1.47GB, 180B 6.33GB입니다. 180B는 파일의 5.7%만 읽습니다.

가중치 하나에 비트가 몇 개 쓰였나요?

GGUF 파일의 API 응답에는 전체 파라미터 수(gguf.total)와 파일별 바이트 수가 들어 있습니다. 바이트에 8을 곱해 파라미터 수로 나누면 임베딩, 정규화, 스케일 값까지 포함한 "가중치 하나당 평균 비트"가 나옵니다.

bits_per_weight = file_bytes * 8 / total_params
파일 크기(GB) 전체 파라미터(B) 비트/가중치
26B Q2_K 11.12 25.23 3.53
26B Q4_K_M 16.80 25.23 5.33
35B IQ1_M 8.24 34.66 1.90
35B Q2_K 12.94 34.66 2.99
35B Q3_K_M 16.76 34.66 3.87
35B Q4_K_M 21.17 34.66 4.89
27B Q6_K 22.43 27.32 6.57
180B Q4_K_XL (4개 샤드) 111.33 176.94 5.03

같은 "Q2_K"라는 이름이 26B에서는 3.53비트, 35B에서는 2.99비트로 나오는 것은 층마다 정밀도를 섞는 혼합 정밀도 양자화라서 그렇습니다. 이름은 블록 구조의 종류를 가리킬 뿐, 평균 비트를 알려 주지 않습니다. 램을 계산할 때는 이름이 아니라 위 공식으로 구한 값이나 실제 파일 크기를 씁니다. 파일 이름과 실제 크기가 어긋나는 사례는 이전 글(2비트라는 이름의 GGUF가 3비트 이름의 파일보다 컸습니다)에서 다뤘습니다.

POCKET GGUF 파일 8개의 가중치당 비트 수

문맥이 길어지면 램은 얼마나 늘어나나요?

파일 밖에서 자라는 메모리가 KV 캐시입니다. 표준 어텐션에서는 층마다, 토큰마다 키와 값을 저장하므로 문맥이 길수록 선형으로 커집니다. 그런데 POCKET 세 모델의 GGUF 헤더를 열어 보면 문맥을 쌓는 층이 전체의 일부입니다. 아래 값은 헤더의 메타데이터에서 그대로 읽었습니다.

헤더 항목 26B (gemma4) 35B (qwen35moe) 180B (qwen4exp)
층 수 30 40 48
선택 전문가 / 전체 전문가 8 / 128 8 / 256 10 / 512
최대 문맥 262,144 262,144 262,144
문맥 전체를 쌓는 층 5개 (KV 헤드 2, 키·값 각 512) 10개 (4층마다 1개, KV 헤드 2, 키·값 각 256) 12개 (4층마다 1개, KV 헤드 2, 키·값 각 256)
나머지 층 슬라이딩 윈도우 25개 (창 1,024, KV 헤드 8, 키·값 각 256) 선형 순환(SSM형) 30개 선형 순환(SSM형) 36개

계산식은 단순합니다. fp16 캐시에서 문맥을 쌓는 층의 토큰당 바이트는 층 수 × KV 헤드 수 × (키 길이 + 값 길이) × 2입니다. 35B는 10 × 2 × (256 + 256) × 2 = 20,480바이트, 180B는 12 × 2 × 512 × 2 = 24,576바이트이고, 26B는 전체 문맥 층 5개가 토큰당 20,480바이트에 슬라이딩 윈도우 층이 창 크기만큼 고정으로 약 0.2GiB를 더합니다. 선형 순환 층은 문맥 길이와 무관한 고정 크기 상태를 가지며, fp32 상태로 가정하면 35B가 약 63MiB, 180B가 약 112MiB입니다.

문맥 길이별 KV 캐시 크기

문맥 길이 26B 35B 180B
8,192 0.35 GiB 0.16 GiB 0.19 GiB
32,768 0.82 GiB 0.63 GiB 0.75 GiB
131,072 2.70 GiB 2.50 GiB 3.00 GiB
262,144 5.20 GiB 5.00 GiB 6.00 GiB
262,144, 모든 층이 문맥을 쌓는다면 30.0 GiB 20.0 GiB 24.0 GiB

맨 아래 줄은 같은 모델에서 모든 층이 문맥 전체를 쌓는다고 가정한 값입니다. 실제 구조는 그 5분의 1에서 4분의 1 수준입니다. 문맥을 262K까지 열어도 KV 캐시가 5~6GiB에서 멈추는 것은 이 구조 덕분입니다. 180B 헤더에는 어텐션 압축 비율과 인덱서 항목이 함께 들어 있는데, 위 값은 그 압축을 적용하지 않고 계산했습니다.

파일 크기에 KV 캐시를 더하면 램 예산은 얼마인가요?

가중치 파일, KV 캐시, 순환 상태를 더한 예산을 GiB로 정리했습니다. 운영체제, 다른 앱, 런타임 버퍼는 따로 잡아야 합니다. 모델카드의 권장 램은 35B 세 빌드만 적혀 있어 함께 두었습니다.

빌드 파일 (GiB) 문맥 8K 예산 문맥 262K 예산 모델카드 권장 램
26B Q2_K 10.36 10.71 15.56 카드에 수치 없음
26B Q4_K_M 15.64 15.99 20.84 카드에 수치 없음
35B IQ1_M 7.67 7.89 12.73 16GB
35B Q2_K 12.05 12.27 17.11 16~24GB
35B Q3_K_M 15.61 15.83 20.67 24GB
35B Q4_K_M 19.71 19.93 24.77 32GB
180B Q4_K_XL 103.69 103.99 109.80 아래 절 참고

35B Q2_K를 예로 들면 문맥 8K 예산이 12.27GiB이고 카드의 권장 하한 16GB는 약 14.9GiB이므로, 약 2.6GiB를 운영체제와 런타임 버퍼에 남겨 둔 셈입니다. 문맥을 262K까지 열면 예산이 17.11GiB가 되어 권장 범위의 중간쯤에 들어갑니다. 빌드를 고르는 순서는 이렇습니다. 쓰려는 문맥 길이로 예산을 계산하고, 거기에 운영체제와 런타임 몫으로 2~4GiB 정도를 더한 램이 있는 가장 큰 빌드를 고르면 됩니다.

111GB 파일은 무엇으로 채워져 있고, 램은 왜 78.8GB였나요?

180B 파일은 4개 샤드입니다. 첫 번째 샤드(10.9MB)는 토크나이저와 메타데이터만 담고 있고, 텐서 1,224개는 샤드 2~4에 들어 있습니다. 각 샤드 앞부분의 텐서 목록(이름, 차원, 양자화 종류)을 읽어 바이트를 합쳤더니 111.3236GB가 나와 실제 파일 합계 111.3237GB와 78KB 차이로 맞았습니다. 이름별로 묶은 결과입니다.

묶음 파라미터 바이트 비중
라우팅 전문가 (ffn_down/gate/up_exps) 120.80B 77.02GB 69.2%
층별 n-gram 임베딩 조회표 (per_layer_token_embd) 51.20B 28.80GB 25.9%
어텐션 2.42B 2.58GB 2.3%
SSM(선형 순환) 0.58B 0.64GB 0.6%
출력층 0.64B 0.68GB 0.6%
토큰 임베딩 0.64B 0.68GB 0.6%
공유 전문가 0.24B 0.25GB 0.2%
기타 (게이트, 하이퍼 연결, 인덱서 등) 0.40B 0.64GB 0.6%

가장 눈에 띄는 것은 조회표입니다. 파라미터 51.2B짜리 표지만 행렬곱에 들어가는 가중치가 아니라, 토큰의 n-gram으로 몇 개 행을 골라 읽는 표입니다. 토큰 하나가 건드리는 것은 이 표의 극히 일부입니다. 모델카드는 CPU 서버 실행에서 램 정점이 파일 크기보다 낮은 이유를 이 층별 n-gram 임베딩을 필요할 때 읽는 구조에서 찾고 있고, 텐서 목록은 그 표가 28.80GB라는 것을 보여 줍니다. 파일 111.33GB에서 조회표 두 개(29.48GB)를 빼면 81.86GB이고, 카드에 보고된 램 정점은 78.8GB입니다. 같은 규모입니다.

이 모델의 시작 체크포인트인 Darwin-180B-RSI-R3는 중국 SuperCLUE 11월 평가에서 수학·과학 추론 공개 가중치 1위, 전체 2위에 올랐고, POCKET-Darwin-180B-GGUF는 그 모델을 텍스트 전용 4비트급 GGUF로 만든 패키지입니다. 라이선스는 Qwen Community License 1.0이어서 다른 POCKET 빌드의 Apache-2.0과 다릅니다. 내려받기 전에 카드의 라이선스 절을 확인하십시오.

속도는 파일 크기가 아니라 무엇이 정하나요?

MoE 모델에서 토큰 하나를 만들 때 읽는 가중치는 "항상 쓰는 가중치(어텐션, 순환, 공유 전문가, 출력층)"와 "라우터가 고른 전문가 몫"의 합입니다. 텐서 목록으로 두 값을 직접 구했습니다. 선택 전문가 비율은 헤더의 8/128, 8/256, 10/512를 썼습니다.

빌드 파일 항상 쓰는 가중치 전문가 전체 토큰당 읽는 양 파일 대비
26B Q2_K 11.12GB 1.22GB 9.28GB 1.80GB 16.2%
35B IQ1_M 8.24GB 0.93GB 7.13GB 1.15GB 14.0%
35B Q2_K 12.94GB 1.10GB 11.66GB 1.47GB 11.3%
35B Q4_K_M 21.17GB 1.37GB 19.50GB 1.98GB 9.3%
180B Q4_K_XL 111.33GB 4.83GB 77.02GB 6.33GB 5.7%

파일 크기와 토큰당 읽는 가중치 비교

모델이 커질수록 파일 대비 토큰당 읽는 비율이 내려갑니다. 35B에서 180B로 가면 파일은 8.6배(Q2_K 기준 12.94GB에서 111.33GB) 커지지만 토큰당 읽는 양은 4.3배(1.47GB에서 6.33GB)만 늘어납니다. 이 값에 모델카드가 기기별로 적어 둔 속도를 곱하면, 각 기기가 만든 가중치 읽기 흐름을 환산할 수 있습니다.

빌드 기기·모드 (모델카드 기재) 속도 환산 읽기 흐름
35B IQ1_M 서버 CPU(Xeon), 16스레드 27.0 tok/s 31 GB/s
35B IQ1_M MacBook M3 Pro, Metal 25.4 tok/s 29 GB/s
35B IQ1_M MacBook M3 Pro, CPU 8스레드 13.8 tok/s 16 GB/s
35B Q2_K MacBook M3 Pro, CPU 8스레드 19.5 tok/s 29 GB/s
180B Q4_K_XL AMD EPYC 9365 1소켓, 16스레드, GPU 없음 18.4~21.0 tok/s 117~133 GB/s

35B 계열은 기기가 달라도 16~31GB/s 구간에 모이고, EPYC 서버는 117~133GB/s까지 나옵니다. 속도는 대략 "토큰당 읽는 바이트 × 기기가 지속적으로 내는 메모리 흐름"으로 정해집니다. 그래서 파일이 8.6배 큰 180B가 서버 CPU에서 초당 18~21토큰으로 돕니다. 만약 111.33GB 전체를 토큰마다 읽는 구조였다면, 같은 133GB/s로도 초당 0.8~1.0토큰에 머물렀을 것입니다. 파일 대비 토큰당 읽는 양의 비율 17.6배가 그 차이입니다.

노트북 결과도 같은 틀로 읽힙니다. RTX 5060 Laptop(VRAM 8GB), 램 32GB, NVMe SSD 조합의 4.17 tok/s는 --cpu-moe로 전문가를 CPU 쪽에 두는 하이브리드 구성입니다. 항상 쓰는 가중치 4.83GB는 VRAM에 들어가고, 전문가 몫(토큰당 1.50GB)만 램과 SSD에서 흘러옵니다. 1.50GB × 4.17은 6.3GB/s로, SSD 한 개가 감당할 수 있는 범위에 들어옵니다. 111GB 파일을 32GB 램 노트북에서 돌릴 수 있는 이유가 이 계산에 있습니다.

내 PC에는 어떤 빌드를 올리면 되나요?

위 표를 순서대로 쓰면 됩니다. 먼저 필요한 문맥 길이로 KV 캐시를 정하고, 파일 크기를 더하고, 운영체제와 런타임 몫을 얹습니다. 35B Q2_K를 CPU로 돌리는 명령은 모델카드에 이렇게 적혀 있습니다.

hf download FINAL-Bench/POCKET-35B-GGUF POCKET-35B-Q2_K.gguf --revision 3870039a87406fb90764b27e3984c8b1a36b269e --local-dir ./POCKET-35B
llama-cli -m ./POCKET-35B/POCKET-35B-Q2_K.gguf --device none -ngl 0 -t 8 -c 4096 -n 256 -p "Explain why local AI can be useful."

180B는 샤드 4개가 모두 같은 폴더에 있어야 하고, 첫 번째 샤드를 -m으로 넘깁니다.

hf download FINAL-Bench/POCKET-Darwin-180B-GGUF --revision 69fc3dd1409507de5dc12d81767f909ac2511567 --include "POCKET-Darwin-180B-UD-Q4_K_XL-*.gguf" --local-dir ./POCKET-Darwin-180B

같은 계산을 내 파일로 해 보려면?

gguf 패키지의 GGUFReader로 텐서 목록을 읽으면 "토큰당 읽는 양"을 바로 구할 수 있습니다. 전문가 텐서는 이름에 _exps가 들어 있고, 임베딩 조회표는 token_embd.weight와 per_layer_token_embd.weight입니다. 아래 코드는 작은 합성 GGUF 파일로 동작을 확인한 것입니다.

from gguf import GGUFReader

r = GGUFReader("POCKET-35B-Q2_K.gguf")
used, total = 8, 256                      # 헤더의 expert_used_count, expert_count
exps = sum(t.n_bytes for t in r.tensors if "_exps" in t.name)
lookup = sum(t.n_bytes for t in r.tensors
             if t.name in ("token_embd.weight", "per_layer_token_embd.weight"))
always = sum(t.n_bytes for t in r.tensors) - exps - lookup
print("토큰당 읽는 GB:", (always + exps * used / total) / 1e9)

KV 캐시는 헤더의 block_count, attention.head_count_kv, attention.key_length, attention.value_length와 full_attention_interval(또는 슬라이딩 윈도우 패턴)로 위 식에 넣으면 됩니다. 헤더는 파일 앞부분만 범위 요청으로 받아도 읽히므로 수십 GB를 내려받지 않고도 계산할 수 있습니다.

이 계산은 어떤 가정 위에 있나요?

  • KV 캐시는 llama.cpp 기본값인 fp16으로 계산했습니다. 캐시를 양자화하면 비례해서 줄어듭니다.
  • 26B의 슬라이딩 윈도우 층은 창 1,024토큰만 유지한다고 보았고, 배치 크기에 따른 여유분은 넣지 않았습니다.
  • 선형 순환 층의 상태 크기(35B 약 63MiB, 180B 약 112MiB)는 헤더의 SSM 항목에서 fp32 상태를 가정해 구한 추정값입니다.
  • 토큰당 읽는 양은 선택 전문가가 전문가 전체에서 고르게 뽑힌다고 보고 used / total 비율을 곱했습니다. 실제 요청에서는 자주 뽑히는 전문가가 있어 캐시 효과가 더해집니다.
  • 속도(tok/s)는 모델카드에 기기별 조건과 함께 적힌 값을 그대로 썼고, 기기마다 빌드와 스레드 수가 다르므로 줄끼리 직접 비교하지 않고 각 줄을 환산 흐름으로만 읽었습니다.
  • 램 예산에는 운영체제, 다른 앱, 런타임 버퍼가 들어 있지 않습니다.

자주 묻는 질문

Q2_K면 가중치가 2비트인가요?
아닙니다. 이름은 양자화 블록 구조의 종류이고, 실제 평균은 파일 크기와 파라미터 수로 구합니다. POCKET 26B Q2_K는 3.53비트, 35B Q2_K는 2.99비트입니다.

파일 크기만큼 램이 있으면 되나요?
문맥 8K 정도에서는 KV 캐시가 0.2~0.4GiB라서 파일 크기에 가깝게 잡아도 되지만, 운영체제와 런타임 몫 몇 GiB는 따로 필요합니다. 문맥을 262K로 열면 5~6GiB가 더 듭니다. 180B처럼 임베딩 조회표가 큰 모델은 파일보다 낮은 램에서도 돕니다.

문맥을 262K까지 늘리면 얼마나 더 드나요?
26B는 5.20GiB, 35B는 5.00GiB, 180B는 6.00GiB입니다(fp16 캐시 기준). 문맥을 쌓는 층이 5~12개뿐이라서 표준 구조 가정(20~30GiB)의 4분의 1 안팎입니다.

32GB 램 노트북에서 180B를 돌릴 수 있나요?
모델카드에는 RTX 5060 Laptop(VRAM 8GB), 램 32GB, NVMe SSD 구성에서 --cpu-moe로 4.17 tok/s가 적혀 있습니다. 전문가를 SSD에서 읽는 구조라 SSD 속도와 램 캐시에 따라 달라집니다. 서버급 CPU(AMD EPYC 9365, 16스레드)에서는 18.4~21.0 tok/s, 램 정점 78.8GB가 보고돼 있습니다.

어디서 내려받나요?
허깅페이스 FINAL-Bench/POCKET-35B-GGUF, POCKET-26B-GGUF, POCKET-Darwin-180B-GGUF에 있고 로그인 없이 받을 수 있습니다. 35B와 26B는 Apache-2.0, 180B는 Qwen Community License 1.0입니다.

출처는 위 세 모델카드(파일 크기, 헤더 메타데이터, 텐서 목록, 기기별 속도와 램 정점)와 허깅페이스 모델 API(gguf.total, 파일 바이트)입니다. 계산 스크립트는 헤더와 텐서 목록을 범위 요청으로 읽어 합산하는 방식입니다.

Further reading

📰 Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.