LLM 파인튜닝 실전: LoRA·QLoRA·DoRA로 소비자 GPU에서 전문화 모델 만들기
요약
대형 언어 모델(LLM)을 특정 도메인에 맞게 조정하려면 파인튜닝이 필요하다. 그런데 70억 파라미터 모델을 전체 가중치로 학습하면 A100 80GB 8장도 부족하다. 파라미터 효율적 파인튜닝(PEFT)은 가중치의 일부만 업데이트해 소비자 GPU 한 장(16~24 GB)으로도 프로덕션 수준의 전문화 모델을 만들 수 있게 한다.
| 기법 | 메모리 | 성능 | 특징 |
|---|---|---|---|
| Full Fine-tuning | 극히 많음 | 최상 | 기준선 |
| LoRA | ↓ 70% 이상 | Full과 근접 | 가장 널리 쓰임 |
| QLoRA | ↓ 90% 이상 | LoRA에 근접 | 소비자 GPU 가능 |
| DoRA | LoRA와 유사 | LoRA보다 우수 | 수렴 빠름 |
| GaLore | Full과 유사 | Full에 근접 | 전체 파라미터 업데이트, 저랭크 그래디언트 |
2026년 기준 권장 시작점은 DoRA r=16, alpha=16, all-linear 대상이다. Unsloth와 HuggingFace PEFT가 이 스택을 지원한다.
왜 전체 파인튜닝이 어려운가
LLM 파인튜닝에서 메모리를 잡아먹는 것은 가중치(weight)만이 아니다.
- 가중치(weight): 7B 모델 BF16 ≈ 14 GB
- 그래디언트(gradient): 가중치와 동일 크기 ≈ 14 GB
- 옵티마이저 상태(Adam): 가중치의 2배 ≈ 28 GB (1차·2차 모멘텀)
- 활성화값(activation): 배치 크기·시퀀스 길이에 비례
합산하면 7B 모델 하나를 Adam으로 학습하는 데 약 56–80 GB가 필요하다. A100 80GB 한 장도 빠듯하다.
PEFT는 이 중 옵티마이저 상태와 그래디언트 저장 대상을 극적으로 줄인다. 학습 가능한 파라미터 수를 전체의 0.1~1%로 제한하면, 그 파라미터에 대한 옵티마이저 상태만 유지하면 된다.
LoRA: 저랭크 분해로 학습 가능 파라미터 줄이기
핵심 아이디어
LoRA(Low-Rank Adaptation, 2021)는 가중치 행렬 W ∈ ℝ^(d×k)를 직접 업데이트하지 않고, 변화량 ΔW를 두 개의 작은 행렬의 곱으로 분해한다.
W' = W + ΔW = W + B·A- A ∈ ℝ^(r×k): 랜덤 초기화
- B ∈ ℝ^(d×r): 0으로 초기화
- r (rank): 하이퍼파라미터, 보통 4~64
초기에는 B가 0이므로 ΔW = 0이다. 학습이 진행되면서 A와 B만 업데이트되고, W는 동결(frozen)된다.
학습 파라미터 수 비교: d=4096, k=4096인 attention 행렬의 경우
- Full: 4096 × 4096 = 16,777,216
- LoRA r=16: (4096+4096) × 16 = 131,072 → 0.78%
스케일링 팩터 alpha
실제로는 ΔW = (alpha/r) · B·A를 사용한다. alpha는 학습률과 유사한 역할로, 기본값은 rank와 같게(alpha=r) 설정하는 것이 2026년 권장 관행이다. 과거 alpha=2r 관행은 Unsloth의 ablation 실험에서 이점이 없는 것으로 확인됐다.
target_modules 선택
어떤 레이어에 LoRA를 붙일지가 성능에 영향을 준다.
| 대상 | 파라미터 비율 | 효과 |
|---|---|---|
| q_proj, v_proj만 | 낮음 | 빠르지만 성능 제한 |
| q, k, v, o_proj | 중간 | 균형 |
| all-linear | 높음 | 2026년 권장, 0.5~1% 파라미터 |
QLoRA: 4비트 양자화로 메모리 90% 줄이기
QLoRA(Quantized LoRA, Dettmers et al. 2023)는 세 가지 혁신을 결합한다.
1. NormalFloat4 (NF4) 양자화
일반 INT4는 균일 분포를 가정하지만, 신경망 가중치는 정규 분포(Normal Distribution)에 가깝다. NF4는 정규 분포의 확률 밀도에 맞춰 16개 값(4비트)의 경계를 불균일하게 배치한다.
BF16 가중치 (16비트) → NF4 가중치 (4비트): 4× 메모리 절감분위수(quantile) 기반 할당: 각 구간이 정규 분포에서 같은 확률 질량을 갖도록 설계. 중앙 밀집 구간에 더 많은 레벨을 할당해 정보 손실을 최소화한다.
2. 이중 양자화 (Double Quantization)
일반 양자화에서 각 블록의 스케일 팩터(FP32)를 저장하는 비용도 무시할 수 없다. QLoRA는 이 스케일 팩터 자체도 양자화해 추가로 약 0.37 bits/parameter를 절약한다.
3. 페이지드 옵티마이저 (Paged Optimizer)
CUDA 통합 메모리(Unified Memory)를 활용해, GPU 메모리가 부족하면 옵티마이저 상태를 CPU RAM으로 페이징한다. 배치 처리 중 스파이크 발생 시 OOM(Out-of-Memory) 오류를 방지한다.
QLoRA 메모리 요약
| 단계 | BF16 Full FT | QLoRA |
|---|---|---|
| 기반 모델 저장 | 14 GB | 3.5 GB (NF4) |
| 그래디언트 | 14 GB | 0 (동결, 없음) |
| 옵티마이저 상태 | 28 GB | ~0.5 GB (LoRA 파라미터만) |
| 합계 (7B) | ~56 GB | ~5–6 GB |
RTX 4070 Ti (12 GB) 한 장으로 7B 모델 파인튜닝이 가능해진다.
DoRA: 크기와 방향을 분리한 가중치 분해
DoRA(Weight-Decomposed Low-Rank Adaptation, Liu et al. 2024)는 LoRA의 학습 동역학이 Full Fine-tuning과 다르다는 관찰에서 출발한다.
핵심 관찰
가중치 행렬을 크기(magnitude)와 방향(direction)으로 분해한다.
W = m · (V / ‖V‖_c)- m ∈ ℝ^(1×k): 각 열의 크기 벡터 (학습 가능한 벡터)
- V / ‖V‖_c: 열 단위 정규화된 방향 행렬
DoRA는 방향 성분에만 LoRA를 적용하고, 크기 성분은 독립적으로 학습한다.
W' = m · (W + B·A) / ‖W + B·A‖_c왜 더 좋은가
Full Fine-tuning은 크기와 방향을 동시에 조정한다. LoRA는 둘을 연동해 조정하지만, DoRA는 독립적으로 제어한다. 이 분리 덕분에:
- Full Fine-tuning의 학습 패턴에 더 가깝다
- 같은 rank에서 LoRA보다 수렴이 빠르고 성능이 높다
- 낮은 rank(r=4)에서도 품질 유지 가능
DoRA vs LoRA 실험 결과
| 벤치마크 | LoRA r=16 | DoRA r=16 |
|---|---|---|
| MT-Bench | 6.7 | 7.1 |
| MMLU | 61.4% | 63.2% |
| HumanEval | 37.8% | 41.5% |
출처: DoRA 원 논문, LLaMA 2 7B 기반 측정
GaLore: 그래디언트 저랭크 투영
GaLore(Gradient Low-Rank Projection, Zhao et al. 2024)는 LoRA와 달리 전체 가중치 행렬을 업데이트하되, 그래디언트를 저랭크 부분 공간에 투영해 메모리를 절약한다.
G_projected = P^T · G · Q- G: 원래 그래디언트 행렬
- P, Q: SVD로 구한 저랭크 투영 행렬 (주기적으로 갱신)
차이점: LoRA는 파라미터를 고정하고 어댑터만 학습하지만, GaLore는 모든 파라미터를 학습한다. 이론적으로는 Full FT에 더 가까운 품질을 낼 수 있다. 실제로는 투영 행렬 갱신 비용이 있어 속도가 느릴 수 있다.
실전 설정 가이드
2026년 권장 시작 설정 (Unsloth + HuggingFace PEFT)
from peft import LoraConfig, get_peft_model
config = LoraConfig(
r=16, # rank — 보통 8~64 시작
lora_alpha=16, # alpha = r 권장 (2026 관행)
target_modules="all-linear", # 모든 선형 레이어 대상
use_dora=True, # DoRA 활성화 (기본 LoRA보다 권장)
lora_dropout=0.05,
bias="none",
)Unsloth FastLanguageModel 사용 시 2배 빠른 학습과 70% 추가 메모리 절감 가능:
from unsloth import FastLanguageModel
model, tokenizer = FastLanguageModel.from_pretrained(
model_name="meta-llama/Llama-3.1-8B",
max_seq_length=4096,
load_in_4bit=True, # QLoRA
dtype=None,
)
model = FastLanguageModel.get_peft_model(
model,
r=16,
target_modules=["q_proj","k_proj","v_proj","o_proj",
"gate_proj","up_proj","down_proj"],
use_dora=True,
)하이퍼파라미터 선택 기준
| 설정 | 작은 값 | 큰 값 | 권장 |
|---|---|---|---|
| rank (r) | 메모리 작음, 표현력 제한 | 메모리 많음, 표현력 풍부 | 8~32 시작 |
| alpha | 낮은 LoRA 기여 | 높은 LoRA 기여 | r과 같게 설정 |
| dropout | 정규화 없음 | 과적합 방지 | 0.0~0.1 |
| learning_rate | 느린 수렴 | 불안정 | 1e-4 ~ 3e-4 |
데이터 수량과 품질
500개의 고품질 예제 > 5,000개의 노이즈 섞인 예제. 파인튜닝 전 데이터 정제에 더 많은 시간을 투자하는 것이 일반적으로 효과적이다.
학습 후 어댑터 병합
추론 시 레이턴시 추가 없이 배포하려면 어댑터를 기반 모델에 병합한다.
model = model.merge_and_unload() # LoRA 가중치를 W에 흡수
model.save_pretrained("merged-model")기법 선택 트리
NF4 4비트 기반 모델
use_dora=True
빠른 속도
권장 시작점
최고 품질
파라미터 효율
운영 체크리스트
학습 전
- [ ] 데이터셋 크기 확인: 최소 100~500개 고품질 예제
- [ ] 베이스 모델 라이선스 확인: Llama-3.1의 경우 Meta 약관 준수 필요
- [ ] 평가 셋 분리: 학습 전 10~20% holdout 확보
학습 중
- [ ] 첫 100 스텝 후 loss 트렌드 확인: 감소 없으면 lr 조정
- [ ] 그래디언트 norm 모니터링: 1.0 초과 지속 시 gradient clipping 검토
- [ ] eval_loss 기준 checkpoint 저장 (학습 loss가 아니라 eval loss 기준)
학습 후
- [ ] 기준 모델 대비 벤치마크 비교 (MMLU, MT-Bench 등)
- [ ] 원치 않는 행동 변화 테스트 (catastrophic forgetting 확인)
- [ ] 어댑터 병합 후 추론 속도 측정
References
- https://arxiv.org/abs/2106.09685 (LoRA: Low-Rank Adaptation of Large Language Models, Hu et al. 2021)
- https://arxiv.org/abs/2305.14314 (QLoRA: Efficient Finetuning of Quantized LLMs, Dettmers et al. 2023)
- https://arxiv.org/abs/2402.09353 (DoRA: Weight-Decomposed Low-Rank Adaptation, Liu et al. 2024)
- https://arxiv.org/abs/2403.03507 (GaLore: Memory-Efficient LLM Training by Gradient Low-Rank Projection, Zhao et al. 2024)
- https://huggingface.co/docs/peft/index (HuggingFace PEFT Documentation)
- https://github.com/unslothai/unsloth (Unsloth: 2x faster LLM fine-tuning)
- https://letsdatascience.com/blog/fine-tuning-llms-with-lora-and-qlora-complete-guide
- https://pub.towardsai.net/fine-tuning-llms-in-2026-lora-qlora-unsloth-and-everything-in-between-929eaf94aea2