모델 파인튜닝 기초 — 사전학습 모델부터 LoRA까지
사전학습된 AI 모델을 받아서 내 데이터로 학습시키는 방법을 정리합니다. 전이학습, 파인튜닝, LoRA 개념을 한 번에.
왜 처음부터 학습시키지 않는가?
GPT나 LLaMA 같은 모델을 처음부터 학습시키려면 GPU 수천 대와 수십억 원이 필요하다. 현실적으로 개인이나 일반 기업이 할 수 있는 일이 아니다.
그래서 남이 이미 잘 학습시켜둔 모델을 받아서, 내 데이터로 살짝만 더 학습시키는 방법이 널리 쓰인다. 비유하자면 대학을 졸업한 사람을 회사에 채용해서 사내 업무만 교육시키는 것과 같다. 신입사원을 유치원부터 다시 가르칠 필요는 없다.
[Pre-trained Model] ── (일반 지식)
│
▼
[+ 내 데이터로 추가 학습]
│
▼
[내 도메인 전문 모델]
이 과정을 전이학습(Transfer Learning), 그중에서도 모델 가중치를 조정하는 단계를 **파인튜닝(Fine-tuning)**이라고 부른다.
사전학습 모델(Pre-trained Model)이란?
대규모 데이터로 미리 학습된 모델을 말한다. 이 모델은 이미 "일반적인 패턴"을 알고 있다.
| 분야 | 대표 모델 | 학습 내용 |
|---|---|---|
| 언어 | LLaMA, Mistral, GPT | 수조 개의 텍스트 토큰 |
| 이미지 | ResNet, ViT, CLIP | ImageNet, LAION 등 |
| 음성 | Whisper, Wav2Vec | 수십만 시간의 오디오 |
이런 모델들은 대부분 Hugging Face Hub에서 무료로 받을 수 있다.
from transformers import AutoModel, AutoTokenizer
# 모델과 토크나이저 불러오기
model = AutoModel.from_pretrained("meta-llama/Llama-3-8B")
tokenizer = AutoTokenizer.from_pretrained("meta-llama/Llama-3-8B")
이렇게 받은 모델은 이미 한국어, 영어, 코드, 상식 같은 걸 "어느 정도" 알고 있다. 내가 할 일은 이 모델을 내가 원하는 작업에 특화시키는 것이다.
전이학습 vs 파인튜닝
두 단어는 자주 혼용되지만, 엄밀하게는 범위가 다르다.
- 전이학습(Transfer Learning): 사전학습된 지식을 새로운 작업으로 "옮기는" 모든 과정. 상위 개념.
- 파인튜닝(Fine-tuning): 전이학습의 구체적인 방법 중 하나. 모델 가중치를 내 데이터로 업데이트한다.
전이학습 (Transfer Learning)
├── Feature Extraction (모델은 고정, 마지막 층만 학습)
├── Fine-tuning (모델 일부 또는 전체를 다시 학습)
└── Prompt Engineering (모델은 그대로, 입력만 조정)
Feature Extraction (특징 추출)
모델의 가중치를 얼려두고(freeze), 마지막에 작업용 분류기만 새로 붙인다. 데이터가 적을 때 유리하다.
import torch.nn as nn
from torchvision import models
# 사전학습 ResNet50 불러오기
model = models.resnet50(pretrained=True)
# 모든 파라미터를 고정 (학습 안 함)
for param in model.parameters():
param.requires_grad = False
# 마지막 분류 레이어만 새 작업(10개 클래스)에 맞게 교체
model.fc = nn.Linear(model.fc.in_features, 10)
# 이제 model.fc만 학습된다
Fine-tuning (파인튜닝)
모델 전체 또는 일부를 함께 학습시킨다. 더 많은 데이터와 GPU가 필요하지만 성능이 좋다.
# 전체 파라미터를 학습 가능하게
for param in model.parameters():
param.requires_grad = True
# 학습률(learning rate)은 아주 작게 설정하는 것이 핵심
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-5)
학습률을 작게 하는 이유는 이미 잘 학습된 가중치를 살살 조정해야지, 크게 흔들면 원래 알던 지식까지 망가지기 때문이다. 이 현상을 **파국적 망각(Catastrophic Forgetting)**이라고 한다.
파인튜닝의 종류
1. Full Fine-tuning (전체 파인튜닝)
모델의 모든 파라미터를 학습시킨다. 성능은 가장 좋지만, 7B 모델 기준 최소 80GB GPU가 필요하다.
학습 대상: 모든 파라미터 (예: 7,000,000,000개)
필요 VRAM: 80GB+
장점: 최고 성능
단점: 비용 폭발, 저장 용량도 큼
2. PEFT (Parameter-Efficient Fine-Tuning)
"전체가 아니라 일부만 학습시키자"는 접근이다. 대표적으로 LoRA, Prefix Tuning, Adapter 등이 있다.
학습 대상: 전체의 0.1 ~ 1% 파라미터
필요 VRAM: 16GB (소비자용 GPU 가능)
장점: 싸고 빠름, 여러 태스크용 어댑터 저장 쉬움
단점: 극한 성능은 Full FT보다 살짝 낮을 수 있음
LoRA (Low-Rank Adaptation)
파인튜닝에서 가장 인기 있는 기법이다. 2021년 Microsoft가 발표한 뒤, 지금은 사실상 표준이 됐다.
핵심 아이디어
모델의 원래 가중치 W를 건드리지 않고, 작은 행렬 두 개 A, B를 옆에 붙여서 그것만 학습시킨다.
원본 가중치 W (고정) + 학습되는 ΔW = B × A
↑
작은 저차원 행렬
수식으로 보면:
출력 = W·x + B·A·x
(고정) (학습)
예를 들어 W가 4096 × 4096 행렬이면 파라미터가 1,600만 개다.
이걸 B(4096×8)과 A(8×4096)으로 쪼개면 6만 5천 개로 줄어든다. 약 250배 감소.
왜 작동하는가?
논문의 가설은 이렇다. "파인튜닝으로 만들어지는 변화량은 사실 저차원(low-rank) 공간에 있다."
쉽게 말해, 모델이 새 작업에 적응할 때 실제로 바뀌어야 하는 "방향"은 몇 개 안 된다는 것이다. 그래서 굳이 전체 공간을 다 학습시킬 필요 없이, 작은 부분공간만 학습시켜도 충분하다.
LoRA 실전 코드 (Hugging Face PEFT)
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
# 1. 기본 모델 로드
model = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
# 2. LoRA 설정
lora_config = LoraConfig(
r=8, # rank: 낮을수록 파라미터 ↓, 성능도 ↓
lora_alpha=16, # scaling 계수 (보통 r의 2배)
target_modules=["q_proj", "v_proj"], # attention의 Q, V에만 적용
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
)
# 3. LoRA 래퍼 씌우기
model = get_peft_model(model, lora_config)
# 학습 가능한 파라미터 확인
model.print_trainable_parameters()
# trainable params: 4,194,304 || all params: 8,034,000,000 || trainable%: 0.05
학습이 끝나면 LoRA 가중치만 따로 저장할 수 있다. 크기는 보통 수십 MB에 불과하다.
model.save_pretrained("./my-lora-adapter")
# 용량: 약 30MB (원본 모델은 16GB)
QLoRA — LoRA의 업그레이드
LoRA는 파라미터 수를 줄였지만, 원본 모델은 여전히 메모리에 올려야 한다. QLoRA는 원본 모델을 4비트로 양자화(quantization) 해서 메모리까지 줄인다.
from transformers import BitsAndBytesConfig
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16,
)
model = AutoModelForCausalLM.from_pretrained(
"meta-llama/Llama-3-8B",
quantization_config=bnb_config,
)
이렇게 하면 RTX 4090 (24GB) 한 장으로 7B 모델 파인튜닝이 가능해진다.
파인튜닝 전체 파이프라인
개념만 아는 것보다 실제 흐름을 보는 게 이해가 빠르다.
1. 데이터 준비
└─ {"instruction": "...", "output": "..."} 형식의 JSONL
2. 모델 & 토크나이저 로드
└─ from_pretrained()
3. LoRA 설정 & 래핑
└─ get_peft_model()
4. 학습 (Trainer 또는 SFTTrainer)
└─ train()
5. 저장 & 병합
└─ merge_and_unload() 후 push_to_hub()
최소 실전 예제
from transformers import TrainingArguments
from trl import SFTTrainer
from datasets import load_dataset
dataset = load_dataset("json", data_files="my_data.jsonl")
training_args = TrainingArguments(
output_dir="./output",
num_train_epochs=3,
per_device_train_batch_size=4,
gradient_accumulation_steps=4,
learning_rate=2e-4,
logging_steps=10,
save_strategy="epoch",
bf16=True,
)
trainer = SFTTrainer(
model=model,
args=training_args,
train_dataset=dataset["train"],
tokenizer=tokenizer,
max_seq_length=1024,
)
trainer.train()
trainer.save_model("./final-model")
데이터는 얼마나 필요한가?
가장 많이 나오는 질문이다. 정답은 없지만 감은 있다.
| 방법 | 적정 데이터 수 | 비고 |
|---|---|---|
| Few-shot Prompt | 3 ~ 10개 | 학습 없이 예시만 제공 |
| LoRA 파인튜닝 | 500 ~ 5,000개 | 도메인 특화에 충분한 경우가 많음 |
| Full Fine-tuning | 10,000개 이상 | 데이터가 적으면 오히려 성능 하락 |
데이터 품질 > 데이터 양이다. 잡다한 10만 개보다 잘 정제된 1,000개가 낫다.
언제 파인튜닝을 해야 할까?
파인튜닝은 만능이 아니다. 먼저 다음 순서로 시도해보는 것이 일반적이다.
1. 좋은 프롬프트 엔지니어링으로 해결되는가? ── 되면 끝
2. RAG(외부 지식 검색)로 해결되는가? ── 되면 끝
3. 그래도 안 되는가? → 그때 파인튜닝
파인튜닝이 필요한 전형적 신호는 다음과 같다.
- 특정 말투/포맷을 일관되게 지키게 하고 싶을 때
- 프롬프트에 넣기엔 너무 많은 도메인 지식을 학습시켜야 할 때
- 프롬프트를 짧게 줄여서 비용/속도를 개선하고 싶을 때
- 공개 모델에 없는 능력을 주입하고 싶을 때
반면 최신 뉴스, 실시간 데이터 같은 건 파인튜닝이 아니라 RAG의 영역이다. 모델을 매번 다시 학습시킬 수는 없다.
정리
| 개념 | 한 줄 요약 |
|---|---|
| Pre-trained Model | 이미 대규모 데이터로 학습된 모델. Hugging Face에서 받는다 |
| Transfer Learning | 사전학습된 지식을 내 작업에 옮기는 모든 기법 |
| Fine-tuning | 모델 가중치를 내 데이터로 업데이트하는 구체적 방법 |
| Feature Extraction | 모델 고정, 마지막 층만 학습 (데이터 적을 때) |
| Full Fine-tuning | 모든 파라미터 학습. 성능 최고, 비용 최고 |
| LoRA | 작은 저차원 행렬만 학습. 0.1%만 학습해도 충분 |
| QLoRA | LoRA + 4비트 양자화. 소비자용 GPU로도 학습 가능 |
파인튜닝은 더 이상 거대 기업만의 영역이 아니다. LoRA와 QLoRA 덕분에 노트북 한 대로도 7B 모델을 내 도메인에 맞게 조정할 수 있는 시대다.
중요한 건 파인튜닝 자체가 목적이 아니라, 문제 해결이 목적이라는 점이다. 프롬프트로 될 일이라면 굳이 학습시키지 말자. 파인튜닝은 "이젠 이게 아니면 안 되겠다" 싶을 때 꺼내는 마지막 카드다.