GGUF 완전 정복: llama.cpp의 양자화 포맷과 실전 사용법
GGUF 파일 구조, Q4_K_M·Q5_K_S 등 양자화 레벨의 차이, Hugging Face에서 모델 다운로드·변환·추론까지 실전 가이드.
지난 글에서 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 양자화 완전 비교
읽어주셔서 감사합니다. 😊