모델 파인튜닝 기초 — 사전학습 모델부터 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 모델을 내 도메인에 맞게 조정할 수 있는 시대다.

중요한 건 파인튜닝 자체가 목적이 아니라, 문제 해결이 목적이라는 점이다. 프롬프트로 될 일이라면 굳이 학습시키지 말자. 파인튜닝은 "이젠 이게 아니면 안 되겠다" 싶을 때 꺼내는 마지막 카드다.