지난 글에서 INT8·INT4 양자화의 수학적 원리와 PTQ·QAT 전략을 다뤘다. 이론을 익혔다면 이제 실제 파일을 손에 쥐어야 한다. Hugging Face에서 "GGUF" 확장자 파일을 본 적 있을 것이다. 오늘은 그 GGUF가 정확히 무엇인지, 어떤 양자화 레벨을 골라야 하는지, 그리고 llama.cpp와 Python에서 어떻게 추론하는지를 처음부터 끝까지 다룬다.
GGUF가 등장한 이유
2023년 8월 이전까지 llama.cpp는 GGML 포맷을 사용했다. GGML은 양자화 정보를 담을 수 있었지만 메타데이터(토크나이저, 아키텍처 정보, 컨텍스트 길이)를 저장하는 표준 방법이 없었고, 모델 구조가 바뀔 때마다 파일 레이아웃도 달라져 역호환성이 엉망이었다. GGUF(GPT-Generated Unified Format)는 이 문제를 해결하기 위해 Georgi Gerganov가 설계한 포맷이다. 핵심 설계 원칙 두 가지는 다음과 같다.
단일 파일에 모든 것을 담는다: 토크나이저 어휘, BPE 병합 규칙, 모델 하이퍼파라미터, 양자화된 가중치까지 하나의 파일에 들어간다. 예전에는 tokenizer_config.json, config.json, 여러 개의 .bin 파일을 함께 배포해야 했다.
mmap으로 제로카피 접근: 파일 내 텐서 데이터 영역이 페이지 경계에 정렬되어 있어, 운영체제의 메모리 맵(mmap)을 통해 디스크에서 GPU 메모리로 직접 로드할 수 있다. 대형 모델을 RAM에 전부 올리지 않고도 추론 가능하다.
GGUF 파일 구조 분해
바이너리 레이아웃을 이해하면 디버깅이 쉬워진다.
헤더(24바이트 고정):
magic:GGUFASCII 문자열 (0x47475546)version: 현재 3 (하위 호환 유지)tensor_count: 텐서 개수 (7B 모델은 약 291개)metadata_kv_count: KV 쌍 개수
메타데이터 KV 쌍: 키(문자열)와 값(다양한 타입)으로 구성된 딕셔너리다. 주요 키들은 다음과 같다.
# 실제 GGUF 메타데이터 키 예시
"general.architecture" # "llama"
"general.name" # "Meta-Llama-3-8B"
"llama.context_length" # 8192
"llama.embedding_length" # 4096
"llama.block_count" # 32
"tokenizer.ggml.model" # "llama"
"tokenizer.ggml.tokens" # [...어휘 목록...]
텐서 정보 배열: 각 텐서마다 이름, 차원 수, 형태, 양자화 타입, 파일 내 오프셋을 저장한다.
텐서 데이터: 실제 양자화된 가중치 블록. ALIGNMENT(기본 32바이트) 단위로 정렬된 패딩 이후 시작한다.
양자화 레벨 해석법
GGUF 파일명에서 양자화 레벨을 읽는 패턴을 익혀야 한다.
- Q숫자: 비트 수. Q4는 4비트, Q8은 8비트.
- _K: K-Quant 방식. 레이어 중요도에 따라 혼합 비트를 적용한다.
- _M / _S / _L: K-Quant의 크기 변형. M(Medium), S(Small), L(Large). 같은 비트 수에서 중요 레이어에 할당하는 고비트 비율이 다르다.
- 숫자만: 단순 균일 양자화. Q4_0은 모든 가중치에 균일하게 4비트 적용.
7B 모델 기준 실전 선택 가이드:
- 8~16GB VRAM GPU → Q5_K_M 또는 Q6_K (최고 품질)
- 6~8GB VRAM GPU → Q4_K_M (품질과 크기의 황금 균형)
- 4~6GB VRAM 또는 RAM 추론 → Q4_K_S 또는 Q4_0
- 4GB 이하 초저사양 → Q3_K_M (품질 손실 감수)
llama.cpp로 추론하기
먼저 llama.cpp를 빌드한다.
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
# CPU 전용
cmake -B build && cmake --build build -j8
# CUDA (NVIDIA GPU)
cmake -B build -DGGML_CUDA=ON && cmake --build build -j8
Hugging Face에서 GGUF 파일을 다운로드한다.
pip install huggingface-hub
huggingface-cli download \
bartowski/Meta-Llama-3.1-8B-Instruct-GGUF \
Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf \
--local-dir ./models
명령줄에서 바로 추론한다.
./build/bin/llama-cli \
-m models/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf \
-p "한국의 수도는?" \
-n 128 \
--temp 0.7 \
-ngl 33 # GPU 레이어 수 (전체 오프로드)
Python에서 llama-cpp-python 활용
Python 바인딩으로 애플리케이션에 직접 통합할 수 있다.
from llama_cpp import Llama
llm = Llama(
model_path="models/Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf",
n_gpu_layers=33, # GPU에 올릴 레이어 수 (-1=전체)
n_ctx=4096, # 컨텍스트 길이
n_batch=512, # 배치 크기
verbose=False,
)
response = llm.create_chat_completion(
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Python의 GIL이란 무엇인가요?"},
],
max_tokens=512,
temperature=0.7,
stream=False,
)
print(response["choices"][0]["message"]["content"])
스트리밍 응답도 간단하다.
for chunk in llm.create_chat_completion(
messages=[{"role": "user", "content": "피타고라스 정리를 설명해줘"}],
stream=True,
):
delta = chunk["choices"][0]["delta"]
if "content" in delta:
print(delta["content"], end="", flush=True)
직접 GGUF로 변환하기
Hugging Face 형식 모델을 GGUF로 변환할 수 있다.
# 의존성 설치
pip install -r requirements.txt
# 변환 (F16 먼저)
python convert_hf_to_gguf.py \
./my-finetuned-model \
--outtype f16 \
--outfile ./my-model-f16.gguf
# 양자화 적용
./build/bin/llama-quantize \
./my-model-f16.gguf \
./my-model-Q4_K_M.gguf \
Q4_K_M
GGUF 메타데이터 직접 읽기
gguf Python 패키지로 파일을 열지 않고도 메타데이터를 확인할 수 있다.
pip install gguf
from gguf import GGUFReader
reader = GGUFReader("Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf")
# 주요 메타데이터 출력
for key in ["general.name", "llama.context_length",
"llama.block_count", "llama.embedding_length"]:
if key in reader.fields:
print(f"{key}: {reader.fields[key].parts[-1]}")
# 텐서 통계
total_params = 0
for t in reader.tensors:
params = 1
for d in t.shape:
params *= d
total_params += params
print(f"총 파라미터: {total_params/1e9:.2f}B")
정리
GGUF는 로컬 LLM 추론의 사실상 표준 포맷이다. 핵심을 요약하면:
- 단일 파일: 토크나이저부터 가중치까지 전부 포함
- K-Quant: 중요 레이어에 상위 비트, 나머지에 하위 비트를 혼합해 같은 크기에서 더 높은 품질
- Q4_K_M: 7B 모델에서 4GB대 크기에 94% 품질을 달성하는 범용 최선택
- mmap: 대용량 모델도 디스크에서 직접 읽어 RAM 사용량 최적화
다음 글에서는 GGUF와 함께 INT4 양자화의 양대 산맥인 AWQ와 GPTQ의 알고리즘 원리와 실전 비교를 다룬다.
지난 글: 양자화 완전 정복: 모델 크기를 절반으로 줄이는 기술
다음 글: AWQ vs GPTQ: 고급 INT4 양자화 완전 비교
읽어주셔서 감사합니다. 😊

