단 하나의 GPU와 3달러로 7B 모델을 파인튜닝하는 방법
요약
QLoRA 기술을 활용하여 단일 GPU와 저렴한 비용으로 7B 모델을 효율적으로 파인튜닝하는 방법을 설명합니다. 4비트 양자화와 저차원 어댑터를 통해 VRAM 사용량을 획기적으로 줄이는 원리를 다룹니다.
핵심 포인트
- QLoRA를 통해 16GB GPU 하나로 7B 모델 파인튜닝 가능
- NF4 데이터 타입을 사용하여 메모리 점유율을 약 4배 감소
- 이중 양자화와 페이지드 옵티마이저로 메모리 효율 극대화
- 전체 파인튜닝 대비 압도적으로 낮은 하드웨어 요구 사양
당신은 7B 모델을 파인튜닝(Fine-tuning)하려면 A100 서버 랙이 필요하다고 생각할지 모릅니다. 하지만 실제로는 16GB 카드 하나와 약 3달러 정도의 대여 컴퓨팅 비용이면 충분합니다. 이 두 믿음 사이의 간극 때문에 많은 팀이 시작조차 하지 못한 채 프로젝트 전체를 포기하고 있습니다.
당신이 필요하다고 생각하는 클러스터는 존재하지 않습니다
대부분의 엔지니어에게 오픈 모델을 파인튜닝하는 데 무엇이 필요한지 물어보면, "하드웨어가 없다"는 식의 답변을 듣게 됩니다. 그들은 전체 파인튜닝(Full fine-tuning)을 상상합니다. 모든 가중치(Weight)가 fp16 형식이고, 모든 파라미터(Parameter)에 대한 그래디언트(Gradients)와 옵티마이저 상태(Optimizer states)가 필요하며, 7B 모델이 첫 번째 배치(Batch)가 들어오기도 전에 VRAM 사용량이 100GB를 넘어서는 상황 말입니다.
그 계산은 실제로 맞으며, 이것이 바로 사람들이 포기하고 프론티어 API(Frontier API)를 대상으로 프롬프트 엔지니어링(Prompt engineering)으로 돌아가려는 본능적인 이유입니다.
하지만 당신은 이미 2023년에 해결된 문제를 풀고 있습니다. 전체 파인튜닝이 유일한 옵션은 아니며, 압도적으로 많은 실무 작업에서 그것은 잘못된 선택입니다. Tim Dettmers와 동료들이 도입한 QLoRA는 메모리 하한선을 대폭 낮추어, 65B 모델이 16비트 전체 파인튜닝 품질과 대등하면서도 단일 48GB GPU에 들어갈 수 있게 만들었습니다.
이를 실제로 배포하는 크기로 축소해 봅시다. 7B 파인튜닝은 16GB 카드에서 여유롭게 실행됩니다. 13B는 24GB 데스크톱 4090에 들어갑니다. 당신은 클러스터를 빌리는 것이 아닙니다. 오후 시간 동안 GPU 하나를 빌리는 것입니다.
왜 4비트면 충분한가, 그리고 메모리는 실제로 어디에 쓰이는가
전체 파인튜닝은 VRAM을 네 가지 요소에 사용합니다: 모델 가중치(Model weights), 그래디언트(Gradients), 옵티마이저 상태(Optimizer states), 그리고 활성화 값(Activations)입니다. QLoRA는 이 중 앞의 세 가지를 동시에 공략합니다.
비결은 깔끔한 분리에 있습니다. 베이스 모델(Base model)은 동결(Frozen)되어 4비트로 저장되며, 신경망이 실제로 가지는 정규 분포 가중치에 정보 이론적으로 최적인 NF4 (4-bit NormalFloat)라는 데이터 타입을 사용합니다. 이 4비트 형태는 저장 용도로만 사용됩니다. 순전파(Forward pass)와 역전파(Backward pass)를 위해 각 블록은 실행 중에 bf16으로 다시 역양자화(De-quantized)되므로, 연산은 고정밀도를 유지하면서도 휴지 상태의 메모리 점유율(Footprint)은 약 4배 감소합니다.
이 동결된 가중치(frozen weights)들에 대해서는 그래디언트(gradients)를 전혀 계산하지 않습니다. 대신, 각 선형 레이어(linear layer)에 결합된 작은 저차원 어댑터(low-rank adapter) 행렬을 학습시키는데, 이는 통상적으로 모델 파라미터의 1% 미만입니다. 전체 파인튜닝(full fine-tuning) 시 VRAM을 조용히 잡아먹는 주범인 옵티마이저 상태(Optimizer state)는 이제 이 아주 작은 어댑터들만을 차지하게 됩니다.
두 가지 작은 혁신이 그 격차를 줄여줍니다. 이중 양자화(Double quantization)는 양자화 상수(quantization constants) 자체를 양자화하여 파라미터당 약 0.37비트를 절약하며, 이는 65B 모델 기준으로 약 3GB에 해당합니다. 페이지드 옵티마이저(Paged optimizers)는 NVIDIA의 통합 메모리(unified memory)를 사용하여, 긴 시퀀스에서 발생할 수 있는 그래디언트 체크포인팅(gradient-checkpointing) 스파이크를 흡수함으로써 OOM(Out of Memory) 오류를 방지합니다.
그 결과는 단순히 참아야 하는 타협안이 아닙니다. 논문 자체의 MMLU 평가에서, 이중 양자화를 적용한 4비트 NF4는 LLaMA 7B부터 65B에 이르기까지 16비트 LoRA의 성능을 재현했습니다. 2026년의 독립적인 실행 결과에 따르면, QLoRA는 표준 벤치마크에서 전체 정밀도(full-precision) LoRA의 1~2% 이내 성능을 보여주었습니다. 측정 가능한 성능 면에서 거의 아무것도 포기할 필요가 없습니다.
실제 실행 비용
이 부분이 이론을 실제 실행 가능한 현실로 바꿔주는 대목입니다. 다음은 QLoRA 파인튜닝 시 베이스 모델, 어댑터 및 활성화 함수(activations)를 포함한 현실적인 4비트 VRAM 점유율(footprints)입니다:
- 7B: 16GB 카드에서 여유롭게 실행 가능
- 13B: 24GB 카드(데스크톱 RTX 4090)에 적합
- 30B ~ 32B: 약 40GB 카드가 필요
- 70B: 약 46GB로, 단일 48GB 카드에 적합
시퀀스 길이(Sequence length)와 배치 크기(batch size)에 따라 이 수치들이 변동되지만, 우려하시는 만큼 크게 변하지는 않습니다. Unsloth를 사용할 경우, 2048 토큰 시퀀스 길이의 8B 모델은 4090에서 예약된 VRAM이 약 6.6GB로 정점을 찍습니다. 여러분이 이미 보유하고 있을지도 모르는 하드웨어로도 충분한 여유 공간(headroom)이 있습니다.
동일한 7B 모델을 전체 파인튜닝 (full fine-tuning) 하는 것과 비교해 보십시오. 가중치 (Weights), 그래디언트 (gradients), 그리고 fp16 상태의 Adam 옵티마이저 상태 (optimizer states) 두 개를 합치면 활성화 함수 (activations)를 고려하기도 전에 이미 100GB를 훌쩍 넘어버립니다. 이는 여러 대의 80GB A100과 이를 조율하기 위한 멀티 GPU (multi-GPU) 설정이 필요함을 의미합니다. QLoRA는 요청을 통해 할당받아야 하는 클러스터(cluster)에서 수행하던 작업을, 초 단위로 대여할 수 있는 단일 카드 한 장으로 축소시킵니다. 4비트 저장 방식에 따른 4배의 용량 감소는 일부일 뿐입니다. 베이스 모델을 동결 (freezing)하고 1% 미만의 어댑터 (adapters)를 학습시키는 것이 옵티마이저 상태라는 거대한 산을 완전히 없애버리는 핵심입니다.
이제 시간과 비용을 따져봅시다. 7B 모델을 23 에포크 (epochs) 동안 QLoRA로 실행하면 A100에서는 약 24시간, RTX 4090에서는 6~8시간이 소요됩니다. RunPod의 커뮤니티 클라우드 (Community Cloud) 4090은 시간당 약 0.34 USD부터, A100 PCIe는 시간당 약 1.39 USD부터 초 단위로 과금됩니다.
계산을 해보십시오. 4090에서 7B 모델을 전체 파인튜닝 하면 약 2~3달러 정도가 듭니다. A100을 사용하면 비용을 조금 더 지불하는 대신 실제 시간 (wall-clock)을 절약하여 거의 비슷한 총비용으로 점심 식사 전에 작업을 마칠 수 있습니다. 여러분의 로드맵을 재정립해야 할 수치는 바로 이것입니다. 커스텀 모델을 만드는 것은 자본 요청 (capital request) 사항이 아니라, 커피 한 잔 값 정도의 비용 문제입니다.
한 번에 성공하는 레시피
도구들이 머릿속에 그려질 정도로 단순해졌습니다. bitsandbytes가 4비트 양자화 (quantization)를 처리하고, PEFT가 어댑터 (adapters)를 처리하며, Unsloth는 메모리를 절약하고 처리량 (throughput)을 대략 두 배로 높여주는 커널 (kernels)로 이 둘을 감쌉니다. 먼저 베이스 모델을 4비트로 로드하는 것부터 시작합니다.
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
...
만약 순수 Transformers 라이브러리를 그대로 사용하고 싶다면, 동일한 세 가지 개념인 NF4 저장, bf16 연산, 이중 양자화 (double quantization) 활성화를 인코딩하는 BitsAndBytesConfig를 사용하면 됩니다.
from transformers import BitsAndBytesConfig
import torch
...
다음으로 어댑터 (adapters)를 부착합니다. 가장 중요한 단 하나의 선택은 단순히 어텐션 투영 (attention projections)뿐만 아니라 모든 선형 레이어 (linear layers)를 타겟팅하는 것입니다. MLP 레이어를 건너뛰는 것은 뚜렷한 이유 없이 파인튜닝 성능이 저하되는 가장 흔한 원인입니다.
model = FastLanguageModel.get_peft_model(
model, r=16, lora_alpha=16,
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
...```
두 개의 하이퍼파라미터(hyperparameters)가 핵심적인 역할을 합니다. 랭크(Rank) $r$은 어댑터(adapter)의 용량을 제어합니다. 16은 강력한 기본값이며, 작업이 진정으로 복잡하다면 32를 사용합니다. 알파(alpha)의 경우, 기존의 `alpha = 2 * r` 관례가 여전히 유효하지만, Unsloth의 2026년 절제 연구(ablations) 결과에 따르면 `alpha = r`이 더 깔끔한 기본값임이 밝혀졌습니다. 그래디언트 체크포인팅(Gradient checkpointing)을 "unsloth"로 설정하면 메모리를 30% 더 절약할 수 있는데, 이는 모델이 메모리에 올라가느냐 아니냐를 결정짓는 결정적인 차이가 되곤 합니다.
다음은 훈련 인자(training arguments)입니다. 큰 배치 사이즈(batch size)보다는 그래디언트 누적(gradient accumulation)을 활용한 작은 배치 사이즈를 선호하십시오. 그래야 유효 배치 사이즈(effective batch size)를 건강한 범위인 4에서 16 사이로 유지하면서도 메모리 부족(out-of-memory) 오류를 피할 수 있기 때문입니다.
from trl import SFTConfig
args = SFTConfig(
...
이 설정은 일주일 동안 튜닝해야 할 시작 단계의 추측치가 아닙니다. 대부분의 지도 미세 조정(supervised fine-tuning) 작업에 있어 최종 결과물에 가까운 설정입니다. 학습률(Learning rate) 2e-4, 1~3 에포크(epochs), 유효 배치 16, 웜업(warmup) 약 5%를 권장합니다. 조절 나사(knobs)를 돌리지 말고 데이터를 바꾸십시오.
## 훈련된 어댑터에서 서빙 가능한 모델로
QLoRA 실행을 통해 얻는 결과물은 수 기가바이트(gigabyte)에 달하는 새로운 모델이 아닙니다. 그것은 어댑터(adapter)입니다. 즉, 동결된 베이스 모델(frozen base model) 위에 놓이는, 흔히 100MB 정도인 작은 저차원 행렬(low-rank matrices) 세트입니다. 이 작은 크기는 하나의 특징입니다. 하나의 베이스 모델에 대해 수십 개의 작업 특화 어댑터를 훈련할 수 있으며, 이들을 모두 저장하더라도 단일 전체 체크포인트(full checkpoint)의 용량보다 적게 차지합니다.
이를 서빙(serve)하는 방법에는 두 가지가 있습니다. 어댑터를 별도로 유지하여 런타임(runtime)에 베이스 모델 위에 로드하는 방식이 있는데, 이를 통해 동작을 핫스왑(hot-swap)할 수 있습니다. 또는 어댑터를 가중치(weights)에 병합(merge)하여 단일 독립형 모델로 만들 수도 있습니다. 대부분의 배포(deployment) 상황에서는 병합 후 내보내기(merge and export) 방식을 권장합니다.
model.save_pretrained_merged("llama-8b-support", tokenizer,
save_method="merged_16bit")
model.save_pretrained_gguf("llama-8b-support", tokenizer,
...
병합된 16비트 (16-bit) 버전은 프로덕션 엔드포인트 (production endpoint)를 위해 vLLM 또는 TGI로 즉시 투입할 수 있습니다. q4_k_m과 같은 방식으로 양자화 (quantized)된 GGUF 내보내기 파일은 GPU가 전혀 없는 노트북에서도 Ollama 또는 llama.cpp를 통해 실행할 수 있습니다. 어댑터 (adapter)를 생성한 바로 그날 오후에, 여러분의 개인 컴퓨터에서 모델이 요청에 응답하는 것으로 작업을 마무리할 수 있습니다.
추론 (inference) 시 주의할 점이 하나 있습니다. 메모리를 절약하기 위해 베이스 모델 (base model)을 4비트로 서빙한다면, 반드시 정확히 그 구성으로 평가하십시오. 16비트 병합 (merge) 상태에서 측정된 품질이 4비트 서빙 경로로 항상 깔끔하게 전이되는 것은 아니며, 그 격차는 배포한 후가 아니라 배포하기 전에 포착하는 것이 가장 쉽습니다.
## 파인튜닝 (fine-tune)이 정답이 아닌 경우
여러분의 3달러를 가장 빠르게 낭비하는 방법은 RAG가 해결해야 할 문제를 파인튜닝하는 것입니다. 2026년에는 질문이 더 이상 "RAG냐 파인튜닝이냐"가 아니라, 각 지능의 요소가 어디에 위치해야 하는가, 즉 가중치 (weights)에 둘 것인지, 검색 (retrieval)에 둘 것인지, 아니면 둘 다에 둘 것인지의 문제입니다.
지식이 자주 바뀌거나, 양이 방대하거나, 인용 (citations)이 필요하거나, 사용자마다 다르다면 검색 (retrieval)을 선택하십시오. 사실 관계, 문서, 가격 등 모델 내부에서 정보가 오래되어(stale) 부끄러운 상황이 생길 수 있는 모든 것은 재학습 (retraining) 없이 업데이트할 수 있는 벡터 스토어 (vector store)에 있어야 합니다. 파인튜닝은 특정 시점의 지식을 모델에 구워 넣는(bakes) 방식이기에, 역동적인 모든 것에는 취약점이 될 수 있습니다.
프롬프팅 (prompting)만으로는 신뢰성 있게 강제할 수 없는 일관된 동작이 필요할 때, 즉 고정된 출력 형식 (output format), 특정 어조 (tone)나 정책, 도메인 추론 (domain reasoning), 또는 매번 반드시 정확해야 하는 구조화된 출력 (structured output)이 필요할 때는 파인튜닝을 선택하십시오. 또한, 호출량이 충분히 많아 작은 파인튜닝 모델이 프런티어 모델 (frontier model)의 호출당 비용보다 경제적일 때, 혹은 지연 시간 (latency) 예산상 검색 단계를 거칠 여유가 없을 때도 파인튜닝이 유리합니다.
성숙한 패턴은 두 가지를 모두 사용하는 것입니다. 스타일, 형식, 결정 동작을 위해서는 파인튜닝을 하고, 사실 관계를 위해서는 검색을 수행하십시오. 원칙만을 내세워 한쪽만을 선택하는 팀은 각 문제를 그에 맞는 도구로 라우팅 (route)하는 팀보다 대개 더 나쁜 제품을 내놓게 됩니다.
## 아무도 경고하지 않는 실패 모드 (failure modes)
QLoRA는 관대한 편이지만, 세 가지 요소가 조용히 실행 과정을 망쳐놓습니다.
과적합 (Overfitting)이 가장 큰 문제이며, 이는 성공처럼 보이는 지표 속에 숨어 있습니다. 만약 훈련 손실 (training loss)이 0.2 미만으로 떨어진다면, 모델이 데이터를 암기했을 가능성이 높으며 일반화 (generalization) 성능은 더 좋아지는 것이 아니라 오히려 나빠질 것입니다. 그런 현상이 보이면 에포크 (epochs)를 줄이거나, 가중치 감쇠 (weight decay)를 높이거나, 알파 (alpha) 값을 절반으로 낮추세요. 3 에포크를 넘기는 것은 거의 항상 일반화 성능을 희생하여 더 예쁜 손실 곡선을 얻는 결과로 이어집니다.
두 번째는 손실 곡선 (loss curve)을 전적으로 신뢰하는 것입니다. 하락하는 손실 곡선이 곧 작동하는 모델을 의미하지는 않습니다. 실제 작업을 반영하는 별도의 평가 데이터셋 (held-out eval)이 필요하며, 이를 전후로 확인하지 않는다면 눈을 가리고 비행하는 것과 같습니다. 도메인 특화 평가 (Domain-specific evaluation)는 베이스 모델이 광고하는 그 어떤 일반적인 벤치마크 점수보다 훨씬 더 중요합니다.
세 번째는 미묘한 용량 불일치 (capacity mismatch)입니다. 만약 파인튜닝 성능이 떨어지는데 데이터가 깨끗하다면, 원인은 방법론의 실패가 아니라 대개 랭크 (rank)를 너무 낮게 설정했거나 타겟 모듈 (target modules)을 너무 좁게 설정했기 때문입니다. QLoRA가 당신의 작업을 학습할 수 없다고 결론 내리기 전에, r 값을 32로 높이고 모든 선형 레이어 (linear layer)를 타겟팅하고 있는지 확인하십시오.
알아둘 만한 선택적인 업그레이드가 하나 있습니다: DoRA (weight-decomposed low-rank adaptation)는 약간의 속도 비용을 대가로 낮은 랭크에서도 종종 조금 더 높은 정확도를 뽑아냅니다. 일반적인 레시피가 작동한 후에 시도해 보되, 그 전에는 하지 마세요.
## 마치며
이 내용을 내재화해야 하는 이유는 파인튜닝이 유행이기 때문이 아닙니다. 시도하는 데 드는 비용이 바닥까지 떨어졌기 때문이며, 시도 비용이야말로 당신이 얼마나 많은 실험을 할 수 있는지를 결정하기 때문입니다.
커스텀 7B 모델을 만드는 데 단돈 3달러와 오후 한나절이 걸린다면, 파인튜닝은 승인을 받아야 하는 분기별 프로젝트가 아니라, 데일리 스탠드업 미팅 전에 직감에 따라 두어 번 해볼 수 있는 일이 됩니다. 이는 어떤 아이디어가 테스트할 가치가 있는지를 변화시킵니다. 저렴한 파인튜닝을 10번 수행하고 그중 작동하는 2개를 남기는 팀이, 여전히 GPU 예산을 기다리고 있는 팀보다 훨씬 더 빠르게 반복 (iterate)할 것입니다.
당신의 프런티어 API (frontier API)가 미묘하게 계속 틀리는, 좁고 형식이 중요한 작업 하나를 선택하세요. 저녁 한때 동안 4090을 대여하십시오. 최악의 경우라도 커피 한 잔 가격으로 당신의 데이터에 대해 구체적인 무언가를 배우게 될 것입니다.
## 리소스 및 참고 문헌
- QLoRA: Efficient Finetuning of Quantized LLMs (Dettmers et al., arXiv)
- LoRA Fine-Tuning Hyperparameters Guide (Unsloth Documentation)
- Making LLMs Even More Accessible with 4-bit Quantization and bitsandbytes (Hugging Face)
- 2026년 LLM 파인튜닝을 위한 GPU VRAM 요구 사항: Full, LoRA, 및 QLoRA 크기 산정 (Spheron)
- 2026년 LLM을 위한 RAG vs 파인튜닝 (Fine-Tuning): 실제 프로덕션에서 작동하는 것은 무엇인가
_원문은 [Medium](https://medium.com/@sebuzdugan/how-to-fine-tune-a-7b-model-for-three-dollars-on-one-gpu-432eb04ba010)에 게시되었습니다._
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기