LLM 파인튜닝 방법 비교: Full vs LoRA vs QLoRA 선택 가이드 2026
LLM 파인튜닝 방법을 Full Fine-tuning·LoRA·QLoRA로 비교합니다. GPU 메모리 계산식(파라미터당 16바이트), QLoRA의 NF4·이중 양자화·페이지드 옵티마이저 원리, LoRA 하이퍼파라미터(r·alpha·target_modules) 권장값 표, PEFT 학습 코드 예제, 목표별 최소 데이터 규모, 어댑터 병합 여부 판단까지 실행 기준으로 정리했습니다.
LLM 파인튜닝은 GPT나 Claude 같은 사전학습 모델을 자사 데이터로 추가 학습시켜 특정 도메인에 맞게 특화하는 기술입니다. 그런데 "파인튜닝을 한다"는 말 안에는 사실 서로 다른 방법이 여러 개 숨어 있습니다. 모델의 모든 가중치를 다시 학습하는 Full Fine-tuning, 작은 어댑터 행렬만 학습하는 LoRA, 여기에 4비트 양자화를 더해 GPU 한 장에서도 돌리는 QLoRA가 대표적입니다. 어떤 방법을 고르느냐에 따라 필요한 GPU, 학습 비용, 품질, 운영 난이도가 적게는 두세 배에서 많게는 열 배까지 차이 납니다. 이 글은 "파인튜닝을 할지 말지"가 아니라 "어떤 파인튜닝 방법을 쓸지"에 초점을 맞춰, 세 가지 대표 방법을 GPU 메모리·학습 속도·품질·적합 데이터 규모 기준으로 비교하고 상황별 선택 기준을 정리했습니다.
파인튜닝 방법은 왜 하나가 아닐까?
2020년대 초만 해도 파인튜닝은 곧 Full Fine-tuning을 의미했습니다. 모델 전체를 자사 데이터로 다시 학습시키는 방식이죠. 그런데 모델 크기가 수십억~수천억 파라미터로 커지면서 문제가 생겼습니다. 7B(70억 파라미터) 모델 하나를 통째로 학습하려면 고가의 GPU 여러 장과 막대한 시간이 들어가고, 체크포인트를 저장할 때마다 모델 전체를 복사해야 합니다.
그래서 등장한 것이 PEFT(Parameter-Efficient Fine-Tuning, 파라미터 효율 파인튜닝) 계열입니다. 모델 가중치 대부분을 그대로 두고 아주 일부만 학습해서, 같은 효과를 훨씬 적은 자원으로 내는 접근입니다. LoRA와 QLoRA가 여기에 속합니다. 즉 오늘날 "파인튜닝 방법 선택"이란 사실상 전체를 학습할지(Full), 일부만 효율적으로 학습할지(PEFT) 를 고르는 문제에 가깝습니다.
Full Fine-tuning: 모델 전체를 다시 학습한다
Full Fine-tuning은 사전학습된 모델의 모든 가중치를 학습 대상으로 삼습니다. 이론적으로 표현력이 가장 크기 때문에, 베이스 모델과 도메인 차이가 매우 크거나(예: 특수 의료·법률 코퍼스) 데이터가 충분할 때 최고 품질을 낼 수 있습니다.
대가는 비용입니다. fp16 기준으로 7B 모델을 학습하려면 모델 가중치뿐 아니라 옵티마이저 상태와 그래디언트까지 메모리에 올려야 해서, 일반적으로 모델 크기의 수 배에 해당하는 GPU 메모리가 필요합니다. 데이터가 적을 때는 기존에 학습된 능력을 잊어버리는 카타스트로픽 포게팅(catastrophic forgetting) 위험도 큽니다.
- 적합한 상황: 데이터가 수만~수십만 샘플 이상, 대규모 GPU 확보 가능, 도메인이 베이스 모델과 크게 다름
- 피해야 할 상황: 데이터 수천 건 이하, 단일 GPU, 빠른 반복 실험이 필요한 초기 단계
Full Fine-tuning에 실제로 필요한 GPU 메모리는 얼마인가
"메모리가 많이 든다"는 말은 견적을 내는 데 쓸 수 없습니다. 숫자로 계산할 수 있습니다.
혼합정밀(bf16) + AdamW 조합으로 Full Fine-tuning을 하면, 파라미터 하나당 다음이 동시에 메모리에 올라가 있어야 합니다.
| 메모리 항목 | 파라미터당 바이트 | 7B 모델 환산 |
|---|---|---|
| 모델 가중치(bf16) | 2 | 약 14 GB |
| 그래디언트(bf16) | 2 | 약 14 GB |
| AdamW 1차 모멘트(fp32) | 4 | 약 28 GB |
| AdamW 2차 모멘트(fp32) | 4 | 약 28 GB |
| fp32 마스터 가중치 | 4 | 약 28 GB |
| 합계(활성화 제외) | 16 | 약 112 GB |
여기에 배치 크기와 시퀀스 길이에 비례하는 활성화(activation) 메모리가 더 붙습니다. 그래디언트 체크포인팅으로 활성화를 줄일 수는 있지만, 위 112GB는 줄지 않습니다. 80GB짜리 H100 한 장에 7B 모델의 Full Fine-tuning이 들어가지 않는 이유가 이것입니다. 실무에서는 ZeRO-3나 FSDP로 옵티마이저 상태를 여러 GPU에 쪼개 담는 방식으로 풀고, 그래서 "GPU 여러 장"이 조건이 됩니다.
같은 계산을 LoRA와 QLoRA에 적용하면 구조가 완전히 달라집니다.
| 방식 | 베이스 모델 | 그래디언트·옵티마이저 대상 | 7B 기준 대략치 |
|---|---|---|---|
| Full FT | bf16 (2 B/param) | 전체 파라미터 | 112 GB + 활성화 |
| LoRA | bf16 동결 (2 B/param) | 어댑터 파라미터만 | 14 GB + 소량 + 활성화 |
| QLoRA | NF4 동결 (약 0.5 B/param) | 어댑터 파라미터만 | 4 GB 내외 + 소량 + 활성화 |
핵심은 옵티마이저 상태가 학습 대상 파라미터에만 붙는다는 점입니다. LoRA로 학습 대상이 전체의 0.5%로 줄면, 파라미터당 14바이트를 차지하던 그래디언트·옵티마이저 항목도 같은 비율로 줄어듭니다. 메모리 절감이 "어댑터가 작아서"가 아니라 "옵티마이저가 작아져서" 생긴다는 것이 이 표가 말하는 바입니다.
LoRA: 작은 어댑터만 학습하는 효율적 방법
LoRA(Low-Rank Adaptation)는 원본 가중치를 동결(freeze) 해 두고, 각 레이어에 저랭크(low-rank) 행렬 두 개(A·B)만 새로 붙여 그것만 학습합니다. 학습 대상 파라미터가 전체의 0.1~1% 수준으로 줄어들어, 메모리와 시간이 크게 절감됩니다. 결과물도 원본 모델이 아니라 수 MB~수십 MB짜리 어댑터 파일로 저장되므로, 하나의 베이스 모델에 여러 어댑터를 갈아 끼우는 운용이 가능합니다. LoRA의 원리와 효과는 LoRA 논문(Hu et al., 2021)에 자세히 정리되어 있습니다.
- 적합한 상황: 중소 규모 데이터, 단일~소수 GPU, 여러 태스크용 어댑터를 따로 관리하고 싶을 때
- 장점: 빠른 실험 사이클, 작은 저장 용량, 베이스 모델 공유
LoRA 하이퍼파라미터: r·alpha·dropout·target_modules를 어떻게 정하나
LoRA를 쓰기로 정한 다음에 실제로 손이 멈추는 지점은 설정값입니다. 네 개만 이해하면 나머지는 기본값으로 둬도 됩니다.
r (랭크) — 어댑터 행렬 A·B의 내부 차원입니다. r이 클수록 표현력이 늘고 학습 파라미터도 비례해 늘어납니다. 원 논문은 태스크 적응 수준이라면 r=8에서도 충분하다고 보고했고, 실무에서는 지시 튜닝처럼 학습 범위가 넓을 때 16~64를 씁니다. r을 32에서 64로 올렸는데 검증 손실이 그대로라면 데이터가 부족한 것이지 랭크가 부족한 것이 아닙니다.
alpha (스케일링 계수) — 어댑터 출력에 alpha / r 배율이 곱해집니다. 즉 alpha는 r과 짝으로만 의미가 있습니다. r을 두 배로 올리면서 alpha를 그대로 두면 실효 학습률이 절반으로 떨어집니다. 관행적으로 alpha = 2r 또는 alpha = r을 쓰고, r을 바꿀 때 alpha도 같이 바꿔 배율을 고정합니다.
lora_dropout — 어댑터 입력에 적용하는 드롭아웃입니다. 데이터가 수천 건 규모로 적을 때 0.05~0.1을 주면 과적합이 눈에 띄게 줄어듭니다. 수만 건 이상이면 0으로 두는 편이 낫습니다.
target_modules — 어느 선형 레이어에 어댑터를 붙일지입니다. 여기가 r보다 결과를 더 크게 가릅니다. 초기 구현들은 어텐션의 q_proj·v_proj에만 붙였는데, QLoRA 논문은 어텐션과 FFN을 포함한 모든 선형 레이어에 붙이는 것이 Full Fine-tuning 품질을 따라잡는 데 결정적이라고 보고했습니다. 품질이 안 나올 때 r부터 올리는 것은 대개 잘못된 순서이고, target_modules를 먼저 넓혀야 합니다.
| 설정 | 소규모 스타일·말투 교정 | 도메인 지식·지시 튜닝 | 품질 상한 추구 |
|---|---|---|---|
| r | 8 | 16~32 | 64 |
| alpha | 16 | 32~64 | 128 |
| lora_dropout | 0.05~0.1 | 0.05 | 0 |
| target_modules | q_proj, v_proj | 어텐션 4종 전부 | 어텐션 + FFN 전 선형층 |
| learning rate | 1e-4 | 1e-4 ~ 2e-4 | 2e-4 |
| epoch | 2~3 | 2~3 | 3~4 |
학습률은 Full Fine-tuning과 자릿수가 다릅니다. Full은 1e-5~2e-5대를 쓰지만 LoRA는 1e-4~2e-4, 즉 열 배가량 높게 잡습니다. 동결된 본체는 움직이지 않고 새로 초기화된 어댑터만 학습하기 때문입니다. Full 기준 학습률을 그대로 가져오면 "학습이 안 되는 것처럼 보이는" 전형적인 실패가 납니다.
QLoRA: 4비트 양자화로 GPU 한 장에서
QLoRA는 LoRA에 양자화(quantization) 를 결합한 방법입니다. 베이스 모델을 4비트(NF4)로 압축해 메모리에 올린 뒤, 그 위에서 LoRA 어댑터만 학습합니다. QLoRA 논문(Dettmers et al., 2023)에 따르면 65B 규모 모델도 단일 48GB GPU 한 장에서 파인튜닝하면서 품질 손실을 최소화할 수 있습니다.
덕분에 예산이 빠듯한 팀이나 큰 모델을 다뤄야 하는 상황에서 현실적인 선택지가 됩니다. 다만 4비트로 압축된 상태이므로, 추론 단계에서 양자화 방식과 속도·품질 트레이드오프를 별도로 점검해야 합니다.
- 적합한 상황: GPU 예산 제약, 큰 모델 파인튜닝, 개인·소규모 팀
- 주의: 추론 환경의 양자화 호환성과 지연시간 검증 필요
QLoRA는 정확히 무엇을 4비트로 바꾸는가
QLoRA를 "4비트로 줄여서 메모리를 아끼는 방법" 정도로 이해하면, 언제 써도 되고 언제 쓰면 안 되는지 판단할 수 없습니다. QLoRA는 서로 다른 세 가지 기법의 묶음이고, 각각이 다른 문제를 풉니다.
1) NF4 — 정규분포에 맞춘 4비트 자료형. 일반적인 4비트 정수 양자화는 값 구간을 균등하게 16칸으로 나눕니다. 그런데 학습된 신경망 가중치는 0 근처에 몰린 정규분포를 따릅니다. 균등하게 나누면 가중치가 거의 없는 바깥 구간에 표현력을 낭비하게 됩니다. NF4(4-bit NormalFloat)는 정규분포의 분위수를 기준으로 16칸을 배치해, 각 칸에 들어가는 가중치 개수가 비슷해지도록 만듭니다. 같은 4비트인데 정보 손실이 더 적은 이유가 이것입니다. 양자화는 블록 단위(기본 64개 가중치)로 수행하며, 블록마다 스케일 상수를 따로 갖습니다.
2) 이중 양자화(Double Quantization) — 상수까지 압축. 블록마다 스케일 상수를 fp32로 들고 있으면, 블록 64개당 4바이트가 추가로 듭니다. 파라미터 하나당 0.5비트에 해당하는 무시할 수 없는 양입니다. 이중 양자화는 이 상수들을 다시 한 번 8비트로 양자화해서 파라미터당 평균 약 0.37비트를 회수합니다. 65B 모델 기준으로 3GB 가까이가 여기서 나옵니다.
3) 페이지드 옵티마이저(Paged Optimizers) — OOM으로 죽지 않게. 긴 시퀀스가 들어오면 그래디언트 체크포인팅 구간에서 메모리가 순간적으로 치솟습니다. 평균 사용량은 여유가 있는데 스파이크 한 번에 학습이 통째로 죽는 상황이죠. 페이지드 옵티마이저는 NVIDIA 통합 메모리를 써서 옵티마이저 상태를 필요할 때 CPU RAM으로 잠시 내보냈다가 다시 가져옵니다. 운영체제의 페이징과 같은 발상입니다. 메모리를 줄이는 기법이 아니라 학습이 끝까지 돌아가게 만드는 기법이라는 점이 앞의 둘과 다릅니다.
이 셋을 합친 결과가 QLoRA 논문(Dettmers et al., 2023)이 보고한 수치입니다. 65B 모델을 48GB GPU 한 장에서, 33B 모델을 24GB 한 장에서 파인튜닝하면서 16비트 Full Fine-tuning 대비 품질 손실을 거의 내지 않았습니다.
그럼에도 QLoRA를 피해야 할 때가 있습니다. 베이스 모델이 NF4로 압축된 채 연산되므로 순전파마다 역양자화가 일어나고, 그만큼 같은 GPU에서도 LoRA보다 학습 속도가 느립니다. 메모리가 이미 충분한데 QLoRA를 쓰면 얻는 것 없이 시간만 더 쓰는 셈입니다. 판단 기준은 단순합니다 — LoRA가 메모리에 들어가면 LoRA를 쓰고, 안 들어갈 때 QLoRA를 씁니다.
방법별 비교표: 한눈에 보는 차이
| 항목 | Full Fine-tuning | LoRA | QLoRA |
|---|---|---|---|
| 학습 파라미터 비율 | 100% | 약 0.1~1% | 약 0.1~1% |
| GPU 메모리(7B 기준) | 매우 높음 | 중간 | 가장 낮음 |
| 학습 속도/비용 | 가장 높음 | 낮음 | 낮음 |
| 결과물 크기 | 모델 전체(수십 GB) | 어댑터(수 MB~) | 어댑터(수 MB~) |
| 품질 상한 | 최고 | 높음(대부분 충분) | 높음(약간의 양자화 영향) |
| 적합 데이터 규모 | 대규모 | 중소~대규모 | 중소~대규모 |
| 운영 난이도 | 높음 | 낮음 | 중간 |
수치는 모델·세팅에 따라 달라지는 일반적인 경향이며, 실제 프로젝트에서는 베이스 모델과 데이터로 소규모 사전 실험을 돌려 확인하는 것이 가장 정확합니다.
내 상황에는 어떤 방법이 맞을까?
복잡해 보이지만 의사결정은 의외로 단순합니다.
- 데이터가 1만 건 미만이고 GPU가 한두 장뿐이다 → QLoRA로 시작하세요. 가장 적은 자원으로 결과를 빠르게 확인할 수 있습니다.
- 여러 도메인/고객사별로 다른 동작이 필요하다 → LoRA로 어댑터를 도메인별로 만들어 두고 교체해 쓰는 구조가 유리합니다.
- 데이터가 충분하고(수만 건+) 멀티 GPU가 있으며 마지막 한 방울의 품질까지 필요하다 → Full Fine-tuning을 검토하세요. 단, LoRA로도 목표 품질이 나오는 경우가 많으니 먼저 비교 실험을 권합니다.
2026년 현재 실무에서는 대부분의 프로젝트가 LoRA 또는 QLoRA로 시작합니다. Full Fine-tuning은 "정말 전체 학습이 필요하다"는 명확한 근거가 있을 때 선택하는 쪽으로 무게가 옮겨졌습니다.
PEFT로 LoRA 파인튜닝을 돌리는 최소 예제
설명만으로는 감이 안 잡히므로, 실제로 돌아가는 최소 구성을 봅니다. Hugging Face의 transformers + peft + trl 조합이 사실상 표준입니다.
먼저 학습 데이터입니다. 지시 튜닝이라면 JSONL 한 줄에 대화 한 건을 담는 형식이 가장 무난합니다.
{"messages": [{"role": "user", "content": "반품 규정 알려줘"}, {"role": "assistant", "content": "구매 후 7일 이내 미개봉 상품에 한해 무료 반품이 가능합니다."}]}
{"messages": [{"role": "user", "content": "배송 얼마나 걸려요"}, {"role": "assistant", "content": "결제 완료 기준 영업일 2~3일 소요되며, 도서산간은 1~2일이 추가됩니다."}]}학습 스크립트는 다음 형태입니다.
from datasets import load_dataset
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig
from peft import LoraConfig
from trl import SFTTrainer, SFTConfig
import torch
model_id = "Qwen/Qwen2.5-7B-Instruct"
bnb = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_use_double_quant=True,
bnb_4bit_compute_dtype=torch.bfloat16,
)
model = AutoModelForCausalLM.from_pretrained(
model_id, quantization_config=bnb, device_map="auto"
)
tokenizer = AutoTokenizer.from_pretrained(model_id)
peft_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=["q_proj", "k_proj", "v_proj", "o_proj",
"gate_proj", "up_proj", "down_proj"],
)
args = SFTConfig(
output_dir="out-lora",
num_train_epochs=3,
per_device_train_batch_size=2,
gradient_accumulation_steps=8,
gradient_checkpointing=True,
learning_rate=2e-4,
lr_scheduler_type="cosine",
warmup_ratio=0.03,
bf16=True,
logging_steps=10,
save_strategy="epoch",
optim="paged_adamw_8bit",
)
dataset = load_dataset("json", data_files="train.jsonl", split="train")
trainer = SFTTrainer(
model=model,
train_dataset=dataset,
peft_config=peft_config,
args=args,
processing_class=tokenizer,
)
trainer.train()
trainer.save_model("out-lora/final")여기서 QLoRA를 LoRA로 바꾸고 싶다면 quantization_config=bnb 한 줄만 빼면 됩니다. 나머지는 그대로입니다. 이 한 줄이 QLoRA와 LoRA를 가르는 전부라는 점이, 앞에서 "메모리에 들어가면 LoRA"라고 말한 판단이 왜 값싼 판단인지 보여줍니다. 바꿔 보고 안 들어가면 되돌리면 됩니다.
유효 배치 크기는 per_device_train_batch_size × gradient_accumulation_steps로 계산합니다. 위 예에서는 2 × 8 = 16입니다. GPU 메모리가 모자라면 앞의 값을 1로 줄이고 뒤를 16으로 올리세요. 학습 결과는 거의 같고 메모리만 줄어듭니다. optim="paged_adamw_8bit"이 앞에서 설명한 페이지드 옵티마이저이고, OOM 스파이크로 학습이 죽는 상황을 막아 줍니다.
학습이 끝나면 out-lora/final 안에는 베이스 모델이 아니라 수십 MB짜리 어댑터 가중치와 설정 파일만 남습니다. 추론할 때는 베이스 모델을 불러온 뒤 PeftModel.from_pretrained(model, "out-lora/final")로 어댑터를 얹습니다.
데이터는 최소 몇 건 있어야 하는가
파인튜닝 문의에서 가장 자주 나오는 질문이고, 답은 "무엇을 바꾸려는지에 따라 자릿수가 다르다" 입니다. 건수 하나로 답이 나오지 않는 이유는 학습시키려는 것이 형식인지, 지식인지, 능력인지가 다르기 때문입니다.
| 목표 | 필요 데이터 규모 | 권장 방법 | 실패 신호 |
|---|---|---|---|
| 말투·출력 형식 고정(JSON 스키마, 답변 톤) | 300~1,000건 | LoRA r=8 | 수백 건에서 이미 형식이 잡히면 더 넣어도 변화 없음 |
| 도메인 용어·사내 규정 반영 | 1,000~10,000건 | LoRA r=16~32 | 검증 손실은 내려가는데 새 질문에 일반화가 안 됨 |
| 분류·추출 등 특정 태스크 | 2,000~20,000건 | LoRA + 태스크별 어댑터 | 클래스 불균형이 그대로 학습됨 |
| 새로운 능력·다른 언어 체계 | 50,000건 이상 | Full FT 검토 | PEFT로 몇 번을 돌려도 상한이 보임 |
| 최신 사실·수시로 바뀌는 정보 | (파인튜닝 부적합) | RAG | 학습 직후에도 오답, 재학습 주기가 감당 안 됨 |
여기서 반드시 짚어야 할 것은 건수보다 품질의 기여가 크다는 점입니다. LIMA 연구(Zhou et al., 2023)는 엄선한 1,000건만으로도 대규모 지시 데이터로 학습한 모델에 근접하는 결과를 보고했습니다. 반대로 중복되고 형식이 흔들리는 2만 건은 1,000건보다 나쁜 결과를 내는 일이 흔합니다. 데이터를 더 모으기 전에 다음 세 가지를 먼저 확인하세요.
- 중복 제거. 같은 질문의 표현만 바꾼 샘플이 수백 건 들어 있으면 모델은 그 패턴만 외웁니다.
- 정답의 일관성. 같은 질문에 서로 다른 정책으로 답한 샘플이 섞여 있으면, 모델은 둘 사이에서 흔들리는 답을 학습합니다. 규정이 바뀐 시점 전후 데이터가 함께 들어가는 경우가 대표적입니다.
- 검증셋 분리. 전체의 10% 정도를 학습에서 완전히 빼 두어야 과적합이 눈에 보입니다. 이걸 안 하면 "학습 손실이 계속 내려가니까 잘 되고 있다"는 착각에 빠집니다.
그리고 대부분의 경우 처음부터 목표 규모를 다 모을 필요가 없습니다. 500건으로 한 번 돌려 보면 "데이터가 부족해서 안 되는 것"인지 "애초에 파인튜닝으로 풀릴 문제가 아닌 것"인지가 갈립니다. 후자라면 데이터를 2만 건 모아도 결과는 같습니다.
파인튜닝 난이도: 실제로 막히는 지점은 따로 있다
"파인튜닝이 어렵다"고 할 때 떠올리는 것은 보통 모델이나 알고리즘입니다. 그런데 실제 프로젝트에서 일정을 잡아먹는 지점은 거의 항상 다른 곳입니다.
| 단계 | 체감 난이도 | 실제로 드는 시간 비중 | 막히는 이유 |
|---|---|---|---|
| 데이터 수집·정제 | 낮다고 착각 | 50~70% | 흩어진 원천, 개인정보 마스킹, 정답 합의 |
| 환경·라이브러리 세팅 | 높다고 착각 | 5~10% | 버전 충돌. 한 번 잡으면 재발 안 함 |
| 학습 실행 | 높다고 착각 | 10% | 대부분 OOM. 배치·체크포인팅으로 해결 |
| 평가 기준 설계 | 낮다고 착각 | 15~25% | "좋아졌다"를 숫자로 정의하지 못함 |
| 서빙·운영 반영 | 중간 | 10% | 추론 양자화 호환성, 어댑터 버전 관리 |
첫 번째 함정은 평가입니다. 학습 손실은 내려가는데 그게 원하는 개선인지 알 수 없는 상태가 가장 흔한 교착입니다. 학습을 시작하기 전에 베이스 모델로 먼저 평가셋을 돌려 점수를 남겨 두세요. 비교 기준 없이 파인튜닝한 모델만 보면 잘한 건지 못한 건지 판단할 방법이 없습니다.
두 번째 함정은 OOM입니다. 그런데 이건 어려운 문제가 아니라 순서가 정해진 문제입니다. 메모리가 터지면 ① per_device_train_batch_size를 1로, ② gradient_checkpointing=True, ③ max_seq_length 축소, ④ QLoRA 전환, ⑤ 모델 크기 하향 순으로 내려가면 거의 해결됩니다. 위로 갈수록 품질 손실이 작으므로 ①부터 시도합니다.
세 번째 함정은 학습률입니다. 앞서 적은 대로 LoRA는 Full 대비 열 배가량 높은 학습률을 씁니다. 1e-5로 LoRA를 돌리면 손실이 거의 움직이지 않고, 이를 "데이터가 부족하다"로 오진하는 일이 자주 생깁니다.
정리하면 파인튜닝의 난이도는 기술이 아니라 데이터와 평가에 있습니다. GPU와 코드는 정해진 순서로 풀리지만, "무엇을 정답으로 볼 것인가"는 조직이 합의해야 하는 문제라서 외주든 내부 개발이든 여기서 가장 오래 걸립니다.
학습이 끝난 뒤: 어댑터를 병합할까, 분리해 둘까
학습 결과물인 LoRA 어댑터는 두 가지 방식으로 운영할 수 있고, 이 선택이 서빙 구조를 결정합니다.
분리 유지(런타임 적용) — 베이스 모델을 한 번만 메모리에 올리고 요청에 따라 어댑터를 갈아 끼웁니다. 고객사별·태스크별 모델이 여러 개 필요할 때 GPU 한 장으로 전부 서빙할 수 있어 비용이 압도적으로 유리합니다. vLLM 같은 서빙 엔진이 멀티 LoRA를 지원합니다. 대신 어댑터 적용만큼 추론 지연이 소폭 늘고, 어댑터 버전 관리 체계가 따로 필요합니다.
병합(merge) — 어댑터 가중치를 베이스 모델에 더해 하나의 모델로 만듭니다. 추론 경로가 일반 모델과 완전히 같아져 지연이 가장 낮고, 어떤 추론 엔진에도 그대로 올라갑니다. 대신 모델 파일이 통째로 하나 더 생기고, 모델 하나당 GPU 메모리를 따로 씁니다.
| 기준 | 분리 유지 | 병합 |
|---|---|---|
| 모델이 여러 개 필요 | 유리 | 불리(모델 수만큼 메모리) |
| 추론 지연 | 소폭 증가 | 가장 낮음 |
| 배포 단순성 | 엔진 지원 필요 | 일반 모델과 동일 |
| A/B 테스트·롤백 | 어댑터 교체로 즉시 | 모델 재배포 필요 |
| 저장 용량 | 어댑터당 수십 MB | 모델당 수십 GB |
한 가지 주의할 점이 있습니다. QLoRA로 학습한 어댑터를 4비트 베이스에 그대로 병합하면 품질이 떨어질 수 있습니다. 어댑터는 bf16으로 학습됐는데 베이스는 NF4로 압축돼 있어 정밀도가 맞지 않기 때문입니다. 병합할 때는 베이스 모델을 bf16으로 다시 불러와 어댑터를 얹은 뒤 병합하고, 그다음 필요하면 서빙용 양자화를 따로 적용하는 순서가 안전합니다.
파인튜닝을 시작하기 전, 정말 파인튜닝이 답일까?
방법을 고르기 전에 한 가지 더 짚을 게 있습니다. 풀고 싶은 문제가 "최신 정보를 정확히 검색해 답하기"라면 파인튜닝보다 RAG가 더 적합할 수 있고, 단순 말투·포맷 교정이라면 프롬프트 엔지니어링만으로 충분할 때도 많습니다. 이 갈림길은 LLM 파인튜닝 vs RAG 완전 가이드에서 의사결정 매트릭스로 정리해 두었습니다. 또한 방법별로 실제 들어가는 비용이 궁금하다면 LLM 파인튜닝 비용 가이드를 함께 참고하시면 좋습니다.
트리숲의 AI-Native 파인튜닝 접근
트리숲(TreeSoop)은 AI-Native Team으로, 팀원 전원이 Claude Code Max 플랜을 기본 개발 환경으로 사용하며 데이터 준비부터 학습·평가·배포까지 하나의 반복 루프로 묶어 진행합니다. 음성인식 같은 도메인 특화 모델을 다뤄 본 경험을 바탕으로, 무작정 Full Fine-tuning을 권하기보다 LoRA·QLoRA로 빠르게 베이스라인을 잡고 품질 목표를 검증한 뒤 필요한 만큼만 자원을 투입하는 방식을 선호합니다. 이런 단계적 접근은 트리숲의 AI-Native 개발 방식에서 일관되게 적용하는 원칙이기도 합니다.
LLM 파인튜닝이나 AI 모델 특화 개발 외주를 검토하고 계시다면 AI-Native 개발사 트리숲에 문의해보세요. 어떤 방법이 ROI 측면에서 합리적인지부터 함께 정리해 드립니다. (문의: 카카오톡 채널)
자주 묻는 질문
Q: LoRA와 QLoRA 중 무엇으로 시작해야 하나요?
GPU 메모리에 여유가 있다면 LoRA가 추론 단계에서 더 단순합니다. GPU가 한 장뿐이거나 모델이 커서 메모리가 부족하다면 QLoRA가 현실적인 선택입니다. 많은 팀이 QLoRA로 가능성을 먼저 검증한 뒤, 운영 단계에서 LoRA나 병합(merge) 방식으로 옮깁니다.
Q: 파인튜닝에 GPU가 꼭 여러 장 필요한가요?
아닙니다. Full Fine-tuning은 대형 GPU가 여러 장 필요할 수 있지만, QLoRA를 쓰면 모델 크기에 따라 GPU 한 장으로도 파인튜닝이 가능합니다. 이것이 PEFT 계열이 등장한 핵심 이유입니다.
Q: LoRA 어댑터를 여러 개 만들어 바꿔 쓸 수 있나요?
가능합니다. 하나의 베이스 모델을 공유하면서 고객사별·태스크별 어댑터를 따로 학습해 두고 상황에 맞게 교체하는 운용이 LoRA의 큰 장점입니다. 저장 용량도 어댑터당 수 MB~수십 MB로 가볍습니다.
Q: 파인튜닝하면 원래 모델의 일반 성능이 떨어지나요?
Full Fine-tuning에서 데이터가 적을 때 카타스트로픽 포게팅으로 일반 능력이 손상될 수 있습니다. LoRA·QLoRA는 원본 가중치를 동결하므로 이 위험이 상대적으로 작습니다. 그래서 데이터가 충분치 않을 때는 PEFT 계열이 더 안전한 선택입니다.
Q: LoRA의 r 값을 올렸는데 품질이 그대로입니다. 더 올려야 하나요?
아닙니다. r보다 target_modules가 결과를 더 크게 가릅니다. 어텐션의 q_proj·v_proj에만 붙어 있다면, r을 올리기 전에 k_proj·o_proj와 FFN(gate/up/down_proj)까지 넓히세요. 그래도 그대로라면 랭크가 아니라 데이터의 문제입니다.
Q: 메모리가 충분한데도 QLoRA를 쓰면 더 좋은가요?
아닙니다. QLoRA는 순전파마다 역양자화가 일어나 같은 GPU에서도 LoRA보다 느립니다. 메모리가 남는 상황이라면 얻는 것 없이 학습 시간만 늘어납니다. LoRA가 들어가면 LoRA, 안 들어갈 때 QLoRA가 기준입니다.
Q: 학습은 됐는데 잘된 건지 판단이 안 됩니다.
파인튜닝을 시작하기 전에 베이스 모델로 평가셋을 먼저 돌려 점수를 남겨 두지 않아서 생기는 문제입니다. 비교 기준이 없으면 어떤 숫자도 해석할 수 없습니다. 평가셋은 학습 데이터에서 완전히 분리한 10% 정도로 만들고, 학습 전 베이스 점수 → 학습 후 점수 순으로 비교하세요.
Q: QLoRA로 학습한 어댑터를 병합해도 되나요?
됩니다만 순서가 중요합니다. 4비트로 압축된 베이스에 bf16 어댑터를 그대로 병합하면 정밀도가 맞지 않아 품질이 떨어질 수 있습니다. 베이스 모델을 bf16으로 다시 불러와 병합한 뒤, 서빙용 양자화는 그다음에 따로 적용하세요.